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_3d
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(3, 1)
23 integer :: nb_list(a3_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(3), dr_min(3)
29 character(len=100) :: fname
30 integer :: count_rate, t_start, t_end
32 print *,
"Running drift_diffusion_3d" 33 print *,
"Number of threads", af_get_max_threads()
41 cc_names=[
"phi",
"old",
"err"])
49 call a3_set_base(tree, 1, ix_list, nb_list)
62 call system_clock(t_start,count_rate)
66 refine_steps=refine_steps+1
68 call a3_loop_box(tree, set_initial_condition)
76 call a3_gc_tree(tree, i_phi, a3_gc_interp_lim, a3_bc_neumann_zero)
84 call a3_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 a3_print_info(tree)
103 call a3_restrict_tree(tree, i_phi)
108 call a3_gc_tree(tree, i_phi, a3_gc_interp_lim, a3_bc_neumann_zero)
110 call system_clock(t_start, count_rate)
115 time_steps = time_steps + 1
116 dr_min = a3_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_3d_", output_cnt
128 call a3_loop_box_arg(tree, set_error, [time])
137 call a3_tree_max_cc(tree, i_err, p_err)
138 call a3_tree_min_cc(tree, i_err, n_err)
139 call a3_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 a3_tree_copy_cc(tree, i_phi, i_phi_old)
154 call a3_loop_boxes(tree, fluxes_koren)
157 call a3_consistent_fluxes(tree, [i_phi])
160 call a3_loop_box_arg(tree, update_solution, [dt])
163 call a3_restrict_tree(tree, i_phi)
167 call a3_loop_box(tree, average_phi)
172 call a3_gc_tree(tree, i_phi, a3_gc_interp_lim, a3_bc_neumann_zero)
178 call a3_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 a3_destroy(tree)
197 subroutine refine_routine(box, cell_flags)
198 type(box3_t),
intent(in) :: box
199 integer,
intent(out) :: cell_flags(box%n_cell, box%n_cell, box%n_cell)
201 integer :: i, j, k, nc
205 do k = 1, nc;
do j = 1, nc;
do i = 1, nc
206 diff = abs(box%cc(i+1, j, k, i_phi) + &
207 box%cc(i-1, j, k, i_phi) + &
208 box%cc(i, j+1, k, i_phi) + &
209 box%cc(i, j-1, k, i_phi) + &
210 box%cc(i, j, k+1, i_phi) + &
211 box%cc(i, j, k-1, i_phi) - &
212 6 * box%cc(i, j, k, 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, k) = af_do_ref
216 else if (diff < 0.1_dp * 0.1e-3_dp)
then 217 cell_flags(i, j, k) = af_rm_ref
219 cell_flags(i, j, k) = af_keep_ref
221 end do; end do; end do
222 end subroutine refine_routine
225 subroutine set_initial_condition(box)
226 type(box3_t),
intent(inout) :: box
227 integer :: i, j, k, nc
231 do k = 0, nc+1;
do j = 0, nc+1;
do i = 0, nc+1
232 rr = a3_r_cc(box, [i, j, k])
233 box%cc(i, j, k, i_phi) = solution(rr, 0.0_dp)
234 end do; end do; end do
235 end subroutine set_initial_condition
238 subroutine set_error(box, time)
239 type(box3_t),
intent(inout) :: box
240 real(dp),
intent(in) :: time(:)
241 integer :: i, j, k, nc
245 do k = 1, nc;
do j = 1, nc;
do i = 1, nc
246 rr = a3_r_cc(box, [i, j, k])
247 box%cc(i, j, k, i_err) = &
248 box%cc(i, j, k, i_phi) - solution(rr, time(1))
249 end do; end do; end do
250 end subroutine set_error
253 function solution(rr, t)
result(sol)
254 real(dp),
intent(in) :: rr(3), t
255 real(dp) :: sol, rr_t(3)
257 rr_t = rr - velocity * t
259 select case (sol_type)
261 sol = sin(rr_t(1))**4 * cos(rr_t(2))**4
263 rr_t = modulo(rr_t, domain_len) / domain_len
264 if (norm2(rr_t - 0.5_dp) < 0.1_dp)
then 270 end function solution
274 subroutine fluxes_koren(boxes, id)
276 type(box3_t),
intent(inout) :: boxes(:)
277 integer,
intent(in) :: id
278 real(dp) :: gradp, gradc, gradn
280 integer :: dim, dix(3), i, j, k, nc
281 real(dp),
allocatable :: cc(:, :, :)
282 real(dp),
allocatable :: v(:, :, :, :)
284 nc = boxes(id)%n_cell
285 inv_dr = 1/boxes(id)%dr
286 allocate(cc(-1:nc+2, -1:nc+2, -1:nc+2))
287 allocate(v(1:nc+1, 1:nc+1, 1:nc+1, 3))
289 call a3_gc_box(boxes, id, i_phi, a3_gc_interp_lim, a3_bc_neumann_zero)
294 call a3_gc2_box(boxes, &
297 a3_gc2_prolong_linear, &
298 a3_bc2_neumann_zero, &
302 v(:, :, :, 1) = velocity(1)
303 v(:, :, :, 2) = velocity(2)
304 v(:, :, :, 3) = velocity(3)
306 call flux_koren_3d(cc, v, nc, 2)
307 boxes(id)%fc(:, :, :, :, i_phi) = v
314 end subroutine fluxes_koren
317 subroutine update_solution(box, dt)
318 type(box3_t),
intent(inout) :: box
319 real(dp),
intent(in) :: dt(:)
321 integer :: i, j, k, nc
326 forall (i = 1:nc, j = 1:nc, k = 1:nc)
327 box%cc(i, j, k, i_phi) = box%cc(i, j, k, i_phi) + dt(1) * inv_dr * ( &
328 box%fc(i, j, k, 1, i_phi) - box%fc(i+1, j, k, 1, i_phi) + &
329 box%fc(i, j, k, 2, i_phi) - box%fc(i, j+1, k, 2, i_phi) + &
330 box%fc(i, j, k, 3, i_phi) - box%fc(i, j, k+1, 3, i_phi))
332 end subroutine update_solution
335 subroutine average_phi(box)
336 type(box3_t),
intent(inout) :: box
338 box%cc(:, :, :, i_phi) = 0.5_dp * (box%cc(:, :, :, i_phi) + &
339 box%cc(:, :, :, i_phi_old))
340 end subroutine average_phi
343 subroutine prolong_to_new_children(tree, refine_info)
344 type(a3_t),
intent(inout) :: tree
345 type(ref_info_t),
intent(in) :: refine_info
346 integer :: lvl, i, id, p_id
348 do lvl = 1, tree%highest_lvl
350 do i = 1,
size(refine_info%lvls(lvl)%add)
351 id = refine_info%lvls(lvl)%add(i)
352 p_id = tree%boxes(id)%parent
355 call a3_prolong_linear(tree%boxes(p_id), tree%boxes(id), i_phi)
362 call a3_gc_ids(tree%boxes, refine_info%lvls(lvl)%add, i_phi, &
363 a3_gc_interp_lim, a3_bc_neumann_zero)
365 end subroutine prolong_to_new_children
367 end program drift_diffusion_3d