1 #include "../src/cpp_macros.h"
5 program check_prolongation
9 integer,
parameter :: box_size = 8
10 integer,
parameter :: n_runs = 50
12 real(dp) :: gradient(NDIM)
13 logical,
parameter :: write_silo = .false.
15 write(*,
'(A,I0,A)')
'program check_prolongation_', ndim,
"d"
16 print *,
"Number of threads", af_get_max_threads()
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")
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")
29 print *,
"Tests passed"
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
39 type(ref_info_t) :: ref_info
40 character(len=100) :: fname
42 print *,
"Testing range of values (", name,
")"
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)
48 call af_init(tree, box_size, [dtimes(1.0_dp)], &
49 [dtimes(box_size)], periodic=[dtimes(.true.)], &
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])
57 call af_adjust_refinement(tree, ref_routine, ref_info, ref_buffer=0)
59 call af_loop_tree(tree, check_range_box, leaves_only=.true.)
62 write(fname,
"(A,I0)")
"output/check_prolongation_" // name &
63 //
"_" // dimname //
"_", iter
64 call af_write_silo(tree, trim(fname), n_cycle=iter)
68 end subroutine test_valid_range
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
76 type(ref_info_t) :: ref_info
77 character(len=100) :: fname
79 print *,
"Testing linear gradient (", name,
")"
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)
85 call af_init(tree, box_size, [dtimes(1.0_dp)], &
86 [dtimes(box_size)], periodic=[dtimes(.false.)], &
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])
95 call af_adjust_refinement(tree, ref_routine, ref_info, ref_buffer=0)
97 call af_loop_tree(tree, check_gradient_box, leaves_only=.true.)
100 write(fname,
"(A,I0)")
"output/check_prolongation_gradient_" &
101 // name //
"_" // dimname //
"_", iter
102 call af_write_silo(tree, trim(fname), n_cycle=iter)
105 end subroutine test_gradient
107 subroutine ref_routine(box, cell_flags)
108 type(box_t),
intent(in) :: box
109 integer,
intent(out) :: cell_flags(DTIMES(box%n_cell))
112 call random_number(rr)
114 if (rr < 0.5_dp**ndim .and. box%lvl < 5)
then
115 cell_flags = af_do_ref
117 cell_flags = af_rm_ref
119 end subroutine ref_routine
121 subroutine set_random_state(box)
122 type(box_t),
intent(inout) :: box
125 call random_number(box%cc(dtimes(1:nc), i_phi))
126 end subroutine set_random_state
128 subroutine set_solution_gradient(box)
129 type(box_t),
intent(inout) :: box
136 r = af_r_cc(box, [ijk])
137 box%cc(ijk, i_phi) = sum(gradient * r)
139 end subroutine set_solution_gradient
141 subroutine check_range_box(tree, id)
142 type(af_t),
intent(inout) :: tree
143 integer,
intent(in) :: id
145 real(dp) :: min_phi, max_phi
146 logical :: mask(DTIMES(0:tree%n_cell+1))
147 integer :: minloc_phi(NDIM), maxloc_phi(NDIM)
153 mask(dtimes(1:nc)) = .true.
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.
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.
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)
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]"
183 end subroutine check_range_box
185 subroutine check_gradient_box(tree, id)
186 type(af_t),
intent(inout) :: tree
187 integer,
intent(in) :: id
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
198 mask(dtimes(1:nc)) = .true.
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.
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.
216 associate(cc => tree%boxes(id)%cc)
221 r = af_r_cc(tree%boxes(id), [ijk])
222 diff(ijk) = abs(sum(gradient * r) - cc(ijk, 1))
226 max_deviation = maxval(diff)
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"
234 end subroutine check_gradient_box
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
247 bc_type = af_bc_dirichlet
248 bc_val = matmul(gradient, coords)
249 end subroutine bc_gradient
Module which contains all Afivo modules, so that a user does not have to include them separately.