Afivo 0.3
All Classes Namespaces Functions Variables Pages
m_af_utils.f90
1!> This module contains all kinds of different 'helper' routines for Afivo. If
2!> the number of routines for a particular topic becomes large, they should
3!> probably be put in a separate module.
5#include "cpp_macros.h"
6 use m_af_types
7
8 implicit none
9 private
10
11 ! Public subroutines
12 public :: af_loop_box
13 public :: af_loop_box_arg
14 public :: af_loop_boxes
15 public :: af_loop_boxes_arg
16 public :: af_loop_tree
17 public :: af_loop_tree_arg
18 public :: af_tree_clear_cc
19 public :: af_box_clear_cc
20 public :: af_tree_clear_ghostcells
21 public :: af_box_clear_ghostcells
22 public :: af_box_add_cc
23 public :: af_box_sub_cc
24 public :: af_tree_times_cc
25 public :: af_tree_apply
26 public :: af_box_times_cc
27 public :: af_box_lincomb_cc
28 public :: af_box_copy_cc_to
29 public :: af_box_copy_cc
30 public :: af_box_copy_ccs
31 public :: af_boxes_copy_cc
32 public :: af_boxes_copy_ccs
33 public :: af_tree_copy_cc
34 public :: af_tree_copy_ccs
35 public :: af_reduction
36 public :: af_reduction_vec
37 public :: af_reduction_loc
38 public :: af_tree_max_cc
39 public :: af_tree_maxabs_cc
40 public :: af_tree_min_cc
41 public :: af_tree_max_fc
42 public :: af_tree_min_fc
43 public :: af_tree_sum_cc
44 public :: af_box_copy_fc
45 public :: af_boxes_copy_fc
46 public :: af_tree_copy_fc
47
48 ! Public functions
49 public :: af_get_id_at
50 public :: af_get_loc
51 public :: af_r_loc
52 public :: af_r_inside
53
54contains
55
56 !> Call procedure for each box in tree
57 subroutine af_loop_box(tree, my_procedure, leaves_only)
58 type(af_t), intent(inout) :: tree
59 procedure(af_subr) :: my_procedure
60 logical, intent(in), optional :: leaves_only
61 logical :: leaves
62 integer :: lvl, i, id
63
64 leaves = .false.; if (present(leaves_only)) leaves = leaves_only
65 if (.not. tree%ready) stop "af_loop_box: set_base has not been called"
66
67 !$omp parallel private(lvl, i, id)
68 do lvl = 1, tree%highest_lvl
69 if (leaves) then
70 !$omp do
71 do i = 1, size(tree%lvls(lvl)%leaves)
72 id = tree%lvls(lvl)%leaves(i)
73 call my_procedure(tree%boxes(id))
74 end do
75 !$omp end do
76 else
77 !$omp do
78 do i = 1, size(tree%lvls(lvl)%ids)
79 id = tree%lvls(lvl)%ids(i)
80 call my_procedure(tree%boxes(id))
81 end do
82 !$omp end do
83 end if
84 end do
85 !$omp end parallel
86 end subroutine af_loop_box
87
88 !> Call procedure for each box in tree, with argument rarg
89 subroutine af_loop_box_arg(tree, my_procedure, rarg, leaves_only)
90 type(af_t), intent(inout) :: tree
91 procedure(af_subr_arg) :: my_procedure
92 real(dp), intent(in) :: rarg(:)
93 logical, intent(in), optional :: leaves_only
94 logical :: leaves
95 integer :: lvl, i, id
96
97 if (.not. tree%ready) stop "Tree not ready"
98 leaves = .false.; if (present(leaves_only)) leaves = leaves_only
99
100 !$omp parallel private(lvl, i, id)
101 do lvl = 1, tree%highest_lvl
102 if (leaves) then
103 !$omp do
104 do i = 1, size(tree%lvls(lvl)%leaves)
105 id = tree%lvls(lvl)%leaves(i)
106 call my_procedure(tree%boxes(id), rarg)
107 end do
108 !$omp end do
109 else
110 !$omp do
111 do i = 1, size(tree%lvls(lvl)%ids)
112 id = tree%lvls(lvl)%ids(i)
113 call my_procedure(tree%boxes(id), rarg)
114 end do
115 !$omp end do
116 end if
117 end do
118 !$omp end parallel
119 end subroutine af_loop_box_arg
120
121 !> Call procedure for each id in tree, giving the list of boxes
122 subroutine af_loop_boxes(tree, my_procedure, leaves_only)
123 type(af_t), intent(inout) :: tree
124 procedure(af_subr_boxes) :: my_procedure
125 logical, intent(in), optional :: leaves_only
126 logical :: leaves
127 integer :: lvl, i, id
128
129 if (.not. tree%ready) stop "Tree not ready"
130 leaves = .false.; if (present(leaves_only)) leaves = leaves_only
131
132 !$omp parallel private(lvl, i, id)
133 do lvl = 1, tree%highest_lvl
134 if (leaves) then
135 !$omp do
136 do i = 1, size(tree%lvls(lvl)%leaves)
137 id = tree%lvls(lvl)%leaves(i)
138 call my_procedure(tree%boxes, id)
139 end do
140 !$omp end do
141 else
142 !$omp do
143 do i = 1, size(tree%lvls(lvl)%ids)
144 id = tree%lvls(lvl)%ids(i)
145 call my_procedure(tree%boxes, id)
146 end do
147 !$omp end do
148 end if
149 end do
150 !$omp end parallel
151 end subroutine af_loop_boxes
152
153 !> Call procedure for each id in tree, giving the list of boxes
154 subroutine af_loop_boxes_arg(tree, my_procedure, rarg, leaves_only)
155 type(af_t), intent(inout) :: tree
156 procedure(af_subr_boxes_arg) :: my_procedure
157 real(dp), intent(in) :: rarg(:)
158 logical, intent(in), optional :: leaves_only
159 logical :: leaves
160 integer :: lvl, i, id
161
162 if (.not. tree%ready) stop "Tree not ready"
163 leaves = .false.; if (present(leaves_only)) leaves = leaves_only
164
165 !$omp parallel private(lvl, i, id)
166 do lvl = 1, tree%highest_lvl
167 if (leaves) then
168 !$omp do
169 do i = 1, size(tree%lvls(lvl)%leaves)
170 id = tree%lvls(lvl)%leaves(i)
171 call my_procedure(tree%boxes, id, rarg)
172 end do
173 !$omp end do
174 else
175 !$omp do
176 do i = 1, size(tree%lvls(lvl)%ids)
177 id = tree%lvls(lvl)%ids(i)
178 call my_procedure(tree%boxes, id, rarg)
179 end do
180 !$omp end do
181 end if
182 end do
183 !$omp end parallel
184 end subroutine af_loop_boxes_arg
185
186 !> Call procedure for each id in tree, passing the tree as first argument
187 subroutine af_loop_tree(tree, my_procedure, leaves_only)
188 type(af_t), intent(inout) :: tree
189 procedure(af_subr_tree) :: my_procedure
190 logical, intent(in), optional :: leaves_only
191 logical :: leaves
192 integer :: lvl, i
193
194 if (.not. tree%ready) stop "Tree not ready"
195 leaves = .false.; if (present(leaves_only)) leaves = leaves_only
196
197 !$omp parallel private(lvl, i)
198 do lvl = 1, tree%highest_lvl
199 if (leaves) then
200 !$omp do
201 do i = 1, size(tree%lvls(lvl)%leaves)
202 call my_procedure(tree, tree%lvls(lvl)%leaves(i))
203 end do
204 !$omp end do
205 else
206 !$omp do
207 do i = 1, size(tree%lvls(lvl)%ids)
208 call my_procedure(tree, tree%lvls(lvl)%ids(i))
209 end do
210 !$omp end do
211 end if
212 end do
213 !$omp end parallel
214 end subroutine af_loop_tree
215
216 !> Call procedure for each id in tree, passing the tree as first argument
217 subroutine af_loop_tree_arg(tree, my_procedure, rarg, leaves_only)
218 type(af_t), intent(inout) :: tree
219 procedure(af_subr_tree_arg) :: my_procedure
220 real(dp), intent(in) :: rarg(:)
221 logical, intent(in), optional :: leaves_only
222 logical :: leaves
223 integer :: lvl, i
224
225 if (.not. tree%ready) stop "Tree not ready"
226 leaves = .false.; if (present(leaves_only)) leaves = leaves_only
227
228 !$omp parallel private(lvl, i)
229 do lvl = 1, tree%highest_lvl
230 if (leaves) then
231 !$omp do
232 do i = 1, size(tree%lvls(lvl)%leaves)
233 call my_procedure(tree, tree%lvls(lvl)%leaves(i), rarg)
234 end do
235 !$omp end do
236 else
237 !$omp do
238 do i = 1, size(tree%lvls(lvl)%ids)
239 call my_procedure(tree, tree%lvls(lvl)%leaves(i), rarg)
240 end do
241 !$omp end do
242 end if
243 end do
244 !$omp end parallel
245 end subroutine af_loop_tree_arg
246
247 !> Returns whether r is inside or within a distance d from box
248 pure function af_r_inside(box, r, d) result(inside)
249 type(box_t), intent(in) :: box
250 real(dp), intent(in) :: r(ndim)
251 real(dp), intent(in), optional :: d
252 real(dp) :: r_max(ndim)
253 logical :: inside
254
255 r_max = box%r_min + box%dr * box%n_cell
256 if (present(d)) then
257 inside = all(r+d >= box%r_min) .and. all(r-d <= r_max)
258 else
259 inside = all(r >= box%r_min) .and. all(r <= r_max)
260 end if
261 end function af_r_inside
262
263 !> Get the id of the finest box containing rr. If highest_lvl is present, do
264 !> not go to a finer level than highest_lvl. If there is no box containing rr,
265 !> return a location of -1
266 pure function af_get_id_at(tree, rr, highest_lvl, guess) result(id)
267 type(af_t), intent(in) :: tree !< Full grid
268 real(dp), intent(in) :: rr(ndim) !< Coordinate
269 integer, intent(in), optional :: highest_lvl !< Maximum level of box
270 integer, intent(in), optional :: guess !< Guess of box id, cannot be used with highest_lvl
271 integer :: id !< Id of finest box containing rr
272
273 integer :: i, id_tmp, i_ch, lvl_max
274
275 lvl_max = af_max_lvl
276 if (present(highest_lvl)) lvl_max = highest_lvl
277
278 id = -1
279
280 if (present(guess)) then
281 ! Check whether the guess is valid
282 if (guess > 0 .and. guess < tree%highest_id) then
283 if (tree%boxes(guess)%in_use .and. &
284 tree%boxes(guess)%lvl <= lvl_max .and. &
285 af_r_inside(tree%boxes(guess), rr)) then
286 id = guess
287 end if
288 end if
289 end if
290
291 if (id == -1) then
292 ! If there was no (valid) guess, find lvl 1 box that includes rr
293 do i = 1, size(tree%lvls(1)%ids)
294 id_tmp = tree%lvls(1)%ids(i)
295 if (af_r_inside(tree%boxes(id_tmp), rr)) then
296 id = id_tmp
297 exit
298 end if
299 end do
300 end if
301
302 if (id > 0) then
303 ! Jump into children for as long as possible
304 do
305 if (tree%boxes(id)%lvl >= lvl_max .or. &
306 .not. af_has_children(tree%boxes(id))) exit
307 i_ch = child_that_contains(tree%boxes(id), rr)
308 id = tree%boxes(id)%children(i_ch)
309 end do
310 end if
311
312 end function af_get_id_at
313
314 !> Get the location of the finest cell containing rr. If highest_lvl is present,
315 !> do not go to a finer level than highest_lvl. If there is no box containing rr,
316 !> return a location of -1
317 pure function af_get_loc(tree, rr, highest_lvl, guess) result(loc)
318 type(af_t), intent(in) :: tree !< Full grid
319 real(dp), intent(in) :: rr(ndim) !< Coordinate
320 integer, intent(in), optional :: highest_lvl !< Maximum level of box
321 !> Guess of box id, cannot be used with highest_lvl
322 integer, intent(in), optional :: guess
323 type(af_loc_t) :: loc !< Location of cell
324
325 loc%id = af_get_id_at(tree, rr, highest_lvl, guess)
326
327 if (loc%id == -1) then
328 loc%ix = -1
329 else
330 loc%ix = af_cc_ix(tree%boxes(loc%id), rr)
331
332 ! Fix indices for points exactly on the boundaries of a box (which could
333 ! get a ghost cell index)
334 where (loc%ix < 1) loc%ix = 1
335 where (loc%ix > tree%n_cell) loc%ix = tree%n_cell
336 end if
337 end function af_get_loc
338
339 !> For a box with children that contains rr, find in which child rr lies
340 pure function child_that_contains(box, rr) result(i_ch)
341 type(box_t), intent(in) :: box !< A box with children
342 real(dp), intent(in) :: rr(ndim) !< Location inside the box
343 integer :: i_ch !< Index of child containing rr
344 real(dp) :: center(ndim)
345
346 i_ch = 1
347 center = box%r_min + box%dr * ishft(box%n_cell, -1)
348
349 if (rr(1) > center(1)) i_ch = i_ch + 1
350#if NDIM > 1
351 if (rr(2) > center(2)) i_ch = i_ch + 2
352#endif
353#if NDIM > 2
354 if (rr(3) > center(3)) i_ch = i_ch + 4
355#endif
356 end function child_that_contains
357
358 !> Get the coordinate of the cell-center at loc
359 pure function af_r_loc(tree, loc) result(r)
360 type(af_t), intent(in) :: tree !< Full grid
361 type(af_loc_t), intent(in) :: loc !< Location object
362 real(dp) :: r(ndim) !< Coordinate at cell center
363 r = tree%boxes(loc%id)%r_min + &
364 (loc%ix-0.5_dp) * tree%boxes(loc%id)%dr
365 end function af_r_loc
366
367 subroutine af_tree_clear_cc(tree, iv)
368 type(af_t), intent(inout) :: tree
369 integer, intent(in) :: iv !< Variable to clear
370 integer :: lvl, i, id
371
372 !$omp parallel private(lvl, i, id)
373 do lvl = 1, tree%highest_lvl
374 !$omp do
375 do i = 1, size(tree%lvls(lvl)%ids)
376 id = tree%lvls(lvl)%ids(i)
377 call af_box_clear_cc(tree%boxes(id), iv)
378 end do
379 !$omp end do
380 end do
381 !$omp end parallel
382 end subroutine af_tree_clear_cc
383
384 !> Set cc(..., iv) = 0
385 subroutine af_box_clear_cc(box, iv)
386 type(box_t), intent(inout) :: box
387 integer, intent(in) :: iv !< Variable to clear
388 box%cc(dtimes(:), iv) = 0
389 end subroutine af_box_clear_cc
390
391 subroutine af_tree_clear_ghostcells(tree, iv)
392 type(af_t), intent(inout) :: tree
393 integer, intent(in) :: iv !< Variable to clear
394 integer :: lvl, i, id
395
396 !$omp parallel private(lvl, i, id)
397 do lvl = 1, tree%highest_lvl
398 !$omp do
399 do i = 1, size(tree%lvls(lvl)%ids)
400 id = tree%lvls(lvl)%ids(i)
401 call af_box_clear_ghostcells(tree%boxes(id), iv)
402 end do
403 !$omp end do
404 end do
405 !$omp end parallel
406 end subroutine af_tree_clear_ghostcells
407
408 !> Set cc(..., iv) = 0
409 subroutine af_box_clear_ghostcells(box, iv)
410 type(box_t), intent(inout) :: box
411 integer, intent(in) :: iv !< Variable to clear
412 integer :: nc
413
414 nc = box%n_cell
415
416#if NDIM == 1
417 box%cc(0, iv) = 0
418 box%cc(nc+1, iv) = 0
419#elif NDIM == 2
420 box%cc(0, :, iv) = 0
421 box%cc(nc+1, :, iv) = 0
422 box%cc(:, 0, iv) = 0
423 box%cc(:, nc+1, iv) = 0
424#elif NDIM == 3
425 box%cc(0, :, :, iv) = 0
426 box%cc(nc+1, :, :, iv) = 0
427 box%cc(:, 0, :, iv) = 0
428 box%cc(:, nc+1, :, iv) = 0
429 box%cc(:, :, 0, iv) = 0
430 box%cc(:, :, nc+1, iv) = 0
431#endif
432 end subroutine af_box_clear_ghostcells
433
434 !> Add cc(..., iv_from) to box%cc(..., iv_to)
435 subroutine af_box_add_cc(box, iv_from, iv_to)
436 type(box_t), intent(inout) :: box
437 integer, intent(in) :: iv_from, iv_to
438 box%cc(dtimes(:), iv_to) = box%cc(dtimes(:), iv_to) + &
439 box%cc(dtimes(:), iv_from)
440 end subroutine af_box_add_cc
441
442 !> Subtract cc(..., iv_from) from box%cc(..., iv_to)
443 subroutine af_box_sub_cc(box, iv_from, iv_to)
444 type(box_t), intent(inout) :: box
445 integer, intent(in) :: iv_from, iv_to
446 box%cc(dtimes(:), iv_to) = box%cc(dtimes(:), iv_to) - &
447 box%cc(dtimes(:), iv_from)
448 end subroutine af_box_sub_cc
449
450 !> Perform cc(..., iv_a) = cc(..., iv_a) 'op' cc(..., iv_b), where 'op' can be
451 !> '+', '*' or '/'
452 subroutine af_tree_apply(tree, iv_a, iv_b, op, eps)
453 type(af_t), intent(inout) :: tree
454 integer, intent(in) :: iv_a, iv_b
455 character(len=*), intent(in) :: op
456 real(dp), intent(in), optional :: eps !< Min value for division
457 integer :: lvl, i, id
458 real(dp) :: use_eps
459
460 use_eps = sqrt(tiny(1.0_dp))
461 if (present(eps)) use_eps = eps
462
463 !$omp parallel private(lvl, i, id)
464 do lvl = 1, tree%highest_lvl
465 !$omp do
466 do i = 1, size(tree%lvls(lvl)%ids)
467 id = tree%lvls(lvl)%ids(i)
468 select case (op)
469 case ('+')
470 tree%boxes(id)%cc(dtimes(:), iv_a) = &
471 tree%boxes(id)%cc(dtimes(:), iv_a) + &
472 tree%boxes(id)%cc(dtimes(:), iv_b)
473 case ('*')
474 tree%boxes(id)%cc(dtimes(:), iv_a) = &
475 tree%boxes(id)%cc(dtimes(:), iv_a) * &
476 tree%boxes(id)%cc(dtimes(:), iv_b)
477 case ('/')
478 tree%boxes(id)%cc(dtimes(:), iv_a) = &
479 tree%boxes(id)%cc(dtimes(:), iv_a) / &
480 max(tree%boxes(id)%cc(dtimes(:), iv_b), eps)
481 case default
482 error stop "af_tree_apply: unknown operand"
483 end select
484 end do
485 !$omp end do
486 end do
487 !$omp end parallel
488 end subroutine af_tree_apply
489
490 subroutine af_tree_times_cc(tree, ivs, facs)
491 type(af_t), intent(inout) :: tree
492 integer, intent(in) :: ivs(:)
493 real(dp), intent(in) :: facs(:)
494 integer :: lvl, i, id, n
495
496 if (size(ivs) /= size(facs)) &
497 error stop "af_times_cc: invalid array size"
498
499 !$omp parallel private(lvl, i, id, n)
500 do lvl = 1, tree%highest_lvl
501 !$omp do
502 do i = 1, size(tree%lvls(lvl)%ids)
503 id = tree%lvls(lvl)%ids(i)
504 do n = 1, size(ivs)
505 call af_box_times_cc(tree%boxes(id), facs(n), ivs(n))
506 end do
507 end do
508 !$omp end do
509 end do
510 !$omp end parallel
511 end subroutine af_tree_times_cc
512
513 !> Multipy cc(..., iv) with a
514 subroutine af_box_times_cc(box, a, iv)
515 type(box_t), intent(inout) :: box
516 real(dp), intent(in) :: a
517 integer, intent(in) :: iv
518 box%cc(dtimes(:), iv) = a * box%cc(dtimes(:), iv)
519 end subroutine af_box_times_cc
520
521 !> Set cc(..., iv_b) = a * cc(..., iv_a) + b * cc(..., iv_b)
522 subroutine af_box_lincomb_cc(box, a, iv_a, b, iv_b)
523 type(box_t), intent(inout) :: box
524 real(dp), intent(in) :: a, b
525 integer, intent(in) :: iv_a, iv_b
526 box%cc(dtimes(:), iv_b) = a * box%cc(dtimes(:), iv_a) + &
527 b * box%cc(dtimes(:), iv_b)
528 end subroutine af_box_lincomb_cc
529
530 !> Copy cc(..., iv_from) from box_in to cc(..., iv_to) on box_out
531 subroutine af_box_copy_cc_to(box_from, iv_from, box_to, iv_to)
532 type(box_t), intent(in) :: box_from
533 type(box_t), intent(inout) :: box_to
534 integer, intent(in) :: iv_from, iv_to
535 box_to%cc(dtimes(:), iv_to) = box_from%cc(dtimes(:), iv_from)
536 end subroutine af_box_copy_cc_to
537
538 !> Copy cc(..., iv_from) to box%cc(..., iv_to)
539 subroutine af_box_copy_cc(box, iv_from, iv_to)
540 type(box_t), intent(inout) :: box
541 integer, intent(in) :: iv_from, iv_to
542 box%cc(dtimes(:), iv_to) = box%cc(dtimes(:), iv_from)
543 end subroutine af_box_copy_cc
544
545 !> Copy cc(..., iv_from) to box%cc(..., iv_to)
546 subroutine af_box_copy_ccs(box, iv_from, iv_to)
547 type(box_t), intent(inout) :: box
548 integer, intent(in) :: iv_from(:), iv_to(:)
549 box%cc(dtimes(:), iv_to) = box%cc(dtimes(:), iv_from)
550 end subroutine af_box_copy_ccs
551
552 !> Copy cc(..., iv_from) to box%cc(..., iv_to) for all ids
553 subroutine af_boxes_copy_cc(boxes, ids, iv_from, iv_to)
554 type(box_t), intent(inout) :: boxes(:)
555 integer, intent(in) :: ids(:), iv_from, iv_to
556 integer :: i
557
558 !$omp parallel do
559 do i = 1, size(ids)
560 call af_box_copy_cc(boxes(ids(i)), iv_from, iv_to)
561 end do
562 !$omp end parallel do
563 end subroutine af_boxes_copy_cc
564
565 !> Copy cc(..., iv_from) to box%cc(..., iv_to) for all ids
566 subroutine af_boxes_copy_ccs(boxes, ids, iv_from, iv_to)
567 type(box_t), intent(inout) :: boxes(:)
568 integer, intent(in) :: ids(:), iv_from(:), iv_to(:)
569 integer :: i
570
571 !$omp parallel do
572 do i = 1, size(ids)
573 call af_box_copy_ccs(boxes(ids(i)), iv_from, iv_to)
574 end do
575 !$omp end parallel do
576 end subroutine af_boxes_copy_ccs
577
578 !> Copy cc(..., iv_from) to box%cc(..., iv_to) for full tree
579 subroutine af_tree_copy_cc(tree, iv_from, iv_to)
580 type(af_t), intent(inout) :: tree
581 integer, intent(in) :: iv_from, iv_to
582 integer :: lvl
583
584 do lvl = 1, tree%highest_lvl
585 call af_boxes_copy_cc(tree%boxes, tree%lvls(lvl)%ids, iv_from, iv_to)
586 end do
587 end subroutine af_tree_copy_cc
588
589 !> Copy cc(..., iv_from) to box%cc(..., iv_to) for full tree
590 subroutine af_tree_copy_ccs(tree, iv_from, iv_to)
591 type(af_t), intent(inout) :: tree
592 integer, intent(in) :: iv_from(:), iv_to(:)
593 integer :: lvl
594
595 do lvl = 1, tree%highest_lvl
596 call af_boxes_copy_ccs(tree%boxes, tree%lvls(lvl)%ids, iv_from, iv_to)
597 end do
598 end subroutine af_tree_copy_ccs
599
600 !> A general scalar reduction method
601 subroutine af_reduction(tree, box_func, reduction, init_val, out_val)
602 type(af_t), intent(in) :: tree !< Tree to do the reduction on
603 real(dp), intent(in) :: init_val !< Initial value for the reduction
604 real(dp), intent(out) :: out_val !< Result of the reduction
605 real(dp) :: tmp, my_val
606 integer :: i, id, lvl
607
608 interface
609 !> Function that returns a scalar
610 real(dp) function box_func(box)
611 import
612 type(box_t), intent(in) :: box
613 end function box_func
614
615 !> Reduction method (e.g., min, max, sum)
616 real(dp) function reduction(a, b)
617 import
618 real(dp), intent(in) :: a, b
619 end function reduction
620 end interface
621
622 if (.not. tree%ready) stop "Tree not ready"
623 out_val = init_val
624 my_val = init_val
625
626 !$omp parallel private(lvl, i, id, tmp) firstprivate(my_val)
627 do lvl = 1, tree%highest_lvl
628 !$omp do
629 do i = 1, size(tree%lvls(lvl)%leaves)
630 id = tree%lvls(lvl)%leaves(i)
631 tmp = box_func(tree%boxes(id))
632 my_val = reduction(tmp, my_val)
633 end do
634 !$omp end do
635 end do
636
637 !$omp critical
638 out_val = reduction(my_val, out_val)
639 !$omp end critical
640 !$omp end parallel
641 end subroutine af_reduction
642
643 !> A general vector reduction method
644 subroutine af_reduction_vec(tree, box_func, reduction, init_val, &
645 out_val, n_vals)
646 type(af_t), intent(in) :: tree !< Tree to do the reduction on
647 integer, intent(in) :: n_vals !< Size of vector
648 real(dp), intent(in) :: init_val(n_vals) !< Initial value for the reduction
649 real(dp), intent(out) :: out_val(n_vals) !< Result of the reduction
650 real(dp) :: tmp(n_vals), my_val(n_vals)
651 integer :: i, id, lvl
652
653 interface
654 !> Function that returns a vector
655 function box_func(box, n_vals) result(vec)
656 import
657 type(box_t), intent(in) :: box
658 integer, intent(in) :: n_vals
659 real(dp) :: vec(n_vals)
660 end function box_func
661
662 !> Reduction method (e.g., min, max, sum)
663 function reduction(vec_1, vec_2, n_vals) result(vec)
664 import
665 integer, intent(in) :: n_vals
666 real(dp), intent(in) :: vec_1(n_vals), vec_2(n_vals)
667 real(dp) :: vec(n_vals)
668 end function reduction
669 end interface
670
671 if (.not. tree%ready) stop "Tree not ready"
672 out_val = init_val
673 my_val = init_val
674
675 !$omp parallel private(lvl, i, id, tmp) firstprivate(my_val)
676 do lvl = 1, tree%highest_lvl
677 !$omp do
678 do i = 1, size(tree%lvls(lvl)%leaves)
679 id = tree%lvls(lvl)%leaves(i)
680 tmp = box_func(tree%boxes(id), n_vals)
681 my_val = reduction(tmp, my_val, n_vals)
682 end do
683 !$omp end do
684 end do
685
686 !$omp critical
687 out_val = reduction(my_val, out_val, n_vals)
688 !$omp end critical
689 !$omp end parallel
690 end subroutine af_reduction_vec
691
692 !> A general scalar reduction method, that returns the location of the
693 !> minimum/maximum value found
694 subroutine af_reduction_loc(tree, iv, box_subr, reduction, &
695 init_val, out_val, out_loc)
696 type(af_t), intent(in) :: tree !< Tree to do the reduction on
697 integer, intent(in) :: iv !< Variable to operate on (can be ignored)
698 real(dp), intent(in) :: init_val !< Initial value for the reduction
699 real(dp), intent(out) :: out_val !< Result of the reduction
700 type(af_loc_t), intent(out) :: out_loc !< Location
701 real(dp) :: tmp, new_val, my_val
702 integer :: i, id, lvl, tmp_ix(ndim)
703 type(af_loc_t) :: my_loc
704
705 interface
706 !> Subroutine that returns a scalar and a cell index
707 subroutine box_subr(box, iv, val, ix)
708 import
709 type(box_t), intent(in) :: box
710 integer, intent(in) :: iv
711 real(dp), intent(out) :: val
712 integer, intent(out) :: ix(ndim)
713 end subroutine box_subr
714
715 !> Reduction method (e.g., min, max, sum)
716 real(dp) function reduction(a, b)
717 import
718 real(dp), intent(in) :: a, b
719 end function reduction
720 end interface
721
722 if (.not. tree%ready) stop "Tree not ready"
723 out_val = init_val
724 my_val = init_val
725 my_loc%id = -1
726 my_loc%ix = -1
727
728 !$omp parallel private(lvl, i, id, tmp, tmp_ix, new_val) &
729 !$omp firstprivate(my_val, my_loc)
730 do lvl = 1, tree%highest_lvl
731 !$omp do
732 do i = 1, size(tree%lvls(lvl)%leaves)
733 id = tree%lvls(lvl)%leaves(i)
734 call box_subr(tree%boxes(id), iv, tmp, tmp_ix)
735 new_val = reduction(tmp, my_val)
736 if (abs(new_val - my_val) > 0) then
737 my_loc%id = id
738 my_loc%ix = tmp_ix
739 my_val = tmp
740 end if
741 end do
742 !$omp end do
743 end do
744
745 !$omp critical
746 new_val = reduction(my_val, out_val)
747 if (abs(new_val - out_val) > 0) then
748 out_loc%id = my_loc%id
749 out_loc%ix = my_loc%ix
750 out_val = my_val
751 end if
752 !$omp end critical
753 !$omp end parallel
754 end subroutine af_reduction_loc
755
756 !> Find maximum value of cc(..., iv). By default, only loop over leaves, and
757 !> ghost cells are not used.
758 subroutine af_tree_max_cc(tree, iv, cc_max, loc)
759 type(af_t), intent(in) :: tree !< Full grid
760 integer, intent(in) :: iv !< Index of variable
761 real(dp), intent(out) :: cc_max !< Maximum value
762 !> Location of maximum
763 type(af_loc_t), intent(out), optional :: loc
764 type(af_loc_t) :: tmp_loc
765
766 call af_reduction_loc(tree, iv, box_max_cc, reduce_max, &
767 -huge(1.0_dp)/10, cc_max, tmp_loc)
768 if (present(loc)) loc = tmp_loc
769 end subroutine af_tree_max_cc
770
771 !> Find maximum value of abs(cc(..., iv)). By default, only loop over leaves,
772 !> and ghost cells are not used.
773 subroutine af_tree_maxabs_cc(tree, iv, cc_max, loc)
774 type(af_t), intent(in) :: tree !< Full grid
775 integer, intent(in) :: iv !< Index of variable
776 real(dp), intent(out) :: cc_max !< Maximum value
777 !> Location of maximum
778 type(af_loc_t), intent(out), optional :: loc
779 type(af_loc_t) :: tmp_loc
780
781 call af_reduction_loc(tree, iv, box_maxabs_cc, reduce_max, &
782 -huge(1.0_dp)/10, cc_max, tmp_loc)
783 if (present(loc)) loc = tmp_loc
784 end subroutine af_tree_maxabs_cc
785
786 !> Find minimum value of cc(..., iv). By default, only loop over leaves, and
787 !> ghost cells are not used.
788 subroutine af_tree_min_cc(tree, iv, cc_min, loc)
789 type(af_t), intent(in) :: tree !< Full grid
790 integer, intent(in) :: iv !< Index of variable
791 real(dp), intent(out) :: cc_min !< Minimum value
792 !> Location of minimum
793 type(af_loc_t), intent(out), optional :: loc
794 type(af_loc_t) :: tmp_loc
795
796 call af_reduction_loc(tree, iv, box_min_cc, reduce_min, &
797 huge(1.0_dp)/10, cc_min, tmp_loc)
798
799 if (present(loc)) loc = tmp_loc
800 end subroutine af_tree_min_cc
801
802 !> Find maximum value of fc(..., dim, iv). By default, only loop over leaves.
803 subroutine af_tree_max_fc(tree, dim, iv, fc_max, loc)
804 type(af_t), intent(in) :: tree !< Full grid
805 integer, intent(in) :: dim !< Flux dimension
806 integer, intent(in) :: iv !< Index of face variable
807 real(dp), intent(out) :: fc_max !< Maximum value
808 !> Location of maximum
809 type(af_loc_t), intent(out), optional :: loc
810 type(af_loc_t) :: tmp_loc
811 integer :: dim_iv
812
813 ! Encode dim and iv in a single variable
814 dim_iv = (dim-1) * tree%n_var_face + iv - 1
815
816 call af_reduction_loc(tree, dim_iv, box_max_fc, reduce_max, &
817 -huge(1.0_dp)/10, fc_max, tmp_loc)
818 if (present(loc)) loc = tmp_loc
819 end subroutine af_tree_max_fc
820
821 !> Find maximum value of fc(..., dim, iv). By default, only loop over leaves.
822 subroutine af_tree_min_fc(tree, dim, iv, fc_min, loc)
823 type(af_t), intent(in) :: tree !< Full grid
824 integer, intent(in) :: dim !< Flux dimension
825 integer, intent(in) :: iv !< Index of face variable
826 real(dp), intent(out) :: fc_min !< Minimum value
827 !> Location of minimum
828 type(af_loc_t), intent(out), optional :: loc
829 type(af_loc_t) :: tmp_loc
830 integer :: dim_iv
831
832 ! Encode dim and iv in a single variable
833 dim_iv = (dim-1) * tree%n_var_face + iv - 1
834
835 call af_reduction_loc(tree, dim_iv, box_min_fc, reduce_min, &
836 huge(1.0_dp)/10, fc_min, tmp_loc)
837 if (present(loc)) loc = tmp_loc
838 end subroutine af_tree_min_fc
839
840 subroutine box_max_cc(box, iv, val, ix)
841 type(box_t), intent(in) :: box
842 integer, intent(in) :: iv
843 real(dp), intent(out) :: val
844 integer, intent(out) :: ix(NDIM)
845 integer :: nc
846
847 nc = box%n_cell
848 ix = maxloc(box%cc(dtimes(1:nc), iv))
849 val = box%cc(dindex(ix), iv)
850 end subroutine box_max_cc
851
852 subroutine box_maxabs_cc(box, iv, val, ix)
853 type(box_t), intent(in) :: box
854 integer, intent(in) :: iv
855 real(dp), intent(out) :: val
856 integer, intent(out) :: ix(NDIM)
857 integer :: nc
858
859 nc = box%n_cell
860 ix = maxloc(abs(box%cc(dtimes(1:nc), iv)))
861 val = abs(box%cc(dindex(ix), iv))
862 end subroutine box_maxabs_cc
863
864 subroutine box_min_cc(box, iv, val, ix)
865 type(box_t), intent(in) :: box
866 integer, intent(in) :: iv
867 real(dp), intent(out) :: val
868 integer, intent(out) :: ix(NDIM)
869 integer :: nc
870
871 nc = box%n_cell
872 ix = minloc(box%cc(dtimes(1:nc), iv))
873 val = box%cc(dindex(ix), iv)
874 end subroutine box_min_cc
875
876 subroutine box_max_fc(box, dim_iv, val, ix)
877 type(box_t), intent(in) :: box
878 integer, intent(in) :: dim_iv
879 real(dp), intent(out) :: val
880 integer, intent(out) :: ix(NDIM)
881 integer :: dim, iv, n_fc, nc, dix(NDIM)
882
883 nc = box%n_cell
884 dix(:) = 0
885
886#if NDIM == 1
887 n_fc = size(box%fc, 3)
888
889 ! Decode dim and iv
890 dim = 1 ! Trivial
891 iv = dim_iv + 1
892 ix = maxloc(box%fc(1:nc+1, dim, iv))
893 val = box%fc(ix(1), dim, iv)
894#elif NDIM == 2
895 n_fc = size(box%fc, 4)
896
897 ! Decode dim and iv
898 dim = dim_iv / n_fc + 1
899 iv = dim_iv - (dim-1) * n_fc + 1
900 ! Also include fluxes at 'upper' boundary
901 dix(dim) = 1
902 ix = maxloc(box%fc(1:nc+dix(1), 1:nc+dix(2), dim, iv))
903 val = box%fc(ix(1), ix(2), dim, iv)
904#elif NDIM == 3
905 n_fc = size(box%fc, 5)
906 ! Decode dim and iv
907 dim = dim_iv / n_fc + 1
908 dix(dim) = 1
909 iv = dim_iv - (dim-1) * n_fc + 1
910 ix = maxloc(box%fc(1:nc+dix(1), 1:nc+dix(2), 1:nc+dix(3), dim, iv))
911 val = box%fc(ix(1), ix(2), ix(3), dim, iv)
912#endif
913 end subroutine box_max_fc
914
915 subroutine box_min_fc(box, dim_iv, val, ix)
916 type(box_t), intent(in) :: box
917 integer, intent(in) :: dim_iv
918 real(dp), intent(out) :: val
919 integer, intent(out) :: ix(NDIM)
920 integer :: dim, iv, n_fc, nc, dix(NDIM)
921
922 nc = box%n_cell
923 dix(:) = 0
924
925#if NDIM == 1
926 n_fc = size(box%fc, 3)
927
928 ! Decode dim and iv
929 dim = 1 ! Trivial
930 iv = dim_iv + 1
931 ix = minloc(box%fc(1:nc+1, dim, iv))
932 val = box%fc(ix(1), dim, iv)
933#elif NDIM == 2
934 n_fc = size(box%fc, 4)
935
936 ! Decode dim and iv
937 dim = dim_iv / n_fc + 1
938 iv = dim_iv - (dim-1) * n_fc + 1
939 ! Also include fluxes at 'upper' boundary
940 dix(dim) = 1
941 ix = minloc(box%fc(1:nc+dix(1), 1:nc+dix(2), dim, iv))
942 val = box%fc(ix(1), ix(2), dim, iv)
943#elif NDIM == 3
944 n_fc = size(box%fc, 5)
945 ! Decode dim and iv
946 dim = dim_iv / n_fc + 1
947 dix(dim) = 1
948 iv = dim_iv - (dim-1) * n_fc + 1
949 ix = minloc(box%fc(1:nc+dix(1), 1:nc+dix(2), 1:nc+dix(3), dim, iv))
950 val = box%fc(ix(1), ix(2), ix(3), dim, iv)
951#endif
952 end subroutine box_min_fc
953
954 real(dp) function reduce_max(a, b)
955 real(dp), intent(in) :: a, b
956 reduce_max = max(a, b)
957 end function reduce_max
958
959 real(dp) function reduce_min(a, b)
960 real(dp), intent(in) :: a, b
961 reduce_min = min(a, b)
962 end function reduce_min
963
964 !> Find weighted sum of cc(..., iv). Only loop over leaves, and ghost cells
965 !> are not used.
966 subroutine af_tree_sum_cc(tree, iv, cc_sum, power)
967 type(af_t), intent(in) :: tree !< Full grid
968 integer, intent(in) :: iv !< Index of variable
969 real(dp), intent(out) :: cc_sum !< Volume-integrated sum of variable
970 integer, intent(in), optional :: power !< Sum of values**power (default: 1)
971 real(dp) :: tmp, my_sum, fac
972 integer :: i, id, lvl, nc, pow
973
974 pow = 1; if (present(power)) pow = power
975
976 if (.not. tree%ready) stop "Tree not ready"
977 my_sum = 0
978
979 !$omp parallel reduction(+: my_sum) private(lvl, i, id, nc, tmp, fac)
980 do lvl = 1, tree%highest_lvl
981 fac = product(af_lvl_dr(tree, lvl))
982
983 !$omp do
984 do i = 1, size(tree%lvls(lvl)%leaves)
985 id = tree%lvls(lvl)%leaves(i)
986 nc = tree%boxes(id)%n_cell
987#if NDIM == 2
988 if (tree%coord_t == af_cyl) then
989 tmp = sum_2pr_box(tree%boxes(id), iv)
990 else
991 tmp = sum(tree%boxes(id)%cc(1:nc, 1:nc, iv)**pow)
992 end if
993#else
994 tmp = sum(tree%boxes(id)%cc(dtimes(1:nc), iv)**pow)
995#endif
996 my_sum = my_sum + fac * tmp
997 end do
998 !$omp end do
999 end do
1000 !$omp end parallel
1001
1002 cc_sum = my_sum
1003
1004#if NDIM == 2
1005 contains
1006
1007 ! Sum of 2 * pi * r * values
1008 pure function sum_2pr_box(box, iv) result(res)
1009 type(box_t), intent(in) :: box
1010 integer, intent(in) :: iv
1011 real(dp), parameter :: twopi = 2 * acos(-1.0_dp)
1012 real(dp) :: res
1013 integer :: i, j, nc
1014
1015 res = 0
1016 nc = box%n_cell
1017
1018 do j = 1, nc
1019 do i = 1, nc
1020 res = res + box%cc(i, j, iv)**pow * af_cyl_radius_cc(box, i)
1021 end do
1022 end do
1023 res = res * twopi
1024 end function sum_2pr_box
1025#endif
1026 end subroutine af_tree_sum_cc
1027
1028 !> Copy fx/fy/fz(..., iv_from) to fx/fy/fz(..., iv_to)
1029 subroutine af_box_copy_fc(box, iv_from, iv_to)
1030 type(box_t), intent(inout) :: box !< Operate on this box
1031 integer, intent(in) :: iv_from !< From this variable
1032 integer, intent(in) :: iv_to !< To this variable
1033 box%fc(dtimes(:),:, iv_to) = box%fc(dtimes(:),:, iv_from)
1034 end subroutine af_box_copy_fc
1035
1036 !> Copy fx/fy/fz(..., iv_from) to fx/fy/fz(..., iv_to) for all ids
1037 subroutine af_boxes_copy_fc(boxes, ids, iv_from, iv_to)
1038 type(box_t), intent(inout) :: boxes(:) !< List of all boxes
1039 integer, intent(in) :: ids(:) !< Operate on these boxes
1040 integer, intent(in) :: iv_from !< From this variable
1041 integer, intent(in) :: iv_to !< To this variable
1042 integer :: i
1043
1044 !$omp parallel do
1045 do i = 1, size(ids)
1046 call af_box_copy_fc(boxes(ids(i)), iv_from, iv_to)
1047 end do
1048 !$omp end parallel do
1049 end subroutine af_boxes_copy_fc
1050
1051 !> Copy fx/fy/fz(..., iv_from) to fx/fy/fz(..., iv_to) for full tree
1052 subroutine af_tree_copy_fc(tree, iv_from, iv_to)
1053 type(af_t), intent(inout) :: tree !< Full grid
1054 integer, intent(in) :: iv_from !< From this variable
1055 integer, intent(in) :: iv_to !< To this variable
1056 integer :: lvl
1057
1058 if (.not. tree%ready) stop "Tree not ready"
1059 do lvl = 1, tree%highest_lvl
1060 call af_boxes_copy_fc(tree%boxes, tree%lvls(lvl)%ids, iv_from, iv_to)
1061 end do
1062 end subroutine af_tree_copy_fc
1063
1064end module m_af_utils
Subroutine that gets a box and an array of reals.
Definition: m_af_types.f90:417
Subroutine that gets a list of boxes, an id and an array of reals.
Definition: m_af_types.f90:431
Subroutine that gets a list of boxes and a box id.
Definition: m_af_types.f90:424
Subroutine that gets a tree, a box id and an array of reals.
Definition: m_af_types.f90:446
Subroutine that gets a tree and a box id.
Definition: m_af_types.f90:439
Subroutine that gets a box.
Definition: m_af_types.f90:411
This module contains the basic types and constants that are used in the NDIM-dimensional version of A...
Definition: m_af_types.f90:3
This module contains all kinds of different 'helper' routines for Afivo. If the number of routines fo...
Definition: m_af_utils.f90:4
Type specifying the location of a cell.
Definition: m_af_types.f90:396
Type which stores all the boxes and levels, as well as some information about the number of boxes,...
Definition: m_af_types.f90:326
The basic building block of afivo: a box with cell-centered and face centered data,...
Definition: m_af_types.f90:286