A drift-diffusion example. Diffusion is implemented with centered differences, and for the drift the Koren flux limiter is used. Time stepping is done with the explicit trapezoidal rule.
7 program drift_diffusion_2d
12 integer,
parameter :: box_size = 8
13 integer,
parameter :: i_phi = 1
14 integer,
parameter :: i_phi_old = 2
15 integer,
parameter :: i_err = 3
16 integer,
parameter :: sol_type = 1
17 real(dp),
parameter :: domain_len = 2 * acos(-1.0_dp)
18 real(dp),
parameter :: dr = domain_len / box_size
21 type(ref_info_t) :: refine_info
22 integer :: ix_list(2, 1)
23 integer :: nb_list(a2_num_neighbors, 1)
24 integer :: refine_steps, time_steps, output_cnt
25 integer :: i, id, n, n_steps
26 real(dp) :: dt, time, end_time, p_err, n_err, sum_phi
27 real(dp) :: dt_adapt, dt_output
28 real(dp) :: diff_coeff, velocity(2), dr_min(2)
29 character(len=100) :: fname
30 integer :: count_rate, t_start, t_end
32 print *,
"Running drift_diffusion_2d" 33 print *,
"Number of threads", af_get_max_threads()
41 cc_names=[
"phi",
"old",
"err"])
49 call a2_set_base(tree, 1, ix_list, nb_list)
62 call system_clock(t_start,count_rate)
66 refine_steps=refine_steps+1
68 call a2_loop_box(tree, set_initial_condition)
76 call a2_gc_tree(tree, i_phi, a2_gc_interp_lim, a2_bc_neumann_zero)
84 call a2_adjust_refinement(tree, &
90 if (refine_info%n_add == 0)
exit 92 call system_clock(t_end, count_rate)
94 write(*,
"(A,i0,A,Es10.3,A)")
" Wall-clock time for ", &
95 refine_steps,
" refinement steps: ", &
96 (t_end-t_start) /
real(count_rate, dp),
" seconds" 98 call a2_print_info(tree)
103 call a2_restrict_tree(tree, i_phi)
108 call a2_gc_tree(tree, i_phi, a2_gc_interp_lim, a2_bc_neumann_zero)
110 call system_clock(t_start, count_rate)
115 time_steps = time_steps + 1
116 dr_min = a2_min_dr(tree)
117 dt = 0.5_dp / (2 * diff_coeff * sum(1/dr_min**2) + &
118 sum(abs(velocity/dr_min)) + epsilon(1.0_dp))
120 n_steps = ceiling(dt_adapt/dt)
121 dt = dt_adapt / n_steps
123 if (output_cnt * dt_output <= time)
then 124 output_cnt = output_cnt + 1
125 write(fname,
"(A,I0)")
"drift_diffusion_2d_", output_cnt
128 call a2_loop_box_arg(tree, set_error, [time])
137 call a2_tree_max_cc(tree, i_err, p_err)
138 call a2_tree_min_cc(tree, i_err, n_err)
139 call a2_tree_sum_cc(tree, i_phi, sum_phi)
140 write(*,
"(2(A,1x,Es12.4,2x))") &
141 " max error:", max(p_err, abs(n_err)), &
145 if (time > end_time)
exit 149 call a2_tree_copy_cc(tree, i_phi, i_phi_old)
154 call a2_loop_boxes(tree, fluxes_koren)
157 call a2_consistent_fluxes(tree, [i_phi])
160 call a2_loop_box_arg(tree, update_solution, [dt])
163 call a2_restrict_tree(tree, i_phi)
167 call a2_loop_box(tree, average_phi)
172 call a2_gc_tree(tree, i_phi, a2_gc_interp_lim, a2_bc_neumann_zero)
178 call a2_adjust_refinement(tree, refine_routine, refine_info, 2)
181 call prolong_to_new_children(tree, refine_info)
184 call system_clock(t_end,count_rate)
185 write(*,
"(A,I0,A,Es10.3,A)") &
186 " Wall-clock time after ",time_steps, &
187 " time steps: ", (t_end-t_start) /
real(count_rate, dp), &
192 call a2_destroy(tree)
197 subroutine refine_routine(box, cell_flags)
198 type(box2_t),
intent(in) :: box
199 integer,
intent(out) :: cell_flags(box%n_cell, box%n_cell)
205 do j = 1, nc;
do i = 1, nc
206 diff = abs(box%cc(i+1, j, i_phi) + &
207 box%cc(i-1, j, i_phi) + &
208 box%cc(i, j+1, i_phi) + &
209 box%cc(i, j-1, i_phi) - &
210 4 * box%cc(i, j, i_phi)) * box%dr
212 if (box%lvl < 2 .or. diff > 0.5e-3_dp .and. box%lvl < 5)
then 213 cell_flags(i, j) = af_do_ref
214 else if (diff < 0.1_dp * 0.1e-3_dp)
then 215 cell_flags(i, j) = af_rm_ref
217 cell_flags(i, j) = af_keep_ref
220 end subroutine refine_routine
223 subroutine set_initial_condition(box)
224 type(box2_t),
intent(inout) :: box
229 do j = 0, nc+1;
do i = 0, nc+1
230 rr = a2_r_cc(box, [i, j])
231 box%cc(i, j, i_phi) = solution(rr, 0.0_dp)
233 end subroutine set_initial_condition
236 subroutine set_error(box, time)
237 type(box2_t),
intent(inout) :: box
238 real(dp),
intent(in) :: time(:)
243 do j = 1, nc;
do i = 1, nc
244 rr = a2_r_cc(box, [i, j])
245 box%cc(i, j, i_err) = &
246 box%cc(i, j, i_phi) - solution(rr, time(1))
248 end subroutine set_error
251 function solution(rr, t)
result(sol)
252 real(dp),
intent(in) :: rr(2), t
253 real(dp) :: sol, rr_t(2)
255 rr_t = rr - velocity * t
257 select case (sol_type)
259 sol = sin(rr_t(1))**4 * cos(rr_t(2))**4
261 rr_t = modulo(rr_t, domain_len) / domain_len
262 if (norm2(rr_t - 0.5_dp) < 0.1_dp)
then 268 end function solution
272 subroutine fluxes_koren(boxes, id)
274 type(box2_t),
intent(inout) :: boxes(:)
275 integer,
intent(in) :: id
276 real(dp) :: gradp, gradc, gradn
278 integer :: dim, dix(2), i, j, nc
279 real(dp),
allocatable :: cc(:, :)
280 real(dp),
allocatable :: v(:, :, :)
282 nc = boxes(id)%n_cell
283 inv_dr = 1/boxes(id)%dr
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
311 end subroutine fluxes_koren
314 subroutine update_solution(box, dt)
315 type(box2_t),
intent(inout) :: box
316 real(dp),
intent(in) :: dt(:)
323 forall (i = 1:nc, j = 1:nc)
324 box%cc(i, j, i_phi) = box%cc(i, j, i_phi) + dt(1) * inv_dr * ( &
325 box%fc(i, j, 1, i_phi) - box%fc(i+1, j, 1, i_phi) + &
326 box%fc(i, j, 2, i_phi) - box%fc(i, j+1, 2, i_phi))
328 end subroutine update_solution
331 subroutine average_phi(box)
332 type(box2_t),
intent(inout) :: box
334 box%cc(:, :, i_phi) = 0.5_dp * (box%cc(:, :, i_phi) + &
335 box%cc(:, :, i_phi_old))
336 end subroutine average_phi
339 subroutine prolong_to_new_children(tree, refine_info)
340 type(a2_t),
intent(inout) :: tree
341 type(ref_info_t),
intent(in) :: refine_info
342 integer :: lvl, i, id, p_id
344 do lvl = 1, tree%highest_lvl
346 do i = 1,
size(refine_info%lvls(lvl)%add)
347 id = refine_info%lvls(lvl)%add(i)
348 p_id = tree%boxes(id)%parent
351 call a2_prolong_linear(tree%boxes(p_id), tree%boxes(id), i_phi)
358 call a2_gc_ids(tree%boxes, refine_info%lvls(lvl)%add, i_phi, &
359 a2_gc_interp_lim, a2_bc_neumann_zero)
361 end subroutine prolong_to_new_children
363 end program drift_diffusion_2d