Afivo  0.3
m_af_utils.f90
1 #include "cpp_macros.h"
2 
5 module m_af_utils
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 
54 contains
55 
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 
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 
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 
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 
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 
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 
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 
266  pure function af_get_id_at(tree, rr, highest_lvl, guess) result(id)
267  type(af_t), intent(in) :: tree
268  real(dp), intent(in) :: rr(ndim)
269  integer, intent(in), optional :: highest_lvl
270  integer, intent(in), optional :: guess
271  integer :: id
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 
317  pure function af_get_loc(tree, rr, highest_lvl, guess) result(loc)
318  type(af_t), intent(in) :: tree
319  real(dp), intent(in) :: rr(ndim)
320  integer, intent(in), optional :: highest_lvl
322  integer, intent(in), optional :: guess
323  type(af_loc_t) :: loc
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 
340  pure function child_that_contains(box, rr) result(i_ch)
341  type(box_t), intent(in) :: box
342  real(dp), intent(in) :: rr(ndim)
343  integer :: i_ch
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 
359  pure function af_r_loc(tree, loc) result(r)
360  type(af_t), intent(in) :: tree
361  type(af_loc_t), intent(in) :: loc
362  real(dp) :: r(ndim)
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
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 
385  subroutine af_box_clear_cc(box, iv)
386  type(box_t), intent(inout) :: box
387  integer, intent(in) :: iv
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
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 
409  subroutine af_box_clear_ghostcells(box, iv)
410  type(box_t), intent(inout) :: box
411  integer, intent(in) :: iv
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 
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 
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 
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
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 
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 
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 
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 
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 
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 
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 
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 
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 
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 
601  subroutine af_reduction(tree, box_func, reduction, init_val, out_val)
602  type(af_t), intent(in) :: tree
603  real(dp), intent(in) :: init_val
604  real(dp), intent(out) :: out_val
605  real(dp) :: tmp, my_val
606  integer :: i, id, lvl
607 
608  interface
609 
610  real(dp) function box_func(box)
611  import
612  type(box_t), intent(in) :: box
613  end function box_func
614 
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 
644  subroutine af_reduction_vec(tree, box_func, reduction, init_val, &
645  out_val, n_vals)
646  type(af_t), intent(in) :: tree
647  integer, intent(in) :: n_vals
648  real(dp), intent(in) :: init_val(n_vals)
649  real(dp), intent(out) :: out_val(n_vals)
650  real(dp) :: tmp(n_vals), my_val(n_vals)
651  integer :: i, id, lvl
652 
653  interface
654 
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 
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 
694  subroutine af_reduction_loc(tree, iv, box_subr, reduction, &
695  init_val, out_val, out_loc)
696  type(af_t), intent(in) :: tree
697  integer, intent(in) :: iv
698  real(dp), intent(in) :: init_val
699  real(dp), intent(out) :: out_val
700  type(af_loc_t), intent(out) :: out_loc
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 
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 
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 
758  subroutine af_tree_max_cc(tree, iv, cc_max, loc)
759  type(af_t), intent(in) :: tree
760  integer, intent(in) :: iv
761  real(dp), intent(out) :: cc_max
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 
773  subroutine af_tree_maxabs_cc(tree, iv, cc_max, loc)
774  type(af_t), intent(in) :: tree
775  integer, intent(in) :: iv
776  real(dp), intent(out) :: cc_max
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 
788  subroutine af_tree_min_cc(tree, iv, cc_min, loc)
789  type(af_t), intent(in) :: tree
790  integer, intent(in) :: iv
791  real(dp), intent(out) :: cc_min
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 
803  subroutine af_tree_max_fc(tree, dim, iv, fc_max, loc)
804  type(af_t), intent(in) :: tree
805  integer, intent(in) :: dim
806  integer, intent(in) :: iv
807  real(dp), intent(out) :: fc_max
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 
822  subroutine af_tree_min_fc(tree, dim, iv, fc_min, loc)
823  type(af_t), intent(in) :: tree
824  integer, intent(in) :: dim
825  integer, intent(in) :: iv
826  real(dp), intent(out) :: fc_min
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 
966  subroutine af_tree_sum_cc(tree, iv, cc_sum, power)
967  type(af_t), intent(in) :: tree
968  integer, intent(in) :: iv
969  real(dp), intent(out) :: cc_sum
970  integer, intent(in), optional :: power
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 
1029  subroutine af_box_copy_fc(box, iv_from, iv_to)
1030  type(box_t), intent(inout) :: box
1031  integer, intent(in) :: iv_from
1032  integer, intent(in) :: iv_to
1033  box%fc(dtimes(:),:, iv_to) = box%fc(dtimes(:),:, iv_from)
1034  end subroutine af_box_copy_fc
1035 
1037  subroutine af_boxes_copy_fc(boxes, ids, iv_from, iv_to)
1038  type(box_t), intent(inout) :: boxes(:)
1039  integer, intent(in) :: ids(:)
1040  integer, intent(in) :: iv_from
1041  integer, intent(in) :: iv_to
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 
1052  subroutine af_tree_copy_fc(tree, iv_from, iv_to)
1053  type(af_t), intent(inout) :: tree
1054  integer, intent(in) :: iv_from
1055  integer, intent(in) :: iv_to
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 
1064 end 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:4
This module contains all kinds of different 'helper' routines for Afivo. If the number of routines fo...
Definition: m_af_utils.f90:5
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