An advection example using the Koren flux limiter. Time stepping is done with the explicit trapezoidal rule.
11 integer,
parameter :: box_size = 8
12 integer,
parameter :: i_phi = 1
13 integer,
parameter :: i_phi_old = 2
14 integer,
parameter :: i_err = 3
15 integer,
parameter :: sol_type = 1
16 real(dp),
parameter :: domain_len = 2 * acos(-1.0_dp)
17 real(dp),
parameter :: dr = domain_len / box_size
20 type(ref_info_t) :: refine_info
21 integer :: ix_list(2, 1)
22 integer :: nb_list(a2_num_neighbors, 1)
23 integer :: refine_steps, time_steps, output_cnt
24 integer :: i, id, n, n_steps
25 real(dp) :: dt, time, end_time, p_err, n_err
26 real(dp) :: sum_phi, sum_phi_t0
27 real(dp) :: dt_adapt, dt_output
28 real(dp) :: velocity(2), dr_min(2)
29 character(len=100) :: fname
30 integer :: count_rate, t_start, t_end
32 print *,
"Running advection_2d" 33 print *,
"Number of threads", af_get_max_threads()
41 cc_names=[
"phi",
"old",
"err"])
43 call a2_set_cc_methods(tree, i_phi, a2_bc_neumann_zero, a2_gc_interp_lim, &
44 prolong=a2_prolong_limit)
52 call a2_set_base(tree, 1, ix_list, nb_list)
64 call system_clock(t_start,count_rate)
68 refine_steps=refine_steps+1
70 call a2_loop_box(tree, set_initial_condition)
78 call a2_gc_tree(tree, i_phi, a2_gc_interp_lim, a2_bc_neumann_zero)
86 call a2_adjust_refinement(tree, &
92 if (refine_info%n_add == 0)
exit 94 call system_clock(t_end, count_rate)
96 write(*,
"(A,i0,A,Es10.3,A)")
" Wall-clock time for ", &
97 refine_steps,
" refinement steps: ", &
98 (t_end-t_start) /
real(count_rate, dp),
" seconds" 100 call a2_print_info(tree)
105 call a2_restrict_tree(tree, i_phi)
110 call a2_gc_tree(tree, i_phi, a2_gc_interp_lim, a2_bc_neumann_zero)
112 call system_clock(t_start, count_rate)
115 call a2_tree_sum_cc(tree, i_phi, sum_phi_t0)
119 time_steps = time_steps + 1
120 dr_min = a2_min_dr(tree)
121 dt = 0.5_dp / (sum(abs(velocity/dr_min)) + epsilon(1.0_dp))
123 n_steps = ceiling(dt_adapt/dt)
124 dt = dt_adapt / n_steps
126 if (output_cnt * dt_output <= time)
then 127 output_cnt = output_cnt + 1
128 write(fname,
"(A,I0)")
"advection_2d_", output_cnt
131 call a2_loop_box_arg(tree, set_error, [time])
135 call a2_write_silo(tree, trim(fname), output_cnt, time, dir=
"output")
139 call a2_tree_max_cc(tree, i_err, p_err)
140 call a2_tree_min_cc(tree, i_err, n_err)
141 call a2_tree_sum_cc(tree, i_phi, sum_phi)
142 write(*,
"(2(A,1x,Es12.4,2x))") &
143 " max error:", max(p_err, abs(n_err)), &
144 "conservation error: ", (sum_phi - sum_phi_t0) / sum_phi_t0
147 if (time > end_time)
exit 151 call a2_tree_copy_cc(tree, i_phi, i_phi_old)
156 call a2_loop_boxes(tree, fluxes_koren)
159 call a2_consistent_fluxes(tree, [i_phi])
162 call a2_loop_box_arg(tree, update_solution, [dt])
165 call a2_restrict_tree(tree, i_phi)
169 call a2_loop_box(tree, average_phi)
174 call a2_gc_tree(tree, i_phi, a2_gc_interp_lim, a2_bc_neumann_zero)
181 call a2_adjust_refinement(tree, refine_routine, refine_info, 1)
185 call system_clock(t_end,count_rate)
186 write(*,
"(A,I0,A,Es10.3,A)") &
187 " Wall-clock time after ",time_steps, &
188 " time steps: ", (t_end-t_start) /
real(count_rate, dp), &
193 call a2_destroy(tree)
199 subroutine refine_routine(box, cell_flags)
200 type(box2_t),
intent(in) :: box
201 integer,
intent(out) :: cell_flags(box%n_cell, box%n_cell)
207 do j = 1, nc;
do i = 1, nc
208 diff = abs(box%cc(i+1, j, i_phi) + &
209 box%cc(i-1, j, i_phi) + &
210 box%cc(i, j+1, i_phi) + &
211 box%cc(i, j-1, i_phi) - &
212 4 * box%cc(i, j, i_phi)) * box%dr
214 if (box%lvl < 2 .or. diff > 0.5e-3_dp .and. box%lvl < 5)
then 215 cell_flags(i, j) = af_do_ref
216 else if (diff < 0.1_dp * 0.1e-3_dp)
then 217 cell_flags(i, j) = af_rm_ref
219 cell_flags(i, j) = af_keep_ref
222 end subroutine refine_routine
226 subroutine set_initial_condition(box)
227 type(box2_t),
intent(inout) :: box
232 do j = 0, nc+1;
do i = 0, nc+1
233 rr = a2_r_cc(box, [i, j])
234 box%cc(i, j, i_phi) = solution(rr, 0.0_dp)
236 end subroutine set_initial_condition
239 subroutine set_error(box, time)
240 type(box2_t),
intent(inout) :: box
241 real(dp),
intent(in) :: time(:)
246 do j = 1, nc;
do i = 1, nc
247 rr = a2_r_cc(box, [i, j])
248 box%cc(i, j, i_err) = &
249 box%cc(i, j, i_phi) - solution(rr, time(1))
251 end subroutine set_error
254 function solution(rr, t)
result(sol)
255 real(dp),
intent(in) :: rr(2), t
256 real(dp) :: sol, rr_t(2)
258 rr_t = rr - velocity * t
260 select case (sol_type)
262 sol = sin(rr_t(1))**4 * cos(rr_t(2))**4
264 rr_t = modulo(rr_t, domain_len) / domain_len
265 if (norm2(rr_t - 0.5_dp) < 0.1_dp)
then 271 end function solution
275 subroutine fluxes_koren(boxes, id)
277 type(box2_t),
intent(inout) :: boxes(:)
278 integer,
intent(in) :: id
280 real(dp),
allocatable :: cc(:, :)
281 real(dp),
allocatable :: v(:, :, :)
283 nc = boxes(id)%n_cell
284 allocate(cc(-1:nc+2, -1:nc+2))
285 allocate(v(1:nc+1, 1:nc+1, 2))
287 call a2_gc_box(boxes, id, i_phi, a2_gc_interp_lim, a2_bc_neumann_zero)
292 call a2_gc2_box(boxes, &
295 a2_gc2_prolong_linear, &
296 a2_bc2_neumann_zero, &
300 v(:, :, 1) = velocity(1)
301 v(:, :, 2) = velocity(2)
303 call flux_koren_2d(cc, v, nc, 2)
304 boxes(id)%fc(:, :, :, i_phi) = v
306 end subroutine fluxes_koren
309 subroutine update_solution(box, dt)
310 type(box2_t),
intent(inout) :: box
311 real(dp),
intent(in) :: dt(:)
318 forall (i = 1:nc, j = 1:nc)
319 box%cc(i, j, i_phi) = box%cc(i, j, i_phi) + dt(1) * inv_dr * ( &
320 box%fc(i, j, 1, i_phi) - box%fc(i+1, j, 1, i_phi) + &
321 box%fc(i, j, 2, i_phi) - box%fc(i, j+1, 2, i_phi))
323 end subroutine update_solution
326 subroutine average_phi(box)
327 type(box2_t),
intent(inout) :: box
329 box%cc(:, :, i_phi) = 0.5_dp * (box%cc(:, :, i_phi) + &
330 box%cc(:, :, i_phi_old))
331 end subroutine average_phi
333 end program advection_2d