9 #include "cpp_macros.h"
19 integer,
intent(in) :: ix
20 integer,
intent(out) :: id
26 integer,
intent(in) :: ix
27 real(dp),
intent(out) :: r(NDIM)
28 real(dp),
intent(out) :: w
32 public :: af_particles_to_grid
39 subroutine af_particles_to_grid(tree, iv, n_particles, get_id, get_rw, &
40 order, density, fill_gc, iv_tmp, offset_particles)
43 use m_af_utils,
only: af_get_id_at, af_tree_clear_cc, af_tree_clear_ghostcells
44 type(
af_t),
intent(inout) :: tree
45 integer,
intent(in) :: iv
46 integer,
intent(in) :: n_particles
49 integer,
intent(in) :: order
51 logical,
intent(in),
optional :: density
53 logical,
intent(in),
optional :: fill_gc
57 integer,
intent(in),
optional :: iv_tmp
59 integer,
intent(in),
optional :: offset_particles
61 integer :: n, m, p_offset
62 integer :: current_thread, current_work
63 integer :: threads_left, work_left
64 integer,
allocatable :: ids(:)
65 integer,
allocatable :: npart_per_box(:)
66 integer,
allocatable :: box_threads(:)
67 integer,
allocatable :: threads(:)
68 real(dp) :: r(ndim), weight
70 logical :: fill_gc_at_end
71 logical :: use_tmp_var
73 allocate(ids(n_particles))
74 allocate(npart_per_box(-1:tree%highest_id))
75 allocate(box_threads(tree%highest_id))
76 allocate(threads(n_particles))
80 if (
present(density)) as_density = density
81 fill_gc_at_end = .true.
82 if (
present(fill_gc)) fill_gc_at_end = fill_gc
84 if (
present(iv_tmp))
then
85 if (iv_tmp > 0) use_tmp_var = .true.
88 if (
present(offset_particles)) p_offset = offset_particles
90 if (use_tmp_var .and. .not. as_density) &
91 error stop
"Use iv_tmp only for density = .true."
95 call get_id(p_offset + n, ids(n))
96 npart_per_box(ids(n)) = npart_per_box(ids(n)) + 1
100 if (sum(npart_per_box(-1:0)) > 0)
then
101 print *,
"af_particles_to_grid: some are outside domain"
103 do n = 1, n_particles
104 if (ids(n) <= af_no_box)
then
105 call get_rw(p_offset + n, r, weight)
114 error stop
"af_particles_to_grid: some are outside domain"
117 threads_left = af_get_max_threads()
120 work_left = n_particles
122 do m = 1, tree%highest_id
123 box_threads(m) = current_thread
124 current_work = current_work + npart_per_box(m)
126 if (current_work > work_left/threads_left)
then
127 current_thread = current_thread + 1
128 threads_left = threads_left - 1
129 work_left = work_left - current_work
135 do n = 1, n_particles
136 threads(n) = box_threads(ids(n))
141 call af_tree_clear_ghostcells(tree, iv)
144 if (use_tmp_var)
call af_tree_clear_cc(tree, iv_tmp)
148 if (use_tmp_var)
then
149 call particles_to_grid_0(tree, iv_tmp, get_rw, ids, &
150 threads, n_particles, .false., p_offset)
151 call add_as_density(tree, iv_tmp, iv)
153 call particles_to_grid_0(tree, iv, get_rw, ids, &
154 threads, n_particles, as_density, p_offset)
157 if (use_tmp_var)
then
158 call particles_to_grid_1(tree, iv_tmp, get_rw, ids, &
159 threads, n_particles, .false., p_offset)
160 call tree_add_from_ghostcells(tree, iv_tmp)
161 call add_as_density(tree, iv_tmp, iv)
163 call particles_to_grid_1(tree, iv, get_rw, ids, &
164 threads, n_particles, as_density, p_offset)
165 call tree_add_from_ghostcells(tree, iv)
168 error stop
"af_particles_to_grid: Invalid interpolation order"
171 call af_restrict_tree(tree, [iv])
173 if (fill_gc_at_end)
then
174 if (.not. tree%has_cc_method(iv))
then
175 print *,
"Variable with index ", iv,
"has no cc_method"
176 print *,
"do this with call af_set_cc_methods(tree, iv, ...)"
177 error stop
"af_particles_to_grid: no ghost cell method defined"
179 call af_gc_tree(tree, [iv])
182 end subroutine af_particles_to_grid
184 subroutine particles_to_grid_0(tree, iv, get_rw, ids, &
185 threads, n_particles, density, p_offset)
187 type(
af_t),
intent(inout) :: tree
188 integer,
intent(in) :: iv
189 integer,
intent(in) :: n_particles
191 integer,
intent(in) :: ids(n_particles)
192 integer,
intent(in) :: threads(n_particles)
193 logical,
intent(in) :: density
194 integer,
intent(in) :: p_offset
195 integer :: n, thread_id, ix(NDIM)
196 real(dp) :: r(NDIM), weight, inv_volume
199 thread_id = omp_get_thread_num()
201 do n = 1, n_particles
202 if (threads(n) /= thread_id) cycle
204 call get_rw(p_offset + n, r, weight)
206 ix = af_cc_ix(tree%boxes(ids(n)), r)
210 where (ix < 1) ix = 1
211 where (ix > tree%n_cell) ix = tree%n_cell
215 if (tree%coord_t == af_cyl)
then
216 inv_volume = 1 / af_cyl_volume_cc(tree%boxes(ids(n)), ix(1))
219 inv_volume = 1 / product(tree%boxes(ids(n))%dr)
222 inv_volume = 1 / product(tree%boxes(ids(n))%dr)
225 tree%boxes(ids(n))%cc(dindex(ix), iv) = &
226 tree%boxes(ids(n))%cc(dindex(ix), iv) + &
229 tree%boxes(ids(n))%cc(dindex(ix), iv) = &
230 tree%boxes(ids(n))%cc(dindex(ix), iv) + &
235 end subroutine particles_to_grid_0
239 subroutine particles_to_grid_1(tree, iv, get_rw, ids, &
240 threads, n_particles, density, p_offset)
242 type(
af_t),
intent(inout) :: tree
243 integer,
intent(in) :: iv
244 integer,
intent(in) :: n_particles
246 integer,
intent(in) :: ids(n_particles)
247 integer,
intent(in) :: threads(n_particles)
248 logical,
intent(in) :: density
249 integer,
intent(in) :: p_offset
250 real(dp) :: tmp(NDIM), inv_dr(NDIM)
251 real(dp) :: wu(NDIM), wl(NDIM), w(DTIMES(2))
252 real(dp) :: inv_volume, r(NDIM), weight
253 integer :: id, ix(NDIM), n, thread_id
255 if (tree%coord_t == af_cyl .and. density) &
256 error stop
"For cylindrical coordinates, use iv_tmp"
260 thread_id = omp_get_thread_num()
262 do n = 1, n_particles
263 if (threads(n) /= thread_id) cycle
265 call get_rw(p_offset + n, r, weight)
268 inv_dr = 1.0_dp/tree%boxes(id)%dr
269 tmp = (r - tree%boxes(id)%r_min) * inv_dr + 0.5_dp
278 w(:, 1) = [wl(1), wu(1)] * wl(2)
279 w(:, 2) = [wl(1), wu(1)] * wu(2)
281 w(:, 1, 1) = [wl(1), wu(1)] * wl(2) * wl(3)
282 w(:, 2, 1) = [wl(1), wu(1)] * wu(2) * wl(3)
283 w(:, 1, 2) = [wl(1), wu(1)] * wl(2) * wu(3)
284 w(:, 2, 2) = [wl(1), wu(1)] * wu(2) * wu(3)
289 inv_volume = 1 / product(tree%boxes(ids(n))%dr)
291 tree%boxes(id)%cc(ix(1):ix(1)+1, iv) = &
292 tree%boxes(id)%cc(ix(1):ix(1)+1, iv) + &
293 w * inv_volume * weight
295 tree%boxes(id)%cc(ix(1):ix(1)+1, ix(2):ix(2)+1, iv) = &
296 tree%boxes(id)%cc(ix(1):ix(1)+1, ix(2):ix(2)+1, iv) + &
297 w * inv_volume * weight
299 tree%boxes(id)%cc(ix(1):ix(1)+1, ix(2):ix(2)+1, ix(3):ix(3)+1, iv) = &
300 tree%boxes(id)%cc(ix(1):ix(1)+1, ix(2):ix(2)+1, ix(3):ix(3)+1, iv) + &
301 w * inv_volume * weight
305 tree%boxes(id)%cc(ix(1):ix(1)+1, iv) = &
306 tree%boxes(id)%cc(ix(1):ix(1)+1, iv) + w * weight
308 tree%boxes(id)%cc(ix(1):ix(1)+1, ix(2):ix(2)+1, iv) = &
309 tree%boxes(id)%cc(ix(1):ix(1)+1, ix(2):ix(2)+1, iv) + &
312 tree%boxes(id)%cc(ix(1):ix(1)+1, ix(2):ix(2)+1, ix(3):ix(3)+1, iv) = &
313 tree%boxes(id)%cc(ix(1):ix(1)+1, ix(2):ix(2)+1, ix(3):ix(3)+1, iv) + &
320 end subroutine particles_to_grid_1
322 subroutine tree_add_from_ghostcells(tree, iv)
323 type(
af_t),
intent(inout) :: tree
324 integer,
intent(in) :: iv
325 integer :: lvl, i, id
328 do lvl = 1, tree%highest_lvl
330 do i = 1,
size(tree%lvls(lvl)%leaves)
331 id = tree%lvls(lvl)%leaves(i)
332 call add_from_ghostcells(tree%boxes, id, iv)
337 end subroutine tree_add_from_ghostcells
339 subroutine add_from_ghostcells(boxes, id, iv)
340 type(
box_t),
intent(inout) :: boxes(:)
341 integer,
intent(in) :: id
342 integer,
intent(in) :: iv
343 integer :: IJK, i0(NDIM), i1(NDIM)
344 integer :: n0(NDIM), n1(NDIM), nb_id, nc
347 nc = boxes(id)%n_cell
350 if (all([ijk] == 0)) cycle
352 nb_id = boxes(id)%neighbor_mat(ijk)
356 if (nb_id <= af_no_box)
then
358 else if (nb_id > af_no_box)
then
359 if (af_has_children(boxes(nb_id))) copy_own = .true.
373 elsewhere ([ijk] == -1)
379 boxes(id)%cc(dslice(i0, i1), iv) = &
380 boxes(id)%cc(dslice(i0, i1), iv) + &
381 boxes(id)%cc(dslice(n0, n1), iv)
391 elsewhere ([ijk] == -1)
397 boxes(id)%cc(dslice(i0, i1), iv) = &
398 boxes(id)%cc(dslice(i0, i1), iv) + &
399 boxes(nb_id)%cc(dslice(n0, n1), iv)
402 end subroutine add_from_ghostcells
405 subroutine add_as_density(tree, iv_from, iv_to)
406 type(af_t),
intent(inout) :: tree
407 integer,
intent(in) :: iv_from
408 integer,
intent(in) :: iv_to
409 integer :: lvl, i, id
412 do lvl = 1, tree%highest_lvl
414 do i = 1,
size(tree%lvls(lvl)%leaves)
415 id = tree%lvls(lvl)%leaves(i)
416 call add_as_density_box(tree%boxes(id), iv_from, iv_to)
421 end subroutine add_as_density
424 subroutine add_as_density_box(box, iv_from, iv_to)
425 type(box_t),
intent(inout) :: box
426 integer,
intent(in) :: iv_from
427 integer,
intent(in) :: iv_to
428 real(dp) :: inv_volume
431 real(dp),
parameter :: twopi = 2 * acos(-1.0_dp)
432 real(dp) :: radius, inv_cyl
435 inv_volume = 1.0_dp / product(box%dr)
438 if (box%coord_t == af_cyl)
then
439 do i = 0, box%n_cell+1
441 radius = abs(af_cyl_radius_cc(box, i))
442 inv_cyl = inv_volume / (twopi * radius)
443 box%cc(i, :, iv_to) = box%cc(i, :, iv_to) + &
444 box%cc(i, :, iv_from) * inv_cyl
447 box%cc(dtimes(:), iv_to) = box%cc(dtimes(:), iv_to) + &
448 box%cc(dtimes(:), iv_from) * inv_volume
451 box%cc(dtimes(:), iv_to) = box%cc(dtimes(:), iv_to) + &
452 box%cc(dtimes(:), iv_from) * inv_volume
454 end subroutine add_as_density_box
To get a particle's coordinates and weight.
This module contains routines related to the filling of ghost cells. Note that corner ghost cells are...
This module contains routines related to , which can interpolate 'to' the grid and 'from' the grid (u...
This module contains routines for restriction: going from fine to coarse variables.
This module contains the basic types and constants that are used in the NDIM-dimensional version of A...
This module contains all kinds of different 'helper' routines for Afivo. If the number of routines fo...
Type which stores all the boxes and levels, as well as some information about the number of boxes,...
The basic building block of afivo: a box with cell-centered and face centered data,...