Afivo  0.3
check_ghostcells.f90
1 #include "../src/cpp_macros.h"
2 !> \example check_ghostcells
3 !>
4 !> This example checks whether ghost cells are non-negative when the solution
5 !> itself is non-negative
6 program check_ghostcells
7  use m_af_all
8  implicit none
9 
10  integer, parameter :: box_size = 8
11  integer, parameter :: n_runs = 50
12  integer :: i_phi
13  real(dp) :: gradient(NDIM)
14  logical, parameter :: write_silo = .false.
15 
16  write(*,'(A,I0,A)') 'program check_ghostcells_', ndim, "d"
17  print *, "Number of threads", af_get_max_threads()
18 
19  ! Check whether ghost cells lie in a valid range
20  call test_valid_range(n_runs)
21 
22  ! Check whether ghost cells are exact for a linear gradient
23  call test_gradient(n_runs)
24 
25  print *, "Tests passed"
26 
27 contains
28 
29  subroutine test_valid_range(max_iter)
30  integer, intent(in) :: max_iter
31  type(af_t) :: tree
32  integer :: iter
33  type(ref_info_t) :: ref_info
34  character(len=100) :: fname
35 
36  print *, "Testing range of ghost cells"
37 
38  call af_add_cc_variable(tree, "phi", ix=i_phi)
39  call af_set_cc_methods(tree, i_phi, af_bc_dirichlet_zero)
40 
41  call af_init(tree, box_size, [dtimes(1.0_dp)], &
42  [dtimes(box_size)], periodic=[dtimes(.true.)], &
43  mem_limit_gb=0.5_dp)
44 
45  do iter = 1, max_iter
46  call af_adjust_refinement(tree, ref_routine, ref_info, ref_buffer=0)
47  call af_loop_box(tree, set_random_state)
48 
49  call af_restrict_ref_boundary(tree, [i_phi])
50  call af_loop_tree(tree, check_range_box, leaves_only=.true.)
51 
52  if (write_silo) then
53  write(fname, "(A,I0)") "output/check_ghostcells_range_" &
54  // dimname // "_", iter
55  call af_write_silo(tree, trim(fname), n_cycle=iter)
56  end if
57  end do
58  end subroutine test_valid_range
59 
60  subroutine test_gradient(max_iter)
61  integer, intent(in) :: max_iter
62  type(af_t) :: tree
63  integer :: iter
64  type(ref_info_t) :: ref_info
65  character(len=100) :: fname
66 
67  print *, "Testing linear gradient"
68 
69  call af_add_cc_variable(tree, "phi", ix=i_phi)
70  call af_set_cc_methods(tree, i_phi, bc_gradient)
71 
72  call af_init(tree, box_size, [dtimes(1.0_dp)], &
73  [dtimes(box_size)], periodic=[dtimes(.false.)], &
74  mem_limit_gb=0.5_dp)
75 
76  do iter = 1, max_iter
77  call random_number(gradient)
78  call af_adjust_refinement(tree, ref_routine, ref_info, ref_buffer=0)
79  call af_loop_box(tree, set_solution_gradient)
80 
81  call af_restrict_ref_boundary(tree, [i_phi])
82  call af_loop_tree(tree, check_gradient_box, leaves_only=.true.)
83 
84  if (write_silo) then
85  write(fname, "(A,I0)") "output/check_ghostcells_gradient_" &
86  // dimname // "_", iter
87  call af_write_silo(tree, trim(fname), n_cycle=iter)
88  end if
89  end do
90  end subroutine test_gradient
91 
92  subroutine ref_routine(box, cell_flags)
93  type(box_t), intent(in) :: box ! A list of all boxes in the tree
94  integer, intent(out) :: cell_flags(DTIMES(box%n_cell))
95  real(dp) :: rr
96 
97  call random_number(rr)
98 
99  if (rr < 0.5_dp**ndim .and. box%lvl < 5) then
100  cell_flags = af_do_ref
101  else
102  cell_flags = af_rm_ref
103  end if
104  end subroutine ref_routine
105 
106  subroutine set_random_state(box)
107  type(box_t), intent(inout) :: box
108  integer :: nc
109  nc = box%n_cell
110  call random_number(box%cc(dtimes(1:nc), i_phi))
111  end subroutine set_random_state
112 
113  subroutine set_solution_gradient(box)
114  type(box_t), intent(inout) :: box
115  integer :: nc, IJK
116  real(dp) :: r(NDIM)
117 
118  nc = box%n_cell
119 
120  do kji_do(1,nc)
121  r = af_r_cc(box, [ijk])
122  box%cc(ijk, i_phi) = sum(gradient * r)
123  end do; close_do
124  end subroutine set_solution_gradient
125 
126  subroutine check_range_box(tree, id)
127  type(af_t), intent(inout) :: tree
128  integer, intent(in) :: id
129  integer :: nc
130  real(dp) :: cc(DTIMES(-1:tree%n_cell+2), 1)
131  logical :: mask(DTIMES(-1:tree%n_cell+2))
132  real(dp) :: min_sides, max_sides
133  integer :: minloc_sides(NDIM), maxloc_sides(NDIM)
134 
135  nc = tree%n_cell
136 
137  call af_gc2_box(tree, id, [i_phi], cc)
138 
139  ! Set the mask for the sides
140  mask = .false.
141 #if NDIM == 1
142  mask(:0) = .true.
143  mask(nc+1:) = .true.
144 #elif NDIM == 2
145  mask(:0, 1:nc) = .true.
146  mask(nc+1:, 1:nc) = .true.
147  mask(1:nc, :0) = .true.
148  mask(1:nc, nc+1:) = .true.
149 #elif NDIM == 3
150  mask(:0, 1:nc, 1:nc) = .true.
151  mask(nc+1:, 1:nc, 1:nc) = .true.
152  mask(1:nc, :0, 1:nc) = .true.
153  mask(1:nc, nc+1:, 1:nc) = .true.
154  mask(1:nc, 1:nc, :0) = .true.
155  mask(1:nc, 1:nc, nc+1:) = .true.
156 #endif
157 
158  min_sides = minval(cc(dtimes(:), 1), mask=mask)
159  minloc_sides = minloc(cc(dtimes(:), 1), mask=mask)
160  max_sides = maxval(cc(dtimes(:), 1), mask=mask)
161  maxloc_sides = maxloc(cc(dtimes(:), 1), mask=mask)
162 
163  if (min_sides < 0 .or. max_sides > 1) then
164  print *, "minimum on sides: ", min_sides, minloc_sides - 2
165  print *, "maximum on sides: ", max_sides, maxloc_sides - 2
166  error stop "min/max not in range [0, 1]"
167  end if
168  end subroutine check_range_box
169 
170  subroutine check_gradient_box(tree, id)
171  type(af_t), intent(inout) :: tree
172  integer, intent(in) :: id
173  integer :: IJK, nc
174  real(dp) :: cc(DTIMES(-1:tree%n_cell+2), 1)
175  logical :: mask(DTIMES(-1:tree%n_cell+2))
176  real(dp) :: diff(DTIMES(-1:tree%n_cell+2))
177  real(dp) :: max_deviation, r(NDIM)
178  real(dp), parameter :: threshold = 1e-13_dp
179 
180  nc = tree%n_cell
181 
182  call af_gc2_box(tree, id, [i_phi], cc)
183 
184  ! Set the mask for the sides
185  mask = .false.
186 #if NDIM == 1
187  mask(:0) = .true.
188  mask(nc+1:) = .true.
189 #elif NDIM == 2
190  mask(:0, 1:nc) = .true.
191  mask(nc+1:, 1:nc) = .true.
192  mask(1:nc, :0) = .true.
193  mask(1:nc, nc+1:) = .true.
194 #elif NDIM == 3
195  mask(:0, 1:nc, 1:nc) = .true.
196  mask(nc+1:, 1:nc, 1:nc) = .true.
197  mask(1:nc, :0, 1:nc) = .true.
198  mask(1:nc, nc+1:, 1:nc) = .true.
199  mask(1:nc, 1:nc, :0) = .true.
200  mask(1:nc, 1:nc, nc+1:) = .true.
201 #endif
202 
203  ! Set solution
204  diff = 0.0_dp
205  do kji_do(0, nc+1)
206  if (mask(ijk)) then
207  r = af_r_cc(tree%boxes(id), [ijk])
208  diff(ijk) = abs(sum(gradient * r) - cc(ijk, 1))
209  end if
210  end do; close_do
211 
212  max_deviation = maxval(diff)
213 
214  if (max_deviation > threshold) then
215  print *, "max deviation from linear solution: ", max_deviation
216  print *, "location: ", maxloc(diff) - 2
217  error stop "max deviation larger than threshold"
218  end if
219  end subroutine check_gradient_box
220 
221  !> Set boundary conditions for a linear gradient solution
222  subroutine bc_gradient(box, nb, iv, coords, bc_val, bc_type)
223  type(box_t), intent(in) :: box
224  integer, intent(in) :: nb
225  integer, intent(in) :: iv
226  real(dp), intent(in) :: coords(NDIM, box%n_cell**(NDIM-1))
227  real(dp), intent(out) :: bc_val(box%n_cell**(NDIM-1))
228  integer, intent(out) :: bc_type
229  integer :: nc
230 
231  nc = box%n_cell
232  bc_type = af_bc_dirichlet
233  bc_val = matmul(gradient, coords)
234  end subroutine bc_gradient
235 
236 end program
Module which contains all Afivo modules, so that a user does not have to include them separately.
Definition: m_af_all.f90:3