5 program particles_gravity_3d
11 integer,
parameter :: box_size = 8
12 integer,
parameter :: n_particles = 100*1000
13 integer,
parameter :: particles_per_cell = 100
14 integer,
parameter :: max_refinement_lvl = 7
15 integer,
parameter :: i_phi = 1
16 integer,
parameter :: i_rho = 2
17 integer,
parameter :: i_tmp = 3
18 integer,
parameter :: i_f(3) = [(i_tmp+n, n=1,3)]
20 real(dp),
parameter :: force_to_accel = 1.0_dp
22 real(dp),
parameter :: domain_len = 1.0_dp
23 real(dp),
parameter :: mean_density = 1.0_dp
24 real(dp),
parameter :: particle_weight = domain_len**3 / n_particles
25 real(dp),
parameter :: dr = domain_len / box_size
26 real(dp),
parameter :: t_end = 5.0_dp
27 real(dp),
parameter :: dt_output = 5e-2_dp
28 real(dp) :: dt = 1.0e-2_dp
31 real(dp),
allocatable :: coordinates(:, :)
32 real(dp),
allocatable :: velocities(:, :)
33 integer,
allocatable :: ids(:)
34 real(dp),
allocatable :: weights(:)
39 type(ref_info_t) :: refine_info
40 integer :: id, ix_list(3, 1)
41 integer :: nb_list(2*3, 1)
42 integer :: count_rate, wc_start, wc_end
43 character(len=100) :: fname
44 real(dp) :: max_vel, time
46 print *,
"Running particles_gravity_3d" 47 print *,
"Number of threads", af_get_max_threads()
56 cc_names=[
"phi",
"rho",
"tmp",
"fx ",
"fy ",
"fz "] &
67 mg%sides_bc => a3_bc_neumann_zero
68 mg%subtract_mean = .true.
73 call a3_set_base(tree, 1, ix_list, nb_list)
77 call a3_set_cc_methods(tree, i_phi, a3_bc_neumann_zero, a3_gc_interp)
78 call a3_set_cc_methods(tree, i_rho, a3_bc_neumann_zero, a3_gc_interp)
80 call a3_set_cc_methods(tree, i_f(n), a3_bc_neumann_zero, a3_gc_interp)
83 allocate(coordinates(3, n_particles))
84 allocate(velocities(3, n_particles))
85 allocate(weights(n_particles))
86 allocate(ids(n_particles))
88 call random_number(coordinates(:, :))
89 call random_number(velocities(:, :))
90 velocities(:, :) = 0.0_dp
91 weights(:) = particle_weight
94 call a3_tree_clear_cc(tree, i_rho)
95 call a3_particles_to_grid(tree, i_rho, coordinates, weights, &
97 call a3_adjust_refinement(tree, refine_routine, refine_info, 2)
98 if (refine_info%n_add == 0)
exit 102 call mg3_fas_fmg(tree, mg, .false., .false.)
103 call mg3_fas_fmg(tree, mg, .false., .true.)
110 call system_clock(wc_start, count_rate)
111 do while (time < t_end)
113 call push_particles(coordinates, velocities, n_particles, dt)
116 call a3_tree_clear_cc(tree, i_rho)
117 call a3_particles_to_grid(tree, i_rho, coordinates, weights, &
119 call a3_loop_box(tree, subtract_mean_density)
121 call mg3_fas_vcycle(tree, mg, .false.)
122 call mg3_fas_vcycle(tree, mg, .true.)
124 call a3_loop_box(tree, compute_forces)
125 call a3_gc_tree(tree, i_f)
127 call update_velocities(tree, coordinates, velocities, &
128 ids, n_particles, dt)
131 max_vel = sqrt(maxval(sum(velocities**2, dim=1)))
132 dt = min(1.1 * dt_prev, dt_output, &
133 0.5_dp * a3_min_dr(tree) / max_vel)
135 call compute_total_energy(tree, coordinates, velocities, &
138 if (modulo(n, 5) == 0)
then 139 call a3_adjust_refinement(tree, refine_routine, refine_info, 2)
142 if (n_output * dt_output <= time)
then 143 call a3_tree_clear_cc(tree, i_rho)
144 call a3_particles_to_grid(tree, i_rho, coordinates, weights, &
146 n_output = n_output + 1
147 write(fname,
"(A,I4.4)")
"particles_gravity_3d_", n_output
148 call a3_write_silo(tree, fname, n_output, time, dir=
"output")
149 print *,
"Time", time,
"n_cells", a3_num_cells_used(tree)
153 call system_clock(wc_end, count_rate)
154 print *,
"Total time: ", (wc_end-wc_start) /
real(count_rate, dp),
" seconds" 158 subroutine compute_total_energy(tree, x, v, ids, n_particles)
159 type(a3_t),
intent(in) :: tree
160 integer,
intent(in) :: n_particles
161 real(dp),
intent(in) :: x(3, n_particles)
162 real(dp),
intent(in) :: v(3, n_particles)
163 integer,
intent(in) :: ids(n_particles)
164 real(dp) :: sum_ken, sum_phi, phi(1)
170 do n = 1, n_particles
171 phi = a3_interp1(tree, x(:, n), [i_phi], 1, ids(n))
172 sum_ken = sum_ken + 0.5_dp * sum(v(:, n)**2)
173 sum_phi = sum_phi + 0.5_dp * phi(1)
175 print *,
"sum energy", sum_ken, sum_phi, sum_ken+sum_phi
176 end subroutine compute_total_energy
178 subroutine push_particles(x, v, n_particles, dt)
179 integer,
intent(in) :: n_particles
180 real(dp),
intent(inout) :: x(3, n_particles)
181 real(dp),
intent(in) :: v(3, n_particles)
182 real(dp),
intent(in) :: dt
186 do n = 1, n_particles
187 x(:, n) = x(:, n) + dt * v(:, n)
188 x(:, n) = modulo(x(:, n), domain_len)
191 end subroutine push_particles
193 subroutine update_velocities(tree, x, v, ids, n_particles, dt)
194 type(a3_t),
intent(in) :: tree
195 integer,
intent(in) :: n_particles
196 real(dp),
intent(in) :: x(3, n_particles)
197 real(dp),
intent(inout) :: v(3, n_particles)
198 integer,
intent(inout) :: ids(:)
199 real(dp),
intent(in) :: dt
204 do n = 1, n_particles
205 a = a3_interp1(tree, x(:, n), i_f, &
207 v(:, n) = v(:, n) + dt * a * force_to_accel
210 end subroutine update_velocities
212 subroutine refine_routine(box, cell_flags)
213 type(box3_t),
intent(in) :: box
214 integer,
intent(out) :: cell_flags(box%n_cell, box%n_cell, box%n_cell)
215 real(dp) :: rho_refine, rho_derefine
219 rho_refine = particles_per_cell * particle_weight / box%dr**3
220 rho_derefine = rho_refine / (2**3 * 4)
222 where (box%cc(1:nc, 1:nc, 1:nc, i_rho) > rho_refine)
223 cell_flags(:, :, :) = af_do_ref
224 elsewhere (box%cc(1:nc, 1:nc, 1:nc, i_rho) < rho_derefine)
225 cell_flags(:, :, :) = af_rm_ref
227 cell_flags(:, :, :) = af_keep_ref
230 if (box%lvl >= max_refinement_lvl)
then 231 where (cell_flags == af_do_ref)
232 cell_flags = af_keep_ref
236 end subroutine refine_routine
238 subroutine compute_forces(box)
239 type(box3_t),
intent(inout) :: box
240 integer :: i, j, k, nc
244 fac = -0.5_dp / box%dr
246 do k = 1, nc;
do j = 1, nc;
do i = 1, nc
247 box%cc(i, j, k, i_f(1)) = fac * &
248 (box%cc(i+1, j, k, i_phi) - box%cc(i-1, j, k, i_phi))
249 box%cc(i, j, k, i_f(2)) = fac * &
250 (box%cc(i, j+1, k, i_phi) - box%cc(i, j-1, k, i_phi))
251 box%cc(i, j, k, i_f(3)) = fac * &
252 (box%cc(i, j, k+1, i_phi) - box%cc(i, j, k-1, i_phi))
253 end do; end do; end do
255 end subroutine compute_forces
257 subroutine subtract_mean_density(box)
258 type(box3_t),
intent(inout) :: box
260 box%cc(:, :, :, i_rho) = box%cc(:, :, :, i_rho) - mean_density
261 end subroutine subtract_mean_density
263 end program particles_gravity_3d
Module which contains all Afivo modules, so that a user does not have to include them separately...