Example showing how to use multigrid for ensuring a vector field is divergence free
1 #include "../src/cpp_macros.h"
6 program poisson_div_cleaning
12 integer,
parameter :: box_size = 8
13 integer,
parameter :: n_iterations = 10
14 integer :: domain_size(NDIM)
15 real(dp) :: domain_length(NDIM)
16 real(dp) :: domain_origin(NDIM)
25 type(ref_info_t) :: refine_info
27 character(len=100) :: fname
30 real(dp),
parameter :: alphar_ = 0.64d0
31 real(dp),
parameter :: ar_ = 0.25d0
32 real(dp),
parameter :: B0 = 1.0_dp
34 print *,
"Running poisson_div_cleaning_" // dimname
35 print *,
"Number of threads", af_get_max_threads()
37 call af_add_cc_variable(tree,
"phi", ix=i_phi)
38 call af_add_cc_variable(tree,
"div_old", ix=i_div_old)
39 call af_add_cc_variable(tree,
"tmp", ix=i_tmp)
40 call af_add_cc_variable(tree,
"div_new", ix=i_div_new)
41 call af_add_cc_variable(tree,
"Bx", ix=i_b(1))
42 call af_add_cc_variable(tree,
"By", ix=i_b(2))
43 call af_add_cc_variable(tree,
"Bz", ix=i_b(3))
44 call af_add_fc_variable(tree,
"B_old", ix=if_b_old)
45 call af_add_fc_variable(tree,
"B_new", ix=if_b_new)
47 domain_length(:) = 1.0_dp
48 domain_origin(:) = -0.5_dp * domain_length(:)
49 domain_size(:) = box_size
53 domain_origin+domain_length, &
58 call af_loop_box(tree, set_initial_condition)
59 call af_adjust_refinement(tree, refine_routine, refine_info)
60 if (refine_info%n_add == 0)
exit
63 call af_print_info(tree)
68 mg%sides_bc => af_bc_dirichlet_zero
70 call mg_init(tree, mg)
72 do mg_iter = 1, n_iterations
73 call mg_fas_fmg(tree, mg, set_residual=.true., have_guess=(mg_iter>1))
74 call af_loop_box(tree, set_error)
75 write(fname,
"(A,I0)")
"output/poisson_div_cleaning_" // &
76 dimname //
"_", mg_iter
77 call af_write_silo(tree, trim(fname))
83 subroutine refine_routine(box, cell_flags)
84 type(box_t),
intent(in) :: box
85 integer,
intent(out) :: cell_flags(DTIMES(box%n_cell))
88 cell_flags = af_do_ref
90 cell_flags = af_keep_ref
92 end subroutine refine_routine
94 real(dp) function Bx(xyz)
95 real(dp),
intent(in) :: xyz(NDIM)
96 real(dp) :: r, t, phi, Bphi
99 bphi = b0 / (t * (1 + t**2)**alphar_) * &
100 sqrt(((1 + t**2)**(2 * alphar_) - 1 - 2 * alphar_ * t**2) / &
102 phi = atan2(xyz(2), xyz(1))
103 bx = -sin(phi) * bphi
106 real(dp) function By(xyz)
107 real(dp),
intent(in) :: xyz(NDIM)
108 real(dp) :: r, t, phi, Bphi
111 bphi = b0 / (t * (1 + t**2)**alphar_) * &
112 sqrt(((1 + t**2)**(2 * alphar_) - 1 - 2 * alphar_ * t**2) / &
114 phi = atan2(xyz(2), xyz(1))
118 real(dp) function Bz(xyz)
119 real(dp),
intent(in) :: xyz(NDIM)
123 bz = b0 / (1 + t**2)**alphar_
127 subroutine set_initial_condition(box)
128 type(box_t),
intent(inout) :: box
130 real(dp) :: xyz(NDIM)
135 do k = 1, nc;
do j = 1, nc;
do i = 1, nc+1
136 box%fc(ijk, 1, if_b_old) = bx(af_r_fc(box, 1, [ijk]))
137 end do;
end do;
end do
140 do k = 1, nc;
do j = 1, nc+1;
do i = 1, nc
141 box%fc(ijk, 2, if_b_old) = by(af_r_fc(box, 2, [ijk]))
142 end do;
end do;
end do
145 do k = 1, nc+1;
do j = 1, nc;
do i = 1, nc
146 box%fc(ijk, 3, if_b_old) = bz(af_r_fc(box, 3, [ijk]))
147 end do;
end do;
end do
150 xyz = af_r_cc(box, [ijk])
153 box%cc(ijk, i_b(:)) = [bx(xyz), by(xyz), bz(xyz)]
156 box%cc(ijk, i_div_old) = &
157 (box%fc(i+1, j, k, 1, if_b_old) - &
158 box%fc(i, j, k, 1, if_b_old)) / box%dr(1) + &
159 (box%fc(i, j+1, k, 2, if_b_old) - &
160 box%fc(i, j, k, 2, if_b_old)) / box%dr(2) + &
161 (box%fc(i, j, k+1, 3, if_b_old) - &
162 box%fc(i, j, k, 3, if_b_old)) / box%dr(3)
164 end subroutine set_initial_condition
166 subroutine set_error(box)
167 type(box_t),
intent(inout) :: box
169 real(dp) :: inv_dr(NDIM)
174 do k = 1, nc;
do j = 1, nc;
do i = 1, nc+1
176 box%fc(ijk, 1, if_b_new) = box%fc(ijk, 1, if_b_old) - inv_dr(1) * &
177 (box%cc(i, j, k, i_phi) - box%cc(i-1, j, k, i_phi))
178 end do;
end do;
end do
180 do k = 1, nc;
do j = 1, nc+1;
do i = 1, nc
182 box%fc(ijk, 2, if_b_new) = box%fc(ijk, 2, if_b_old) - inv_dr(2) * &
183 (box%cc(i, j, k, i_phi) - box%cc(i, j-1, k, i_phi))
184 end do;
end do;
end do
186 do k = 1, nc+1;
do j = 1, nc;
do i = 1, nc
188 box%fc(ijk, 3, if_b_new) = box%fc(ijk, 3, if_b_old) - inv_dr(3) * &
189 (box%cc(i, j, k, i_phi) - box%cc(i, j, k-1, i_phi))
190 end do;
end do;
end do
194 box%cc(ijk, i_div_new) = &
195 (box%fc(i+1, j, k, 1, if_b_new) - &
196 box%fc(i, j, k, 1, if_b_new)) / box%dr(1) + &
197 (box%fc(i, j+1, k, 2, if_b_new) - &
198 box%fc(i, j, k, 2, if_b_new)) / box%dr(2) + &
199 (box%fc(i, j, k+1, 3, if_b_new) - &
200 box%fc(i, j, k, 3, if_b_new)) / box%dr(3)
202 end subroutine set_error
204 end program poisson_div_cleaning
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.