Afivo  0.3
multigrid_matrix_3d.f90
1 
6 program multigrid_matrix_3d
7  use m_a3_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(a3_t) :: tree
23  type(ref_info_t) :: refine_info
24  integer :: mg_iter
25  integer :: ix_list(3, n_boxes_base)
26  real(dp) :: dr, residu(2), my_sum
27  character(len=100) :: fname
28  type(mg3_t) :: mg
29  integer :: lvl, i, id, p_id
30 
31  print *, "Running multigrid_matrix_3d"
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 a3_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, 1] ! Set index of box 1
49 
50  ! Create the base mesh, using the box indices and their neighbor information
51  call a3_set_base(tree, 1, ix_list)
52 
53  do
54  call a3_loop_box(tree, set_initial_condition)
55  call a3_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 mg3_init_mg(mg)
78 
79  do mg_iter = 1, n_iterations
80  call mg3_fas_fmg(tree, mg, set_residual=.true., have_guess=(mg_iter>1))
81  ! call mg3_fas_vcycle(tree, mg, set_residual=.true.)
82 
83  call a3_tree_min_cc(tree, i_tmp, residu(1))
84  call a3_tree_max_cc(tree, i_tmp, residu(2))
85  call a3_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_3d_", mg_iter
89  call a3_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(box3_t), intent(in) :: box
97  integer, intent(out) :: cell_flags(box%n_cell, 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(box3_t), intent(inout) :: box
109  integer :: i, j, k, nc
110  real(dp) :: rr(3), inv_dr2, dr2
111 
112  nc = box%n_cell
113  dr2 = box%dr**2
114  inv_dr2 = 1/box%dr**2
115 
116  do k = 0, nc+1; do j = 0, nc+1; do i = 0, nc+1
117  ! Get the coordinate of the cell center at i, j, k
118  rr = a3_r_cc(box, [i, j, k])
119  rr = rr - 2.0_dp
120 
121  box%cc(i, j, k, i_rhs) = 0.0_dp
122  box%cc(i, j, k, i_phi) = 0.0_dp
123 
124  ! box%cc(i, j, k, i_ins) = (sum(rr**2)-1)**3 - rr(1)**2 * rr(2)**3 ! Heart
125  ! box%cc(i, j, k, i_ins) = norm2(rr-0.5_dp)-0.25_dp ! Circle
126  ! box%cc(i, j, k, i_ins) = sqrt(200 * rr(1)**2 + rr(2)**2) - 1.5_dp ! Sharp ellipse
127  box%cc(i, j, k, i_ins) = sum(abs(rr)) - 0.5_dp ! Square
128  ! box%cc(i, j, k, i_ins) = 1.0_dp ! No boundary
129 
130  end do; end do; end do
131 
132  end subroutine set_initial_condition
133 
134  subroutine box_matrix(box, i_out, mg)
135  type(box3_t), intent(inout) :: box
136  integer, intent(in) :: i_out
137  type(mg3_t), intent(in) :: mg
138  integer :: i, j, nc, i_phi
139  real(dp) :: inv_dr_sq, coeffs(2*3+1), vals(2*3+1)
140  integer :: k
141 
142  nc = box%n_cell
143  inv_dr_sq = 1 / box%dr**2
144  i_phi = mg%i_phi
145 
146  do k = 1, nc
147  do j = 1, nc
148  do i = 1, nc
149  coeffs(1:2) = box%fc(i:i+1, j, k, 1, if_mat_nb)
150  coeffs(3:4) = box%fc(i, j:j+1, k, 2, if_mat_nb)
151  coeffs(5:6) = box%fc(i, j, k:k+1, 3, if_mat_nb)
152  coeffs(7) = box%cc(i, j, k, i_mat_diag)
153 
154  vals(1) = box%cc(i-1, j, k, i_phi)
155  vals(2) = box%cc(i+1, j, k, i_phi)
156  vals(3) = box%cc(i, j-1, k, i_phi)
157  vals(4) = box%cc(i, j+1, k, i_phi)
158  vals(5) = box%cc(i, j, k-1, i_phi)
159  vals(6) = box%cc(i, j, k+1, i_phi)
160  vals(7) = box%cc(i, j, k, i_phi)
161 
162  box%cc(i, j, k, i_out) = sum(coeffs * vals)
163  end do
164  end do
165  end do
166  end subroutine box_matrix
167 
168  subroutine box_gsrb(box, redblack_cntr, mg)
169  type(box3_t), intent(inout) :: box
170  integer, intent(in) :: redblack_cntr
171  type(mg3_t), intent(in) :: mg
172  integer :: i, i0, j, nc, i_phi, i_rhs
173  real(dp) :: inv_dr_sq, coeffs(2*3+1), vals(2*3)
174  integer :: k
175 
176  nc = box%n_cell
177  inv_dr_sq = 1 / box%dr**2
178  i_phi = mg%i_phi
179  i_rhs = mg%i_rhs
180 
181  do k = 1, nc
182  do j = 1, nc
183  i0 = 2 - iand(ieor(redblack_cntr, k+j), 1)
184  do i = i0, nc, 2
185  coeffs(1:2) = box%fc(i:i+1, j, k, 1, if_mat_nb)
186  coeffs(3:4) = box%fc(i, j:j+1, k, 2, if_mat_nb)
187  coeffs(5:6) = box%fc(i, j, k:k+1, 3, if_mat_nb)
188  coeffs(7) = box%cc(i, j, k, i_mat_diag)
189 
190  vals(1) = box%cc(i-1, j, k, i_phi)
191  vals(2) = box%cc(i+1, j, k, i_phi)
192  vals(3) = box%cc(i, j-1, k, i_phi)
193  vals(4) = box%cc(i, j+1, k, i_phi)
194  vals(5) = box%cc(i, j, k-1, i_phi)
195  vals(6) = box%cc(i, j, k+1, i_phi)
196 
197  box%cc(i, j, k, i_phi) = (box%cc(i, j, k, i_rhs) - &
198  sum(coeffs(1:6) * vals)) / coeffs(7)
199  end do
200  end do
201  end do
202  end subroutine box_gsrb
203 
204  subroutine restrict_matrix(boxes, p_id, iv_diag, ivf_nb)
205  type(box3_t), intent(inout) :: boxes(:)
206  integer, intent(in) :: p_id
207  integer, intent(in) :: iv_diag
208  integer, intent(in) :: ivf_nb
209  integer :: c_id, nc, n
210 
211  nc = boxes(p_id)%n_cell
212 
213  do n = 1, a3_num_children
214  c_id = boxes(p_id)%children(n)
215  if (c_id <= af_no_box) cycle
216  call a3_restrict_box(boxes(c_id), boxes(p_id), iv_diag)
217  call a3_restrict_box_face(boxes(c_id), boxes(p_id), ivf_nb)
218  end do
219 
220  boxes(p_id)%cc(1:nc, 1:nc, 1:nc, iv_diag) = &
221  boxes(p_id)%cc(1:nc, 1:nc, 1:nc, iv_diag) * 0.25_dp
222  boxes(p_id)%fc(1:nc+1, 1:nc+1, 1:nc+1, 1:3, ivf_nb) = &
223  boxes(p_id)%fc(1:nc+1, 1:nc+1, 1:nc+1, 1:3, ivf_nb) * 0.25_dp
224 
225  end subroutine restrict_matrix
226 
227  ! This fills ghost cells near physical boundaries using Neumann zero
228  subroutine bc_dirichlet_one(box, nb, iv, bc_type)
229  type(box3_t), intent(inout) :: box
230  integer, intent(in) :: nb, iv
231  integer, intent(out) :: bc_type
232 
233  bc_type = af_bc_dirichlet
234  call a3_set_box_gc(box, nb, iv, 1.0_dp)
235  end subroutine bc_dirichlet_one
236 
237 end program multigrid_matrix_3d
Module which contains all Afivo modules, so that a user does not have to include them separately...
Definition: m_a3_all.f90:4