Afivo 0.3
All Classes Namespaces Functions Variables Pages
m_af_types.f90
1!> This module contains the basic types and constants that are used in the
2!> NDIM-dimensional version of Afivo, together with some basic routines.
4#include "cpp_macros.h"
5 use iso_c_binding, only: c_ptr
6
7 implicit none
8 public
9
10 ! dp stands for double precision (8 byte reals)
11 integer, parameter :: dp = kind(0.0d0)
12
13 !> Highest allowed refinement level
14 integer, parameter :: af_max_lvl = 30
15
16 !> Lowest allowed refinement level
17 integer, parameter :: af_min_lvl = 1
18
19 !> Maximum number of variables
20 integer, parameter :: af_max_num_vars = 1024
21
22 !> Value indicating you want to derefine a box
23 integer, parameter :: af_rm_ref = -1
24
25 !> Value indicating you want to keep a box's refinement
26 integer, parameter :: af_keep_ref = 0
27
28 !> Value indicating you want to refine a box
29 integer, parameter :: af_do_ref = 1
30
31 !> The children of a box are removed (for internal use)
32 integer, parameter :: af_derefine = -2
33
34 !> A box will be refined (for internal use)
35 integer, parameter :: af_refine = 2
36
37 !> Special value indicating there is no box
38 integer, parameter :: af_no_box = 0
39
40 !> Special value indicating a physical (non-periodic) boundary
41 integer, parameter :: af_phys_boundary = -1
42
43 !> Each box contains a tag, for which bits can be set. This is the initial
44 !> value, which should not be used by the user
45 integer, parameter :: af_init_tag = -huge(1)
46
47 !> Default coordinate system
48 integer, parameter :: af_xyz = 1
49
50 !> Cylindrical coordinate system
51 integer, parameter :: af_cyl = 2
52
53 !> Names of coordinate systems
54 character(len=*), parameter :: af_coord_names(2) = &
55 ["Cartesian ", "Cylindrical"]
56
57 !> Value to indicate a Dirichlet boundary condition
58 integer, parameter :: af_bc_dirichlet = -10
59
60 !> Value to indicate a Neumann boundary condition
61 integer, parameter :: af_bc_neumann = -11
62
63 !> Value to indicate a continuous boundary condition
64 integer, parameter :: af_bc_continuous = -12
65
66 !> Value to indicate a Dirichlet boundary condition in which a value is copied
67 !> to the ghost cells, without any type of extrapolation. This can be useful
68 !> for hyperbolic PDEs
69 integer, parameter :: af_bc_dirichlet_copy = -13
70
71 !> Maximum length of the names of variables
72 integer, parameter :: af_nlen = 20
73
74 !> Type which contains the indices of all boxes at a refinement level, as well
75 !> as a list with all the "leaf" boxes and non-leaf (parent) boxes
76 type lvl_t
77 integer, allocatable :: ids(:) !< indices of boxes of level
78 integer, allocatable :: leaves(:) !< all ids(:) that are leaves
79 integer, allocatable :: parents(:) !< all ids(:) that have children
80 end type lvl_t
81
82 !> Type that contains the refinement changes in a level
84 integer, allocatable :: add(:) !< Id's of newly added boxes
85 end type ref_lvl_t
86
87 !> Type that contains the refinement changes in a tree
89 integer :: n_add = 0 !< Total number of added boxes
90 integer :: n_rm = 0 !< Total number removed boxes
91 integer, allocatable :: rm(:) !< Ids of removed boxes
92 type(ref_lvl_t), allocatable :: lvls(:) !< Ids of added boxes per level
93 end type ref_info_t
94
95#if NDIM == 1
96 !> Number of children
97 integer, parameter :: af_num_children = 2
98
99 !> Index offset for each child
100 integer, parameter :: af_child_dix(1, 2) = reshape([0,1], [1,2])
101 !> Children adjacent to a neighbor
102 integer, parameter :: af_child_adj_nb(1, 2) = reshape([1,2], [1,2])
103 !> Which children have a low index per dimension
104 logical, parameter :: af_child_low(1, 2) = reshape([.true., .false.], [1, 2])
105 !> Whether a child located in the 'upper' direction (1 or 0)
106
107 !> Number of neighbors
108 integer, parameter :: af_num_neighbors = 2
109 !> Lower-x neighbor
110 integer, parameter :: af_neighb_lowx = 1
111 !> Upper-x neighbor
112 integer, parameter :: af_neighb_highx = 2
113
114 !> Index offsets of neighbors
115 integer, parameter :: af_neighb_dix(1, 2) = reshape([-1,1], [1,2])
116 !> Which neighbors have a lower index
117 logical, parameter :: af_neighb_low(2) = [.true., .false.]
118 !> The low neighbors
119 integer, parameter :: af_low_neighbs(1) = [1]
120 !> The high neighbors
121 integer, parameter :: af_high_neighbs(1) = [2]
122 !> Opposite of nb_low, but now as -1,1 integers
123 integer, parameter :: af_neighb_high_pm(2) = [-1, 1]
124
125 !> Reverse neighbors
126 integer, parameter :: af_neighb_rev(2) = [2, 1]
127 !> Direction (dimension) for a neighbor
128 integer, parameter :: af_neighb_dim(2) = [1, 1]
129#elif NDIM == 2
130 !> Number of children
131 integer, parameter :: af_num_children = 4
132
133 !> Index offset for each child
134 integer, parameter :: af_child_dix(2, 4) = reshape([0,0,1,0,0,1,1,1], [2,4])
135 !> Children adjacent to a neighbor
136 integer, parameter :: af_child_adj_nb(2, 4) = reshape([1,3,2,4,1,2,3,4], [2,4])
137 !> Which children have a low index per dimension
138 logical, parameter :: af_child_low(2, 4) = reshape([.true., .true., &
139 .false., .true., .true., .false., .false., .false.], [2, 4])
140
141 !> Number of neighbors
142 integer, parameter :: af_num_neighbors = 4
143 !> Lower-x neighbor
144 integer, parameter :: af_neighb_lowx = 1
145 !> Upper-x neighbor
146 integer, parameter :: af_neighb_highx = 2
147 !> Lower-y neighbor
148 integer, parameter :: af_neighb_lowy = 3
149 !> Upper-y neighbor
150 integer, parameter :: af_neighb_highy = 4
151
152 !> Index offsets of neighbors
153 integer, parameter :: af_neighb_dix(2, 4) = reshape([-1,0,1,0,0,-1,0,1], [2,4])
154 !> Which neighbors have a lower index
155 logical, parameter :: af_neighb_low(4) = [.true., .false., .true., .false.]
156 !> The low neighbors
157 integer, parameter :: af_low_neighbs(2) = [1, 3]
158 !> The high neighbors
159 integer, parameter :: af_high_neighbs(2) = [2, 4]
160 !> Opposite of nb_low, but now as -1,1 integers
161 integer, parameter :: af_neighb_high_pm(4) = [-1, 1, -1, 1]
162
163 !> Reverse neighbors
164 integer, parameter :: af_neighb_rev(4) = [2, 1, 4, 3]
165 !> Direction (dimension) for a neighbor
166 integer, parameter :: af_neighb_dim(4) = [1, 1, 2, 2]
167#elif NDIM == 3
168 !> Number of children
169 integer, parameter :: af_num_children = 8
170
171 !> Index offset for each child
172 integer, parameter :: af_child_dix(3, 8) = reshape( &
173 [0,0,0, 1,0,0, 0,1,0, 1,1,0, &
174 0,0,1, 1,0,1, 0,1,1, 1,1,1], [3,8])
175 !> Children adjacent to a neighbor
176 integer, parameter :: af_child_adj_nb(4, 6) = reshape( &
177 [1,3,5,7, 2,4,6,8, 1,2,5,6, 3,4,7,8, 1,2,3,4, 5,6,7,8], [4,6])
178 !> Which children have a low index per dimension
179 logical, parameter :: af_child_low(3, 8) = reshape([ &
180 .true., .true., .true., .false., .true., .true., &
181 .true., .false., .true., .false., .false., .true., &
182 .true., .true., .false., .false., .true., .false., &
183 .true., .false., .false., .false., .false., .false.], [3, 8])
184
185 !> Number of neighbors
186 integer, parameter :: af_num_neighbors = 6
187 !> Lower-x neighbor
188 integer, parameter :: af_neighb_lowx = 1
189 !> Upper-x neighbor
190 integer, parameter :: af_neighb_highx = 2
191 !> Lower-y neighbor
192 integer, parameter :: af_neighb_lowy = 3
193 !> Upper-y neighbor
194 integer, parameter :: af_neighb_highy = 4
195 !> Lower-z neighbor
196 integer, parameter :: af_neighb_lowz = 5
197 !> Upper-z neighbor
198 integer, parameter :: af_neighb_highz = 6
199 !> Index offsets of neighbors
200 integer, parameter :: af_neighb_dix(3, 6) = reshape( &
201 [-1,0,0, 1,0,0, 0,-1,0, 0,1,0, 0,0,-1, 0,0,1], [3,6])
202 !> Which neighbors have a lower index
203 logical, parameter :: af_neighb_low(6) = &
204 [.true., .false., .true., .false., .true., .false.]
205 !> The low neighbors
206 integer, parameter :: af_low_neighbs(3) = [1, 3, 5]
207 !> The high neighbors
208 integer, parameter :: af_high_neighbs(3) = [2, 4, 6]
209 !> Opposite of nb_low, but now as -1,1 integers
210 integer, parameter :: af_neighb_high_pm(6) = [-1, 1, -1, 1, -1, 1]
211 !> Reverse neighbors
212 integer, parameter :: af_neighb_rev(6) = [2, 1, 4, 3, 6, 5]
213 !> Direction (dimension) for a neighbor
214 integer, parameter :: af_neighb_dim(6) = [1, 1, 2, 2, 3, 3]
215
216 !> Number of edgse
217 integer, parameter :: af_num_edges = 12
218 !> Coordinate parallel to edge
219 integer, parameter :: af_edge_dim(12) = &
220 [1,1,1,1, 2,2,2,2, 3,3,3,3]
221 !> Direction of edge
222 integer, parameter :: af_edge_dir(3, 12) = reshape( &
223 [0,-1,-1, 0,1,-1, 0,-1,1, 0,1,1, &
224 -1,0,-1, 1,0,-1, -1,0,1, 1,0,1, &
225 -1,-1,0, 1,-1,0, -1,1,0, 1,1,0], [3, 12])
226 !> Neighbors adjacent to edges
227 integer, parameter :: af_nb_adj_edge(2, 12) = reshape( &
228 [3,5, 4,5, 3,6, 4,6, &
229 1,5, 2,5, 1,6, 2,6, &
230 1,3, 2,3, 1,4, 2,4], [2,12])
231 !> Minimum index of edge (1 indicates n_cell + 1)
232 integer, parameter :: af_edge_min_ix(3, 12) = reshape( &
233 [0,0,0, 0,1,0, 0,0,1, 0,1,1, &
234 0,0,0, 1,0,0, 0,0,1, 1,0,1, &
235 0,0,0, 1,0,0, 0,1,0, 1,1,0], [3,12])
236#endif
237
238 !> Collection of methods for a cell-centered variable
240 !> Prolongation method
241 procedure(af_subr_prolong), pointer, nopass :: prolong => null()
242 !> Restriction method
243 procedure(af_subr_restrict), pointer, nopass :: restrict => null()
244 !> Boundary condition routine
245 procedure(af_subr_bc), pointer, nopass :: bc => null()
246 !> Refinement boundary routine
247 procedure(af_subr_rb), pointer, nopass :: rb => null()
248 !> Custom boundary condition routine
249 procedure(af_subr_bc_custom), pointer, nopass :: bc_custom => null()
250 !> Function defining the values of this variables
251 procedure(af_subr_funcval), pointer, nopass :: funcval => null()
252 !> The type of limiter to use for prolongation
253 integer :: prolong_limiter = -1
254 end type af_cc_methods
255
256 !> Value indicating the absence of a stencil
257 integer, parameter :: af_stencil_none = 0
258
259 !> Type for storing a numerical stencil for a box
261 !> The key identifying the stencil
262 integer :: key = af_stencil_none
263 !> Shape of the stencil
264 integer :: shape = af_stencil_none
265 !> What kind of stencil is stored (constant, variable, sparse)
266 integer :: stype = -1
267 !> Whether to correct gradients for cylindrical coordinates
268 logical :: cylindrical_gradient = .false.
269 !> Stencil coefficients for constant stencil, shape (n_coeff)
270 real(dp), allocatable :: c(:)
271 !> Stencil coefficients for variable stencil, shape (n_coeff, IJK)
272 real(dp), allocatable :: v(:, dtimes(:))
273 !> Optional extra scalar, for example to map boundary conditions to
274 !> right-hand side, shape (IJK)
275 real(dp), allocatable :: f(dtimes(:))
276 !> Correction for boundary conditions, shape (IJK)
277 real(dp), allocatable :: bc_correction(dtimes(:))
278 !> Indices of sparse coefficients, shape(NDIM, n)
279 integer, allocatable :: sparse_ix(:, :)
280 !> Values of sparse coefficients, shape(n_coeff, n)
281 real(dp), allocatable :: sparse_v(:, :)
282 end type stencil_t
283
284 !> The basic building block of afivo: a box with cell-centered and face
285 !> centered data, and information about its position, neighbors, children etc.
286 type box_t
287 integer :: lvl !< level of the box
288 logical :: in_use=.false. !< is the box in use?
289 integer :: tag=af_init_tag !< for the user
290 integer :: ix(ndim) !< index in the domain
291 integer :: parent !< index of parent in box list
292 !> index of children in box list
293 integer :: children(af_num_children)
294 !> index of neighbors in box list
295 integer :: neighbors(af_num_neighbors)
296 !> matrix with neighbors (including diagonal ones)
297 integer :: neighbor_mat(dtimes(-1:1))
298 integer :: n_cell !< number of cells per dimension
299 real(dp) :: dr(ndim) !< width/height of a cell
300 real(dp) :: r_min(ndim) !< min coords. of box
301 integer :: coord_t !< Coordinate type (e.g. Cartesian)
302 real(dp), allocatable :: cc(dtimes(:), :) !< cell centered variables
303 real(dp), allocatable :: fc(dtimes(:), :, :) !< face centered variables
304
305 !> Number of physical boundaries
306 integer :: n_bc = 0
307 !> List of boundary condition directions
308 integer, allocatable :: bc_index_to_nb(:)
309 !> Direction to boundary condition index
310 integer :: nb_to_bc_index(af_num_neighbors)
311 !> Boundary condition types
312 integer, allocatable :: bc_type(:, :)
313 !> Stored boundary conditions
314 real(dp), allocatable :: bc_val(:, :, :)
315 !> Coordinates of physical boundaries
316 real(dp), allocatable :: bc_coords(:, :, :)
317
318 !> How many stencils have been stored
319 integer :: n_stencils = 0
320 !> List of stencils
321 type(stencil_t), allocatable :: stencils(:)
322 end type box_t
323
324 !> Type which stores all the boxes and levels, as well as some information
325 !> about the number of boxes, variables and levels.
326 type af_t
327 logical :: ready = .false. !< Is tree ready for use?
328 integer :: box_limit !< maximum number of boxes
329 integer :: highest_lvl = 0 !< highest level present
330 integer :: highest_id = 0 !< highest box index present
331 integer :: n_cell !< number of cells per dimension
332 integer :: n_var_cell = 0 !< number of cell-centered variables
333 integer :: n_var_face = 0 !< number of face-centered variables
334 integer :: coord_t !< Type of coordinates
335 integer :: coarse_grid_size(ndim) = -1 !< Size of the coarse grid (if rectangular)
336 logical :: periodic(ndim) = .false. !< Which dimensions are periodic
337 real(dp) :: r_base(ndim) !< min. coords of box at index (1,1)
338 real(dp) :: dr_base(ndim) !< cell spacing at lvl 1
339
340 !> Names of cell-centered variables
341 character(len=af_nlen) :: cc_names(af_max_num_vars)
342
343 !> Names of face-centered variables
344 character(len=af_nlen) :: fc_names(af_max_num_vars)
345
346 !> Number of copies of the variable (for e.g. time-stepping)
347 integer :: cc_num_copies(af_max_num_vars) = 1
348
349 !> Whether to include the variable in the output
350 logical :: cc_write_output(af_max_num_vars) = .true.
351
352 !> Whether to include a cell-centered variable in binary output
353 logical :: cc_write_binary(af_max_num_vars) = .true.
354
355 !> Whether to include a face-centered variable in binary output
356 logical :: fc_write_binary(af_max_num_vars) = .true.
357
358 !> Methods for cell-centered variables
359 type(af_cc_methods) :: cc_methods(af_max_num_vars)
360
361 !> Number of stencil keys that have been stored
362 integer :: n_stencil_keys_stored = 0
363
364 !> For which cell-centered variables methods have been set
365 logical :: has_cc_method(af_max_num_vars) = .false.
366
367 !> Indices of cell-centered variables with methods
368 integer, allocatable :: cc_auto_vars(:)
369
370 !> Indices of cell-centered variables defined by a function
371 integer, allocatable :: cc_func_vars(:)
372
373 !> List storing the tree levels
374 type(lvl_t) :: lvls(af_min_lvl:af_max_lvl)
375
376 !> List of all boxes
377 type(box_t), allocatable :: boxes(:)
378
379 !> List of all removed boxes (that can be reused)
380 integer, allocatable :: removed_ids(:)
381
382 !> Number of removed boxes
383 integer :: n_removed_ids = 0
384
385 !> Multigrid: index of variable coefficient
386 integer :: mg_i_eps = -1
387
388 !> Multigrid: index of variable for level set function
389 integer :: mg_i_lsf = -1
390
391 !> Current multigrid operator mask
392 integer :: mg_current_operator_mask = -1
393 end type af_t
394
395 !> Type specifying the location of a cell
397 integer :: id = -1 !< Id of the box that the cell is in
398 integer :: ix(ndim) = -1 !< Index inside the box
399 end type af_loc_t
400
401 abstract interface
402 !> Subroutine for setting refinement flags
403 subroutine af_subr_ref(box, cell_flags)
404 import
405 type(box_t), intent(in) :: box !< Box to inspect
406 !> Cell refinement flags
407 integer, intent(out) :: cell_flags(DTIMES(box%n_cell))
408 end subroutine af_subr_ref
409
410 !> Subroutine that gets a box
411 subroutine af_subr(box)
412 import
413 type(box_t), intent(inout) :: box
414 end subroutine af_subr
415
416 !> Subroutine that gets a box and an array of reals
417 subroutine af_subr_arg(box, rarg)
418 import
419 type(box_t), intent(inout) :: box
420 real(dp), intent(in) :: rarg(:)
421 end subroutine af_subr_arg
422
423 !> Subroutine that gets a list of boxes and a box id
424 subroutine af_subr_boxes(boxes, id)
425 import
426 type(box_t), intent(inout) :: boxes(:)
427 integer, intent(in) :: id
428 end subroutine af_subr_boxes
429
430 !> Subroutine that gets a list of boxes, an id and an array of reals
431 subroutine af_subr_boxes_arg(boxes, id, rarg)
432 import
433 type(box_t), intent(inout) :: boxes(:)
434 integer, intent(in) :: id
435 real(dp), intent(in) :: rarg(:)
436 end subroutine af_subr_boxes_arg
437
438 !> Subroutine that gets a tree and a box id
439 subroutine af_subr_tree(tree, id)
440 import
441 type(af_t), intent(inout) :: tree
442 integer, intent(in) :: id
443 end subroutine af_subr_tree
444
445 !> Subroutine that gets a tree, a box id and an array of reals
446 subroutine af_subr_tree_arg(tree, id, rarg)
447 import
448 type(af_t), intent(inout) :: tree
449 integer, intent(in) :: id
450 real(dp), intent(in) :: rarg(:)
451 end subroutine af_subr_tree_arg
452
453 !> To fill ghost cells near refinement boundaries.
454 subroutine af_subr_rb(boxes, id, nb, iv, op_mask)
455 import
456 type(box_t), intent(inout) :: boxes(:) !< Array with all boxes
457 integer, intent(in) :: id !< Id of the box that needs to have ghost cells filled
458 integer, intent(in) :: nb !< Neighbor direction in which ghost cells need to be filled
459 integer, intent(in) :: iv !< Variable for which ghost cells are filled
460 integer, intent(in) :: op_mask !< Mask for multigrid operators
461 end subroutine af_subr_rb
462
463 !> To fill ghost cells near physical boundaries
464 subroutine af_subr_bc(box, nb, iv, coords, bc_val, bc_type)
465 import
466 type(box_t), intent(in) :: box !< Box that needs b.c.
467 integer, intent(in) :: nb !< Direction
468 integer, intent(in) :: iv !< Index of variable
469 real(dp), intent(in) :: coords(NDIM, box%n_cell**(NDIM-1)) !< Coordinates of boundary
470 real(dp), intent(out) :: bc_val(box%n_cell**(NDIM-1)) !< Boundary values
471 integer, intent(out) :: bc_type !< Type of b.c.
472 end subroutine af_subr_bc
473
474 !> To fill ghost cells near physical boundaries in a custom way. If the
475 !> number of ghost cells to fill is greater than one (n_gc > 1), fill ghost
476 !> cells in the optional argument cc.
477 subroutine af_subr_bc_custom(box, nb, iv, n_gc, cc)
478 import
479 type(box_t), intent(inout) :: box !< Box that needs b.c.
480 integer, intent(in) :: nb !< Direction
481 integer, intent(in) :: iv !< Index of variable
482 integer, intent(in) :: n_gc !< Number of ghost cells to fill
483 !> If n_gc > 1, fill ghost cell values in this array instead of box%cc
484 real(dp), intent(inout), optional :: &
485 cc(DTIMES(1-n_gc:box%n_cell+n_gc))
486 end subroutine af_subr_bc_custom
487
488 !> To set cell-centered variables based on a user-defined function. This
489 !> can be useful to avoid recomputing values. The values should also be set
490 !> in ghost cells.
491 subroutine af_subr_funcval(box, iv)
492 import
493 type(box_t), intent(inout) :: box !< Box to fill values in
494 integer, intent(in) :: iv !< Index of variable
495 end subroutine af_subr_funcval
496
497 !> Subroutine for prolongation
498 subroutine af_subr_prolong(box_p, box_c, iv, iv_to, add, limiter)
499 import
500 type(box_t), intent(in) :: box_p !< Parent box
501 type(box_t), intent(inout) :: box_c !< Child box
502 integer, intent(in) :: iv !< Variable to fill
503 integer, intent(in), optional :: iv_to !< Destination variable
504 logical, intent(in), optional :: add !< Add to old values
505 integer, intent(in), optional :: limiter !< What kind of limiter to use
506 end subroutine af_subr_prolong
507
508 !> Subroutine for restriction
509 subroutine af_subr_restrict(box_c, box_p, ivs, use_geometry)
510 import
511 type(box_t), intent(in) :: box_c !< Child box to restrict
512 type(box_t), intent(inout) :: box_p !< Parent box to restrict to
513 integer, intent(in) :: ivs(:) !< Variables to restrict
514 !> If set to false, don't use geometry
515 logical, intent(in), optional :: use_geometry
516 end subroutine af_subr_restrict
517 end interface
518
519 ! *** Types related to multigrid ***
520
521 ! The mg module supports different multigrid operators, and uses these tags to
522 ! identify boxes / operators
523 integer, parameter :: mg_normal_operator = 1
524 integer, parameter :: mg_lsf_operator = 2
525 integer, parameter :: mg_eps_operator = 3
526 integer, parameter :: mg_auto_operator = 4
527
528 integer, parameter :: mg_normal_box = 0 !< Normal box (no eps/lsf)
529 integer, parameter :: mg_lsf_box = 1 !< Box has level set function
530 integer, parameter :: mg_veps_box = 2 !< Box has variable coefficient
531 integer, parameter :: mg_ceps_box = 4 !< Box has constant coefficient /= 1
532
533 integer, parameter :: mg_prolong_linear = 17 !< Linear prolongation
534 integer, parameter :: mg_prolong_sparse = 18 !< Sparse linear prolongation
535 integer, parameter :: mg_prolong_auto = 19 !< Automatic prolongation
536
537 !> Stencil key for level set function distance
538 integer, parameter :: mg_lsf_distance_key = 31
539 !> Stencil key for level set function mask
540 integer, parameter :: mg_lsf_mask_key = 32
541
542 ! Labels for the different steps of a multigrid cycle
543 integer, parameter :: mg_cycle_down = 1
544 integer, parameter :: mg_cycle_up = 3
545
546 !> Generic type for the coarse grid solver
548 type(c_ptr) :: matrix
549 type(c_ptr) :: rhs
550 type(c_ptr) :: phi
551 type(c_ptr) :: solver
552 type(c_ptr) :: grid
553
554 !> Stores coefficient to convert boundary conditions to the right-hand side
555 real(dp), allocatable :: bc_to_rhs(:, :, :)
556
557 !> Stores coefficients to use with level set function
558 real(dp), allocatable :: lsf_fac(dtimes(:), :)
559
560 integer :: symmetric = 1
561 integer :: solver_type = -1
562 integer :: max_iterations = 50
563 integer :: n_cycle_down = 1
564 integer :: n_cycle_up = 1
565 real(dp) :: tolerance = 1e-6_dp
566
567 !> Minimum number of unknowns to use OpenMP parallelization
568 integer :: min_unknowns_for_openmp = 10*1000
569 end type coarse_solve_t
570
571 !> Type to store multigrid options in
572 type :: mg_t
573 !> Variable holding solution
574 integer :: i_phi = -1
575 !> Variable holding right-hand side
576 integer :: i_rhs = -1
577 !> Internal variable (holding prev. solution)
578 integer :: i_tmp = -1
579
580 !> Mask to determine box types
581 integer :: operator_mask = -1
582 !> Index of variable coefficient, automatically set
583 integer :: i_eps = -1
584 !> Optional variable for level set function, automatically set
585 integer :: i_lsf = -1
586
587 !> Number of relaxation cycles in downward sweep
588 integer :: n_cycle_down = 2
589 !> Number of relaxation cycles in upward sweep
590 integer :: n_cycle_up = 2
591
592 !> Whether the structure has been initialized
593 logical :: initialized = .false.
594 !> Does the smoother use corner ghost cells
595 logical :: use_corners = .false.
596 !> Whether to subtract mean from solution
597 logical :: subtract_mean = .false.
598
599 !> Store lambda^2 for Helmholtz equations (L phi - lamda phi = f)
600 real(dp) :: helmholtz_lambda = 0.0_dp
601
602 !> Boundary value for level set function (if lsf_boundary_function is not
603 !> set)
604 real(dp) :: lsf_boundary_value = 0.0_dp
605
606 !> Safety factor for gradient of level set function
607 real(dp) :: lsf_gradient_safety_factor = 1.5_dp
608
609 !> Minimal length scale to resolve (on coarser grids)
610 real(dp) :: lsf_length_scale = 1e100_dp
611
612 !> Tolerance for line search algorithm
613 real(dp) :: lsf_tol = 1e-8_dp
614
615 !> Minimum relative distance to boundaries (to avoid division by zero)
616 real(dp) :: lsf_min_rel_distance = 1e-4_dp
617
618 !> Whether to use a custom prolongation stencil
619 logical :: lsf_use_custom_prolongation = .false.
620
621 !> Level-set function
622 procedure(mg_func_lsf), pointer, nopass :: lsf => null()
623
624 !> Routine to determine distance from level-set function
625 procedure(mg_lsf_distf), pointer, nopass :: lsf_dist => null()
626
627 !> Function to get boundary value for level set function
628 procedure(mg_func_lsf), pointer, nopass :: lsf_boundary_function => null()
629
630 !> Routine to call for filling ghost cells near physical boundaries
631 procedure(af_subr_bc), pointer, nopass :: sides_bc => null()
632
633 !> Routine to call for filling ghost cells near refinement boundaries
634 procedure(af_subr_rb), pointer, nopass :: sides_rb => null()
635
636 !> Subroutine that performs the (non)linear operator
637 procedure(mg_box_op), pointer, nopass :: box_op => null()
638
639 !> What kind of operator to use
640 integer :: operator_type = mg_auto_operator
641
642 !> Key indicating which stencil is to be used for the operator
643 integer :: operator_key = af_stencil_none
644
645 !> What kind of prolongation operator to use
646 integer :: prolongation_type = mg_prolong_auto
647
648 !> Key indicating which stencil is to be used for the operator
649 integer :: prolongation_key = af_stencil_none
650
651 !> Subroutine that performs Gauss-Seidel relaxation on a box
652 procedure(mg_box_gsrb), pointer, nopass :: box_gsrb => null()
653
654 !> Subroutine that corrects the children of a box
655 procedure(mg_box_corr), pointer, nopass :: box_corr => null()
656
657 !> Subroutine for restriction
658 procedure(mg_box_rstr), pointer, nopass :: box_rstr => null()
659
660 !> Subroutine for getting the stencil
661 procedure(mg_box_stencil), pointer, nopass :: box_stencil => null()
662
663 !> Structure holding data for the coarse grid solver
664 type(coarse_solve_t) :: csolver
665 end type mg_t
666
667 abstract interface
668 !> Subroutine that performs A * cc(..., i_in) = cc(..., i_out)
669 subroutine mg_box_op(box, i_out, mg)
670 import
671 type(box_t), intent(inout) :: box !< The box to operate on
672 type(mg_t), intent(in) :: mg !< Multigrid options
673 integer, intent(in) :: i_out !< Index of output variable
674 end subroutine mg_box_op
675
676 !> Subroutine that performs Gauss-Seidel relaxation
677 subroutine mg_box_gsrb(box, redblack_cntr, mg)
678 import
679 type(box_t), intent(inout) :: box !< The box to operate on
680 type(mg_t), intent(in) :: mg !< Multigrid options
681 integer, intent(in) :: redblack_cntr !< Iteration counter
682 end subroutine mg_box_gsrb
683
684 subroutine mg_box_corr(box_p, box_c, mg)
685 import
686 type(box_t), intent(inout) :: box_c
687 type(box_t), intent(in) :: box_p
688 type(mg_t), intent(in) :: mg !< Multigrid options
689 end subroutine mg_box_corr
690
691 subroutine mg_box_rstr(box_c, box_p, iv, mg)
692 import
693 type(box_t), intent(in) :: box_c !< Child box to restrict
694 type(box_t), intent(inout) :: box_p !< Parent box to restrict to
695 integer, intent(in) :: iv !< Variable to restrict
696 type(mg_t), intent(in) :: mg !< Multigrid options
697 end subroutine mg_box_rstr
698
699 subroutine mg_box_stencil(box, mg, stencil, bc_to_rhs, lsf_fac)
700 import
701 type(box_t), intent(in) :: box
702 type(mg_t), intent(in) :: mg
703 real(dp), intent(inout) :: stencil(2*NDIM+1, DTIMES(box%n_cell))
704 real(dp), intent(inout) :: bc_to_rhs(box%n_cell**(NDIM-1), af_num_neighbors)
705 real(dp), intent(inout) :: lsf_fac(DTIMES(box%n_cell))
706 end subroutine mg_box_stencil
707
708 !> Level set function
709 real(dp) function mg_func_lsf(rr)
710 import
711 real(dp), intent(in) :: rr(ndim) !< Coordinates
712 end function mg_func_lsf
713
714 !> Compute distance to boundary starting at point a going to point b, in
715 !> the range from [0, 1], with 1 meaning there is no boundary
716 real(dp) function mg_lsf_distf(a, b, mg)
717 import
718 real(dp), intent(in) :: a(ndim)
719 real(dp), intent(in) :: b(ndim)
720 type(mg_t), intent(in) :: mg
721 end function mg_lsf_distf
722 end interface
723
724contains
725
726 !> Get number of threads
727 integer function af_get_max_threads()
728 use omp_lib, only: omp_get_max_threads
729 af_get_max_threads = omp_get_max_threads()
730 end function af_get_max_threads
731
732 !> Get tree info
733 subroutine af_print_info(tree)
734 type(af_t), intent(in) :: tree !< The tree
735 character(len=15) :: fmt_string
736
737 if (.not. allocated(tree%boxes)) then
738 print *, "af_init has not been called for this tree"
739 else if (.not. tree%ready) then
740 print *, "af_set_base has not been called for this tree"
741 else
742 write(*, "(A)") ""
743 write(*, "(A)") " *** af_print_info(tree) ***"
744 write(*, "(A,I10)") " Current maximum level: ", tree%highest_lvl
745 write(*, "(A,I10)") " Number of boxes used: ", af_num_boxes_used(tree)
746 write(*, "(A,I10)") " Number of leaves used: ", af_num_leaves_used(tree)
747 write(*, "(A,I10)") " Memory limit(boxes): ", tree%box_limit
748 write(*, "(A,E10.2)") " Memory limit(GByte): ", &
749 tree%box_limit * 0.5_dp**30 * &
750 af_box_bytes(tree%n_cell, tree%n_var_cell, tree%n_var_face)
751 write(*, "(A,I10)") " Highest id in box list: ", tree%highest_id
752 write(*, "(A,I10)") " Size of box list: ", size(tree%boxes)
753 write(*, "(A,I10)") " Box size (cells): ", tree%n_cell
754 write(*, "(A,I10)") " Number of cc variables: ", tree%n_var_cell
755 write(*, "(A,I10)") " Number of fc variables: ", tree%n_var_face
756 write(*, "(A,A15)") " Type of coordinates: ", &
757 af_coord_names(tree%coord_t)
758 write(fmt_string, "(A,I0,A)") "(A,", ndim, "E10.2)"
759 write(*, fmt_string) " min. coords: ", tree%r_base
760 write(*, fmt_string) " dr at level one: ", tree%dr_base
761 write(*, "(A,E10.2)") " minval(dr): ", af_min_dr(tree)
762 write(*, "(A)") ""
763 end if
764 end subroutine af_print_info
765
766 pure function af_box_bytes(n_cell, n_var_cell, n_var_face) result(box_bytes)
767 integer, intent(in) :: n_cell !< number of cells per dimension
768 integer, intent(in) :: n_var_cell !< number of cell-centered variables
769 integer, intent(in) :: n_var_face !< number of face-centered variables
770 integer :: box_bytes
771 type(box_t) :: dummy_box
772
773 box_bytes = 8 * n_var_cell * (n_cell + 2)**ndim + &
774 8 * n_var_face * (n_cell + 1) * n_cell**(ndim-1) + &
775 int(storage_size(dummy_box) / 8)
776 end function af_box_bytes
777
778 pure function af_num_boxes_used(tree) result(n_boxes)
779 type(af_t), intent(in) :: tree
780 integer :: n_boxes, lvl
781
782 n_boxes = 0
783 do lvl = 1, tree%highest_lvl
784 n_boxes = n_boxes + size(tree%lvls(lvl)%ids)
785 end do
786 end function af_num_boxes_used
787
788 pure function af_num_leaves_used(tree) result(n_boxes)
789 type(af_t), intent(in) :: tree
790 integer :: n_boxes, lvl
791
792 n_boxes = 0
793 do lvl = 1, tree%highest_lvl
794 n_boxes = n_boxes + size(tree%lvls(lvl)%leaves)
795 end do
796 end function af_num_leaves_used
797
798 pure function af_num_cells_used(tree) result(n_cells)
799 type(af_t), intent(in) :: tree
800 integer :: n_cells
801
802 n_cells = af_num_leaves_used(tree) * tree%n_cell**ndim
803 end function af_num_cells_used
804
805 pure function af_total_volume(tree) result(vol)
806 type(af_t), intent(in) :: tree
807 real(dp) :: vol
808 integer :: i, id
809 real(dp) :: r0, r1, box_len(ndim)
810 real(dp), parameter :: pi = acos(-1.0_dp)
811
812 box_len = tree%n_cell * tree%dr_base
813
814 if (ndim == 2 .and. tree%coord_t == af_cyl) then
815 vol = 0.0_dp
816 do i = 1, size(tree%lvls(1)%ids)
817 id = tree%lvls(1)%ids(i)
818 r0 = tree%boxes(id)%r_min(1)
819 r1 = r0 + box_len(1)
820 vol = vol + pi * (r1**2 - r0**2) * box_len(ndim)
821 end do
822 else
823 vol = size(tree%lvls(1)%ids) * product(box_len)
824 end if
825 end function af_total_volume
826
827 !> Return .true. if a box has children
828 elemental logical function af_has_children(box)
829 type(box_t), intent(in) :: box
830
831 ! Boxes are either fully refined or not, so we only need to check one of the
832 ! children
833 af_has_children = (box%children(1) /= af_no_box)
834 end function af_has_children
835
836 !> Return .true. where there is a physical/periodic boundary. Detecting
837 !> physical boundaries is straightforward (simply test whether neighbors(i) <
838 !> af_no_box), but periodic boundaries require a comparison of their spatial
839 !> index.
840 pure function af_is_phys_boundary(boxes, id, nbs) result(boundary)
841 type(box_t), intent(in) :: boxes(:) !< List of boxes
842 integer, intent(in) :: id !< Box to inspect
843 integer, intent(in) :: nbs(:) !< Neighbor directions
844 logical :: boundary(size(nbs))
845 integer :: n, nb, p_id, nb_id, dim, dix
846
847 do n = 1, size(nbs)
848 nb = nbs(n)
849 nb_id = boxes(id)%neighbors(nb)
850
851 if (nb_id < af_no_box) then
852 boundary(n) = .true. ! Physical boundary
853 else ! There could be a periodic boundary
854 dim = af_neighb_dim(nb)
855
856 if (nb_id == af_no_box) then
857 ! Refinement boundary, compute index difference on parent (which is
858 ! guaranteed to be there)
859 p_id = boxes(id)%parent
860 nb_id = boxes(p_id)%neighbors(nb)
861 dix = boxes(nb_id)%ix(dim) - boxes(p_id)%ix(dim)
862 else
863 ! Normal neighbor, compute index difference
864 dix = boxes(nb_id)%ix(dim) - boxes(id)%ix(dim)
865 end if
866
867 if (dix /= af_neighb_high_pm(nb)) then
868 ! The difference in index is not the expected +-1, so a periodic
869 ! boundary
870 boundary(n) = .true.
871 else
872 boundary(n) = .false.
873 end if
874 end if
875 end do
876
877 end function af_is_phys_boundary
878
879 !> Check whether a refinement boundary is present, either fine-to-coarse or
880 !> coarse-to-fine
881 pure logical function af_is_ref_boundary(boxes, id, nb)
882 type(box_t), intent(in) :: boxes(:) !< List of boxes
883 integer, intent(in) :: id !< Box to inspect
884 integer, intent(in) :: nb !< Neighbor direction
885 integer :: nb_id
886
887 af_is_ref_boundary = .false.
888 nb_id = boxes(id)%neighbors(nb)
889
890 if (nb_id == af_no_box) then
891 af_is_ref_boundary = .true.
892 else if (nb_id > af_no_box) then
893 if (.not. af_has_children(boxes(id)) .and. &
894 af_has_children(boxes(nb_id))) then
895 af_is_ref_boundary = .true.
896 end if
897 end if
898 end function af_is_ref_boundary
899
900 !> Get the offset of a box with respect to its parent (e.g. in 2d, there can
901 !> be a child at offset 0,0, one at n_cell/2,0, one at 0,n_cell/2 and one at
902 !> n_cell/2, n_cell/2)
903 pure function af_get_child_offset(box, nb) result(ix_offset)
904 type(box_t), intent(in) :: box !< A child box
905 integer, intent(in), optional :: nb !< Optional: get index on parent neighbor
906 integer :: ix_offset(ndim)
907
908 ix_offset = iand(box%ix-1, 1) * ishft(box%n_cell, -1) ! * n_cell / 2
909 if (present(nb)) ix_offset = ix_offset - af_neighb_dix(:, nb) * box%n_cell
910 end function af_get_child_offset
911
912 !> Given a cell index on box, get index of the closest cell at its parent
913 pure function af_get_ix_on_parent(box, ix) result(p_ix)
914 type(box_t), intent(in) :: box !< A child box
915 integer, intent(in) :: ix(ndim) !< Index on child box
916 integer :: p_ix(ndim)
917 p_ix = af_get_child_offset(box) + ishft(ix+1, -1)
918 end function af_get_ix_on_parent
919
920 !> Given a cell index on box, get index on a neighbor
921 pure function af_get_ix_on_neighb(box, ix, nb) result(nb_ix)
922 type(box_t), intent(in) :: box !< A box
923 integer, intent(in) :: ix(ndim) !< Index on box
924 integer, intent(in) :: nb !< Neighbor identifier
925 integer :: nb_ix(ndim), nb_dim
926
927 nb_dim = af_neighb_dim(nb)
928 nb_ix = ix
929 nb_ix(nb_dim) = nb_ix(nb_dim) - af_neighb_high_pm(nb) * box%n_cell
930 end function af_get_ix_on_neighb
931
932 !> Given a list of neighbor directions, compute the index offset
933 pure function af_neighb_offset(nbs) result(dix)
934 integer, intent(in) :: nbs(:) !< List of neighbor directions
935 integer :: n, dim, dix(ndim)
936
937 dix = 0
938 do n = 1, size(nbs)
939 dim = af_neighb_dim(nbs(n))
940 dix(dim) = dix(dim) + af_neighb_high_pm(nbs(n))
941 end do
942 end function af_neighb_offset
943
944 !> Get index range of boundary cells inside a box facing neighbor nb
945 subroutine af_get_index_bc_inside(nb, nc, n_gc, lo, hi)
946 integer, intent(in) :: nb !< Neighbor direction
947 integer, intent(in) :: nc !< box size
948 integer, intent(in) :: n_gc !< Number of ghost cells
949 integer, intent(out) :: lo(NDIM)
950 integer, intent(out) :: hi(NDIM)
951 integer :: nb_dim
952
953 ! Determine index range next to boundary
954 nb_dim = af_neighb_dim(nb)
955 lo(:) = 1
956 hi(:) = nc
957 if (af_neighb_low(nb)) then
958 lo(nb_dim) = 1
959 hi(nb_dim) = n_gc
960 else
961 lo(nb_dim) = nc - n_gc + 1
962 hi(nb_dim) = nc
963 end if
964 end subroutine af_get_index_bc_inside
965
966 !> Get index range of ghost cells facing neighbor nb
967 subroutine af_get_index_bc_outside(nb, nc, n_gc, lo, hi)
968 integer, intent(in) :: nb !< Neighbor direction
969 integer, intent(in) :: nc !< box size
970 integer, intent(in) :: n_gc !< Number of ghost cells
971 integer, intent(out) :: lo(NDIM)
972 integer, intent(out) :: hi(NDIM)
973 integer :: nb_dim
974
975 ! Determine index range next to boundary
976 nb_dim = af_neighb_dim(nb)
977 lo(:) = 1
978 hi(:) = nc
979 if (af_neighb_low(nb)) then
980 lo(nb_dim) = 1 - n_gc
981 hi(nb_dim) = 0
982 else
983 lo(nb_dim) = nc + 1
984 hi(nb_dim) = nc + n_gc
985 end if
986 end subroutine af_get_index_bc_outside
987
988 !> Get index range of boundary FACES inside a box facing neighbor nb
989 subroutine af_get_index_bface_inside(nb, nc, n_gc, lo, hi)
990 integer, intent(in) :: nb !< Neighbor direction
991 integer, intent(in) :: nc !< box size
992 integer, intent(in) :: n_gc !< Number of ghost cells
993 integer, intent(out) :: lo(NDIM)
994 integer, intent(out) :: hi(NDIM)
995 integer :: nb_dim
996
997 ! Determine index range next to boundary
998 nb_dim = af_neighb_dim(nb)
999 lo(:) = 1
1000 hi(:) = nc
1001 if (af_neighb_low(nb)) then
1002 lo(nb_dim) = 1
1003 hi(nb_dim) = n_gc
1004 else
1005 lo(nb_dim) = nc - n_gc + 2
1006 hi(nb_dim) = nc + 1
1007 end if
1008 end subroutine af_get_index_bface_inside
1009
1010 !> Compute the 'child index' for a box with spatial index ix. With 'child
1011 !> index' we mean the index in the children(:) array of its parent.
1012 pure integer function af_ix_to_ichild(ix)
1013 integer, intent(in) :: ix(ndim) !< Spatial index of the box
1014 ! The index can range from 1 (all ix odd) and 2**NDIM (all ix even)
1015#if NDIM == 1
1016 af_ix_to_ichild = 2 - iand(ix(1), 1)
1017#elif NDIM == 2
1018 af_ix_to_ichild = 4 - 2 * iand(ix(2), 1) - iand(ix(1), 1)
1019#elif NDIM == 3
1020 af_ix_to_ichild = &
1021 8 - 4 * iand(ix(3), 1) - 2 * iand(ix(2), 1) - iand(ix(1), 1)
1022#endif
1023 end function af_ix_to_ichild
1024
1025 !> Get the cell index in which r lies. This routine does not check whether r
1026 !> is actually located inside the box.
1027 pure function af_cc_ix(box, r) result(cc_ix)
1028 type(box_t), intent(in) :: box
1029 real(dp), intent(in) :: r(ndim)
1030 integer :: cc_ix(ndim)
1031 cc_ix = ceiling((r - box%r_min) / box%dr)
1032 end function af_cc_ix
1033
1034 !> Get the location of the cell center with index cc_ix
1035 pure function af_r_cc(box, cc_ix) result(r)
1036 type(box_t), intent(in) :: box
1037 integer, intent(in) :: cc_ix(ndim)
1038 real(dp) :: r(ndim)
1039 r = box%r_min + (cc_ix-0.5_dp) * box%dr
1040 end function af_r_cc
1041
1042 !> Get the location of the face parallel to dim with index fc_ix
1043 pure function af_r_fc(box, dim, fc_ix) result(r)
1044 type(box_t), intent(in) :: box
1045 integer, intent(in) :: dim
1046 integer, intent(in) :: fc_ix(ndim)
1047 real(dp) :: r(ndim)
1048 r = box%r_min + (fc_ix-0.5_dp) * box%dr
1049 r(dim) = r(dim) - 0.5_dp * box%dr(dim)
1050 end function af_r_fc
1051
1052 !> Get a general location with index cc_ix (like af_r_cc but using reals)
1053 pure function af_rr_cc(box, cc_ix) result(r)
1054 type(box_t), intent(in) :: box
1055 real(dp), intent(in) :: cc_ix(ndim)
1056 real(dp) :: r(ndim)
1057 r = box%r_min + (cc_ix-0.5_dp) * box%dr
1058 end function af_rr_cc
1059
1060 !> Return the coordinate of the center of a box
1061 pure function af_r_center(box) result(r_center)
1062 type(box_t), intent(in) :: box
1063 real(dp) :: r_center(ndim)
1064 r_center = box%r_min + 0.5_dp * box%n_cell * box%dr
1065 end function af_r_center
1066
1067 !> Return finest dr that is used in the tree
1068 pure function af_min_dr(tree) result(dr)
1069 type(af_t), intent(in) :: tree
1070 real(dp) :: dr !< Output: dr at the finest lvl of the tree
1071 dr = minval(af_lvl_dr(tree, tree%highest_lvl))
1072 end function af_min_dr
1073
1074 !> Return dr at lvl
1075 pure function af_lvl_dr(tree, lvl) result(dr)
1076 type(af_t), intent(in) :: tree
1077 integer, intent(in) :: lvl
1078 real(dp) :: dr(ndim) !< Output: dr at the finest lvl of the tree
1079 dr = tree%dr_base * 0.5_dp**(lvl-1)
1080 end function af_lvl_dr
1081
1082 subroutine af_set_box_gc(box, nb, iv, gc_scalar, gc_array)
1083 type(box_t), intent(inout) :: box !< Box to operate on
1084 integer, intent(in) :: nb !< Ghost cell direction
1085 integer, intent(in) :: iv !< Ghost cell variable
1086 real(dp), optional, intent(in) :: gc_scalar !< Scalar value for ghost cells
1087#if NDIM == 1
1088 real(dp), optional, intent(in) :: gc_array(1) !< Array for ghost cells
1089#elif NDIM == 2
1090 real(dp), optional, intent(in) :: gc_array(box%n_cell) !< Array for ghost cells
1091#elif NDIM == 3
1092 !> Array for ghost cells
1093 real(dp), optional, intent(in) :: gc_array(box%n_cell, box%n_cell)
1094#endif
1095 integer :: nc
1096
1097 nc = box%n_cell
1098
1099 if (present(gc_array)) then
1100 select case (nb)
1101#if NDIM == 1
1102 case (af_neighb_lowx)
1103 box%cc(0, iv) = gc_array(1)
1104 case (af_neighb_highx)
1105 box%cc(nc+1, iv) = gc_array(1)
1106#elif NDIM == 2
1107 case (af_neighb_lowx)
1108 box%cc(0, 1:nc, iv) = gc_array
1109 case (af_neighb_highx)
1110 box%cc(nc+1, 1:nc, iv) = gc_array
1111 case (af_neighb_lowy)
1112 box%cc(1:nc, 0, iv) = gc_array
1113 case (af_neighb_highy)
1114 box%cc(1:nc, nc+1, iv) = gc_array
1115#elif NDIM == 3
1116 case (af_neighb_lowx)
1117 box%cc(0, 1:nc, 1:nc, iv) = gc_array
1118 case (af_neighb_highx)
1119 box%cc(nc+1, 1:nc, 1:nc, iv) = gc_array
1120 case (af_neighb_lowy)
1121 box%cc(1:nc, 0, 1:nc, iv) = gc_array
1122 case (af_neighb_highy)
1123 box%cc(1:nc, nc+1, 1:nc, iv) = gc_array
1124 case (af_neighb_lowz)
1125 box%cc(1:nc, 1:nc, 0, iv) = gc_array
1126 case (af_neighb_highz)
1127 box%cc(1:nc, 1:nc, nc+1, iv) = gc_array
1128#endif
1129 end select
1130 else if (present(gc_scalar)) then
1131 select case (nb)
1132#if NDIM == 1
1133 case (af_neighb_lowx)
1134 box%cc(0, iv) = gc_scalar
1135 case (af_neighb_highx)
1136 box%cc(nc+1, iv) = gc_scalar
1137#elif NDIM == 2
1138 case (af_neighb_lowx)
1139 box%cc(0, 1:nc, iv) = gc_scalar
1140 case (af_neighb_highx)
1141 box%cc(nc+1, 1:nc, iv) = gc_scalar
1142 case (af_neighb_lowy)
1143 box%cc(1:nc, 0, iv) = gc_scalar
1144 case (af_neighb_highy)
1145 box%cc(1:nc, nc+1, iv) = gc_scalar
1146#elif NDIM == 3
1147 case (af_neighb_lowx)
1148 box%cc(0, 1:nc, 1:nc, iv) = gc_scalar
1149 case (af_neighb_highx)
1150 box%cc(nc+1, 1:nc, 1:nc, iv) = gc_scalar
1151 case (af_neighb_lowy)
1152 box%cc(1:nc, 0, 1:nc, iv) = gc_scalar
1153 case (af_neighb_highy)
1154 box%cc(1:nc, nc+1, 1:nc, iv) = gc_scalar
1155 case (af_neighb_lowz)
1156 box%cc(1:nc, 1:nc, 0, iv) = gc_scalar
1157 case (af_neighb_highz)
1158 box%cc(1:nc, 1:nc, nc+1, iv) = gc_scalar
1159#endif
1160 end select
1161 else
1162 stop "af_set_box_gc: requires gc_scalar or gc_array"
1163 end if
1164 end subroutine af_set_box_gc
1165
1166#if NDIM == 2
1167 !> Get the radius of the cell center with first index i
1168 pure function af_cyl_radius_cc(box, i) result(r)
1169 type(box_t), intent(in) :: box
1170 integer, intent(in) :: i
1171 real(dp) :: r
1172 r = box%r_min(1) + (i-0.5_dp) * box%dr(1)
1173 end function af_cyl_radius_cc
1174
1175 !> Get the volume of the cell with first index i
1176 pure function af_cyl_volume_cc(box, i) result(dvol)
1177 type(box_t), intent(in) :: box
1178 integer, intent(in) :: i
1179 real(dp), parameter :: two_pi = 2 * acos(-1.0_dp)
1180 real(dp) :: dvol
1181 dvol = two_pi * (box%r_min(1) + (i-0.5_dp) * box%dr(1)) * product(box%dr)
1182 end function af_cyl_volume_cc
1183
1184 !> Get the normalized weights of the 'inner' and 'outer' children of a cell
1185 !> with index ix. Note that the cell centers of the children are located at
1186 !> -/+ 0.25 dr compared to the parent.
1187 subroutine af_cyl_child_weights(box, i, inner, outer)
1188 type(box_t), intent(in) :: box
1189 integer, intent(in) :: i
1190 real(dp), intent(out) :: inner, outer
1191 real(dp) :: tmp
1192
1193 tmp = 0.25_dp * box%dr(1) / af_cyl_radius_cc(box, i)
1194 inner = 1 - tmp
1195 outer = 1 + tmp
1196 end subroutine af_cyl_child_weights
1197
1198 !> Get the factors for the left and right flux in each cell
1199 subroutine af_cyl_flux_factors(box, flux_factors)
1200 type(box_t), intent(in) :: box
1201 real(dp), intent(out) :: flux_factors(2, box%n_cell)
1202 integer :: i
1203 real(dp) :: r, inv_r
1204
1205 do i = 1, box%n_cell
1206 r = af_cyl_radius_cc(box, i)
1207 inv_r = 1/r
1208 flux_factors(1, i) = (r - 0.5_dp * box%dr(1)) * inv_r
1209 flux_factors(2, i) = (r + 0.5_dp * box%dr(1)) * inv_r
1210 end do
1211 end subroutine af_cyl_flux_factors
1212#endif
1213
1214 !> Get coordinates at the faces of a box boundary
1215 subroutine af_get_face_coords(box, nb, coords)
1216 type(box_t), intent(in) :: box
1217 integer, intent(in) :: nb
1218 real(dp), intent(out) :: coords(NDIM, box%n_cell**(NDIM-1))
1219 integer :: i, nb_dim, bc_dim(NDIM-1)
1220 integer, parameter :: all_dims(NDIM) = [(i, i = 1, ndim)]
1221 real(dp) :: rmin(NDIM)
1222#if NDIM == 3
1223 integer :: j, ix
1224#endif
1225
1226 nb_dim = af_neighb_dim(nb)
1227 bc_dim = pack(all_dims, all_dims /= nb_dim)
1228 rmin(bc_dim) = box%r_min(bc_dim) + 0.5_dp * box%dr(bc_dim)
1229
1230 if (af_neighb_low(nb)) then
1231 rmin(nb_dim) = box%r_min(nb_dim)
1232 else
1233 rmin(nb_dim) = box%r_min(nb_dim) + box%n_cell * box%dr(nb_dim)
1234 end if
1235
1236#if NDIM == 1
1237 coords(nb_dim, 1) = rmin(nb_dim)
1238#elif NDIM == 2
1239 do i = 1, box%n_cell
1240 coords(bc_dim, i) = rmin(bc_dim) + (i-1) * box%dr(bc_dim)
1241 coords(nb_dim, i) = rmin(nb_dim)
1242 end do
1243#elif NDIM == 3
1244 ix = 0
1245 do j = 1, box%n_cell
1246 do i = 1, box%n_cell
1247 ix = ix + 1
1248 coords(bc_dim, ix) = rmin(bc_dim) + [i-1, j-1] * box%dr(bc_dim)
1249 coords(nb_dim, ix) = rmin(nb_dim)
1250 end do
1251 end do
1252#endif
1253 end subroutine af_get_face_coords
1254
1255end module m_af_types
Subroutine that gets a box and an array of reals.
Definition: m_af_types.f90:417
To fill ghost cells near physical boundaries in a custom way. If the number of ghost cells to fill is...
Definition: m_af_types.f90:477
To fill ghost cells near physical boundaries.
Definition: m_af_types.f90:464
Subroutine that gets a list of boxes, an id and an array of reals.
Definition: m_af_types.f90:431
Subroutine that gets a list of boxes and a box id.
Definition: m_af_types.f90:424
To set cell-centered variables based on a user-defined function. This can be useful to avoid recomput...
Definition: m_af_types.f90:491
Subroutine for prolongation.
Definition: m_af_types.f90:498
To fill ghost cells near refinement boundaries.
Definition: m_af_types.f90:454
Subroutine for setting refinement flags.
Definition: m_af_types.f90:403
Subroutine for restriction.
Definition: m_af_types.f90:509
Subroutine that gets a tree, a box id and an array of reals.
Definition: m_af_types.f90:446
Subroutine that gets a tree and a box id.
Definition: m_af_types.f90:439
Subroutine that gets a box.
Definition: m_af_types.f90:411
Subroutine that performs Gauss-Seidel relaxation.
Definition: m_af_types.f90:677
Subroutine that performs A * cc(..., i_in) = cc(..., i_out)
Definition: m_af_types.f90:669
Level set function.
Definition: m_af_types.f90:709
Compute distance to boundary starting at point a going to point b, in the range from [0,...
Definition: m_af_types.f90:716
This module contains the basic types and constants that are used in the NDIM-dimensional version of A...
Definition: m_af_types.f90:3
Collection of methods for a cell-centered variable.
Definition: m_af_types.f90:239
Type specifying the location of a cell.
Definition: m_af_types.f90:396
Type which stores all the boxes and levels, as well as some information about the number of boxes,...
Definition: m_af_types.f90:326
The basic building block of afivo: a box with cell-centered and face centered data,...
Definition: m_af_types.f90:286
Generic type for the coarse grid solver.
Definition: m_af_types.f90:547
Type which contains the indices of all boxes at a refinement level, as well as a list with all the "l...
Definition: m_af_types.f90:76
Type to store multigrid options in.
Definition: m_af_types.f90:572
Type that contains the refinement changes in a tree.
Definition: m_af_types.f90:88
Type that contains the refinement changes in a level.
Definition: m_af_types.f90:83
Type for storing a numerical stencil for a box.
Definition: m_af_types.f90:260