Example showing how to use multigrid and compare with an analytic solution. A standard 5-point Laplacian is used in cylindrical coordinates.
5 program poisson_cyl_analytic
10 integer,
parameter :: box_size = 8
11 integer,
parameter :: n_iterations = 10
20 real(dp),
parameter :: domain_len = 1.25e-2_dp
21 real(dp),
parameter :: pi = acos(-1.0_dp)
22 real(dp),
parameter :: sigma = 4e-4_dp * sqrt(0.5_dp)
23 real(dp),
parameter :: rz_source(2) = [0.0_dp, 0.5_dp] * domain_len
24 real(dp),
parameter :: epsilon_source = 8.85e-12_dp
25 real(dp),
parameter :: Q_source = 3e18_dp * 1.6022e-19_dp * &
26 sigma**3 * sqrt(2 * pi)**3
29 type(ref_info_t) :: ref_info
31 real(dp) :: residu(2), anal_err(2), max_val
32 character(len=100) :: fname
34 integer :: count_rate,t_start, t_end
36 print *,
"Running poisson_cyl_analytic"
37 print *,
"Number of threads", af_get_max_threads()
39 call af_add_cc_variable(tree,
"phi", ix=i_phi)
40 call af_add_cc_variable(tree,
"rhs", ix=i_rhs)
41 call af_add_cc_variable(tree,
"err", ix=i_err)
42 call af_add_cc_variable(tree,
"sol", ix=i_sol)
43 call af_add_cc_variable(tree,
"tmp", ix=i_tmp)
44 call af_add_cc_variable(tree,
"Dx", ix=i_gradx)
45 call af_add_cc_variable(tree,
"eDx", ix=i_egradx)
50 [1.25e-2_dp, 1.25e-2_dp], &
51 [box_size, box_size], &
54 call af_print_info(tree)
56 call system_clock(t_start, count_rate)
59 call af_loop_box(tree, set_init_cond)
62 call af_adjust_refinement(tree, ref_routine, ref_info)
65 if (ref_info%n_add == 0)
exit
67 call system_clock(t_end, count_rate)
69 write(*,
"(A,Es10.3,A)")
" Wall-clock time generating AMR grid: ", &
70 (t_end-t_start) / real(count_rate,dp),
" seconds"
72 call af_print_info(tree)
78 mg%sides_bc => sides_bc
84 call mg_init(tree, mg)
86 print *,
"Multigrid iteration | max residual | max rel. error"
87 call system_clock(t_start, count_rate)
89 do mg_iter = 1, n_iterations
93 call mg_fas_fmg(tree, mg, .true., mg_iter>1)
96 call af_loop_box(tree, set_err)
99 call af_tree_min_cc(tree, i_tmp, residu(1))
100 call af_tree_max_cc(tree, i_tmp, residu(2))
101 call af_tree_min_cc(tree, i_err, anal_err(1))
102 call af_tree_max_cc(tree, i_err, anal_err(2))
103 call af_tree_max_cc(tree, i_phi, max_val)
104 anal_err = anal_err / max_val
106 write(*,
"(I8,2Es14.5)") mg_iter, maxval(abs(residu)), &
107 maxval(abs(anal_err))
109 write(fname,
"(A,I0)")
"output/poisson_cyl_analytic_", mg_iter
110 call af_write_silo(tree, trim(fname))
112 call system_clock(t_end, count_rate)
114 write(*,
"(A,I0,A,E10.3,A)") &
115 " Wall-clock time after ", n_iterations, &
116 " iterations: ", (t_end-t_start) / real(count_rate, dp), &
121 call af_destroy(tree)
126 subroutine ref_routine(box, cell_flags)
127 type(box_t),
intent(in) :: box
128 integer,
intent(out) :: cell_flags(box%n_cell, box%n_cell)
133 dr2 = maxval(box%dr)**2
138 crv = dr2 * abs(box%cc(i, j, i_rhs))
141 if (crv > 1e-1_dp .and. box%lvl < 10)
then
142 cell_flags(i, j) = af_do_ref
144 cell_flags(i, j) = af_keep_ref
148 end subroutine ref_routine
151 subroutine set_init_cond(box)
152 type(box_t),
intent(inout) :: box
154 real(dp) :: rz(2), gradx
160 rz = af_r_cc(box, [i,j])
163 box%cc(i, j, i_rhs) = - q_source * &
164 exp(-sum((rz - rz_source)**2) / (2 * sigma**2)) / &
165 (sigma**3 * sqrt(2 * pi)**3 * epsilon_source)
167 box%cc(i, j, i_sol) = solution(rz)
173 gradx = 0.5_dp * (box%cc(i+1, j, i_sol) - &
174 box%cc(i-1, j, i_sol)) / box%dr(1)
175 box%cc(i, j, i_gradx) = gradx
179 end subroutine set_init_cond
181 real(dp) function solution(rz_in)
182 real(dp),
intent(in) :: rz_in(2)
185 d = norm2(rz_in - rz_source)
188 if (d < sqrt(epsilon(1.0d0)))
then
189 erf_d = sqrt(2.0_dp/pi) / sigma
191 erf_d = erf(d * sqrt(0.5_dp) / sigma) / d
194 solution = erf_d * q_source / (4 * pi * epsilon_source)
195 end function solution
198 subroutine set_err(box)
199 type(box_t),
intent(inout) :: box
201 real(dp) :: rz(2), gradx
206 rz = af_r_cc(box, [i,j])
207 box%cc(i, j, i_err) = box%cc(i, j, i_phi) - box%cc(i, j, i_sol)
209 gradx = 0.5_dp * (box%cc(i+1, j, i_phi) - &
210 box%cc(i-1, j, i_phi)) / box%dr(1)
211 box%cc(i, j, i_egradx) = gradx - box%cc(i, j, i_gradx)
214 end subroutine set_err
217 subroutine sides_bc(box, nb, iv, coords, bc_val, bc_type)
218 type(box_t),
intent(in) :: box
219 integer,
intent(in) :: nb
220 integer,
intent(in) :: iv
221 real(dp),
intent(in) :: coords(NDIM, box%n_cell**(NDIM-1))
222 real(dp),
intent(out) :: bc_val(box%n_cell**(NDIM-1))
223 integer,
intent(out) :: bc_type
226 if (nb == af_neighb_lowx)
then
228 bc_type = af_bc_neumann
232 bc_type = af_bc_dirichlet
235 do n = 1, box%n_cell**(ndim-1)
236 bc_val(n) = solution(coords(:, n))
239 end subroutine sides_bc
241 end program poisson_cyl_analytic
Module which contains all Afivo modules, so that a user does not have to include them separately.