Afivo  0.3
m_flux_schemes.f90
1 
6 
7  implicit none
8  private
9 
10  integer, parameter :: dp = kind(0.0d0)
11 
12  public :: flux_diff_1d, flux_diff_2d, flux_diff_3d
13  public :: flux_koren_1d, flux_koren_2d, flux_koren_3d
14 
15 contains
16 
18  subroutine flux_diff_1d(cc, dc, inv_dr, nc, ngc)
19  integer, intent(in) :: nc
20  integer, intent(in) :: ngc
21  real(dp), intent(in) :: cc(1-ngc:nc+ngc)
23  real(dp), intent(inout) :: dc(1:nc+1)
24  real(dp), intent(in) :: inv_dr
25  integer :: i
26 
27  do i = 1, nc+1
28  dc(i) = -dc(i) * (cc(i) - cc(i-1)) * inv_dr
29  end do
30  end subroutine flux_diff_1d
31 
33  subroutine flux_diff_2d(cc, dc, inv_dr, nc, ngc)
34  integer, intent(in) :: nc
35  integer, intent(in) :: ngc
37  real(dp), intent(in) :: cc(1-ngc:nc+ngc, 1-ngc:nc+ngc)
39  real(dp), intent(inout) :: dc(1:nc+1, 1:nc+1, 2)
40  real(dp), intent(in) :: inv_dr
41  real(dp) :: cc_1d(1-ngc:nc+ngc), dc_1d(1:nc+1)
42  integer :: n
43 
44  do n = 1, nc
45  ! x-fluxes
46  call flux_diff_1d(cc(:, n), dc(:, n, 1), inv_dr, nc, ngc)
47 
48  ! y-fluxes (use temporary variables for efficiency)
49  cc_1d = cc(n, :)
50  dc_1d = dc(n, :, 2)
51  call flux_diff_1d(cc_1d, dc_1d, inv_dr, nc, ngc)
52  dc(n, :, 2) = dc_1d ! Copy result
53  end do
54  end subroutine flux_diff_2d
55 
57  subroutine flux_diff_3d(cc, dc, inv_dr, nc, ngc)
58 
59  integer, intent(in) :: nc
61  integer, intent(in) :: ngc
63  real(dp), intent(in) :: cc(1-ngc:nc+ngc, 1-ngc:nc+ngc, 1-ngc:nc+ngc)
65  real(dp), intent(inout) :: dc(1:nc+1, 1:nc+1, 1:nc+1, 3)
67  real(dp), intent(in) :: inv_dr
68  real(dp) :: cc_1d(1-ngc:nc+ngc), dc_1d(1:nc+1)
69  integer :: n, m
70 
71  do m = 1, nc
72  do n = 1, nc
73  ! x-fluxes
74  call flux_diff_1d(cc(:, n, m), dc(:, n, m, 1), &
75  inv_dr, nc, ngc)
76 
77  ! y-fluxes (use temporary variables for efficiency)
78  cc_1d = cc(n, :, m)
79  dc_1d = dc(n, :, m, 2)
80  call flux_diff_1d(cc_1d, dc_1d, inv_dr, nc, ngc)
81  dc(n, :, m, 2) = dc_1d ! Copy result
82 
83  ! z-fluxes (use temporary variables for efficiency)
84  cc_1d = cc(n, m, :)
85  dc_1d = dc(n, m, :, 3)
86  call flux_diff_1d(cc_1d, dc_1d, inv_dr, nc, ngc)
87  dc(n, m, :, 3) = dc_1d ! Copy result
88  end do
89  end do
90  end subroutine flux_diff_3d
91 
93  subroutine flux_koren_1d(cc, v, nc, ngc)
94  integer, intent(in) :: nc
95  integer, intent(in) :: ngc
96  real(dp), intent(in) :: cc(1-ngc:nc+ngc)
98  real(dp), intent(inout) :: v(1:nc+1)
99  real(dp) :: gradp, gradc, gradn
100  integer :: n
101 
102  do n = 1, nc+1
103  gradc = cc(n) - cc(n-1) ! Current gradient
104  if (v(n) < 0.0_dp) then
105  gradn = cc(n+1) - cc(n) ! Next gradient
106  v(n) = v(n) * (cc(n) - koren_mlim(gradc, gradn))
107  else ! v(n) > 0
108  gradp = cc(n-1) - cc(n-2) ! Previous gradient
109  v(n) = v(n) * (cc(n-1) + koren_mlim(gradc, gradp))
110  end if
111  end do
112 
113  end subroutine flux_koren_1d
114 
116  subroutine flux_koren_2d(cc, v, nc, ngc)
117  integer, intent(in) :: nc
118  integer, intent(in) :: ngc
120  real(dp), intent(in) :: cc(1-ngc:nc+ngc, 1-ngc:nc+ngc)
122  real(dp), intent(inout) :: v(1:nc+1, 1:nc+1, 2)
123  real(dp) :: cc_1d(1-ngc:nc+ngc), v_1d(1:nc+1)
124  integer :: n
125 
126  do n = 1, nc
127  ! x-fluxes
128  call flux_koren_1d(cc(:, n), v(:, n, 1), nc, ngc)
129 
130  ! y-fluxes (use temporary variables for efficiency)
131  cc_1d = cc(n, :)
132  v_1d = v(n, :, 2)
133  call flux_koren_1d(cc_1d, v_1d, nc, ngc)
134  v(n, :, 2) = v_1d ! Copy result
135  end do
136  end subroutine flux_koren_2d
137 
139  subroutine flux_koren_3d(cc, v, nc, ngc)
141  integer, intent(in) :: nc
143  integer, intent(in) :: ngc
145  real(dp), intent(in) :: cc(1-ngc:nc+ngc, 1-ngc:nc+ngc, 1-ngc:nc+ngc)
147  real(dp), intent(inout) :: v(1:nc+1, 1:nc+1, 1:nc+1, 3)
148  real(dp) :: cc_1d(1-ngc:nc+ngc), v_1d(1:nc+1)
149  integer :: n, m
150 
151  do m = 1, nc
152  do n = 1, nc
153  ! x-fluxes
154  call flux_koren_1d(cc(:, n, m), v(:, n, m, 1), &
155  nc, ngc)
156 
157  ! y-fluxes (use temporary variables for efficiency)
158  cc_1d = cc(n, :, m)
159  v_1d = v(n, :, m, 2)
160  call flux_koren_1d(cc_1d, v_1d, nc, ngc)
161  v(n, :, m, 2) = v_1d ! Copy result
162 
163  ! z-fluxes (use temporary variables for efficiency)
164  cc_1d = cc(n, m, :)
165  v_1d = v(n, m, :, 3)
166  call flux_koren_1d(cc_1d, v_1d, nc, ngc)
167  v(n, m, :, 3) = v_1d ! Copy result
168  end do
169  end do
170  end subroutine flux_koren_3d
171 
176  elemental function koren_mlim(a, b) result(bphi)
177  real(dp), intent(in) :: a
178  real(dp), intent(in) :: b
179  real(dp), parameter :: sixth = 1/6.0_dp
180  real(dp) :: bphi, aa, ab
181 
182  aa = a * a
183  ab = a * b
184 
185  if (ab <= 0) then
186  ! a and b have different sign or one of them is zero, so r is either 0,
187  ! inf or negative (special case a == b == 0 is ignored)
188  bphi = 0
189  else if (aa <= 0.25_dp * ab) then
190  ! 0 < a/b <= 1/4, limiter has value a/b
191  bphi = a
192  else if (aa <= 2.5_dp * ab) then
193  ! 1/4 < a/b <= 2.5, limiter has value (1+2*a/b)/6
194  bphi = sixth * (b + 2*a)
195  else
196  ! (1+2*a/b)/6 >= 1, limiter has value 1
197  bphi = b
198  end if
199  end function koren_mlim
200 
201 end module m_flux_schemes
Module containing a couple simple flux schemes for scalar advection/diffusion problems.