Afivo  0.3
m_af_stencil.f90
1 !> This module contains functionality for dealing with numerical stencils
3 #include "cpp_macros.h"
4  use m_af_types
5 
6  implicit none
7  private
8 
9  !> Initial size of stencil list
10  integer, parameter :: stencil_list_initial_size = 10
11 
12  integer, parameter, public :: stencil_constant = 1 !< Constant stencil
13  integer, parameter, public :: stencil_variable = 2 !< Variable stencil
14  integer, parameter, public :: stencil_sparse = 3 !< Sparse stencil
15 
16  !> Number of predefined stencil shapes
17  integer, parameter, private :: num_shapes = 5
18 
19  !> 3/5/7 point stencil in 1D/2D/3D
20  integer, parameter, public :: af_stencil_357 = 1
21 
22  !> Prolongation stencil using nearest 2, 3, 4 neighbors in 1D-3D
23  integer, parameter, public :: af_stencil_p234 = 2
24 
25  !> Prolongation stencil using nearest 2, 4, 8 neighbors in 1D-3D
26  integer, parameter, public :: af_stencil_p248 = 3
27 
28  !> Stencil for direct neighbors
29  integer, parameter, public :: af_stencil_246 = 4
30 
31  !> Stencil for masking
32  integer, parameter, public :: af_stencil_mask = 5
33 
34  !> Number of coefficients in the stencils
35  integer, parameter, public :: af_stencil_sizes(num_shapes) = &
36  [2*ndim+1, ndim+1, 2**ndim, 2*ndim, 1]
37 
38  abstract interface
39  !> Subroutine for setting a stencil on a box
40  subroutine af_subr_stencil(box, stencil)
41  import
42  type(box_t), intent(in) :: box !< Box to set stencil for
43  type(stencil_t), intent(inout) :: stencil !< Stencil to set
44  end subroutine af_subr_stencil
45  end interface
46 
47  public :: af_stencil_print_info
48  public :: af_stencil_index
49  public :: af_stencil_prepare_store
50  public :: af_stencil_remove
51  public :: af_stencil_store_box
52  public :: af_stencil_check_box
53  public :: af_stencil_allocate_coeff
54  public :: af_stencil_store
55  public :: af_stencil_apply
56  public :: af_stencil_apply_box
57  public :: af_stencil_gsrb_box
58  public :: af_stencil_prolong_box
59  public :: af_stencil_get_box
60  public :: af_stencil_try_constant
61 
62 contains
63 
64  !> Print statistics about the stencils in the tree
65  subroutine af_stencil_print_info(tree)
66  type(af_t), intent(in) :: tree
67  integer :: id, n_stencils_stored
68  integer :: n_boxes_with_stencils
69  integer :: n_constant_stored, n_variable_stored
70  integer :: n, n_stencils, n_sparse_stored
71 
72  n_stencils_stored = 0
73  n_constant_stored = 0
74  n_variable_stored = 0
75  n_sparse_stored = 0
76  n_boxes_with_stencils = 0
77 
78  do id = 1, tree%highest_id
79  if (.not. tree%boxes(id)%in_use) cycle
80 
81  n_stencils = tree%boxes(id)%n_stencils
82  if (n_stencils > 0) then
83  n_boxes_with_stencils = n_boxes_with_stencils + 1
84  n_stencils_stored = n_stencils_stored + n_stencils
85 
86  do n = 1, n_stencils
87  select case (tree%boxes(id)%stencils(n)%stype)
88  case (stencil_constant)
89  n_constant_stored = n_constant_stored + 1
90  case (stencil_variable)
91  n_variable_stored = n_variable_stored + 1
92  case (stencil_sparse)
93  n_sparse_stored = n_sparse_stored + 1
94  end select
95  end do
96  end if
97  end do
98 
99  write(*, '(A)') ''
100  write(*, '(A)') ' ** Information about stencils **'
101  write(*, '(A, I0)') ' #boxes with stencils: ', n_boxes_with_stencils
102  write(*, '(A, I0)') ' #stencils stored: ', n_stencils_stored
103  write(*, '(A, I0)') ' #constant stencils: ', n_constant_stored
104  write(*, '(A, I0)') ' #variable stencils: ', n_variable_stored
105  write(*, '(A, I0)') ' #sparse stencils: ', n_sparse_stored
106  end subroutine af_stencil_print_info
107 
108  !> Get index of a stencil, or af_stencil_none is not present
109  pure integer function af_stencil_index(box, key)
110  type(box_t), intent(in) :: box
111  integer, intent(in) :: key
112  integer :: i
113 
114  af_stencil_index = af_stencil_none
115  do i = 1, box%n_stencils
116  if (box%stencils(i)%key == key) then
117  af_stencil_index = i
118  exit
119  end if
120  end do
121  end function af_stencil_index
122 
123  !> Store a constant stencil
124  subroutine af_stencil_store(tree, key, set_stencil)
125  type(af_t), intent(inout) :: tree
126  integer, intent(in) :: key !< Stencil key
127  !> Method to set a stencil
128  procedure(af_subr_stencil) :: set_stencil
129  integer :: lvl, i, id
130 
131  !$omp parallel private(lvl, i, id)
132  do lvl = 1, tree%highest_lvl
133  !$omp do
134  do i = 1, size(tree%lvls(lvl)%ids)
135  id = tree%lvls(lvl)%ids(i)
136  call af_stencil_store_box(tree%boxes(id), key, set_stencil)
137  end do
138  !$omp end do
139  end do
140  !$omp end parallel
141  end subroutine af_stencil_store
142 
143  !> Prepare to store a stencil
144  subroutine af_stencil_prepare_store(box, key, ix)
145  type(box_t), intent(inout) :: box
146  integer, intent(in) :: key !< Stencil key
147  integer, intent(out) :: ix !< Index to store stencil
148  type(stencil_t), allocatable :: tmp(:)
149 
150  ix = af_stencil_index(box, key)
151 
152  if (ix == af_stencil_none) then
153  ! Allocate storage if necessary
154  if (.not. allocated(box%stencils)) then
155  allocate(box%stencils(stencil_list_initial_size))
156  else if (box%n_stencils == size(box%stencils)) then
157  allocate(tmp(2 * box%n_stencils))
158  tmp(1:box%n_stencils) = box%stencils
159  call move_alloc(tmp, box%stencils)
160  end if
161 
162  box%n_stencils = box%n_stencils + 1
163  ix = box%n_stencils
164  box%stencils(ix)%key = key
165  else
166  error stop "Stencil with this key has already been stored"
167  end if
168  end subroutine af_stencil_prepare_store
169 
170  !> Allocate storage for stencil coefficients
171  subroutine af_stencil_allocate_coeff(stencil, nc, use_f, n_sparse)
172  type(stencil_t), intent(inout) :: stencil !< Stencil
173  !> Number of cells per box dimension
174  integer, intent(in) :: nc
175  !> Whether storage for the extra arrays f and bc_correction is required
176  !> (only for variable stencils)
177  logical, intent(in), optional :: use_f
178  !> Number of entries for sparse stencil
179  integer, intent(in), optional :: n_sparse
180  logical :: allocate_f
181  integer :: n_coeff
182 
183  allocate_f = .false.; if (present(use_f)) allocate_f = use_f
184  if (stencil%shape < 1 .or. stencil%shape > num_shapes) &
185  error stop "Unknown stencil shape"
186 
187  n_coeff = af_stencil_sizes(stencil%shape)
188 
189  select case (stencil%stype)
190  case (stencil_constant)
191  if (.not. allocated(stencil%c)) then
192  allocate(stencil%c(n_coeff))
193  else if (size(stencil%c) /= n_coeff) then
194  deallocate(stencil%c)
195  allocate(stencil%c(n_coeff))
196  end if
197 
198  ! Clean up other storage if it is present
199  if (allocated(stencil%v)) deallocate(stencil%v)
200  if (allocated(stencil%f)) deallocate(stencil%f, stencil%bc_correction)
201  if (allocated(stencil%sparse_v)) &
202  deallocate(stencil%sparse_v, stencil%sparse_ix)
203  case (stencil_variable)
204  if (.not. allocated(stencil%v)) then
205  allocate(stencil%v(n_coeff, dtimes(nc)))
206  else if (size(stencil%v, 1) /= n_coeff) then
207  deallocate(stencil%v)
208  allocate(stencil%v(n_coeff, dtimes(nc)))
209  end if
210 
211  if (allocate_f .and. .not. allocated(stencil%f)) then
212  allocate(stencil%f(dtimes(nc)))
213  allocate(stencil%bc_correction(dtimes(nc)))
214  else if (.not. allocate_f .and. allocated(stencil%f)) then
215  deallocate(stencil%f, stencil%bc_correction)
216  end if
217 
218  ! Clean up other storage if it is present
219  if (allocated(stencil%c)) deallocate(stencil%c)
220  if (allocated(stencil%sparse_v)) &
221  deallocate(stencil%sparse_v, stencil%sparse_ix)
222  case (stencil_sparse)
223  if (.not. present(n_sparse)) error stop "n_sparse required"
224 
225  if (.not. allocated(stencil%sparse_v)) then
226  allocate(stencil%sparse_ix(ndim, n_sparse))
227  allocate(stencil%sparse_v(n_coeff, n_sparse))
228  else if (any(size(stencil%sparse_v) /= [n_coeff, n_sparse])) then
229  deallocate(stencil%sparse_v)
230  deallocate(stencil%sparse_ix)
231  allocate(stencil%sparse_ix(ndim, n_sparse))
232  allocate(stencil%sparse_v(n_coeff, n_sparse))
233  end if
234 
235  ! Clean up other storage if it is present
236  if (allocated(stencil%c)) deallocate(stencil%c)
237  if (allocated(stencil%v)) deallocate(stencil%v)
238  if (allocated(stencil%f)) deallocate(stencil%f, stencil%bc_correction)
239  case default
240  error stop "Unknow stencil%stype"
241  end select
242  end subroutine af_stencil_allocate_coeff
243 
244  !> Remove a stencil
245  subroutine af_stencil_remove(tree, key)
246  type(af_t), intent(inout) :: tree
247  integer, intent(in) :: key !< Stencil key
248  integer :: lvl, i, id
249 
250  !$omp parallel private(lvl, i, id)
251  do lvl = 1, tree%highest_lvl
252  !$omp do
253  do i = 1, size(tree%lvls(lvl)%ids)
254  id = tree%lvls(lvl)%ids(i)
255  call af_stencil_remove_box(tree%boxes(id), key)
256  end do
257  !$omp end do
258  end do
259  !$omp end parallel
260  end subroutine af_stencil_remove
261 
262  !> Store a stencil for a box
263  subroutine af_stencil_store_box(box, key, set_stencil)
264  type(box_t), intent(inout) :: box
265  integer, intent(in) :: key !< Stencil key
266  !> Method to set a stencil
267  procedure(af_subr_stencil) :: set_stencil
268  integer :: ix
269 
270  call af_stencil_prepare_store(box, key, ix)
271  call set_stencil(box, box%stencils(ix))
272  end subroutine af_stencil_store_box
273 
274  !> Remove a stencil from a box. This will change the order of other stencils.
275  subroutine af_stencil_remove_box(box, key)
276  type(box_t), intent(inout) :: box
277  integer, intent(in) :: key !< Stencil key
278  integer :: ix
279  type(stencil_t) :: empty_stencil
280 
281  ix = af_stencil_index(box, key)
282  if (ix == af_stencil_none) error stop "Stencil not present"
283 
284  ! Ensure there are no gaps in the stencil list
285  if (ix == box%n_stencils) then
286  box%stencils(ix) = empty_stencil
287  else
288  box%stencils(ix) = box%stencils(box%n_stencils)
289  box%stencils(box%n_stencils) = empty_stencil
290  end if
291 
292  box%n_stencils = box%n_stencils - 1
293  end subroutine af_stencil_remove_box
294 
295  !> Check if a stencil was correctly stored for a box
296  subroutine af_stencil_check_box(box, key, ix)
297  type(box_t), intent(in) :: box !< Box
298  integer, intent(in) :: key !< Stencil key
299  integer, intent(in) :: ix !< Stencil index
300 
301  if (key == af_stencil_none) &
302  error stop "key == af_stencil_none"
303 
304  if (af_stencil_index(box, key) /= ix) &
305  error stop "Stencil with key not found at index"
306 
307  associate(stencil => box%stencils(ix))
308  if (stencil%shape < 1 .or. stencil%shape > num_shapes) &
309  error stop "Unknown stencil shape"
310  select case (stencil%stype)
311  case (stencil_constant)
312  if (.not. allocated(stencil%c)) &
313  error stop "stencil%c not allocated"
314  case (stencil_variable)
315  if (.not. allocated(stencil%v)) &
316  error stop "stencil%v not allocated"
317  case (stencil_sparse)
318  if (.not. allocated(stencil%sparse_ix)) &
319  error stop "stencil%sparse_ix not allocated"
320  if (.not. allocated(stencil%sparse_v)) &
321  error stop "stencil%sparse_v not allocated"
322  case default
323  error stop "Unknow stencil%stype"
324  end select
325  end associate
326  end subroutine af_stencil_check_box
327 
328  subroutine af_stencil_apply(tree, key, iv, i_out)
329  type(af_t), intent(inout) :: tree !< Operate on this box
330  integer, intent(in) :: key !< Stencil key
331  integer, intent(in) :: iv !< Input variable
332  integer, intent(in) :: i_out !< Output variable
333 
334  integer :: lvl, i, id
335 
336  !$omp parallel private(lvl, i, id)
337  do lvl = 1, tree%highest_lvl
338  !$omp do
339  do i = 1, size(tree%lvls(lvl)%ids)
340  id = tree%lvls(lvl)%ids(i)
341  call af_stencil_apply_box(tree%boxes(id), key, iv, i_out)
342  end do
343  !$omp end do
344  end do
345  !$omp end parallel
346  end subroutine af_stencil_apply
347 
348  subroutine af_stencil_apply_box(box, key, iv, i_out)
349  type(box_t), intent(inout) :: box !< Operate on this box
350  integer, intent(in) :: key !< Stencil key
351  integer, intent(in) :: iv !< Input variable
352  integer, intent(in) :: i_out !< Output variable
353  integer :: i
354 
355  i = af_stencil_index(box, key)
356  if (i == af_stencil_none) error stop "Stencil not stored"
357 
358  select case (box%stencils(i)%shape)
359  case (af_stencil_357)
360  call stencil_apply_357(box, box%stencils(i), iv, i_out)
361  case default
362  error stop "Unknown stencil"
363  end select
364  end subroutine af_stencil_apply_box
365 
366  !> Apply a 3/5/7-point stencil in 1D/2D/3D
367  subroutine stencil_apply_357(box, stencil, iv, i_out)
368  type(box_t), intent(inout) :: box !< Operate on this box
369  type(stencil_t), intent(in) :: stencil !< Stencil
370  integer, intent(in) :: iv !< Input variable
371  integer, intent(in) :: i_out !< Output variable
372  real(dp) :: c(2*NDIM+1)
373  integer :: IJK
374 #if NDIM == 2
375  real(dp) :: rfac(2, box%n_cell), c_cyl(2*NDIM+1)
376  real(dp) :: cc_cyl(2*NDIM+1, box%n_cell)
377 #endif
378 
379  if (iv == i_out) error stop "Cannot have iv == i_out"
380  if (stencil%stype == stencil_sparse) error stop "sparse not implemented"
381 
382  associate(cc => box%cc, nc => box%n_cell)
383 
384 #if NDIM == 1
385  if (stencil%stype == stencil_constant) then
386  c = stencil%c
387  do kji_do(1, nc)
388  cc(i, i_out) = &
389  c(1) * cc(i, iv) + c(2) * cc(i-1, iv) + c(3) * cc(i+1, iv)
390  end do; close_do
391  else
392  do kji_do(1, nc)
393  c = stencil%v(:, ijk)
394  cc(i, i_out) = &
395  c(1) * cc(i, iv) + c(2) * cc(i-1, iv) + c(3) * cc(i+1, iv)
396  end do; close_do
397  end if
398 #elif NDIM == 2
399  if (stencil%cylindrical_gradient) then
400  ! Correct for cylindrical coordinates, assuming the elements correspond
401  ! to a gradient operation
402  call af_cyl_flux_factors(box, rfac)
403 
404  if (stencil%stype == stencil_constant) then
405  c = stencil%c
406 
407  ! Pre-compute coefficients for each i-index
408  do i = 1, nc
409  cc_cyl(2:3, i) = rfac(1:2, i) * c(2:3)
410  cc_cyl(1, i) = c(1) - (cc_cyl(2, i) - c(2)) &
411  - (cc_cyl(3, i) - c(3))
412  cc_cyl(4:, i) = c(4:)
413  end do
414 
415  do kji_do(1, nc)
416  cc(i, j, i_out) = &
417  cc_cyl(1, i) * cc(i, j, iv) + &
418  cc_cyl(2, i) * cc(i-1, j, iv) + &
419  cc_cyl(3, i) * cc(i+1, j, iv) + &
420  cc_cyl(4, i) * cc(i, j-1, iv) + &
421  cc_cyl(5, i) * cc(i, j+1, iv)
422  end do; close_do
423  else
424  ! Variable stencil
425  do kji_do(1, nc)
426  c = stencil%v(:, ijk)
427  c_cyl(2:3) = rfac(1:2, i) * c(2:3)
428  c_cyl(1) = c(1) - (c_cyl(2) - c(2)) - (c_cyl(3) - c(3))
429  c_cyl(4:) = c(4:)
430  cc(i, j, i_out) = &
431  c_cyl(1) * cc(i, j, iv) + &
432  c_cyl(2) * cc(i-1, j, iv) + &
433  c_cyl(3) * cc(i+1, j, iv) + &
434  c_cyl(4) * cc(i, j-1, iv) + &
435  c_cyl(5) * cc(i, j+1, iv)
436  end do; close_do
437  end if
438  else
439  ! No cylindrical gradient correction
440  if (stencil%stype == stencil_constant) then
441  c = stencil%c
442  do kji_do(1, nc)
443  cc(i, j, i_out) = &
444  c(1) * cc(i, j, iv) + &
445  c(2) * cc(i-1, j, iv) + &
446  c(3) * cc(i+1, j, iv) + &
447  c(4) * cc(i, j-1, iv) + &
448  c(5) * cc(i, j+1, iv)
449  end do; close_do
450  else
451  do kji_do(1, nc)
452  c = stencil%v(:, ijk)
453  cc(i, j, i_out) = &
454  c(1) * cc(i, j, iv) + &
455  c(2) * cc(i-1, j, iv) + &
456  c(3) * cc(i+1, j, iv) + &
457  c(4) * cc(i, j-1, iv) + &
458  c(5) * cc(i, j+1, iv)
459  end do; close_do
460  end if
461  end if
462 #elif NDIM == 3
463  if (stencil%stype == stencil_constant) then
464  c = stencil%c
465  do kji_do(1, nc)
466  cc(i, j, k, i_out) = &
467  c(1) * cc(i, j, k, iv) + &
468  c(2) * cc(i-1, j, k, iv) + &
469  c(3) * cc(i+1, j, k, iv) + &
470  c(4) * cc(i, j-1, k, iv) + &
471  c(5) * cc(i, j+1, k, iv) + &
472  c(6) * cc(i, j, k-1, iv) + &
473  c(7) * cc(i, j, k+1, iv)
474  end do; close_do
475  else
476  do kji_do(1, nc)
477  c = stencil%v(:, ijk)
478  cc(i, j, k, i_out) = &
479  c(1) * cc(i, j, k, iv) + &
480  c(2) * cc(i-1, j, k, iv) + &
481  c(3) * cc(i+1, j, k, iv) + &
482  c(4) * cc(i, j-1, k, iv) + &
483  c(5) * cc(i, j+1, k, iv) + &
484  c(6) * cc(i, j, k-1, iv) + &
485  c(7) * cc(i, j, k+1, iv)
486  end do; close_do
487  end if
488 #endif
489 
490  if (allocated(stencil%bc_correction)) then
491  cc(dtimes(1:nc), i_out) = cc(dtimes(1:nc), i_out) - &
492  stencil%bc_correction
493  end if
494  end associate
495 
496  end subroutine stencil_apply_357
497 
498  ! subroutine stencil_correct_bc_357(box, stencil, iv, tmp)
499  ! type(box_t), intent(inout) :: box !< Operate on this box
500  ! type(stencil_t), intent(in) :: stencil !< Stencil
501  ! integer, intent(in) :: iv !< Input variable
502  ! real(dp), intent(inout) :: tmp(DTIMES(box%n_cell))
503  ! integer :: bc_ix, bc_type, nb, lo(NDIM), hi(NDIM)
504  ! integer :: nb_dim, olo(NDIM), ohi(NDIM)
505  ! real(dp) :: bc_val(box%n_cell**(NDIM-1))
506  ! real(dp) :: stencil_coeffs(box%n_cell**(NDIM-1))
507  ! real(dp) :: values_inside(box%n_cell**(NDIM-1))
508  ! real(dp) :: values_outside(box%n_cell**(NDIM-1))
509 
510  ! do bc_ix = 1, box%n_bc
511  ! nb = box%bc_index_to_nb(bc_ix)
512 
513  ! bc_val = box%bc_val(:, iv, bc_ix)
514  ! bc_type = box%bc_type(iv, bc_ix)
515 
516  ! ! Determine index range next to boundary
517  ! call af_get_index_bc_inside(nb, box%n_cell, 1, lo, hi)
518  ! call af_get_index_bc_outside(nb, box%n_cell, 1, olo, ohi)
519 
520  ! ! Get stencil coefficients near boundary
521  ! if (stencil%constant) then
522  ! stencil_coeffs = stencil%c(nb+1)
523  ! else
524  ! stencil_coeffs = pack(stencil%v(nb+1, &
525  ! DSLICE(lo, hi)), .true.)
526  ! end if
527 
528  ! values_inside = pack(box%cc(DSLICE(lo, hi), iv), .true.)
529  ! values_outside = pack(box%cc(DSLICE(olo, ohi), iv), .true.)
530 
531  ! select case (bc_type)
532  ! case (af_bc_dirichlet)
533  ! ! Dirichlet value at cell face, so compute gradient over h/2
534  ! ! E.g. 1 -2 1 becomes 0 -3 1 for a 1D Laplacian
535  ! tmp(DSLICE(lo, hi)) = tmp(DSLICE(lo, hi)) &
536  ! + reshape(2 * stencil_coeffs * bc_val - &
537  ! stencil_coeffs * (values_inside + values_outside), &
538  ! hi - lo + 1)
539  ! case (af_bc_neumann)
540  ! nb_dim = af_neighb_dim(nb)
541  ! ! E.g. 1 -2 1 becomes 0 -1 1 for a 1D Laplacian
542  ! tmp(DSLICE(lo, hi)) = tmp(DSLICE(lo, hi)) &
543  ! - reshape(stencil_coeffs * (values_outside - values_inside) &
544  ! - stencil_coeffs * af_neighb_high_pm(nb) * box%dr(nb_dim) * &
545  ! bc_val, hi - lo + 1)
546  ! case default
547  ! error stop "unsupported boundary condition"
548  ! end select
549  ! end do
550  ! end subroutine stencil_correct_bc_357
551 
552  subroutine af_stencil_prolong_box(box_p, box_c, key, iv, iv_to, add)
553  type(box_t), intent(in) :: box_p !< Parent box
554  type(box_t), intent(inout) :: box_c !< Child box
555  integer, intent(in) :: key !< Stencil key
556  integer, intent(in) :: iv !< Input variable
557  integer, intent(in) :: iv_to !< Destination variable
558  logical, intent(in), optional :: add !< Add to old values
559  logical :: add_to
560  integer :: i
561 
562  add_to = .false.
563  if (present(add)) add_to = add
564 
565  i = af_stencil_index(box_c, key)
566  if (i == af_stencil_none) error stop "Stencil not stored"
567 
568  select case (box_c%stencils(i)%shape)
569  case (af_stencil_p234)
570  call stencil_prolong_234(box_p, box_c, box_c%stencils(i), &
571  iv, iv_to, add_to)
572  case (af_stencil_p248)
573  call stencil_prolong_248(box_p, box_c, box_c%stencils(i), &
574  iv, iv_to, add_to)
575  case default
576  print *, "box_c%stencils(i)%shape: ", box_c%stencils(i)%shape
577  error stop "Unknown stencil"
578  end select
579  end subroutine af_stencil_prolong_box
580 
581  !> Linear prolongation using nearest NDIM+1 neighbors
582  subroutine stencil_prolong_234(box_p, box_c, stencil, iv, iv_to, add)
583  type(box_t), intent(in) :: box_p !< Parent box
584  type(box_t), intent(inout) :: box_c !< Child box
585  type(stencil_t), intent(in) :: stencil !< Stencil
586  integer, intent(in) :: iv !< Input variable
587  integer, intent(in) :: iv_to !< Destination variable
588  logical, intent(in) :: add !< Add to old values
589 
590  integer :: nc, ix_offset(NDIM), IJK
591  integer :: IJK_(c1), IJK_(c2)
592  real(dp) :: c(NDIM+1)
593 
594  nc = box_c%n_cell
595  ix_offset = af_get_child_offset(box_c)
596  if (stencil%stype == stencil_sparse) error stop "sparse not implemented"
597  if (.not. add) box_c%cc(dtimes(1:nc), iv_to) = 0
598 
599  ! In these loops, we calculate the closest coarse index (_c1), and the
600  ! one-but-closest (_c2). The fine cell lies in between.
601 #if NDIM == 1
602  if (stencil%stype == stencil_constant) then
603  c = stencil%c
604  do i = 1, nc
605  i_c1 = ix_offset(1) + ishft(i+1, -1) ! (i+1)/2
606  i_c2 = i_c1 + 1 - 2 * iand(i, 1) ! even: +1, odd: -1
607  box_c%cc(ijk, iv_to) = box_c%cc(ijk, iv_to) + &
608  c(1) * box_p%cc(i_c1, iv) + &
609  c(2) * box_p%cc(i_c2, iv)
610  end do
611  else
612  do i = 1, nc
613  c = stencil%v(:, ijk)
614  i_c1 = ix_offset(1) + ishft(i+1, -1) ! (i+1)/2
615  i_c2 = i_c1 + 1 - 2 * iand(i, 1) ! even: +1, odd: -1
616  box_c%cc(ijk, iv_to) = box_c%cc(ijk, iv_to) + &
617  c(1) * box_p%cc(i_c1, iv) + &
618  c(2) * box_p%cc(i_c2, iv)
619  end do
620  end if
621 #elif NDIM == 2
622  if (stencil%stype == stencil_constant) then
623  c = stencil%c
624  do j = 1, nc
625  j_c1 = ix_offset(2) + ishft(j+1, -1) ! (j+1)/2
626  j_c2 = j_c1 + 1 - 2 * iand(j, 1) ! even: +1, odd: -1
627  do i = 1, nc
628  i_c1 = ix_offset(1) + ishft(i+1, -1) ! (i+1)/2
629  i_c2 = i_c1 + 1 - 2 * iand(i, 1) ! even: +1, odd: -1
630  box_c%cc(ijk, iv_to) = box_c%cc(ijk, iv_to) + &
631  c(1) * box_p%cc(i_c1, j_c1, iv) + &
632  c(2) * box_p%cc(i_c2, j_c1, iv) + &
633  c(3) * box_p%cc(i_c1, j_c2, iv)
634  end do
635  end do
636  else
637  do j = 1, nc
638  j_c1 = ix_offset(2) + ishft(j+1, -1) ! (j+1)/2
639  j_c2 = j_c1 + 1 - 2 * iand(j, 1) ! even: +1, odd: -1
640  do i = 1, nc
641  i_c1 = ix_offset(1) + ishft(i+1, -1) ! (i+1)/2
642  i_c2 = i_c1 + 1 - 2 * iand(i, 1) ! even: +1, odd: -1
643  c = stencil%v(:, ijk)
644  box_c%cc(ijk, iv_to) = box_c%cc(ijk, iv_to) + &
645  c(1) * box_p%cc(i_c1, j_c1, iv) + &
646  c(2) * box_p%cc(i_c2, j_c1, iv) + &
647  c(3) * box_p%cc(i_c1, j_c2, iv)
648  end do
649  end do
650  end if
651 #elif NDIM == 3
652  if (stencil%stype == stencil_constant) then
653  c = stencil%c
654  do k = 1, nc
655  k_c1 = ix_offset(3) + ishft(k+1, -1) ! (k+1)/2
656  k_c2 = k_c1 + 1 - 2 * iand(k, 1) ! even: +1, odd: -1
657  do j = 1, nc
658  j_c1 = ix_offset(2) + ishft(j+1, -1) ! (j+1)/2
659  j_c2 = j_c1 + 1 - 2 * iand(j, 1) ! even: +1, odd: -1
660  do i = 1, nc
661  i_c1 = ix_offset(1) + ishft(i+1, -1) ! (i+1)/2
662  i_c2 = i_c1 + 1 - 2 * iand(i, 1) ! even: +1, odd: -1
663  box_c%cc(ijk, iv_to) = box_c%cc(ijk, iv_to) + &
664  c(1) * box_p%cc(i_c1, j_c1, k_c1, iv) + &
665  c(2) * box_p%cc(i_c2, j_c1, k_c1, iv) + &
666  c(3) * box_p%cc(i_c1, j_c2, k_c1, iv) + &
667  c(4) * box_p%cc(i_c1, j_c1, k_c2, iv)
668  end do
669  end do
670  end do
671  else
672  do k = 1, nc
673  k_c1 = ix_offset(3) + ishft(k+1, -1) ! (k+1)/2
674  k_c2 = k_c1 + 1 - 2 * iand(k, 1) ! even: +1, odd: -1
675  do j = 1, nc
676  j_c1 = ix_offset(2) + ishft(j+1, -1) ! (j+1)/2
677  j_c2 = j_c1 + 1 - 2 * iand(j, 1) ! even: +1, odd: -1
678  do i = 1, nc
679  i_c1 = ix_offset(1) + ishft(i+1, -1) ! (i+1)/2
680  i_c2 = i_c1 + 1 - 2 * iand(i, 1) ! even: +1, odd: -1
681  c = stencil%v(:, ijk)
682  box_c%cc(ijk, iv_to) = box_c%cc(ijk, iv_to) + &
683  c(1) * box_p%cc(i_c1, j_c1, k_c1, iv) + &
684  c(2) * box_p%cc(i_c2, j_c1, k_c1, iv) + &
685  c(3) * box_p%cc(i_c1, j_c2, k_c1, iv) + &
686  c(4) * box_p%cc(i_c1, j_c1, k_c2, iv)
687  end do
688  end do
689  end do
690  end if
691 #endif
692  end subroutine stencil_prolong_234
693 
694  !> (Bi-/tri-)linear prolongation using nearest 2**NDIM neighbors
695  subroutine stencil_prolong_248(box_p, box_c, stencil, iv, iv_to, add)
696  type(box_t), intent(in) :: box_p !< Parent box
697  type(box_t), intent(inout) :: box_c !< Child box
698  type(stencil_t), intent(in) :: stencil !< Stencil
699  integer, intent(in) :: iv !< Input variable
700  integer, intent(in) :: iv_to !< Destination variable
701  logical, intent(in) :: add !< Add to old values
702 
703  integer :: nc, ix_offset(NDIM), IJK
704  integer :: IJK_(c1), IJK_(c2)
705  real(dp) :: c(2**NDIM)
706 
707  nc = box_c%n_cell
708  ix_offset = af_get_child_offset(box_c)
709  if (stencil%stype == stencil_sparse) error stop "sparse not implemented"
710  if (.not. add) box_c%cc(dtimes(1:nc), iv_to) = 0
711 
712  ! In these loops, we calculate the closest coarse index (_c1), and the
713  ! one-but-closest (_c2). The fine cell lies in between.
714 #if NDIM == 1
715  if (stencil%stype == stencil_constant) then
716  c = stencil%c
717  do i = 1, nc
718  i_c1 = ix_offset(1) + ishft(i+1, -1) ! (i+1)/2
719  i_c2 = i_c1 + 1 - 2 * iand(i, 1) ! even: +1, odd: -1
720  box_c%cc(ijk, iv_to) = box_c%cc(ijk, iv_to) + &
721  c(1) * box_p%cc(i_c1, iv) + &
722  c(2) * box_p%cc(i_c2, iv)
723  end do
724  else
725  do i = 1, nc
726  c = stencil%v(:, ijk)
727  i_c1 = ix_offset(1) + ishft(i+1, -1) ! (i+1)/2
728  i_c2 = i_c1 + 1 - 2 * iand(i, 1) ! even: +1, odd: -1
729  box_c%cc(ijk, iv_to) = box_c%cc(ijk, iv_to) + &
730  c(1) * box_p%cc(i_c1, iv) + &
731  c(2) * box_p%cc(i_c2, iv)
732  end do
733  end if
734 #elif NDIM == 2
735  if (stencil%stype == stencil_constant) then
736  c = stencil%c
737  do j = 1, nc
738  j_c1 = ix_offset(2) + ishft(j+1, -1) ! (j+1)/2
739  j_c2 = j_c1 + 1 - 2 * iand(j, 1) ! even: +1, odd: -1
740  do i = 1, nc
741  i_c1 = ix_offset(1) + ishft(i+1, -1) ! (i+1)/2
742  i_c2 = i_c1 + 1 - 2 * iand(i, 1) ! even: +1, odd: -1
743  box_c%cc(ijk, iv_to) = box_c%cc(ijk, iv_to) + &
744  c(1) * box_p%cc(i_c1, j_c1, iv) + &
745  c(2) * box_p%cc(i_c2, j_c1, iv) + &
746  c(3) * box_p%cc(i_c1, j_c2, iv) + &
747  c(4) * box_p%cc(i_c2, j_c2, iv)
748  end do
749  end do
750  else
751  do j = 1, nc
752  j_c1 = ix_offset(2) + ishft(j+1, -1) ! (j+1)/2
753  j_c2 = j_c1 + 1 - 2 * iand(j, 1) ! even: +1, odd: -1
754  do i = 1, nc
755  i_c1 = ix_offset(1) + ishft(i+1, -1) ! (i+1)/2
756  i_c2 = i_c1 + 1 - 2 * iand(i, 1) ! even: +1, odd: -1
757  c = stencil%v(:, ijk)
758  box_c%cc(ijk, iv_to) = box_c%cc(ijk, iv_to) + &
759  c(1) * box_p%cc(i_c1, j_c1, iv) + &
760  c(2) * box_p%cc(i_c2, j_c1, iv) + &
761  c(3) * box_p%cc(i_c1, j_c2, iv) + &
762  c(4) * box_p%cc(i_c2, j_c2, iv)
763  end do
764  end do
765  end if
766 #elif NDIM == 3
767  if (stencil%stype == stencil_constant) then
768  c = stencil%c
769  do k = 1, nc
770  k_c1 = ix_offset(3) + ishft(k+1, -1) ! (k+1)/2
771  k_c2 = k_c1 + 1 - 2 * iand(k, 1) ! even: +1, odd: -1
772  do j = 1, nc
773  j_c1 = ix_offset(2) + ishft(j+1, -1) ! (j+1)/2
774  j_c2 = j_c1 + 1 - 2 * iand(j, 1) ! even: +1, odd: -1
775  do i = 1, nc
776  i_c1 = ix_offset(1) + ishft(i+1, -1) ! (i+1)/2
777  i_c2 = i_c1 + 1 - 2 * iand(i, 1) ! even: +1, odd: -1
778  box_c%cc(ijk, iv_to) = box_c%cc(ijk, iv_to) + &
779  c(1) * box_p%cc(i_c1, j_c1, k_c1, iv) + &
780  c(2) * box_p%cc(i_c2, j_c1, k_c1, iv) + &
781  c(3) * box_p%cc(i_c1, j_c2, k_c1, iv) + &
782  c(4) * box_p%cc(i_c2, j_c2, k_c1, iv) + &
783  c(5) * box_p%cc(i_c1, j_c1, k_c2, iv) + &
784  c(6) * box_p%cc(i_c2, j_c1, k_c2, iv) + &
785  c(7) * box_p%cc(i_c1, j_c2, k_c2, iv) + &
786  c(8) * box_p%cc(i_c2, j_c2, k_c2, iv)
787  end do
788  end do
789  end do
790  else
791  do k = 1, nc
792  k_c1 = ix_offset(3) + ishft(k+1, -1) ! (k+1)/2
793  k_c2 = k_c1 + 1 - 2 * iand(k, 1) ! even: +1, odd: -1
794  do j = 1, nc
795  j_c1 = ix_offset(2) + ishft(j+1, -1) ! (j+1)/2
796  j_c2 = j_c1 + 1 - 2 * iand(j, 1) ! even: +1, odd: -1
797  do i = 1, nc
798  i_c1 = ix_offset(1) + ishft(i+1, -1) ! (i+1)/2
799  i_c2 = i_c1 + 1 - 2 * iand(i, 1) ! even: +1, odd: -1
800  c = stencil%v(:, ijk)
801  box_c%cc(ijk, iv_to) = box_c%cc(ijk, iv_to) + &
802  c(1) * box_p%cc(i_c1, j_c1, k_c1, iv) + &
803  c(2) * box_p%cc(i_c2, j_c1, k_c1, iv) + &
804  c(3) * box_p%cc(i_c1, j_c2, k_c1, iv) + &
805  c(4) * box_p%cc(i_c2, j_c2, k_c1, iv) + &
806  c(5) * box_p%cc(i_c1, j_c1, k_c2, iv) + &
807  c(6) * box_p%cc(i_c2, j_c1, k_c2, iv) + &
808  c(7) * box_p%cc(i_c1, j_c2, k_c2, iv) + &
809  c(8) * box_p%cc(i_c2, j_c2, k_c2, iv)
810  end do
811  end do
812  end do
813  end if
814 #endif
815  end subroutine stencil_prolong_248
816 
817  !> Perform Gauss-Seidel red-black on a stencil
818  subroutine af_stencil_gsrb_box(box, key, redblack, iv, i_rhs)
819  type(box_t), intent(inout) :: box !< Operate on this box
820  integer, intent(in) :: key !< Stencil key
821  integer, intent(in) :: redblack !< Even or odd integer
822  integer, intent(in) :: iv !< Solve for variable
823  integer, intent(in) :: i_rhs !< Right-hand side
824  integer :: i
825 
826  i = af_stencil_index(box, key)
827  if (i == af_stencil_none) error stop "Stencil not stored"
828 
829  select case (box%stencils(i)%shape)
830  case (af_stencil_357)
831  call stencil_gsrb_357(box, box%stencils(i), redblack, iv, i_rhs)
832  case default
833  error stop "Unknown stencil"
834  end select
835  end subroutine af_stencil_gsrb_box
836 
837  !> Perform Gauss-Seidel red-black on a 3/5/7-point stencil in 1D/2D/3D
838  subroutine stencil_gsrb_357(box, stencil, redblack, iv, i_rhs)
839  type(box_t), intent(inout) :: box !< Operate on this box
840  type(stencil_t), intent(in) :: stencil !< Stencil
841  integer, intent(in) :: redblack !< Even or odd integer
842  integer, intent(in) :: iv !< Solve for variable
843  integer, intent(in) :: i_rhs !< Right-hand side
844 
845  real(dp) :: c(2*NDIM+1), inv_c1
846  integer :: IJK, i0, nc
847 #if NDIM == 2
848  real(dp) :: rfac(2, box%n_cell), c_cyl(2*NDIM+1)
849  real(dp) :: cc_cyl(2*NDIM+1, box%n_cell), inv_cc1(box%n_cell)
850 #endif
851 
852  if (stencil%stype == stencil_sparse) error stop "sparse not implemented"
853  nc = box%n_cell
854 
855  associate(cc => box%cc, nc => box%n_cell)
856  if (allocated(stencil%bc_correction)) then
857  cc(dtimes(1:nc), i_rhs) = cc(dtimes(1:nc), i_rhs) + &
858  stencil%bc_correction
859  end if
860 
861 #if NDIM == 1
862  i0 = 2 - iand(redblack, 1)
863  if (stencil%stype == stencil_constant) then
864  c = stencil%c
865  inv_c1 = 1 / c(1)
866 
867  do i = i0, nc, 2
868  cc(ijk, iv) = (cc(ijk, i_rhs) &
869  - c(2) * cc(i-1, iv) &
870  - c(3) * cc(i+1, iv)) * inv_c1
871  end do
872  else
873  do i = i0, nc, 2
874  c = stencil%v(:, ijk)
875  cc(ijk, iv) = (cc(ijk, i_rhs) &
876  - c(2) * cc(i-1, iv) &
877  - c(3) * cc(i+1, iv)) / c(1)
878  end do
879  end if
880 #elif NDIM == 2
881  if (stencil%cylindrical_gradient) then
882  ! Correct for cylindrical coordinates, assuming the elements correspond
883  ! to a gradient operation
884  call af_cyl_flux_factors(box, rfac)
885 
886  if (stencil%stype == stencil_constant) then
887  c = stencil%c
888 
889  ! Pre-compute coefficients for each i-index
890  do i = 1, nc
891  cc_cyl(2:3, i) = rfac(1:2, i) * c(2:3)
892  cc_cyl(1, i) = c(1) - (cc_cyl(2, i) - c(2)) &
893  - (cc_cyl(3, i) - c(3))
894  cc_cyl(4:, i) = c(4:)
895  inv_cc1(i) = 1 / cc_cyl(1, i)
896  end do
897 
898  do j = 1, nc
899  i0 = 2 - iand(ieor(redblack, j), 1)
900  do i = i0, nc, 2
901  cc(ijk, iv) = (cc(ijk, i_rhs) &
902  - cc_cyl(2, i) * cc(i-1, j, iv) &
903  - cc_cyl(3, i) * cc(i+1, j, iv) &
904  - cc_cyl(4, i) * cc(i, j-1, iv) &
905  - cc_cyl(5, i) * cc(i, j+1, iv)) * inv_cc1(i)
906  end do
907  end do
908  else
909  ! Variable stencil
910  do j = 1, nc
911  i0 = 2 - iand(ieor(redblack, j), 1)
912  do i = i0, nc, 2
913  c = stencil%v(:, ijk)
914  c_cyl(2:3) = rfac(1:2, i) * c(2:3)
915  c_cyl(1) = c(1) - (c_cyl(2) - c(2)) - (c_cyl(3) - c(3))
916  c_cyl(4:) = c(4:)
917 
918  cc(ijk, iv) = (cc(ijk, i_rhs) &
919  - c_cyl(2) * cc(i-1, j, iv) &
920  - c_cyl(3) * cc(i+1, j, iv) &
921  - c_cyl(4) * cc(i, j-1, iv) &
922  - c_cyl(5) * cc(i, j+1, iv)) / c_cyl(1)
923  end do
924  end do
925  end if
926  else ! No cylindrical gradient correction
927  if (stencil%stype == stencil_constant) then
928  c = stencil%c
929  inv_c1 = 1 / c(1)
930 
931  do j = 1, nc
932  i0 = 2 - iand(ieor(redblack, j), 1)
933  do i = i0, nc, 2
934  cc(ijk, iv) = (cc(ijk, i_rhs) &
935  - c(2) * cc(i-1, j, iv) &
936  - c(3) * cc(i+1, j, iv) &
937  - c(4) * cc(i, j-1, iv) &
938  - c(5) * cc(i, j+1, iv)) * inv_c1
939  end do
940  end do
941  else
942  do j = 1, nc
943  i0 = 2 - iand(ieor(redblack, j), 1)
944  do i = i0, nc, 2
945  c = stencil%v(:, ijk)
946  cc(ijk, iv) = (cc(ijk, i_rhs) &
947  - c(2) * cc(i-1, j, iv) &
948  - c(3) * cc(i+1, j, iv) &
949  - c(4) * cc(i, j-1, iv) &
950  - c(5) * cc(i, j+1, iv)) / c(1)
951  end do
952  end do
953  end if
954  end if
955 #elif NDIM == 3
956  if (stencil%stype == stencil_constant) then
957  c = stencil%c
958  inv_c1 = 1 / c(1)
959 
960  do k = 1, nc
961  do j = 1, nc
962  i0 = 2 - iand(ieor(redblack, k+j), 1)
963  do i = i0, nc, 2
964  cc(ijk, iv) = (cc(ijk, i_rhs) &
965  - c(2) * cc(i-1, j, k, iv) &
966  - c(3) * cc(i+1, j, k, iv) &
967  - c(4) * cc(i, j-1, k, iv) &
968  - c(5) * cc(i, j+1, k, iv) &
969  - c(6) * cc(i, j, k-1, iv) &
970  - c(7) * cc(i, j, k+1, iv)) * inv_c1
971  end do
972  end do
973  end do
974  else
975  do k = 1, nc
976  do j = 1, nc
977  i0 = 2 - iand(ieor(redblack, k+j), 1)
978  do i = i0, nc, 2
979  c = stencil%v(:, ijk)
980  cc(ijk, iv) = (cc(ijk, i_rhs) &
981  - c(2) * cc(i-1, j, k, iv) &
982  - c(3) * cc(i+1, j, k, iv) &
983  - c(4) * cc(i, j-1, k, iv) &
984  - c(5) * cc(i, j+1, k, iv) &
985  - c(6) * cc(i, j, k-1, iv) &
986  - c(7) * cc(i, j, k+1, iv)) / c(1)
987  end do
988  end do
989  end do
990  end if
991 #endif
992 
993  if (allocated(stencil%bc_correction)) then
994  cc(dtimes(1:nc), i_rhs) = cc(dtimes(1:nc), i_rhs) - &
995  stencil%bc_correction
996  end if
997  end associate
998  end subroutine stencil_gsrb_357
999 
1000  !> Convert a variable stencil to constant one if possible
1001  subroutine af_stencil_try_constant(box, ix, abs_tol, success)
1002  type(box_t), intent(inout) :: box
1003  integer, intent(in) :: ix !< Stencil index
1004  real(dp), intent(in) :: abs_tol !< Absolute tolerance
1005  logical :: success !< Whether the stencil was converted
1006  integer :: ijk, nc, n_coeff
1007 
1008  if (box%stencils(ix)%stype == stencil_sparse) &
1009  error stop "sparse not implemented"
1010  if (.not. allocated(box%stencils(ix)%v)) &
1011  error stop "No variable stencil present"
1012 
1013  nc = box%n_cell
1014  success = .false.
1015 
1016  ! Check if all coefficients are the same, otherwise return
1017  do kji_do(1, nc)
1018  if (any(abs(box%stencils(ix)%v(:, ijk) - &
1019  box%stencils(ix)%v(:, dtimes(1))) > abs_tol)) return
1020  end do; close_do
1021 
1022  box%stencils(ix)%stype = stencil_constant
1023  n_coeff = size(box%stencils(ix)%v, 1)
1024  allocate(box%stencils(ix)%c(n_coeff))
1025  box%stencils(ix)%c = box%stencils(ix)%v(:, dtimes(1))
1026  deallocate(box%stencils(ix)%v)
1027  success = .true.
1028  end subroutine af_stencil_try_constant
1029 
1030  !> Get the stencil for a box
1031  subroutine af_stencil_get_box(box, key, v)
1032  type(box_t), intent(inout) :: box !< Operate on this box
1033  integer, intent(in) :: key !< Stencil key
1034  !> Stencil coefficients
1035  real(dp), intent(inout) :: v(:, dtimes(:))
1036  integer :: i
1037 
1038  i = af_stencil_index(box, key)
1039  if (i == af_stencil_none) error stop "Stencil not stored"
1040 
1041  select case (box%stencils(i)%shape)
1042  case (af_stencil_357)
1043  call stencil_get_357(box, box%stencils(i), v)
1044  case default
1045  error stop "Unknown stencil"
1046  end select
1047  end subroutine af_stencil_get_box
1048 
1049  !> Get the stencil for all cells in a box
1050  subroutine stencil_get_357(box, stencil, v)
1051  type(box_t), intent(inout) :: box !< Box
1052  type(stencil_t), intent(in) :: stencil !< Stencil
1053  !> Stencil coefficients
1054  real(dp), intent(inout) :: v(:, DTIMES(:))
1055 #if NDIM == 2
1056  real(dp) :: c_cyl(size(v, 1)), rfac(2, box%n_cell)
1057 #endif
1058  integer :: IJK, nc
1059 
1060  nc = box%n_cell
1061 
1062  if (size(v, 1) /= af_stencil_sizes(stencil%shape)) &
1063  error stop "Argument v has wrong size"
1064 
1065  if (stencil%stype == stencil_constant) then
1066  do kji_do(1, nc)
1067  v(:, ijk) = stencil%c
1068  end do; close_do
1069  else
1070  v = stencil%v
1071  end if
1072 
1073 #if NDIM == 2
1074  if (stencil%cylindrical_gradient) then
1075  ! Correct for cylindrical coordinates, assuming the elements correspond
1076  ! to a gradient operation
1077  call af_cyl_flux_factors(box, rfac)
1078  do kji_do(1, nc)
1079  c_cyl(2:3) = rfac(1:2, i) * v(2:3, ijk)
1080  c_cyl(1) = v(1, ijk) - (c_cyl(2) - v(2, ijk)) &
1081  - (c_cyl(3) - v(3, ijk))
1082  c_cyl(4:) = v(4:, ijk)
1083  v(:, ijk) = c_cyl
1084  end do; close_do
1085  end if
1086 #endif
1087  end subroutine stencil_get_357
1088 
1089 end module m_af_stencil
Subroutine for setting a stencil on a box.
This module contains functionality for dealing with numerical stencils.
Definition: m_af_stencil.f90:2
This module contains the basic types and constants that are used in the NDIM-dimensional version of A...
Definition: m_af_types.f90:3
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
Type for storing a numerical stencil for a box.
Definition: m_af_types.f90:260