Afivo  0.3
m_af_flux_schemes.f90
1 #include "cpp_macros.h"
2 
5  use m_af_types
6  use m_af_limiters
7 
8  implicit none
9  private
10 
11  interface
12  subroutine subr_prim_cons(n_values, n_vars, u)
13  import
14  integer, intent(in) :: n_values, n_vars
15  real(dp), intent(inout) :: u(n_values, n_vars)
16  end subroutine subr_prim_cons
17 
18  subroutine subr_max_wavespeed(nf, n_var, flux_dim, u, w)
19  import
20  integer, intent(in) :: nf
21  integer, intent(in) :: n_var
22  integer, intent(in) :: flux_dim
23  real(dp), intent(in) :: u(nf, n_var)
24  real(dp), intent(out) :: w(nf)
25  end subroutine subr_max_wavespeed
26 
27  subroutine subr_flux(nf, n_var, flux_dim, u, flux, box, line_ix, s_deriv)
28  import
29  integer, intent(in) :: nf
30  integer, intent(in) :: n_var
31  integer, intent(in) :: flux_dim
32  real(dp), intent(in) :: u(nf, n_var)
33  real(dp), intent(out) :: flux(nf, n_var)
34  type(box_t), intent(in) :: box
35  integer, intent(in) :: line_ix(NDIM-1)
36  integer, intent(in) :: s_deriv
37  end subroutine subr_flux
38 
39  subroutine subr_flux_upwind(nf, n_var, flux_dim, u, flux, cfl_sum, &
40  n_other_dt, other_dt, box, line_ix, s_deriv)
41  import
42  integer, intent(in) :: nf
43  integer, intent(in) :: n_var
44  integer, intent(in) :: flux_dim
45  real(dp), intent(in) :: u(nf, n_var)
46  real(dp), intent(out) :: flux(nf, n_var)
48  real(dp), intent(out) :: cfl_sum(nf-1)
49  integer, intent(in) :: n_other_dt
50  real(dp), intent(inout) :: other_dt(n_other_dt)
51  type(box_t), intent(in) :: box
52  integer, intent(in) :: line_ix(NDIM-1)
53  integer, intent(in) :: s_deriv
54  end subroutine subr_flux_upwind
55 
56  subroutine subr_flux_modify(nf, n_var, flux_dim, flux, box, line_ix, s_deriv)
57  import
58  integer, intent(in) :: nf
59  integer, intent(in) :: n_var
60  integer, intent(in) :: flux_dim
61  real(dp), intent(inout) :: flux(nf, n_var)
62  type(box_t), intent(in) :: box
63  integer, intent(in) :: line_ix(NDIM-1)
64  integer, intent(in) :: s_deriv
65  end subroutine subr_flux_modify
66 
67  subroutine subr_flux_dir(box, line_ix, s_deriv, n_var, flux_dim, direction_positive)
68  import
69  type(box_t), intent(in) :: box
70  integer, intent(in) :: line_ix(NDIM-1)
71  integer, intent(in) :: s_deriv
72  integer, intent(in) :: n_var
73  integer, intent(in) :: flux_dim
75  logical, intent(out) :: direction_positive(box%n_cell+1, n_var)
76  end subroutine subr_flux_dir
77 
78  subroutine subr_line_modify(n_cc, n_var, cc_line, flux_dim, box, line_ix, s_deriv)
79  import
80  integer, intent(in) :: n_cc
81  integer, intent(in) :: n_var
82  real(dp), intent(inout) :: cc_line(n_cc, n_var)
83  integer, intent(in) :: flux_dim
84  type(box_t), intent(in) :: box
85  integer, intent(in) :: line_ix(NDIM-1)
86  integer, intent(in) :: s_deriv
87  end subroutine subr_line_modify
88 
89  subroutine subr_source(box, dt, n_vars, i_cc, s_deriv, s_out, n_dt, dt_lim, mask)
90  import
91  type(box_t), intent(inout) :: box
92  real(dp), intent(in) :: dt
93  integer, intent(in) :: n_vars
94  integer, intent(in) :: i_cc(n_vars)
95  integer, intent(in) :: s_deriv
96  integer, intent(in) :: s_out
98  integer, intent(in) :: n_dt
100  real(dp), intent(inout) :: dt_lim(n_dt)
102  logical, intent(in) :: mask(DTIMES(box%n_cell))
103  end subroutine subr_source
104 
105  subroutine subr_box_mask(box, mask)
106  import
107  type(box_t), intent(in) :: box
108  logical, intent(out) :: mask(DTIMES(box%n_cell))
109  end subroutine subr_box_mask
110  end interface
111 
112  public :: flux_diff_1d, flux_diff_2d, flux_diff_3d
113  public :: flux_koren_1d, flux_koren_2d, flux_koren_3d
114  public :: flux_upwind_1d, flux_upwind_2d, flux_upwind_3d
115  public :: flux_kurganovtadmor_1d, reconstruct_lr_1d
116  public :: flux_generic_box, flux_generic_tree
117  public :: flux_upwind_box, flux_upwind_tree
118  public :: flux_update_densities
119  public :: flux_dummy_conversion
120  public :: flux_dummy_source
121  public :: flux_dummy_modify
122  public :: flux_dummy_line_modify
123  public :: flux_get_line_cc, flux_get_line_1cc
124  public :: flux_get_line_fc, flux_get_line_1fc
125 
126 contains
127 
129  subroutine flux_diff_1d(cc, dc, inv_dr, nc, ngc)
130  integer, intent(in) :: nc
131  integer, intent(in) :: ngc
132  real(dp), intent(in) :: cc(1-ngc:nc+ngc)
134  real(dp), intent(inout) :: dc(1:nc+1)
135  real(dp), intent(in) :: inv_dr
136  integer :: i
137 
138  do i = 1, nc+1
139  dc(i) = -dc(i) * (cc(i) - cc(i-1)) * inv_dr
140  end do
141  end subroutine flux_diff_1d
142 
144  subroutine flux_diff_2d(cc, dc, inv_dr, nc, ngc)
145  integer, intent(in) :: nc
146  integer, intent(in) :: ngc
148  real(dp), intent(in) :: cc(1-ngc:nc+ngc, 1-ngc:nc+ngc)
150  real(dp), intent(inout) :: dc(1:nc+1, 1:nc+1, 2)
151  real(dp), intent(in) :: inv_dr(2)
152  real(dp) :: cc_1d(1-ngc:nc+ngc), dc_1d(1:nc+1)
153  integer :: n
154 
155  do n = 1, nc
156  ! x-fluxes
157  call flux_diff_1d(cc(:, n), dc(:, n, 1), inv_dr(1), nc, ngc)
158 
159  ! y-fluxes (use temporary variables for efficiency)
160  cc_1d = cc(n, :)
161  dc_1d = dc(n, :, 2)
162  call flux_diff_1d(cc_1d, dc_1d, inv_dr(2), nc, ngc)
163  dc(n, :, 2) = dc_1d ! Copy result
164  end do
165  end subroutine flux_diff_2d
166 
168  subroutine flux_diff_3d(cc, dc, inv_dr, nc, ngc)
169 
170  integer, intent(in) :: nc
172  integer, intent(in) :: ngc
174  real(dp), intent(in) :: cc(1-ngc:nc+ngc, 1-ngc:nc+ngc, 1-ngc:nc+ngc)
176  real(dp), intent(inout) :: dc(1:nc+1, 1:nc+1, 1:nc+1, 3)
178  real(dp), intent(in) :: inv_dr(3)
179  real(dp) :: cc_1d(1-ngc:nc+ngc), dc_1d(1:nc+1)
180  integer :: n, m
181 
182  do m = 1, nc
183  do n = 1, nc
184  ! x-fluxes
185  call flux_diff_1d(cc(:, n, m), dc(:, n, m, 1), &
186  inv_dr(1), nc, ngc)
187 
188  ! y-fluxes (use temporary variables for efficiency)
189  cc_1d = cc(n, :, m)
190  dc_1d = dc(n, :, m, 2)
191  call flux_diff_1d(cc_1d, dc_1d, inv_dr(2), nc, ngc)
192  dc(n, :, m, 2) = dc_1d ! Copy result
193 
194  ! z-fluxes (use temporary variables for efficiency)
195  cc_1d = cc(n, m, :)
196  dc_1d = dc(n, m, :, 3)
197  call flux_diff_1d(cc_1d, dc_1d, inv_dr(3), nc, ngc)
198  dc(n, m, :, 3) = dc_1d ! Copy result
199  end do
200  end do
201  end subroutine flux_diff_3d
202 
204  subroutine flux_koren_1d(cc, v, nc, ngc)
205  integer, intent(in) :: nc
206  integer, intent(in) :: ngc
207  real(dp), intent(in) :: cc(1-ngc:nc+ngc)
209  real(dp), intent(inout) :: v(1:nc+1)
210  real(dp) :: gradp, gradc, gradn
211  integer :: n
212 
213  do n = 1, nc+1
214  gradc = cc(n) - cc(n-1) ! Current gradient
215  if (v(n) < 0.0_dp) then
216  gradn = cc(n+1) - cc(n) ! Next gradient
217  v(n) = v(n) * (cc(n) - 0.5_dp * af_limiter_koren(gradc, gradn))
218  else ! v(n) > 0
219  gradp = cc(n-1) - cc(n-2) ! Previous gradient
220  v(n) = v(n) * (cc(n-1) + 0.5_dp * af_limiter_koren(gradc, gradp))
221  end if
222  end do
223 
224  end subroutine flux_koren_1d
225 
227  subroutine flux_koren_2d(cc, v, nc, ngc)
228  integer, intent(in) :: nc
229  integer, intent(in) :: ngc
231  real(dp), intent(in) :: cc(1-ngc:nc+ngc, 1-ngc:nc+ngc)
233  real(dp), intent(inout) :: v(1:nc+1, 1:nc+1, 2)
234  real(dp) :: cc_1d(1-ngc:nc+ngc), v_1d(1:nc+1)
235  integer :: n
236 
237  do n = 1, nc
238  ! x-fluxes
239  call flux_koren_1d(cc(:, n), v(:, n, 1), nc, ngc)
240 
241  ! y-fluxes (use temporary variables for efficiency)
242  cc_1d = cc(n, :)
243  v_1d = v(n, :, 2)
244  call flux_koren_1d(cc_1d, v_1d, nc, ngc)
245  v(n, :, 2) = v_1d ! Copy result
246  end do
247  end subroutine flux_koren_2d
248 
252  subroutine reconstruct_lr_1d(nc, ngc, n_vars, cc, u_l, u_r, limiter)
253  integer, intent(in) :: nc
254  integer, intent(in) :: ngc
255  integer, intent(in) :: n_vars
256  real(dp), intent(in) :: cc(1-ngc:nc+ngc, n_vars)
258  real(dp), intent(inout) :: u_l(1:nc+1, n_vars)
260  real(dp), intent(inout) :: u_r(1:nc+1, n_vars)
261  integer, intent(in) :: limiter
262  real(dp) :: slopes(0:nc+1, n_vars)
263 
264  associate(a=>cc(1:nc+2, :) - cc(0:nc+1, :), &
265  b=>cc(0:nc+1, :) - cc(-1:nc, :))
266  ! Compute limited slopes at the cell centers
267  slopes = af_limiter_apply(a, b, limiter)
268 
269  ! Reconstruct values on the faces
270  u_l(1:nc+1, :) = cc(0:nc, :) + 0.5_dp * slopes(0:nc, :) ! left
271 
272  if (af_limiter_symmetric(limiter)) then
273  u_r(1:nc+1, :) = cc(1:nc+1, :) - 0.5_dp * slopes(1:nc+1, :) ! right
274  else
275  slopes = af_limiter_apply(b, a, limiter)
276  u_r(1:nc+1, :) = cc(1:nc+1, :) - 0.5_dp * slopes(1:nc+1, :) ! right
277  end if
278  end associate
279  end subroutine reconstruct_lr_1d
280 
282  subroutine reconstruct_upwind_1d(nc, ngc, n_vars, cc, u_f, limiter, direction_positive)
283  integer, intent(in) :: nc
284  integer, intent(in) :: ngc
285  integer, intent(in) :: n_vars
286  real(dp), intent(in) :: cc(1-ngc:nc+ngc, n_vars)
288  real(dp), intent(inout) :: u_f(1:nc+1, n_vars)
289  integer, intent(in) :: limiter
291  logical, intent(in) :: direction_positive(nc+1, n_vars)
292 
293  associate(a=>cc(1:nc+2, :) - cc(0:nc+1, :), &
294  b=>cc(0:nc+1, :) - cc(-1:nc, :))
295  where (direction_positive)
296  u_f = cc(0:nc, :) + 0.5_dp * &
297  af_limiter_apply(a(1:nc+1, :), b(1:nc+1, :), limiter)
298  elsewhere
299  u_f = cc(1:nc+1, :) - 0.5_dp * &
300  af_limiter_apply(b(2:nc+2, :), a(2:nc+2, :), limiter)
301  end where
302  end associate
303  end subroutine reconstruct_upwind_1d
304 
306  subroutine flux_kurganovtadmor_1d(n_values, n_vars, flux_l, flux_r, &
307  u_l, u_r, wmax, flux)
308  integer, intent(in) :: n_values
309  integer, intent(in) :: n_vars
310  real(dp), intent(in) :: flux_l(n_values, n_vars)
311  real(dp), intent(in) :: flux_r(n_values, n_vars)
312  real(dp), intent(in) :: u_l(n_values, n_vars)
313  real(dp), intent(in) :: u_r(n_values, n_vars)
314  real(dp), intent(in) :: wmax(n_values)
315  real(dp), intent(inout) :: flux(n_values, n_vars)
316 
317  flux = 0.5_dp * (flux_l + flux_r - spread(wmax, 2, n_vars) * (u_r - u_l))
318  end subroutine flux_kurganovtadmor_1d
319 
320  subroutine flux_update_densities(tree, dt, n_vars, i_cc, n_vars_flux, i_cc_flux, i_flux, &
321  s_deriv, n_prev, s_prev, w_prev, s_out, add_source_box, n_dt, dt_lim, get_mask)
322  type(af_t), intent(inout) :: tree
323  real(dp), intent(in) :: dt
324  integer, intent(in) :: n_vars
325  integer, intent(in) :: i_cc(n_vars)
326  integer, intent(in) :: n_vars_flux
327  integer, intent(in) :: i_cc_flux(n_vars_flux)
328  integer, intent(in) :: i_flux(n_vars_flux)
329  integer, intent(in) :: s_deriv
330  integer, intent(in) :: n_prev
331  integer, intent(in) :: s_prev(n_prev)
332  real(dp), intent(in) :: w_prev(n_prev)
333  integer, intent(in) :: s_out
335  procedure(subr_source) :: add_source_box
337  integer, intent(in) :: n_dt
339  real(dp), intent(out) :: dt_lim(n_dt)
341  procedure(subr_box_mask), optional :: get_mask
342  integer :: lvl, n, id, ijk, nc, i_var, iv
343  logical :: mask(dtimes(tree%n_cell))
344  real(dp) :: dt_dr(ndim), my_dt(n_dt)
345  real(dp) :: rfac(2, tree%n_cell)
346 
347  nc = tree%n_cell
348  rfac = 0.0_dp ! Prevent warnings in 3D
349 
350  dt_lim = 1e100_dp
351 
352  !$omp parallel private(lvl, n, id, IJK, dt_dr, i_var, rfac, iv, mask, my_dt) &
353  !$omp &reduction(min:dt_lim)
354  my_dt = 1e100_dp
355 
356  do lvl = 1, tree%highest_lvl
357  !$omp do
358  do n = 1, size(tree%lvls(lvl)%leaves)
359  id = tree%lvls(lvl)%leaves(n)
360  dt_dr = dt/tree%boxes(id)%dr
361 
362  associate(cc => tree%boxes(id)%cc, fc => tree%boxes(id)%fc)
363  if (present(get_mask)) then
364  call get_mask(tree%boxes(id), mask)
365  else
366  mask = .true.
367  end if
368 
369  do i_var = 1, n_vars
370  iv = i_cc(i_var)
371  do kji_do(1, nc)
372  tree%boxes(id)%cc(ijk, iv+s_out) = sum(w_prev * &
373  tree%boxes(id)%cc(ijk, iv+s_prev))
374  end do; close_do
375  end do
376 
377  call add_source_box(tree%boxes(id), dt, n_vars, i_cc, s_deriv, &
378  s_out, n_dt, my_dt, mask)
379  dt_lim = min(dt_lim, my_dt)
380 
381 #if NDIM == 1
382  do kji_do(1, nc)
383  if (mask(ijk)) then
384  cc(i, i_cc_flux+s_out) = cc(i, i_cc_flux+s_out) + &
385  dt_dr(1) * &
386  (fc(i, 1, i_flux) - fc(i+1, 1, i_flux))
387  end if
388  end do; close_do
389 #elif NDIM == 2
390  if (tree%coord_t == af_cyl) then
391  call af_cyl_flux_factors(tree%boxes(id), rfac)
392  do kji_do(1, nc)
393  if (mask(ijk)) then
394  cc(i, j, i_cc_flux+s_out) = cc(i, j, i_cc_flux+s_out) + &
395  dt_dr(1) * (&
396  rfac(1, i) * fc(i, j, 1, i_flux) - &
397  rfac(2, i) * fc(i+1, j, 1, i_flux)) &
398  + dt_dr(2) * &
399  (fc(i, j, 2, i_flux) - fc(i, j+1, 2, i_flux))
400  end if
401  end do; close_do
402  else
403  do kji_do(1, nc)
404  if (mask(ijk)) then
405  cc(i, j, i_cc_flux+s_out) = cc(i, j, i_cc_flux+s_out) + &
406  dt_dr(1) * &
407  (fc(i, j, 1, i_flux) - fc(i+1, j, 1, i_flux)) &
408  + dt_dr(2) * &
409  (fc(i, j, 2, i_flux) - fc(i, j+1, 2, i_flux))
410  end if
411  end do; close_do
412  end if
413 #elif NDIM == 3
414  do kji_do(1, nc)
415  if (mask(ijk)) then
416  cc(i, j, k, i_cc_flux+s_out) = cc(i, j, k, i_cc_flux+s_out) + &
417  dt_dr(1) * &
418  (fc(i, j, k, 1, i_flux) - fc(i+1, j, k, 1, i_flux)) + &
419  dt_dr(2) * &
420  (fc(i, j, k, 2, i_flux) - fc(i, j+1, k, 2, i_flux)) + &
421  dt_dr(3) * &
422  (fc(i, j, k, 3, i_flux) - fc(i, j, k+1, 3, i_flux))
423  end if
424  end do; close_do
425 #endif
426  end associate
427  end do
428  !$omp end do
429  end do
430  !$omp end parallel
431  end subroutine flux_update_densities
432 
434  subroutine flux_generic_tree(tree, n_vars, i_cc, s_deriv, i_flux, dt_lim, &
435  max_wavespeed, flux_from_primitives, flux_modify, line_modify, &
436  to_primitive, to_conservative, limiter)
437  use m_af_restrict
438  use m_af_core
439  type(af_t), intent(inout) :: tree
440  integer, intent(in) :: n_vars
441  integer, intent(in) :: i_cc(n_vars)
442  integer, intent(in) :: s_deriv
443  integer, intent(in) :: i_flux(n_vars)
445  real(dp), intent(out) :: dt_lim
447  procedure(subr_max_wavespeed) :: max_wavespeed
449  procedure(subr_flux) :: flux_from_primitives
451  procedure(subr_flux_modify) :: flux_modify
453  procedure(subr_line_modify) :: line_modify
455  procedure(subr_prim_cons) :: to_primitive
457  procedure(subr_prim_cons) :: to_conservative
459  integer, intent(in) :: limiter
460  real(dp) :: my_dt
461 
462  integer :: lvl, i
463 
464  ! Ensure ghost cells near refinement boundaries can be properly filled
465  call af_restrict_ref_boundary(tree, i_cc+s_deriv)
466 
467  dt_lim = 1e100_dp
468  my_dt = 1e100_dp
469 
470  !$omp parallel private(lvl, i, my_dt) reduction(min:dt_lim)
471  do lvl = 1, tree%highest_lvl
472  !$omp do
473  do i = 1, size(tree%lvls(lvl)%leaves)
474  call flux_generic_box(tree, tree%lvls(lvl)%leaves(i), tree%n_cell, &
475  n_vars, i_cc, s_deriv, i_flux, my_dt, max_wavespeed, &
476  flux_from_primitives, flux_modify, line_modify, &
477  to_primitive, to_conservative, limiter)
478  dt_lim = min(dt_lim, my_dt)
479  end do
480  !$omp end do
481  end do
482  !$omp end parallel
483 
484  ! Compute coarse fluxes from the fine ones at refinement boundaries
485  call af_consistent_fluxes(tree, i_flux)
486 
487  end subroutine flux_generic_tree
488 
490  subroutine flux_generic_box(tree, id, nc, n_vars, i_cc, s_deriv, i_flux, dt_lim, &
491  max_wavespeed, flux_from_primitives, flux_modify, line_modify, &
492  to_primitive, to_conservative, limiter)
493  use m_af_types
494  use m_af_ghostcell
495  type(af_t), intent(inout) :: tree
496  integer, intent(in) :: id
497  integer, intent(in) :: nc
498  integer, intent(in) :: n_vars
499  integer, intent(in) :: i_cc(n_vars)
500  integer, intent(in) :: s_deriv
501  integer, intent(in) :: i_flux(n_vars)
503  real(dp), intent(out) :: dt_lim
505  procedure(subr_max_wavespeed) :: max_wavespeed
507  procedure(subr_flux) :: flux_from_primitives
509  procedure(subr_flux_modify) :: flux_modify
511  procedure(subr_line_modify) :: line_modify
513  procedure(subr_prim_cons) :: to_primitive
515  procedure(subr_prim_cons) :: to_conservative
517  integer, intent(in) :: limiter
518 
519 
520  real(dp) :: cc(dtimes(-1:nc+2), n_vars)
521  real(dp) :: cc_line(-1:nc+2, n_vars)
522  real(dp) :: flux(nc+1, n_vars)
523  real(dp) :: u_l(nc+1, n_vars), u_r(nc+1, n_vars)
524  real(dp) :: w_l(nc+1), w_r(nc+1)
525  real(dp) :: flux_l(nc+1, n_vars), flux_r(nc+1, n_vars)
526  real(dp) :: cfl_sum(dtimes(nc)), cfl_sum_line(nc), inv_dr(ndim)
527  integer :: flux_dim, line_ix(ndim-1)
528 #if NDIM > 1
529  integer :: i
530 #endif
531 #if NDIM > 2
532  integer :: j
533 #endif
534 
535  inv_dr = 1/tree%boxes(id)%dr
536 
537  ! Get two layers of ghost cell data
538  call af_gc2_box(tree, id, i_cc+s_deriv, cc)
539 
540  ! This will contain the sum of CFL-related conditions. For example, one can
541  ! write dt * (vx/dx + vy/dy) < 1. This sum will then contain (vx/dx +
542  ! vy/dy).
543  cfl_sum = 0.0_dp
544 
545  ! Jannis: Below, there are function calls in the inner part of a loop. When
546  ! I did some benchmarks, it was not significantly slower than using a buffer
547  ! and fewer functions calls.
548 
549  do flux_dim = 1, ndim
550 #if NDIM > 2
551  do j = 1, nc
552 #endif
553 #if NDIM > 1
554  do i = 1, nc
555 #endif
556  ! Extract cell-centered values along a line
557  select case (flux_dim)
558 #if NDIM == 1
559  case (1)
560  cc_line = cc(:, :)
561 #elif NDIM == 2
562  case (1)
563  cc_line = cc(:, i, :)
564  case (2)
565  cc_line = cc(i, :, :)
566 #elif NDIM == 3
567  case (1)
568  cc_line = cc(:, i, j, :)
569  case (2)
570  cc_line = cc(i, :, j, :)
571  case (3)
572  cc_line = cc(i, j, :, :)
573 #endif
574  end select
575 
576 #if NDIM == 2
577  line_ix = [i]
578 #elif NDIM == 3
579  line_ix = [i, j]
580 #endif
581 
582  ! Optionally modify data, e.g. to take into account a boundary
583  call line_modify(nc+4, n_vars, cc_line, flux_dim, &
584  tree%boxes(id), line_ix, s_deriv)
585 
586  ! Flux computation is based on primitive variables (this can be a
587  ! dummy procedure)
588  call to_primitive(nc+4, n_vars, cc_line)
589 
590  ! Reconstruct to cell faces, getting a left and right state at
591  ! every face
592  call reconstruct_lr_1d(nc, 2, n_vars, cc_line, u_l, u_r, limiter)
593 
594  ! Determine the maximal wave speed for the left and right state
595  call max_wavespeed(nc+1, n_vars, flux_dim, u_l, w_l)
596  call max_wavespeed(nc+1, n_vars, flux_dim, u_r, w_r)
597 
598  ! Compute the fluxes for the left and right state
599  call flux_from_primitives(nc+1, n_vars, flux_dim, u_l, flux_l, &
600  tree%boxes(id), line_ix, s_deriv)
601  call flux_from_primitives(nc+1, n_vars, flux_dim, u_r, flux_r, &
602  tree%boxes(id), line_ix, s_deriv)
603 
604  ! Convert back to conservative form
605  call to_conservative(nc+1, n_vars, u_l)
606  call to_conservative(nc+1, n_vars, u_r)
607 
608  ! Get maximum of left/right wave speed
609  w_l = max(w_l, w_r)
610 
611  ! Get maximal wave speed for each cell center
612  cfl_sum_line = max(w_l(1:nc), w_l(2:nc+1)) * inv_dr(ndim)
613 
614  ! Combine left and right fluxes to obtain a single flux
615  call flux_kurganovtadmor_1d(nc+1, n_vars, flux_l, flux_r, &
616  u_l, u_r, w_l, flux)
617 
618  ! Potentially add other flux components
619  call flux_modify(nc+1, n_vars, flux_dim, flux, &
620  tree%boxes(id), line_ix, s_deriv)
621 
622  ! Store the computed fluxes
623  select case (flux_dim)
624 #if NDIM == 1
625  case (1)
626  tree%boxes(id)%fc(:, flux_dim, i_flux) = flux
627  cfl_sum = cfl_sum + cfl_sum_line
628 #elif NDIM == 2
629  case (1)
630  tree%boxes(id)%fc(:, i, flux_dim, i_flux) = flux
631  cfl_sum(:, i) = cfl_sum(:, i) + cfl_sum_line
632  case (2)
633  tree%boxes(id)%fc(i, :, flux_dim, i_flux) = flux
634  cfl_sum(i, :) = cfl_sum(i, :) + cfl_sum_line
635 #elif NDIM == 3
636  case (1)
637  tree%boxes(id)%fc(:, i, j, flux_dim, i_flux) = flux
638  cfl_sum(:, i, j) = cfl_sum(:, i, j) + cfl_sum_line
639  case (2)
640  tree%boxes(id)%fc(i, :, j, flux_dim, i_flux) = flux
641  cfl_sum(i, :, j) = cfl_sum(i, :, j) + cfl_sum_line
642  case (3)
643  tree%boxes(id)%fc(i, j, :, flux_dim, i_flux) = flux
644  cfl_sum(i, j, :) = cfl_sum(i, j, :) + cfl_sum_line
645 #endif
646  end select
647 #if NDIM > 1
648  end do
649 #endif
650 #if NDIM > 2
651  end do
652 #endif
653  end do
654 
655  ! Determine maximal time step
656  dt_lim = 1/max(maxval(cfl_sum), 1e-100_dp)
657 
658  end subroutine flux_generic_box
659 
661  subroutine flux_upwind_tree(tree, n_vars, i_cc, s_deriv, i_flux, n_dt, dt_lim, &
662  flux_upwind, flux_direction, line_modify, limiter)
663  use m_af_restrict
664  use m_af_core
665  type(af_t), intent(inout) :: tree
666  integer, intent(in) :: n_vars
667  integer, intent(in) :: i_cc(n_vars)
668  integer, intent(in) :: s_deriv
669  integer, intent(in) :: i_flux(n_vars)
671  integer, intent(in) :: n_dt
673  real(dp), intent(out) :: dt_lim(n_dt)
675  procedure(subr_flux_upwind) :: flux_upwind
677  procedure(subr_flux_dir) :: flux_direction
679  procedure(subr_line_modify) :: line_modify
681  integer, intent(in) :: limiter
682  integer :: lvl, i
683  real(dp) :: my_dt(n_dt)
684 
685  ! Ensure ghost cells near refinement boundaries can be properly filled
686  call af_restrict_ref_boundary(tree, i_cc+s_deriv)
687 
688  dt_lim = 1e100_dp
689  my_dt = 1e100_dp
690 
691  !$omp parallel private(lvl, i, my_dt) reduction(min:dt_lim)
692  do lvl = 1, tree%highest_lvl
693  !$omp do
694  do i = 1, size(tree%lvls(lvl)%leaves)
695  call flux_upwind_box(tree, tree%lvls(lvl)%leaves(i), tree%n_cell, &
696  n_vars, i_cc, s_deriv, i_flux, n_dt, my_dt, flux_upwind, &
697  flux_direction, line_modify, limiter)
698  dt_lim = min(dt_lim, my_dt)
699  end do
700  !$omp end do
701  end do
702  !$omp end parallel
703 
704  ! Compute coarse fluxes from the fine ones at refinement boundaries
705  call af_consistent_fluxes(tree, i_flux)
706 
707  end subroutine flux_upwind_tree
708 
710  subroutine flux_upwind_box(tree, id, nc, n_vars, i_cc, s_deriv, i_flux, &
711  n_dt, dt_lim, flux_upwind, flux_direction, line_modify, limiter)
712  use m_af_types
713  use m_af_ghostcell
714  type(af_t), intent(inout) :: tree
715  integer, intent(in) :: id
716  integer, intent(in) :: nc
717  integer, intent(in) :: n_vars
718  integer, intent(in) :: i_cc(n_vars)
719  integer, intent(in) :: s_deriv
720  integer, intent(in) :: i_flux(n_vars)
722  integer, intent(in) :: n_dt
723  real(dp), intent(inout) :: dt_lim(n_dt)
725  procedure(subr_flux_upwind) :: flux_upwind
727  procedure(subr_flux_dir) :: flux_direction
729  procedure(subr_line_modify) :: line_modify
731  integer, intent(in) :: limiter
732 
733  real(dp) :: cc(dtimes(-1:nc+2), n_vars)
734  real(dp) :: cc_line(-1:nc+2, n_vars)
735  real(dp) :: flux(nc+1, n_vars)
736  real(dp) :: u_l(nc+1, n_vars)
737  real(dp) :: cfl_sum(dtimes(nc)), cfl_sum_line(nc)
738  real(dp) :: other_dt(n_dt-1)
739  logical :: direction_positive(nc+1, n_vars)
740  integer :: flux_dim, line_ix(ndim-1)
741 #if NDIM > 1
742  integer :: i
743 #endif
744 #if NDIM > 2
745  integer :: j
746 #endif
747 
748  ! Get two layers of ghost cell data
749  call af_gc2_box(tree, id, i_cc+s_deriv, cc)
750 
751  ! This will contain the sum of CFL-related conditions. For example, one can
752  ! write dt * (vx/dx + vy/dy) < 1. This sum will then contain (vx/dx +
753  ! vy/dy).
754  cfl_sum = 0.0_dp
755  dt_lim(2:) = 1e100_dp
756  other_dt = 1e100_dp
757 
758  associate(fc => tree%boxes(id)%fc)
759  do flux_dim = 1, ndim
760 #if NDIM > 2
761  do j = 1, nc
762 #endif
763 #if NDIM > 1
764  do i = 1, nc
765 #endif
766  ! Extract cell-centered values along a line
767  select case (flux_dim)
768 #if NDIM == 1
769  case (1)
770  cc_line = cc(:, :)
771 #elif NDIM == 2
772  case (1)
773  cc_line = cc(:, i, :)
774  case (2)
775  cc_line = cc(i, :, :)
776 #elif NDIM == 3
777  case (1)
778  cc_line = cc(:, i, j, :)
779  case (2)
780  cc_line = cc(i, :, j, :)
781  case (3)
782  cc_line = cc(i, j, :, :)
783 #endif
784  end select
785 
786 #if NDIM == 2
787  line_ix = [i]
788 #elif NDIM == 3
789  line_ix = [i, j]
790 #endif
791  call flux_direction(tree%boxes(id), line_ix, s_deriv, &
792  n_vars, flux_dim, direction_positive)
793 
794  ! Optionally modify data, e.g. to take into account a boundary
795  call line_modify(nc+4, n_vars, cc_line, flux_dim, &
796  tree%boxes(id), line_ix, s_deriv)
797 
798  ! Reconstruct to cell faces
799  call reconstruct_upwind_1d(nc, 2, n_vars, cc_line, u_l, &
800  limiter, direction_positive)
801 
802  call flux_upwind(nc+1, n_vars, flux_dim, u_l, flux, cfl_sum_line, &
803  n_dt-1, other_dt, tree%boxes(id), line_ix, s_deriv)
804  dt_lim(2:) = min(dt_lim(2:), other_dt)
805 
806  ! Store the computed fluxes
807  select case (flux_dim)
808 #if NDIM == 1
809  case (1)
810  fc(:, flux_dim, i_flux) = flux
811  cfl_sum = cfl_sum + cfl_sum_line
812 #elif NDIM == 2
813  case (1)
814  fc(:, i, flux_dim, i_flux) = flux
815  cfl_sum(:, i) = cfl_sum(:, i) + cfl_sum_line
816  case (2)
817  fc(i, :, flux_dim, i_flux) = flux
818  cfl_sum(i, :) = cfl_sum(i, :) + cfl_sum_line
819 #elif NDIM == 3
820  case (1)
821  fc(:, i, j, flux_dim, i_flux) = flux
822  cfl_sum(:, i, j) = cfl_sum(:, i, j) + cfl_sum_line
823  case (2)
824  fc(i, :, j, flux_dim, i_flux) = flux
825  cfl_sum(i, :, j) = cfl_sum(i, :, j) + cfl_sum_line
826  case (3)
827  fc(i, j, :, flux_dim, i_flux) = flux
828  cfl_sum(i, j, :) = cfl_sum(i, j, :) + cfl_sum_line
829 #endif
830  end select
831 #if NDIM > 1
832  end do
833 #endif
834 #if NDIM > 2
835  end do
836 #endif
837  end do
838  end associate
839 
840  ! Determine maximal CFL time step
841  dt_lim(1) = 1/maxval(cfl_sum)
842 
843  end subroutine flux_upwind_box
844 
848  subroutine flux_get_line_cc(box, ivs, flux_dim, line_ix, cc_line)
849  type(box_t), intent(in) :: box
850  integer, intent(in) :: ivs(:)
851  integer, intent(in) :: flux_dim
852  integer, intent(in) :: line_ix(ndim-1)
853  real(dp), intent(inout) :: cc_line(box%n_cell+2, size(ivs))
854 
855  select case (flux_dim)
856 #if NDIM == 1
857  case (1)
858  cc_line = box%cc(:, ivs)
859 #elif NDIM == 2
860  case (1)
861  cc_line = box%cc(:, line_ix(1), ivs)
862  case (2)
863  cc_line = box%cc(line_ix(1), :, ivs)
864 #elif NDIM == 3
865  case (1)
866  cc_line = box%cc(:, line_ix(1), line_ix(2), ivs)
867  case (2)
868  cc_line = box%cc(line_ix(1), :, line_ix(2), ivs)
869  case (3)
870  cc_line = box%cc(line_ix(1), line_ix(2), :, ivs)
871 #endif
872  end select
873  end subroutine flux_get_line_cc
874 
878  subroutine flux_get_line_1cc(box, iv, flux_dim, line_ix, cc_line)
879  type(box_t), intent(in) :: box
880  integer, intent(in) :: iv
881  integer, intent(in) :: flux_dim
882  integer, intent(in) :: line_ix(ndim-1)
883  real(dp), intent(inout) :: cc_line(box%n_cell+2)
884 
885  select case (flux_dim)
886 #if NDIM == 1
887  case (1)
888  cc_line = box%cc(:, iv)
889 #elif NDIM == 2
890  case (1)
891  cc_line = box%cc(:, line_ix(1), iv)
892  case (2)
893  cc_line = box%cc(line_ix(1), :, iv)
894 #elif NDIM == 3
895  case (1)
896  cc_line = box%cc(:, line_ix(1), line_ix(2), iv)
897  case (2)
898  cc_line = box%cc(line_ix(1), :, line_ix(2), iv)
899  case (3)
900  cc_line = box%cc(line_ix(1), line_ix(2), :, iv)
901 #endif
902  end select
903  end subroutine flux_get_line_1cc
904 
907  subroutine flux_get_line_fc(box, ivs, flux_dim, line_ix, fc_line)
908  type(box_t), intent(in) :: box
909  integer, intent(in) :: ivs(:)
910  integer, intent(in) :: flux_dim
911  integer, intent(in) :: line_ix(ndim-1)
912  real(dp), intent(inout) :: fc_line(box%n_cell+1, size(ivs))
913 
914  select case (flux_dim)
915 #if NDIM == 1
916  case (1)
917  fc_line = box%fc(:, flux_dim, ivs)
918 #elif NDIM == 2
919  case (1)
920  fc_line = box%fc(:, line_ix(1), flux_dim, ivs)
921  case (2)
922  fc_line = box%fc(line_ix(1), :, flux_dim, ivs)
923 #elif NDIM == 3
924  case (1)
925  fc_line = box%fc(:, line_ix(1), line_ix(2), flux_dim, ivs)
926  case (2)
927  fc_line = box%fc(line_ix(1), :, line_ix(2), flux_dim, ivs)
928  case (3)
929  fc_line = box%fc(line_ix(1), line_ix(2), :, flux_dim, ivs)
930 #endif
931  end select
932  end subroutine flux_get_line_fc
933 
936  subroutine flux_get_line_1fc(box, iv, flux_dim, line_ix, fc_line)
937  type(box_t), intent(in) :: box
938  integer, intent(in) :: iv
939  integer, intent(in) :: flux_dim
940  integer, intent(in) :: line_ix(ndim-1)
941  real(dp), intent(inout) :: fc_line(box%n_cell+1)
942 
943  select case (flux_dim)
944 #if NDIM == 1
945  case (1)
946  fc_line = box%fc(:, flux_dim, iv)
947 #elif NDIM == 2
948  case (1)
949  fc_line = box%fc(:, line_ix(1), flux_dim, iv)
950  case (2)
951  fc_line = box%fc(line_ix(1), :, flux_dim, iv)
952 #elif NDIM == 3
953  case (1)
954  fc_line = box%fc(:, line_ix(1), line_ix(2), flux_dim, iv)
955  case (2)
956  fc_line = box%fc(line_ix(1), :, line_ix(2), flux_dim, iv)
957  case (3)
958  fc_line = box%fc(line_ix(1), line_ix(2), :, flux_dim, iv)
959 #endif
960  end select
961  end subroutine flux_get_line_1fc
962 
964  subroutine flux_koren_3d(cc, v, nc, ngc)
965 
966  integer, intent(in) :: nc
968  integer, intent(in) :: ngc
970  real(dp), intent(in) :: cc(1-ngc:nc+ngc, 1-ngc:nc+ngc, 1-ngc:nc+ngc)
972  real(dp), intent(inout) :: v(1:nc+1, 1:nc+1, 1:nc+1, 3)
973  real(dp) :: cc_1d(1-ngc:nc+ngc), v_1d(1:nc+1)
974  integer :: n, m
975 
976  do m = 1, nc
977  do n = 1, nc
978  ! x-fluxes
979  call flux_koren_1d(cc(:, n, m), v(:, n, m, 1), &
980  nc, ngc)
981 
982  ! y-fluxes (use temporary variables for efficiency)
983  cc_1d = cc(n, :, m)
984  v_1d = v(n, :, m, 2)
985  call flux_koren_1d(cc_1d, v_1d, nc, ngc)
986  v(n, :, m, 2) = v_1d ! Copy result
987 
988  ! z-fluxes (use temporary variables for efficiency)
989  cc_1d = cc(n, m, :)
990  v_1d = v(n, m, :, 3)
991  call flux_koren_1d(cc_1d, v_1d, nc, ngc)
992  v(n, m, :, 3) = v_1d ! Copy result
993  end do
994  end do
995  end subroutine flux_koren_3d
996 
998  subroutine flux_upwind_1d(cc, v, nc, ngc)
999  integer, intent(in) :: nc
1000  integer, intent(in) :: ngc
1001  real(dp), intent(in) :: cc(1-ngc:nc+ngc)
1003  real(dp), intent(inout) :: v(1:nc+1)
1004  integer :: n
1005 
1006  do n = 1, nc+1
1007  if (v(n) < 0.0_dp) then
1008  v(n) = v(n) * cc(n)
1009  else ! v(n) > 0
1010  v(n) = v(n) * cc(n-1)
1011  end if
1012  end do
1013 
1014  end subroutine flux_upwind_1d
1015 
1017  subroutine flux_upwind_2d(cc, v, nc, ngc)
1018  integer, intent(in) :: nc
1019  integer, intent(in) :: ngc
1021  real(dp), intent(in) :: cc(1-ngc:nc+ngc, 1-ngc:nc+ngc)
1023  real(dp), intent(inout) :: v(1:nc+1, 1:nc+1, 2)
1024  real(dp) :: cc_1d(1-ngc:nc+ngc), v_1d(1:nc+1)
1025  integer :: n
1026 
1027  do n = 1, nc
1028  ! x-fluxes
1029  call flux_upwind_1d(cc(:, n), v(:, n, 1), nc, ngc)
1030 
1031  ! y-fluxes (use temporary variables for efficiency)
1032  cc_1d = cc(n, :)
1033  v_1d = v(n, :, 2)
1034  call flux_upwind_1d(cc_1d, v_1d, nc, ngc)
1035  v(n, :, 2) = v_1d ! Copy result
1036  end do
1037  end subroutine flux_upwind_2d
1038 
1040  subroutine flux_upwind_3d(cc, v, nc, ngc)
1041 
1042  integer, intent(in) :: nc
1044  integer, intent(in) :: ngc
1046  real(dp), intent(in) :: cc(1-ngc:nc+ngc, 1-ngc:nc+ngc, 1-ngc:nc+ngc)
1048  real(dp), intent(inout) :: v(1:nc+1, 1:nc+1, 1:nc+1, 3)
1049  real(dp) :: cc_1d(1-ngc:nc+ngc), v_1d(1:nc+1)
1050  integer :: n, m
1051 
1052  do m = 1, nc
1053  do n = 1, nc
1054  ! x-fluxes
1055  call flux_upwind_1d(cc(:, n, m), v(:, n, m, 1), &
1056  nc, ngc)
1057 
1058  ! y-fluxes (use temporary variables for efficiency)
1059  cc_1d = cc(n, :, m)
1060  v_1d = v(n, :, m, 2)
1061  call flux_upwind_1d(cc_1d, v_1d, nc, ngc)
1062  v(n, :, m, 2) = v_1d ! Copy result
1063 
1064  ! z-fluxes (use temporary variables for efficiency)
1065  cc_1d = cc(n, m, :)
1066  v_1d = v(n, m, :, 3)
1067  call flux_upwind_1d(cc_1d, v_1d, nc, ngc)
1068  v(n, m, :, 3) = v_1d ! Copy result
1069  end do
1070  end do
1071  end subroutine flux_upwind_3d
1072 
1074  subroutine flux_dummy_conversion(n_values, n_vars, u)
1075  integer, intent(in) :: n_values, n_vars
1076  real(dp), intent(inout) :: u(n_values, n_vars)
1077  end subroutine flux_dummy_conversion
1078 
1079  subroutine flux_dummy_source(box, dt, n_vars, i_cc, s_deriv, s_out, n_dt, dt_lim, mask)
1080  type(box_t), intent(inout) :: box
1081  real(dp), intent(in) :: dt
1082  integer, intent(in) :: n_vars
1083  integer, intent(in) :: i_cc(n_vars)
1084  integer, intent(in) :: s_deriv
1085  integer, intent(in) :: s_out
1086  integer, intent(in) :: n_dt
1087  real(dp), intent(inout) :: dt_lim(n_dt)
1088  logical, intent(in) :: mask(dtimes(box%n_cell))
1089  end subroutine flux_dummy_source
1090 
1091  subroutine flux_dummy_modify(nf, n_var, flux_dim, flux, box, line_ix, s_deriv)
1092  integer, intent(in) :: nf
1093  integer, intent(in) :: n_var
1094  integer, intent(in) :: flux_dim
1095  real(dp), intent(inout) :: flux(nf, n_var)
1096  type(box_t), intent(in) :: box
1097  integer, intent(in) :: line_ix(ndim-1)
1098  integer, intent(in) :: s_deriv
1099  end subroutine flux_dummy_modify
1100 
1101  subroutine flux_dummy_line_modify(n_cc, n_var, cc_line, flux_dim, box, &
1102  line_ix, s_deriv)
1103  integer, intent(in) :: n_cc
1104  integer, intent(in) :: n_var
1105  real(dp), intent(inout) :: cc_line(n_cc, n_var)
1106  integer, intent(in) :: flux_dim
1107  type(box_t), intent(in) :: box
1108  integer, intent(in) :: line_ix(ndim-1)
1109  integer, intent(in) :: s_deriv
1110  end subroutine flux_dummy_line_modify
1111 
1112 end module m_af_flux_schemes
This module contains the core routines of Afivo, namely those that deal with initializing and changin...
Definition: m_af_core.f90:4
Module containing a couple flux schemes for solving hyperbolic problems explicitly,...
This module contains routines related to the filling of ghost cells. Note that corner ghost cells are...
Module containing slope limiters.
This module contains routines for restriction: going from fine to coarse variables.
This module contains the basic types and constants that are used in the NDIM-dimensional version of A...
Definition: m_af_types.f90:4
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