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