Afivo  0.3
multigrid_matrix_2d.f90
1 
6 program multigrid_matrix_2d
7  use m_a2_all
8 
9  implicit none
10 
11  integer, parameter :: box_size = 16
12  integer, parameter :: n_boxes_base = 1
13  integer, parameter :: n_iterations = 10
14  integer, parameter :: n_var_cell = 5
15  integer, parameter :: i_phi = 1
16  integer, parameter :: i_rhs = 2
17  integer, parameter :: i_tmp = 3
18  integer, parameter :: i_mat_diag = 4
19  integer, parameter :: i_ins = 5
20  integer, parameter :: if_mat_nb = 1
21 
22  type(a2_t) :: tree
23  type(ref_info_t) :: refine_info
24  integer :: mg_iter
25  integer :: ix_list(2, n_boxes_base)
26  real(dp) :: dr, residu(2), my_sum
27  character(len=100) :: fname
28  type(mg2_t) :: mg
29  integer :: lvl, i, id, p_id
30 
31  print *, "Running multigrid_matrix_2d"
32  print *, "Number of threads", af_get_max_threads()
33 
34  ! The cell spacing at the coarsest grid level
35  dr = 4.0_dp / box_size
36 
37  ! Initialize tree
38  call a2_init(tree, & ! Tree to initialize
39  box_size, & ! A box contains box_size**DIM cells
40  n_var_cell, & ! Number of cell-centered variables
41  1, & ! Number of face-centered variables
42  dr, & ! Distance between cells on base level
43  coarsen_to=2, & ! Add coarsened levels for multigrid
44  cc_names=["phi", "rhs", "tmp", "a00", "ins"]) ! Variable names
45 
46  ! Set up geometry. These indices are used to define the coordinates of a box,
47  ! by default the box at [1,1] touches the origin (x,y) = (0,0)
48  ix_list(:, 1) = [1, 1] ! Set index of box 1
49 
50  ! Create the base mesh, using the box indices and their neighbor information
51  call a2_set_base(tree, 1, ix_list)
52 
53  do
54  call a2_loop_box(tree, set_initial_condition)
55  call a2_adjust_refinement(tree, refine_routine, refine_info)
56  if (refine_info%n_add == 0) exit
57  end do
58 
59  ! Restrict matrix
60  do lvl = tree%highest_lvl-1, lbound(tree%lvls, 1), -1
61  do i = 1, size(tree%lvls(lvl)%parents)
62  p_id = tree%lvls(lvl)%parents(i)
63  call restrict_matrix(tree%boxes, p_id, i_mat_diag, if_mat_nb)
64  end do
65  end do
66 
67  ! Initialize the multigrid options. This performs some basics checks and sets
68  ! default values where necessary.
69  mg%i_phi = i_phi ! Solution variable
70  mg%i_rhs = i_rhs ! Right-hand side variable
71  mg%i_tmp = i_tmp ! Variable for temporary space
72  mg%sides_bc => bc_dirichlet_one
73 
74  mg%box_op => box_matrix
75  mg%box_gsrb => box_gsrb
76 
77  call mg2_init_mg(mg)
78 
79  do mg_iter = 1, n_iterations
80  call mg2_fas_fmg(tree, mg, set_residual=.true., have_guess=(mg_iter>1))
81  ! call mg2_fas_vcycle(tree, mg, set_residual=.true.)
82 
83  call a2_tree_min_cc(tree, i_tmp, residu(1))
84  call a2_tree_max_cc(tree, i_tmp, residu(2))
85  call a2_tree_sum_cc(tree, i_phi, my_sum)
86  write(*,"(I8,13x,2Es14.5)") mg_iter, maxval(abs(residu)), my_sum
87 
88  write(fname, "(A,I0)") "multigrid_matrix_2d_", mg_iter
89  call a2_write_silo(tree, trim(fname), dir="output")
90  end do
91 
92 contains
93 
94  ! Return the refinement flags for box
95  subroutine refine_routine(box, cell_flags)
96  type(box2_t), intent(in) :: box
97  integer, intent(out) :: cell_flags(box%n_cell, box%n_cell)
98 
99  if (box%lvl < 3) then
100  cell_flags(:, :) = af_do_ref
101  else
102  cell_flags(:, :) = af_keep_ref
103  end if
104  end subroutine refine_routine
105 
106  ! This routine sets the initial conditions for each box
107  subroutine set_initial_condition(box)
108  type(box2_t), intent(inout) :: box
109  integer :: i, j, nc
110  real(dp) :: rr(2), inv_dr2, dr2
111 
112  nc = box%n_cell
113  dr2 = box%dr**2
114  inv_dr2 = 1/box%dr**2
115 
116  do j = 0, nc+1; do i = 0, nc+1
117  ! Get the coordinate of the cell center at i, j
118  rr = a2_r_cc(box, [i, j])
119  rr = rr - 2.0_dp
120 
121  box%cc(i, j, i_rhs) = 0.0_dp
122  box%cc(i, j, i_phi) = 0.0_dp
123 
124  ! box%cc(i, j, i_ins) = (sum(rr**2)-1)**3 - rr(1)**2 * rr(2)**3 ! Heart
125  ! box%cc(i, j, i_ins) = norm2(rr-0.5_dp)-0.25_dp ! Circle
126  ! box%cc(i, j, i_ins) = sqrt(200 * rr(1)**2 + rr(2)**2) - 1.5_dp ! Sharp ellipse
127  box%cc(i, j, i_ins) = sum(abs(rr)) - 0.5_dp ! Square
128  ! box%cc(i, j, i_ins) = 1.0_dp ! No boundary
129 
130  end do; end do
131 
132  ! Center matrix coeff
133  do j = 1, nc
134  do i = 1, nc
135  box%cc(i, j, i_mat_diag) = -4 * inv_dr2
136  end do
137  end do
138 
139  do j = 1, nc
140  do i = 1, nc+1
141  if (box%cc(i-1, j, i_ins) < 0 .or. box%cc(i, j, i_ins) < 0) then
142  ! Left boundary
143  box%fc(i, j, 1, if_mat_nb) = 0
144  box%cc(i-1, j, i_rhs) = box%cc(i-1, j, i_rhs) - 2*inv_dr2
145  box%cc(i-1, j, i_mat_diag) = box%cc(i-1, j, i_mat_diag) - inv_dr2
146  box%cc(i, j, i_rhs) = box%cc(i, j, i_rhs) - 2*inv_dr2
147  box%cc(i, j, i_mat_diag) = box%cc(i, j, i_mat_diag) - inv_dr2
148  else
149  box%fc(i, j, 1, if_mat_nb) = inv_dr2
150  end if
151  end do
152  end do
153 
154  do j = 1, nc+1
155  do i = 1, nc
156  if (box%cc(i, j-1, i_ins) < 0 .or. box%cc(i, j, i_ins) < 0) then
157  ! Bottom boundary
158  box%fc(i, j, 2, if_mat_nb) = 0
159  box%cc(i, j-1, i_rhs) = box%cc(i, j-1, i_rhs) - 2*inv_dr2
160  box%cc(i, j-1, i_mat_diag) = box%cc(i, j-1, i_mat_diag) - inv_dr2
161  box%cc(i, j, i_rhs) = box%cc(i, j, i_rhs) - 2*inv_dr2
162  box%cc(i, j, i_mat_diag) = box%cc(i, j, i_mat_diag) - inv_dr2
163  else
164  box%fc(i, j, 2, if_mat_nb) = inv_dr2
165  end if
166  end do
167  end do
168 
169  end subroutine set_initial_condition
170 
171  subroutine box_matrix(box, i_out, mg)
172  type(box2_t), intent(inout) :: box
173  integer, intent(in) :: i_out
174  type(mg2_t), intent(in) :: mg
175  integer :: i, j, nc, i_phi
176  real(dp) :: inv_dr_sq, coeffs(2*2+1), vals(2*2+1)
177 
178  nc = box%n_cell
179  inv_dr_sq = 1 / box%dr**2
180  i_phi = mg%i_phi
181 
182  do j = 1, nc
183  do i = 1, nc
184  coeffs(1:2) = box%fc(i:i+1, j, 1, if_mat_nb)
185  coeffs(3:4) = box%fc(i, j:j+1, 2, if_mat_nb)
186  coeffs(5) = box%cc(i, j, i_mat_diag)
187 
188  vals(1) = box%cc(i-1, j, i_phi)
189  vals(2) = box%cc(i+1, j, i_phi)
190  vals(3) = box%cc(i, j-1, i_phi)
191  vals(4) = box%cc(i, j+1, i_phi)
192  vals(5) = box%cc(i, j, i_phi)
193 
194  box%cc(i, j, i_out) = sum(coeffs * vals)
195  end do
196  end do
197  end subroutine box_matrix
198 
199  subroutine box_gsrb(box, redblack_cntr, mg)
200  type(box2_t), intent(inout) :: box
201  integer, intent(in) :: redblack_cntr
202  type(mg2_t), intent(in) :: mg
203  integer :: i, i0, j, nc, i_phi, i_rhs
204  real(dp) :: inv_dr_sq, coeffs(2*2+1), vals(2*2)
205 
206  nc = box%n_cell
207  inv_dr_sq = 1 / box%dr**2
208  i_phi = mg%i_phi
209  i_rhs = mg%i_rhs
210 
211  do j = 1, nc
212  i0 = 2 - iand(ieor(redblack_cntr, j), 1)
213  do i = i0, nc, 2
214  coeffs(1:2) = box%fc(i:i+1, j, 1, if_mat_nb)
215  coeffs(3:4) = box%fc(i, j:j+1, 2, if_mat_nb)
216  coeffs(5) = box%cc(i, j, i_mat_diag)
217 
218  vals(1) = box%cc(i-1, j, i_phi)
219  vals(2) = box%cc(i+1, j, i_phi)
220  vals(3) = box%cc(i, j-1, i_phi)
221  vals(4) = box%cc(i, j+1, i_phi)
222 
223  box%cc(i, j, i_phi) = (box%cc(i, j, i_rhs) - &
224  sum(coeffs(1:4) * vals)) / coeffs(5)
225  end do
226  end do
227  end subroutine box_gsrb
228 
229  subroutine restrict_matrix(boxes, p_id, iv_diag, ivf_nb)
230  type(box2_t), intent(inout) :: boxes(:)
231  integer, intent(in) :: p_id
232  integer, intent(in) :: iv_diag
233  integer, intent(in) :: ivf_nb
234  integer :: c_id, nc, n
235 
236  nc = boxes(p_id)%n_cell
237 
238  do n = 1, a2_num_children
239  c_id = boxes(p_id)%children(n)
240  if (c_id <= af_no_box) cycle
241  call a2_restrict_box(boxes(c_id), boxes(p_id), iv_diag)
242  call a2_restrict_box_face(boxes(c_id), boxes(p_id), ivf_nb)
243  end do
244 
245  boxes(p_id)%cc(1:nc, 1:nc, iv_diag) = &
246  boxes(p_id)%cc(1:nc, 1:nc, iv_diag) * 0.25_dp
247  boxes(p_id)%fc(1:nc+1, 1:nc+1, 1:2, ivf_nb) = &
248  boxes(p_id)%fc(1:nc+1, 1:nc+1, 1:2, ivf_nb) * 0.25_dp
249 
250  end subroutine restrict_matrix
251 
252  ! This fills ghost cells near physical boundaries using Neumann zero
253  subroutine bc_dirichlet_one(box, nb, iv, bc_type)
254  type(box2_t), intent(inout) :: box
255  integer, intent(in) :: nb, iv
256  integer, intent(out) :: bc_type
257 
258  bc_type = af_bc_dirichlet
259  call a2_set_box_gc(box, nb, iv, 1.0_dp)
260  end subroutine bc_dirichlet_one
261 
262 end program multigrid_matrix_2d
Module which contains all Afivo modules, so that a user does not have to include them separately...
Definition: m_a2_all.f90:4