1 #include "../src/cpp_macros.h"
5 program particles_gravity
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 = 5
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**ndim / n_particles
25 real(dp),
parameter :: t_end = 0.1_dp
26 real(dp),
parameter :: dt_output = 5e-2_dp
27 real(dp) :: dt = 1.0e-2_dp
30 real(dp),
allocatable :: coordinates(:, :)
31 real(dp),
allocatable :: velocities(:, :)
32 integer,
allocatable :: ids(:)
33 real(dp),
allocatable :: weights(:)
38 type(ref_info_t) :: refine_info
39 integer :: count_rate, wc_start, wc_end
40 character(len=100) :: fname
41 real(dp) :: max_vel, time
43 print *,
"Running particles_gravity_" // dimname //
""
44 print *,
"Number of threads", af_get_max_threads()
46 call af_add_cc_variable(tree,
"phi", ix=i_phi)
47 call af_add_cc_variable(tree,
"rho", ix=i_rho)
48 call af_add_cc_variable(tree,
"tmp", ix=i_tmp)
49 call af_add_cc_variable(tree,
"fx", ix=i_f(1))
51 call af_add_cc_variable(tree,
"fy", ix=i_f(2))
54 call af_add_cc_variable(tree,
"fz", ix=i_f(3))
60 [dtimes(domain_len)], &
62 periodic=[dtimes(.true.)])
67 mg%sides_bc => af_bc_neumann_zero
68 mg%subtract_mean = .true.
70 call mg_init(tree, mg)
74 call af_set_cc_methods(tree, i_rho, af_bc_neumann_zero, af_gc_interp)
76 call af_set_cc_methods(tree, i_f(n), af_bc_neumann_zero, af_gc_interp)
79 allocate(coordinates(ndim, n_particles))
80 allocate(velocities(ndim, n_particles))
81 allocate(weights(n_particles))
82 allocate(ids(n_particles))
84 call random_number(coordinates(:, :))
85 call random_number(velocities(:, :))
86 velocities(:, :) = 0.0_dp
87 weights(:) = particle_weight
90 call af_tree_clear_cc(tree, i_rho)
91 call af_particles_to_grid(tree, i_rho, n_particles, get_id, get_rw, 1)
92 call af_adjust_refinement(tree, refine_routine, refine_info, 2)
93 if (refine_info%n_add == 0)
exit
97 call mg_fas_fmg(tree, mg, .false., .false.)
98 call mg_fas_fmg(tree, mg, .false., .true.)
105 call system_clock(wc_start, count_rate)
106 do while (time < t_end)
108 call push_particles(coordinates, velocities, n_particles, dt)
111 call af_tree_clear_cc(tree, i_rho)
112 call af_particles_to_grid(tree, i_rho, n_particles, get_id, get_rw, 1)
113 call af_loop_box(tree, subtract_mean_density)
115 call mg_fas_vcycle(tree, mg, .false.)
116 call mg_fas_vcycle(tree, mg, .true.)
118 call af_loop_box(tree, compute_forces)
119 call af_gc_tree(tree, i_f)
121 call update_velocities(tree, coordinates, velocities, &
122 ids, n_particles, dt)
125 max_vel = sqrt(maxval(sum(velocities**2, dim=1)))
126 dt = min(1.1 * dt_prev, dt_output, &
127 0.5_dp * af_min_dr(tree) / max_vel)
129 call compute_total_energy(tree, coordinates, velocities, &
132 if (modulo(n, 5) == 0)
then
133 call af_adjust_refinement(tree, refine_routine, refine_info, 2)
136 if (n_output * dt_output <= time)
then
137 call af_tree_clear_cc(tree, i_rho)
138 call af_particles_to_grid(tree, i_rho, n_particles, get_id, get_rw, 1)
139 n_output = n_output + 1
140 write(fname,
"(A,I4.4)")
"output/particles_gravity_" // dimname //
"_", n_output
141 call af_write_silo(tree, fname, n_output, time)
142 print *,
"Time", time,
"n_cells", af_num_cells_used(tree)
146 call system_clock(wc_end, count_rate)
147 print *,
"Total time: ", (wc_end-wc_start) / real(count_rate, dp),
" seconds"
151 subroutine compute_total_energy(tree, x, v, ids, n_particles)
152 type(af_t),
intent(in) :: tree
153 integer,
intent(in) :: n_particles
154 real(dp),
intent(in) :: x(NDIM, n_particles)
155 real(dp),
intent(in) :: v(NDIM, n_particles)
156 integer,
intent(inout) :: ids(n_particles)
157 real(dp) :: sum_ken, sum_phi, phi(1)
164 do n = 1, n_particles
165 phi = af_interp1(tree, x(:, n), [i_phi], success, ids(n))
166 if (.not. success) error stop
"compute_total_energy: interpolation error"
167 sum_ken = sum_ken + 0.5_dp * sum(v(:, n)**2)
168 sum_phi = sum_phi + 0.5_dp * phi(1)
170 print *,
"sum energy", sum_ken, sum_phi, sum_ken+sum_phi
171 end subroutine compute_total_energy
173 subroutine push_particles(x, v, n_particles, dt)
174 integer,
intent(in) :: n_particles
175 real(dp),
intent(inout) :: x(NDIM, n_particles)
176 real(dp),
intent(in) :: v(NDIM, n_particles)
177 real(dp),
intent(in) :: dt
181 do n = 1, n_particles
182 x(:, n) = x(:, n) + dt * v(:, n)
183 x(:, n) = modulo(x(:, n), domain_len)
186 end subroutine push_particles
188 subroutine update_velocities(tree, x, v, ids, n_particles, dt)
189 type(af_t),
intent(in) :: tree
190 integer,
intent(in) :: n_particles
191 real(dp),
intent(in) :: x(NDIM, n_particles)
192 real(dp),
intent(inout) :: v(NDIM, n_particles)
193 integer,
intent(inout) :: ids(:)
194 real(dp),
intent(in) :: dt
200 do n = 1, n_particles
201 a = af_interp1(tree, x(:, n), i_f, success, id_guess=ids(n))
202 if (.not. success) error stop
"update velocities: interpolation error"
203 v(:, n) = v(:, n) + dt * a * force_to_accel
206 end subroutine update_velocities
208 subroutine refine_routine(box, cell_flags)
209 type(box_t),
intent(in) :: box
210 integer,
intent(out) :: cell_flags(DTIMES(box%n_cell))
211 real(dp) :: rho_refine, rho_derefine
215 rho_refine = particles_per_cell * particle_weight / product(box%dr)
216 rho_derefine = rho_refine / (2**ndim * 4)
218 where (box%cc(dtimes(1:nc), i_rho) > rho_refine)
219 cell_flags(dtimes(:)) = af_do_ref
220 elsewhere (box%cc(dtimes(1:nc), i_rho) < rho_derefine)
221 cell_flags(dtimes(:)) = af_rm_ref
223 cell_flags(dtimes(:)) = af_keep_ref
226 if (box%lvl >= max_refinement_lvl)
then
227 where (cell_flags == af_do_ref)
228 cell_flags = af_keep_ref
232 end subroutine refine_routine
234 subroutine compute_forces(box)
235 type(box_t),
intent(inout) :: box
237 real(dp) :: fac(NDIM)
240 fac = -0.5_dp / box%dr
244 box%cc(i, i_f(1)) = fac(1) * &
245 (box%cc(i+1, i_phi) - box%cc(i-1, i_phi))
247 box%cc(i, j, i_f(1)) = fac(1) * &
248 (box%cc(i+1, j, i_phi) - box%cc(i-1, j, i_phi))
249 box%cc(i, j, i_f(2)) = fac(2) * &
250 (box%cc(i, j+1, i_phi) - box%cc(i, j-1, i_phi))
252 box%cc(i, j, k, i_f(1)) = fac(1) * &
253 (box%cc(i+1, j, k, i_phi) - box%cc(i-1, j, k, i_phi))
254 box%cc(i, j, k, i_f(2)) = fac(2) * &
255 (box%cc(i, j+1, k, i_phi) - box%cc(i, j-1, k, i_phi))
256 box%cc(i, j, k, i_f(3)) = fac(3) * &
257 (box%cc(i, j, k+1, i_phi) - box%cc(i, j, k-1, i_phi))
261 end subroutine compute_forces
263 subroutine subtract_mean_density(box)
264 type(box_t),
intent(inout) :: box
266 box%cc(dtimes(:), i_rho) = box%cc(dtimes(:), i_rho) - mean_density
267 end subroutine subtract_mean_density
269 subroutine get_id(n, id)
270 integer,
intent(in) :: n
271 integer,
intent(out) :: id
273 id = af_get_id_at(tree, coordinates(:, n), guess=ids(n))
275 end subroutine get_id
277 subroutine get_rw(n, r, w)
278 integer,
intent(in) :: n
279 real(dp),
intent(out) :: r(NDIM)
280 real(dp),
intent(out) :: w
282 r = coordinates(:, n)
284 end subroutine get_rw
286 end program particles_gravity
Module which contains all Afivo modules, so that a user does not have to include them separately.