Afivo  0.3
poisson_cyl_analytic.f90
1 
5 program poisson_cyl_analytic
6  use m_a2_all
7 
8  implicit none
9 
10  integer, parameter :: box_size = 8
11  integer, parameter :: n_boxes_base = 1
12  integer, parameter :: n_iterations = 10
13  integer, parameter :: n_var_cell = 5
14  integer, parameter :: i_phi = 1
15  integer, parameter :: i_rhs = 2
16  integer, parameter :: i_err = 3
17  integer, parameter :: i_sol = 4
18  integer, parameter :: i_tmp = 5
19 
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
27 
28  type(a2_t) :: tree
29  type(ref_info_t) :: ref_info
30  integer :: mg_iter
31  integer :: ix_list(2, n_boxes_base)
32  real(dp) :: dr, residu(2), anal_err(2), max_val
33  character(len=100) :: fname
34  type(mg2_t) :: mg
35  integer :: count_rate,t_start, t_end
36 
37  print *, "Running poisson_cyl_analytic"
38  print *, "Number of threads", af_get_max_threads()
39 
40  ! The cell spacing at the coarsest grid level
41  dr = 1.25e-2_dp / box_size
42 
43  ! Initialize tree
44  call a2_init(tree, & ! Tree to initialize
45  box_size, & ! A box contains box_size**DIM cells
46  n_var_cell, & ! Number of cell-centered variables
47  0, & ! Number of face-centered variables
48  dr, & ! Distance between cells on base level
49  coarsen_to=2, & ! Add coarsened levels for multigrid
50  coord=af_cyl, & ! Cylindrical coordinates
51  cc_names=["phi", "rhs", "err", "sol", "tmp"]) ! Variable names
52 
53  ! Set up geometry. These indices are used to define the coordinates of a box,
54  ! by default the box at [1,1] touches the origin (x,y) = (0,0)
55  ix_list(:, 1) = [1,1] ! Set index of box 1
56 
57  ! Create the base mesh, using the box indices and their neighbor information
58  call a2_set_base(tree, 1, ix_list)
59  call a2_print_info(tree)
60 
61  call system_clock(t_start, count_rate)
62  do
63  ! For each box, set the initial conditions
64  call a2_loop_box(tree, set_init_cond)
65 
66  ! This updates the refinement of the tree, by at most one level per call.
67  call a2_adjust_refinement(tree, ref_routine, ref_info)
68 
69  ! If no new boxes have been added, exit the loop
70  if (ref_info%n_add == 0) exit
71  end do
72  call system_clock(t_end, count_rate)
73 
74  write(*,"(A,Es10.3,A)") " Wall-clock time generating AMR grid: ", &
75  (t_end-t_start) / real(count_rate,dp), " seconds"
76 
77  call a2_print_info(tree)
78 
79  ! Set the multigrid options.
80  mg%i_phi = i_phi ! Solution variable
81  mg%i_rhs = i_rhs ! Right-hand side variable
82  mg%i_tmp = i_tmp ! Variable for temporary space
83  mg%sides_bc => sides_bc ! Method for boundary conditions Because we use
84 
85  ! Automatically detect the right methods
86  mg%box_op => mg2_auto_op
87  mg%box_gsrb => mg2_auto_gsrb
88  mg%box_corr => mg2_auto_corr
89 
90  ! Initialize the multigrid options. This performs some basics checks and sets
91  ! default values where necessary.
92  ! This routine does not initialize the multigrid variables i_phi, i_rhs
93  ! and i_tmp. These variables will be initialized at the first call of mg2_fas_fmg
94  call mg2_init_mg(mg)
95 
96  print *, "Multigrid iteration | max residual | max rel. error"
97  call system_clock(t_start, count_rate)
98 
99  do mg_iter = 1, n_iterations
100  ! Perform a FAS-FMG cycle (full approximation scheme, full multigrid). The
101  ! third argument controls whether the residual is stored in i_tmp. The
102  ! fourth argument controls whether to improve the current solution.
103  call mg2_fas_fmg(tree, mg, .true., mg_iter>1)
104 
105  ! Compute the error compared to the analytic solution
106  call a2_loop_box(tree, set_err)
107 
108  ! Determine the minimum and maximum residual and error
109  call a2_tree_min_cc(tree, i_tmp, residu(1))
110  call a2_tree_max_cc(tree, i_tmp, residu(2))
111  call a2_tree_min_cc(tree, i_err, anal_err(1))
112  call a2_tree_max_cc(tree, i_err, anal_err(2))
113  call a2_tree_max_cc(tree, i_phi, max_val)
114  anal_err = anal_err / max_val
115 
116  write(*,"(I8,2Es14.5)") mg_iter, maxval(abs(residu)), &
117  maxval(abs(anal_err))
118 
119  write(fname, "(A,I0)") "poisson_cyl_analytic_", mg_iter
120  call a2_write_vtk(tree, trim(fname), dir="output")
121  end do
122  call system_clock(t_end, count_rate)
123 
124  write(*, "(A,I0,A,E10.3,A)") &
125  " Wall-clock time after ", n_iterations, &
126  " iterations: ", (t_end-t_start) / real(count_rate, dp), &
127  " seconds"
128 
129  ! This call is not really necessary here, but cleaning up the data in a tree
130  ! is important if your program continues with other tasks.
131  call a2_destroy(tree)
132 
133 contains
134 
135  ! Set refinement flags for box
136  subroutine ref_routine(box, cell_flags)
137  type(box2_t), intent(in) :: box
138  integer, intent(out) :: cell_flags(box%n_cell, box%n_cell)
139  integer :: i, j, nc
140  real(dp) :: crv
141 
142  nc = box%n_cell
143 
144  ! Compute the "curvature" in phi
145  do j = 1, nc
146  do i = 1, nc
147  crv = box%dr**2 * abs(box%cc(i, j, i_rhs))
148 
149  ! And refine if it exceeds a threshold
150  if (crv > 1e-1_dp .and. box%lvl < 10) then
151  cell_flags(i, j) = af_do_ref
152  else
153  cell_flags(i, j) = af_keep_ref
154  end if
155  end do
156  end do
157  end subroutine ref_routine
158 
159  ! This routine sets the initial conditions for each box
160  subroutine set_init_cond(box)
161  type(box2_t), intent(inout) :: box
162  integer :: i, j, nc
163  real(dp) :: rz(2)
164 
165  nc = box%n_cell
166 
167  do j = 0, nc+1
168  do i = 0, nc+1
169  rz = a2_r_cc(box, [i,j]) - rz_source
170 
171  ! Gaussian source term
172  box%cc(i, j, i_rhs) = - q_source * &
173  exp(-sum(rz**2) / (2 * sigma**2)) / &
174  (sigma**3 * sqrt(2 * pi)**3 * epsilon_source)
175  end do
176  end do
177  end subroutine set_init_cond
178 
179  real(dp) function solution(rz_in)
180  real(dp), intent(in) :: rz_in(2)
181  real(dp) :: d, erf_d
182 
183  d = norm2(rz_in - rz_source)
184 
185  ! Take limit when d -> 0
186  if (d < sqrt(epsilon(1.0d0))) then
187  erf_d = sqrt(2.0_dp/pi) / sigma
188  else
189  erf_d = erf(d * sqrt(0.5_dp) / sigma) / d
190  end if
191 
192  solution = erf_d * q_source / (4 * pi * epsilon_source)
193  end function solution
194 
195  ! Compute error compared to the analytic solution
196  subroutine set_err(box)
197  type(box2_t), intent(inout) :: box
198  integer :: i, j, nc
199  real(dp) :: rz(2)
200 
201  nc = box%n_cell
202  do j = 1, nc
203  do i = 1, nc
204  rz = a2_r_cc(box, [i,j])
205  box%cc(i, j, i_sol) = solution(rz)
206  box%cc(i, j, i_err) = box%cc(i, j, i_phi) - box%cc(i, j, i_sol)
207  end do
208  end do
209  end subroutine set_err
210 
211  ! This routine sets boundary conditions for a box, by filling its ghost cells
212  ! with approriate values. Note that on the axis (a boundary in the lower-x
213  ! direction) we should use a Neumann zero condition in cylindrical
214  ! coordinates.
215  subroutine sides_bc(box, nb, iv, bc_type)
216  type(box2_t), intent(inout) :: box
217  integer, intent(in) :: nb ! Direction for the boundary condition
218  integer, intent(in) :: iv ! Index of variable
219  integer, intent(out) :: bc_type ! Type of boundary condition
220  real(dp) :: rz(2)
221  integer :: n, nc
222 
223  nc = box%n_cell
224 
225  select case (nb)
226  case (a2_neighb_lowx) ! Neumann zero on axis
227  bc_type = af_bc_neumann
228  box%cc(0, 1:nc, iv) = 0
229  case (a2_neighb_highx) ! Use solution on other boundaries
230  bc_type = af_bc_dirichlet
231  do n = 1, nc
232  rz = a2_rr_cc(box, [nc+0.5_dp, real(n, dp)])
233  box%cc(nc+1, n, iv) = solution(rz)
234  end do
235  case (a2_neighb_lowy)
236  bc_type = af_bc_dirichlet
237  do n = 1, nc
238  rz = a2_rr_cc(box, [real(n, dp), 0.5_dp])
239  box%cc(n, 0, iv) = solution(rz)
240  end do
241  case (a2_neighb_highy)
242  bc_type = af_bc_dirichlet
243  do n = 1, nc
244  rz = a2_rr_cc(box, [real(n, dp), nc+0.5_dp])
245  box%cc(n, nc+1, iv) = solution(rz)
246  end do
247  end select
248  end subroutine sides_bc
249 
250 end program poisson_cyl_analytic
Module which contains all Afivo modules, so that a user does not have to include them separately...
Definition: m_a2_all.f90:4