Example showing how to use multigrid and compare with an analytic solution, using the method of manufactured solutions. A standard 5-point Laplacian is used in cylindrical coordinates.
12 integer,
parameter :: box_size = 8
13 integer,
parameter :: n_iterations = 10
18 real(dp),
parameter :: lambda = 1000.0_dp
21 type(ref_info_t) :: ref_info
23 real(dp) :: residu(2), anal_err(2)
24 character(len=100) :: fname
27 integer :: count_rate,t_start, t_end
29 print *,
"Running helmholtz_cyl"
30 print *,
"Number of threads", af_get_max_threads()
33 call gauss_init(gs, [1.0_dp, 1.0_dp], [0.01_dp, 0.04_dp], &
34 reshape([0.0_dp, 0.25_dp, 0.0_dp, 0.75_dp], [2,2]))
36 call af_add_cc_variable(tree,
"phi", ix=i_phi)
37 call af_add_cc_variable(tree,
"rhs", ix=i_rhs)
38 call af_add_cc_variable(tree,
"err", ix=i_err)
39 call af_add_cc_variable(tree,
"tmp", ix=i_tmp)
45 [box_size, box_size], &
48 call af_print_info(tree)
50 call system_clock(t_start, count_rate)
53 call af_loop_box(tree, set_init_cond)
56 call af_adjust_refinement(tree, ref_routine, ref_info)
59 if (ref_info%n_add == 0)
exit
61 call system_clock(t_end, count_rate)
63 write(*,
"(A,Es10.3,A)")
" Wall-clock time generating AMR grid: ", &
64 (t_end-t_start) / real(count_rate,dp),
" seconds"
66 call af_print_info(tree)
72 mg%sides_bc => sides_bc
73 mg%helmholtz_lambda = lambda
79 call mg_init(tree, mg)
81 print *,
"Multigrid iteration | max residual | max error"
82 call system_clock(t_start, count_rate)
84 do mg_iter = 1, n_iterations
88 call mg_fas_fmg(tree, mg, .true., mg_iter>1)
91 call af_loop_box(tree, set_err)
94 call af_tree_min_cc(tree, i_tmp, residu(1))
95 call af_tree_max_cc(tree, i_tmp, residu(2))
96 call af_tree_min_cc(tree, i_err, anal_err(1))
97 call af_tree_max_cc(tree, i_err, anal_err(2))
98 write(*,
"(I8,2Es14.5)") mg_iter, maxval(abs(residu)), &
101 write(fname,
"(A,I0)")
"output/helmholtz_cyl_", mg_iter
102 call af_write_vtk(tree, trim(fname))
104 call system_clock(t_end, count_rate)
106 write(*,
"(A,I0,A,E10.3,A)") &
107 " Wall-clock time after ", n_iterations, &
108 " iterations: ", (t_end-t_start) / real(count_rate, dp), &
113 call af_destroy(tree)
118 subroutine ref_routine(box, cell_flags)
119 type(box_t),
intent(in) :: box
120 integer,
intent(out) :: cell_flags(box%n_cell, box%n_cell)
125 dr2 = maxval(box%dr)**2
130 crv = dr2 * abs(box%cc(i, j, i_rhs))
133 if (crv > 5.0e-4_dp)
then
134 cell_flags(i, j) = af_do_ref
136 cell_flags(i, j) = af_keep_ref
145 end subroutine ref_routine
148 subroutine set_init_cond(box)
149 type(box_t),
intent(inout) :: box
157 rz = af_r_cc(box, [i,j])
158 box%cc(i, j, i_rhs) = gauss_laplacian_cyl(gs, rz) - &
159 lambda * gauss_value(gs, rz)
162 end subroutine set_init_cond
165 subroutine set_err(box)
166 type(box_t),
intent(inout) :: box
173 rz = af_r_cc(box, [i,j])
174 box%cc(i, j, i_err) = box%cc(i, j, i_phi) - gauss_value(gs, rz)
177 end subroutine set_err
180 subroutine sides_bc(box, nb, iv, coords, bc_val, bc_type)
181 type(box_t),
intent(in) :: box
182 integer,
intent(in) :: nb
183 integer,
intent(in) :: iv
184 real(dp),
intent(in) :: coords(NDIM, box%n_cell**(NDIM-1))
185 real(dp),
intent(out) :: bc_val(box%n_cell**(NDIM-1))
186 integer,
intent(out) :: bc_type
189 if (nb == af_neighb_lowx)
then
191 bc_type = af_bc_neumann
195 bc_type = af_bc_dirichlet
198 do n = 1, box%n_cell**(ndim-1)
199 bc_val(n) = gauss_value(gs, coords(:, n))
202 end subroutine sides_bc
204 end program helmholtz_cyl
Module which contains all Afivo modules, so that a user does not have to include them separately.
This module can be used to construct solutions consisting of one or more Gaussians.