Afivo  0.3
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.
3 module m_af_types
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
83  type ref_lvl_t
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
396  type af_loc_t
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 
724 contains
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 
1255 end 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