Afivo  0.3
m_a2_utils.f90
1 
5 module m_a2_utils
6  use m_a2_types
7 
8  implicit none
9  private
10 
11  ! Public subroutines
12  public :: a2_loop_box
13  public :: a2_loop_box_arg
14  public :: a2_loop_boxes
15  public :: a2_loop_boxes_arg
16  public :: a2_tree_clear_cc
17  public :: a2_box_clear_cc
18  public :: a2_tree_clear_ghostcells
19  public :: a2_box_clear_ghostcells
20  public :: a2_box_add_cc
21  public :: a2_box_sub_cc
22  public :: a2_tree_times_cc
23  public :: a2_tree_apply
24  public :: a2_box_times_cc
25  public :: a2_box_lincomb_cc
26  public :: a2_box_copy_cc_to
27  public :: a2_box_copy_cc
28  public :: a2_boxes_copy_cc
29  public :: a2_tree_copy_cc
30  public :: a2_reduction
31  public :: a2_reduction_vec
32  public :: a2_reduction_loc
33  public :: a2_tree_max_cc
34  public :: a2_tree_min_cc
35  public :: a2_tree_max_fc
36  public :: a2_tree_sum_cc
37  public :: a2_box_copy_fc
38  public :: a2_boxes_copy_fc
39  public :: a2_tree_copy_fc
40 
41  ! Public functions
42  public :: a2_get_id_at
43  public :: a2_get_loc
44  public :: a2_r_loc
45  public :: a2_r_inside
46  public :: a2_n_cell
47 
48 contains
49 
51  subroutine a2_loop_box(tree, my_procedure, leaves_only)
52  type(a2_t), intent(inout) :: tree
53  procedure(a2_subr) :: my_procedure
54  logical, intent(in), optional :: leaves_only
55  logical :: leaves
56  integer :: lvl, i, id
57 
58  leaves = .false.; if (present(leaves_only)) leaves = leaves_only
59  if (.not. tree%ready) stop "a2_loop_box: set_base has not been called"
60 
61  !$omp parallel private(lvl, i, id)
62  do lvl = lbound(tree%lvls, 1), tree%highest_lvl
63  if (leaves) then
64  !$omp do
65  do i = 1, size(tree%lvls(lvl)%leaves)
66  id = tree%lvls(lvl)%leaves(i)
67  call my_procedure(tree%boxes(id))
68  end do
69  !$omp end do
70  else
71  !$omp do
72  do i = 1, size(tree%lvls(lvl)%ids)
73  id = tree%lvls(lvl)%ids(i)
74  call my_procedure(tree%boxes(id))
75  end do
76  !$omp end do
77  end if
78  end do
79  !$omp end parallel
80  end subroutine a2_loop_box
81 
83  subroutine a2_loop_box_arg(tree, my_procedure, rarg, leaves_only)
84  type(a2_t), intent(inout) :: tree
85  procedure(a2_subr_arg) :: my_procedure
86  real(dp), intent(in) :: rarg(:)
87  logical, intent(in), optional :: leaves_only
88  logical :: leaves
89  integer :: lvl, i, id
90 
91  if (.not. tree%ready) stop "Tree not ready"
92  leaves = .false.; if (present(leaves_only)) leaves = leaves_only
93 
94  !$omp parallel private(lvl, i, id)
95  do lvl = lbound(tree%lvls, 1), tree%highest_lvl
96  if (leaves) then
97  !$omp do
98  do i = 1, size(tree%lvls(lvl)%leaves)
99  id = tree%lvls(lvl)%leaves(i)
100  call my_procedure(tree%boxes(id), rarg)
101  end do
102  !$omp end do
103  else
104  !$omp do
105  do i = 1, size(tree%lvls(lvl)%ids)
106  id = tree%lvls(lvl)%ids(i)
107  call my_procedure(tree%boxes(id), rarg)
108  end do
109  !$omp end do
110  end if
111  end do
112  !$omp end parallel
113  end subroutine a2_loop_box_arg
114 
116  subroutine a2_loop_boxes(tree, my_procedure, leaves_only)
117  type(a2_t), intent(inout) :: tree
118  procedure(a2_subr_boxes) :: my_procedure
119  logical, intent(in), optional :: leaves_only
120  logical :: leaves
121  integer :: lvl, i, id
122 
123  if (.not. tree%ready) stop "Tree not ready"
124  leaves = .false.; if (present(leaves_only)) leaves = leaves_only
125 
126  !$omp parallel private(lvl, i, id)
127  do lvl = lbound(tree%lvls, 1), tree%highest_lvl
128  if (leaves) then
129  !$omp do
130  do i = 1, size(tree%lvls(lvl)%leaves)
131  id = tree%lvls(lvl)%leaves(i)
132  call my_procedure(tree%boxes, id)
133  end do
134  !$omp end do
135  else
136  !$omp do
137  do i = 1, size(tree%lvls(lvl)%ids)
138  id = tree%lvls(lvl)%ids(i)
139  call my_procedure(tree%boxes, id)
140  end do
141  !$omp end do
142  end if
143  end do
144  !$omp end parallel
145  end subroutine a2_loop_boxes
146 
148  subroutine a2_loop_boxes_arg(tree, my_procedure, rarg, leaves_only)
149  type(a2_t), intent(inout) :: tree
150  procedure(a2_subr_boxes_arg) :: my_procedure
151  real(dp), intent(in) :: rarg(:)
152  logical, intent(in), optional :: leaves_only
153  logical :: leaves
154  integer :: lvl, i, id
155 
156  if (.not. tree%ready) stop "Tree not ready"
157  leaves = .false.; if (present(leaves_only)) leaves = leaves_only
158 
159  !$omp parallel private(lvl, i, id)
160  do lvl = lbound(tree%lvls, 1), tree%highest_lvl
161  if (leaves) then
162  !$omp do
163  do i = 1, size(tree%lvls(lvl)%leaves)
164  id = tree%lvls(lvl)%leaves(i)
165  call my_procedure(tree%boxes, id, rarg)
166  end do
167  !$omp end do
168  else
169  !$omp do
170  do i = 1, size(tree%lvls(lvl)%ids)
171  id = tree%lvls(lvl)%ids(i)
172  call my_procedure(tree%boxes, id, rarg)
173  end do
174  !$omp end do
175  end if
176  end do
177  !$omp end parallel
178  end subroutine a2_loop_boxes_arg
179 
181  pure function a2_r_inside(box, r, d) result(inside)
182  type(box2_t), intent(in) :: box
183  real(dp), intent(in) :: r(2)
184  real(dp), intent(in), optional :: d
185  real(dp) :: r_max(2)
186  logical :: inside
187 
188  r_max = box%r_min + box%dr * box%n_cell
189  if (present(d)) then
190  inside = all(r+d >= box%r_min) .and. all(r-d <= r_max)
191  else
192  inside = all(r >= box%r_min) .and. all(r <= r_max)
193  end if
194  end function a2_r_inside
195 
199  pure function a2_get_id_at(tree, rr, highest_lvl, guess) result(id)
200  type(a2_t), intent(in) :: tree
201  real(dp), intent(in) :: rr(2)
202  integer, intent(in), optional :: highest_lvl
203  integer, intent(in), optional :: guess
204  integer :: id
205 
206  integer :: i, i_ch, lvl_max
207 
208  if (present(guess)) then
209  id = guess
210  if (id > 0 .and. id < tree%highest_id) then
211  if (tree%boxes(id)%in_use .and. &
212  a2_r_inside(tree%boxes(id), rr)) then
213 
214  ! Jump into potential children for as long as possible
215  do while (a2_has_children(tree%boxes(id)))
216  i_ch = child_that_contains(tree%boxes(id), rr)
217  id = tree%boxes(id)%children(i_ch)
218  end do
219 
220  ! return ! Exit routine
221  end if
222  end if
223  end if
224 
225  lvl_max = tree%lvl_limit
226  if (present(highest_lvl)) lvl_max = highest_lvl
227 
228  ! Find lvl 1 box that includes rr
229  do i = 1, size(tree%lvls(1)%ids)
230  id = tree%lvls(1)%ids(i)
231  if (a2_r_inside(tree%boxes(id), rr)) exit
232  end do
233 
234  if (i > size(tree%lvls(1)%ids)) then
235  ! Not inside any box
236  id = -1
237  else
238  ! Jump into children for as long as possible
239  do
240  if (tree%boxes(id)%lvl >= lvl_max .or. &
241  .not. a2_has_children(tree%boxes(id))) exit
242  i_ch = child_that_contains(tree%boxes(id), rr)
243  id = tree%boxes(id)%children(i_ch)
244  end do
245  end if
246 
247  end function a2_get_id_at
248 
252  pure function a2_get_loc(tree, rr, highest_lvl, guess) result(loc)
253  type(a2_t), intent(in) :: tree
254  real(dp), intent(in) :: rr(2)
255  integer, intent(in), optional :: highest_lvl
257  integer, intent(in), optional :: guess
258  type(a2_loc_t) :: loc
259 
260  loc%id = a2_get_id_at(tree, rr, highest_lvl, guess)
261 
262  if (loc%id == -1) then
263  loc%ix = -1
264  else
265  loc%ix = a2_cc_ix(tree%boxes(loc%id), rr)
266 
267  ! Fix indices for points exactly on the boundaries of a box (which could
268  ! get a ghost cell index)
269  where (loc%ix < 1) loc%ix = 1
270  where (loc%ix > tree%n_cell) loc%ix = tree%n_cell
271  end if
272  end function a2_get_loc
273 
275  pure function child_that_contains(box, rr) result(i_ch)
276  type(box2_t), intent(in) :: box
277  real(dp), intent(in) :: rr(2)
278  integer :: i_ch
279  real(dp) :: center(2)
280 
281  i_ch = 1
282  center = box%r_min + box%dr * ishft(box%n_cell, -1)
283 
284  if (rr(1) > center(1)) i_ch = i_ch + 1
285  if (rr(2) > center(2)) i_ch = i_ch + 2
286  end function child_that_contains
287 
289  pure function a2_r_loc(tree, loc) result(r)
290  type(a2_t), intent(in) :: tree
291  type(a2_loc_t), intent(in) :: loc
292  real(dp) :: r(2)
293  r = tree%boxes(loc%id)%r_min + &
294  (loc%ix-0.5_dp) * tree%boxes(loc%id)%dr
295  end function a2_r_loc
296 
297  subroutine a2_tree_clear_cc(tree, iv)
298  type(a2_t), intent(inout) :: tree
299  integer, intent(in) :: iv
300  integer :: lvl, i, id
301 
302  !$omp parallel private(lvl, i, id)
303  do lvl = lbound(tree%lvls, 1), tree%highest_lvl
304  !$omp do
305  do i = 1, size(tree%lvls(lvl)%ids)
306  id = tree%lvls(lvl)%ids(i)
307  call a2_box_clear_cc(tree%boxes(id), iv)
308  end do
309  !$omp end do
310  end do
311  !$omp end parallel
312  end subroutine a2_tree_clear_cc
313 
315  subroutine a2_box_clear_cc(box, iv)
316  type(box2_t), intent(inout) :: box
317  integer, intent(in) :: iv
318  box%cc(:,:, iv) = 0
319  end subroutine a2_box_clear_cc
320 
321  subroutine a2_tree_clear_ghostcells(tree, iv)
322  type(a2_t), intent(inout) :: tree
323  integer, intent(in) :: iv
324  integer :: lvl, i, id
325 
326  !$omp parallel private(lvl, i, id)
327  do lvl = lbound(tree%lvls, 1), tree%highest_lvl
328  !$omp do
329  do i = 1, size(tree%lvls(lvl)%ids)
330  id = tree%lvls(lvl)%ids(i)
331  call a2_box_clear_ghostcells(tree%boxes(id), iv)
332  end do
333  !$omp end do
334  end do
335  !$omp end parallel
336  end subroutine a2_tree_clear_ghostcells
337 
339  subroutine a2_box_clear_ghostcells(box, iv)
340  type(box2_t), intent(inout) :: box
341  integer, intent(in) :: iv
342  integer :: nc
343 
344  nc = box%n_cell
345 
346  box%cc(0, :, iv) = 0
347  box%cc(nc+1, :, iv) = 0
348  box%cc(:, 0, iv) = 0
349  box%cc(:, nc+1, iv) = 0
350  end subroutine a2_box_clear_ghostcells
351 
353  subroutine a2_box_add_cc(box, iv_from, iv_to)
354  type(box2_t), intent(inout) :: box
355  integer, intent(in) :: iv_from, iv_to
356  box%cc(:,:, iv_to) = box%cc(:,:, iv_to) + box%cc(:,:, iv_from)
357  end subroutine a2_box_add_cc
358 
360  subroutine a2_box_sub_cc(box, iv_from, iv_to)
361  type(box2_t), intent(inout) :: box
362  integer, intent(in) :: iv_from, iv_to
363  box%cc(:,:, iv_to) = box%cc(:,:, iv_to) - box%cc(:,:, iv_from)
364  end subroutine a2_box_sub_cc
365 
368  subroutine a2_tree_apply(tree, iv_a, iv_b, op, eps)
369  type(a2_t), intent(inout) :: tree
370  integer, intent(in) :: iv_a, iv_b
371  character(len=*), intent(in) :: op
372  real(dp), intent(in), optional :: eps
373  integer :: lvl, i, id
374  real(dp) :: use_eps
375 
376  use_eps = sqrt(tiny(1.0_dp))
377  if (present(eps)) use_eps = eps
378 
379  !$omp parallel private(lvl, i, id)
380  do lvl = lbound(tree%lvls, 1), tree%highest_lvl
381  !$omp do
382  do i = 1, size(tree%lvls(lvl)%ids)
383  id = tree%lvls(lvl)%ids(i)
384  select case (op)
385  case ('+')
386  tree%boxes(id)%cc(:, :, iv_a) = &
387  tree%boxes(id)%cc(:, :, iv_a) + &
388  tree%boxes(id)%cc(:, :, iv_b)
389  case ('*')
390  tree%boxes(id)%cc(:, :, iv_a) = &
391  tree%boxes(id)%cc(:, :, iv_a) * &
392  tree%boxes(id)%cc(:, :, iv_b)
393  case ('/')
394  tree%boxes(id)%cc(:, :, iv_a) = &
395  tree%boxes(id)%cc(:, :, iv_a) / &
396  max(tree%boxes(id)%cc(:, :, iv_b), eps)
397  case default
398  error stop "a2_tree_apply: unknown operand"
399  end select
400  end do
401  !$omp end do
402  end do
403  !$omp end parallel
404  end subroutine a2_tree_apply
405 
406  subroutine a2_tree_times_cc(tree, ivs, facs)
407  type(a2_t), intent(inout) :: tree
408  integer, intent(in) :: ivs(:)
409  real(dp), intent(in) :: facs(:)
410  integer :: lvl, i, id, n
411 
412  if (size(ivs) /= size(facs)) &
413  error stop "a2_times_cc: invalid array size"
414 
415  !$omp parallel private(lvl, i, id, n)
416  do lvl = lbound(tree%lvls, 1), tree%highest_lvl
417  !$omp do
418  do i = 1, size(tree%lvls(lvl)%ids)
419  id = tree%lvls(lvl)%ids(i)
420  do n = 1, size(ivs)
421  call a2_box_times_cc(tree%boxes(id), facs(n), ivs(n))
422  end do
423  end do
424  !$omp end do
425  end do
426  !$omp end parallel
427  end subroutine a2_tree_times_cc
428 
430  subroutine a2_box_times_cc(box, a, iv)
431  type(box2_t), intent(inout) :: box
432  real(dp), intent(in) :: a
433  integer, intent(in) :: iv
434  box%cc(:,:, iv) = a * box%cc(:,:, iv)
435  end subroutine a2_box_times_cc
436 
438  subroutine a2_box_lincomb_cc(box, a, iv_a, b, iv_b)
439  type(box2_t), intent(inout) :: box
440  real(dp), intent(in) :: a, b
441  integer, intent(in) :: iv_a, iv_b
442  box%cc(:,:, iv_b) = a * box%cc(:,:, iv_a) + b * box%cc(:,:, iv_b)
443  end subroutine a2_box_lincomb_cc
444 
446  subroutine a2_box_copy_cc_to(box_from, iv_from, box_to, iv_to)
447  type(box2_t), intent(in) :: box_from
448  type(box2_t), intent(inout) :: box_to
449  integer, intent(in) :: iv_from, iv_to
450  box_to%cc(:,:, iv_to) = box_from%cc(:,:, iv_from)
451  end subroutine a2_box_copy_cc_to
452 
454  subroutine a2_box_copy_cc(box, iv_from, iv_to)
455  type(box2_t), intent(inout) :: box
456  integer, intent(in) :: iv_from, iv_to
457  box%cc(:,:, iv_to) = box%cc(:,:, iv_from)
458  end subroutine a2_box_copy_cc
459 
461  subroutine a2_boxes_copy_cc(boxes, ids, iv_from, iv_to)
462  type(box2_t), intent(inout) :: boxes(:)
463  integer, intent(in) :: ids(:), iv_from, iv_to
464  integer :: i
465 
466  !$omp parallel do
467  do i = 1, size(ids)
468  call a2_box_copy_cc(boxes(ids(i)), iv_from, iv_to)
469  end do
470  !$omp end parallel do
471  end subroutine a2_boxes_copy_cc
472 
474  subroutine a2_tree_copy_cc(tree, iv_from, iv_to)
475  type(a2_t), intent(inout) :: tree
476  integer, intent(in) :: iv_from, iv_to
477  integer :: lvl
478 
479  do lvl = lbound(tree%lvls, 1), tree%highest_lvl
480  call a2_boxes_copy_cc(tree%boxes, tree%lvls(lvl)%ids, iv_from, iv_to)
481  end do
482  end subroutine a2_tree_copy_cc
483 
485  subroutine a2_reduction(tree, box_func, reduction, init_val, out_val)
486  type(a2_t), intent(in) :: tree
487  real(dp), intent(in) :: init_val
488  real(dp), intent(out) :: out_val
489  real(dp) :: tmp, my_val
490  integer :: i, id, lvl
491 
492  interface
493 
494  real(dp) function box_func(box)
495  import
496  type(box2_t), intent(in) :: box
497  end function box_func
498 
500  real(dp) function reduction(a, b)
501  import
502  real(dp), intent(in) :: a, b
503  end function reduction
504  end interface
505 
506  if (.not. tree%ready) stop "Tree not ready"
507  out_val = init_val
508  my_val = init_val
509 
510  !$omp parallel private(lvl, i, id, tmp) firstprivate(my_val)
511  do lvl = lbound(tree%lvls, 1), tree%highest_lvl
512  !$omp do
513  do i = 1, size(tree%lvls(lvl)%leaves)
514  id = tree%lvls(lvl)%leaves(i)
515  tmp = box_func(tree%boxes(id))
516  my_val = reduction(tmp, my_val)
517  end do
518  !$omp end do
519  end do
520 
521  !$omp critical
522  out_val = reduction(my_val, out_val)
523  !$omp end critical
524  !$omp end parallel
525  end subroutine a2_reduction
526 
528  subroutine a2_reduction_vec(tree, box_func, reduction, init_val, &
529  out_val, n_vals)
530  type(a2_t), intent(in) :: tree
531  integer, intent(in) :: n_vals
532  real(dp), intent(in) :: init_val(n_vals)
533  real(dp), intent(out) :: out_val(n_vals)
534  real(dp) :: tmp(n_vals), my_val(n_vals)
535  integer :: i, id, lvl
536 
537  interface
538 
539  function box_func(box, n_vals) result(vec)
540  import
541  type(box2_t), intent(in) :: box
542  integer, intent(in) :: n_vals
543  real(dp) :: vec(n_vals)
544  end function box_func
545 
547  function reduction(vec_1, vec_2, n_vals) result(vec)
548  import
549  integer, intent(in) :: n_vals
550  real(dp), intent(in) :: vec_1(n_vals), vec_2(n_vals)
551  real(dp) :: vec(n_vals)
552  end function reduction
553  end interface
554 
555  if (.not. tree%ready) stop "Tree not ready"
556  out_val = init_val
557  my_val = init_val
558 
559  !$omp parallel private(lvl, i, id, tmp) firstprivate(my_val)
560  do lvl = lbound(tree%lvls, 1), tree%highest_lvl
561  !$omp do
562  do i = 1, size(tree%lvls(lvl)%leaves)
563  id = tree%lvls(lvl)%leaves(i)
564  tmp = box_func(tree%boxes(id), n_vals)
565  my_val = reduction(tmp, my_val, n_vals)
566  end do
567  !$omp end do
568  end do
569 
570  !$omp critical
571  out_val = reduction(my_val, out_val, n_vals)
572  !$omp end critical
573  !$omp end parallel
574  end subroutine a2_reduction_vec
575 
578  subroutine a2_reduction_loc(tree, iv, box_subr, reduction, &
579  init_val, out_val, out_loc)
580  type(a2_t), intent(in) :: tree
581  integer, intent(in) :: iv
582  real(dp), intent(in) :: init_val
583  real(dp), intent(out) :: out_val
584  type(a2_loc_t), intent(out) :: out_loc
585  real(dp) :: tmp, new_val, my_val
586  integer :: i, id, lvl, tmp_ix(2)
587  type(a2_loc_t) :: my_loc
588 
589  interface
590 
591  subroutine box_subr(box, iv, val, ix)
592  import
593  type(box2_t), intent(in) :: box
594  integer, intent(in) :: iv
595  real(dp), intent(out) :: val
596  integer, intent(out) :: ix(2)
597  end subroutine box_subr
598 
600  real(dp) function reduction(a, b)
601  import
602  real(dp), intent(in) :: a, b
603  end function reduction
604  end interface
605 
606  if (.not. tree%ready) stop "Tree not ready"
607  out_val = init_val
608  my_val = init_val
609  my_loc%id = -1
610  my_loc%ix = -1
611 
612  !$omp parallel private(lvl, i, id, tmp, tmp_ix, new_val) &
613  !$omp firstprivate(my_val, my_loc)
614  do lvl = lbound(tree%lvls, 1), tree%highest_lvl
615  !$omp do
616  do i = 1, size(tree%lvls(lvl)%leaves)
617  id = tree%lvls(lvl)%leaves(i)
618  call box_subr(tree%boxes(id), iv, tmp, tmp_ix)
619  new_val = reduction(tmp, my_val)
620  if (abs(new_val - my_val) > 0) then
621  my_loc%id = id
622  my_loc%ix = tmp_ix
623  my_val = tmp
624  end if
625  end do
626  !$omp end do
627  end do
628 
629  !$omp critical
630  new_val = reduction(my_val, out_val)
631  if (abs(new_val - out_val) > 0) then
632  out_loc%id = my_loc%id
633  out_loc%ix = my_loc%ix
634  out_val = my_val
635  end if
636  !$omp end critical
637  !$omp end parallel
638  end subroutine a2_reduction_loc
639 
642  subroutine a2_tree_max_cc(tree, iv, cc_max, loc)
643  type(a2_t), intent(in) :: tree
644  integer, intent(in) :: iv
645  real(dp), intent(out) :: cc_max
647  type(a2_loc_t), intent(out), optional :: loc
648  type(a2_loc_t) :: tmp_loc
649 
650  call a2_reduction_loc(tree, iv, box_max_cc, reduce_max, &
651  -huge(1.0_dp)/10, cc_max, tmp_loc)
652  if (present(loc)) loc = tmp_loc
653  end subroutine a2_tree_max_cc
654 
657  subroutine a2_tree_min_cc(tree, iv, cc_min, loc)
658  type(a2_t), intent(in) :: tree
659  integer, intent(in) :: iv
660  real(dp), intent(out) :: cc_min
662  type(a2_loc_t), intent(out), optional :: loc
663  type(a2_loc_t) :: tmp_loc
664 
665  call a2_reduction_loc(tree, iv, box_min_cc, reduce_min, &
666  huge(1.0_dp)/10, cc_min, tmp_loc)
667 
668  if (present(loc)) loc = tmp_loc
669  end subroutine a2_tree_min_cc
670 
672  subroutine a2_tree_max_fc(tree, dim, iv, fc_max, loc)
673  type(a2_t), intent(in) :: tree
674  integer, intent(in) :: dim
675  integer, intent(in) :: iv
676  real(dp), intent(out) :: fc_max
678  type(a2_loc_t), intent(out), optional :: loc
679  type(a2_loc_t) :: tmp_loc
680  integer :: dim_iv
681 
682  ! Encode dim and iv in a single variable
683  dim_iv = (dim-1) * tree%n_var_face + iv - 1
684 
685  call a2_reduction_loc(tree, dim_iv, box_max_fc, reduce_max, &
686  -huge(1.0_dp)/10, fc_max, tmp_loc)
687  if (present(loc)) loc = tmp_loc
688  end subroutine a2_tree_max_fc
689 
690  subroutine box_max_cc(box, iv, val, ix)
691  type(box2_t), intent(in) :: box
692  integer, intent(in) :: iv
693  real(dp), intent(out) :: val
694  integer, intent(out) :: ix(2)
695  integer :: nc
696 
697  nc = box%n_cell
698  ix = maxloc(box%cc(1:nc, 1:nc, iv))
699  val = box%cc(ix(1), ix(2), iv)
700  end subroutine box_max_cc
701 
702  subroutine box_min_cc(box, iv, val, ix)
703  type(box2_t), intent(in) :: box
704  integer, intent(in) :: iv
705  real(dp), intent(out) :: val
706  integer, intent(out) :: ix(2)
707  integer :: nc
708 
709  nc = box%n_cell
710  ix = minloc(box%cc(1:nc, 1:nc, iv))
711  val = box%cc(ix(1), ix(2), iv)
712  end subroutine box_min_cc
713 
714  subroutine box_max_fc(box, dim_iv, val, ix)
715  type(box2_t), intent(in) :: box
716  integer, intent(in) :: dim_iv
717  real(dp), intent(out) :: val
718  integer, intent(out) :: ix(2)
719  integer :: dim, iv, n_fc, nc, dix(2)
720 
721  nc = box%n_cell
722  dix(:) = 0
723 
724  n_fc = size(box%fc, 4)
725 
726  ! Decode dim and iv
727  dim = dim_iv / n_fc + 1
728  iv = dim_iv - (dim-1) * n_fc + 1
729  ! Also include fluxes at 'upper' boundary
730  dix(dim) = 1
731  ix = maxloc(box%fc(1:nc+dix(1), 1:nc+dix(2), dim, iv))
732  val = box%fc(ix(1), ix(2), dim, iv)
733  end subroutine box_max_fc
734 
735  real(dp) function reduce_max(a, b)
736  real(dp), intent(in) :: a, b
737  reduce_max = max(a, b)
738  end function reduce_max
739 
740  real(dp) function reduce_min(a, b)
741  real(dp), intent(in) :: a, b
742  reduce_min = min(a, b)
743  end function reduce_min
744 
747  subroutine a2_tree_sum_cc(tree, iv, cc_sum)
748  type(a2_t), intent(in) :: tree
749  integer, intent(in) :: iv
750  real(dp), intent(out) :: cc_sum
751  real(dp) :: tmp, my_sum, fac
752  integer :: i, id, lvl, nc
753 
754  if (.not. tree%ready) stop "Tree not ready"
755  my_sum = 0
756 
757  !$omp parallel reduction(+: my_sum) private(lvl, i, id, nc, tmp, fac)
758  do lvl = lbound(tree%lvls, 1), tree%highest_lvl
759  fac = a2_lvl_dr(tree, lvl)**2
760 
761  !$omp do
762  do i = 1, size(tree%lvls(lvl)%leaves)
763  id = tree%lvls(lvl)%leaves(i)
764  nc = tree%boxes(id)%n_cell
765  if (tree%coord_t == af_cyl) then
766  tmp = sum_2pr_box(tree%boxes(id), iv)
767  else
768  tmp = sum(tree%boxes(id)%cc(1:nc, 1:nc, iv))
769  end if
770  my_sum = my_sum + fac * tmp
771  end do
772  !$omp end do
773  end do
774  !$omp end parallel
775 
776  cc_sum = my_sum
777 
778  contains
779 
780  ! Sum of 2 * pi * r * values
781  pure function sum_2pr_box(box, iv) result(res)
782  type(box2_t), intent(in) :: box
783  integer, intent(in) :: iv
784  real(dp), parameter :: twopi = 2 * acos(-1.0_dp)
785  real(dp) :: res
786  integer :: i, j, nc
787 
788  res = 0
789  nc = box%n_cell
790 
791  do j = 1, nc
792  do i = 1, nc
793  res = res + box%cc(i, j, iv) * a2_cyl_radius_cc(box, i)
794  end do
795  end do
796  res = res * twopi
797  end function sum_2pr_box
798  end subroutine a2_tree_sum_cc
799 
801  subroutine a2_box_copy_fc(box, iv_from, iv_to)
802  type(box2_t), intent(inout) :: box
803  integer, intent(in) :: iv_from
804  integer, intent(in) :: iv_to
805  box%fc(:,:,:, iv_to) = box%fc(:,:,:, iv_from)
806  end subroutine a2_box_copy_fc
807 
809  subroutine a2_boxes_copy_fc(boxes, ids, iv_from, iv_to)
810  type(box2_t), intent(inout) :: boxes(:)
811  integer, intent(in) :: ids(:)
812  integer, intent(in) :: iv_from
813  integer, intent(in) :: iv_to
814  integer :: i
815 
816  !$omp parallel do
817  do i = 1, size(ids)
818  call a2_box_copy_fc(boxes(ids(i)), iv_from, iv_to)
819  end do
820  !$omp end parallel do
821  end subroutine a2_boxes_copy_fc
822 
824  subroutine a2_tree_copy_fc(tree, iv_from, iv_to)
825  type(a2_t), intent(inout) :: tree
826  integer, intent(in) :: iv_from
827  integer, intent(in) :: iv_to
828  integer :: lvl
829 
830  if (.not. tree%ready) stop "Tree not ready"
831  do lvl = lbound(tree%lvls, 1), tree%highest_lvl
832  call a2_boxes_copy_fc(tree%boxes, tree%lvls(lvl)%ids, iv_from, iv_to)
833  end do
834  end subroutine a2_tree_copy_fc
835 
839  pure function a2_n_cell(tree, lvl) result(n_cell)
840  type(a2_t), intent(in) :: tree
841  integer, intent(in) :: lvl
842  integer :: n_cell
843 
844  if (lvl >= 1) then
845  n_cell = tree%n_cell
846  else
847  n_cell = tree%n_cell / (2**(1-lvl))
848  end if
849  end function a2_n_cell
850 
851 end module m_a2_utils
Subroutine that gets a box and an array of reals.
Definition: m_a2_types.f90:146
This module contains all kinds of different &#39;helper&#39; routines for Afivo. If the number of routines fo...
Definition: m_a2_utils.f90:5
Type which stores all the boxes and levels, as well as some information about the number of boxes...
Definition: m_a2_types.f90:93
This module contains the basic types and constants that are used in the 2-dimensional version of Afiv...
Definition: m_a2_types.f90:5
Subroutine that gets a list of boxes, an id and an array of reals.
Definition: m_a2_types.f90:160
Type specifying the location of a cell.
Definition: m_a2_types.f90:124
The basic building block of afivo: a box with cell-centered and face centered data, and information about its position, neighbors, children etc.
Definition: m_a2_types.f90:71
Subroutine that gets a box.
Definition: m_a2_types.f90:140
Subroutine that gets a list of boxes and a box id.
Definition: m_a2_types.f90:153