Afivo 0.3
All Classes Namespaces Functions Variables Pages
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
6program 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
27contains
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
236end program
Module which contains all Afivo modules, so that a user does not have to include them separately.
Definition: m_af_all.f90:3