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])
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) + &
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) + &
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)
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
To get a particle's coordinates and weight.
This module contains routines related to , which can interpolate 'to' the grid and 'from' the grid (u...