amun-code/sources/interpolations.F90
Grzegorz Kowal 0b1da7d42d INTERPOLATIONS: Enable positivity fix by default.
Signed-off-by: Grzegorz Kowal <grzegorz@amuncode.org>
2020-11-11 08:49:27 -03:00

5746 lines
156 KiB
Fortran
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

!!******************************************************************************
!!
!! This file is part of the AMUN source code, a program to perform
!! Newtonian or relativistic magnetohydrodynamical simulations on uniform or
!! adaptive mesh.
!!
!! Copyright (C) 2008-2020 Grzegorz Kowal <grzegorz@amuncode.org>
!!
!! This program is free software: you can redistribute it and/or modify
!! it under the terms of the GNU General Public License as published by
!! the Free Software Foundation, either version 3 of the License, or
!! (at your option) any later version.
!!
!! This program is distributed in the hope that it will be useful,
!! but WITHOUT ANY WARRANTY; without even the implied warranty of
!! MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
!! GNU General Public License for more details.
!!
!! You should have received a copy of the GNU General Public License
!! along with this program. If not, see <http://www.gnu.org/licenses/>.
!!
!!******************************************************************************
!!
!! module: INTERPOLATIONS
!!
!! This module provides subroutines to interpolate variables and reconstruct
!! the Riemann states.
!!
!!
!!******************************************************************************
!
module interpolations
#ifdef PROFILE
! import external subroutines
!
use timers, only : set_timer, start_timer, stop_timer
#endif /* PROFILE */
! module variables are not implicit by default
!
implicit none
#ifdef PROFILE
! timer indices
!
integer , save :: imi, imr, imf, imc
#endif /* PROFILE */
! interfaces for procedure pointers
!
abstract interface
subroutine interfaces_iface(positive, h, q, qi)
logical , intent(in) :: positive
real(kind=8), dimension(:) , intent(in) :: h
real(kind=8), dimension(:,:,:) , intent(in) :: q
real(kind=8), dimension(:,:,:,:,:), intent(out) :: qi
end subroutine
subroutine reconstruct_iface(h, fc, fl, fr)
real(kind=8) , intent(in) :: h
real(kind=8), dimension(:), intent(in) :: fc
real(kind=8), dimension(:), intent(out) :: fl, fr
end subroutine
function limiter_iface(x, a, b) result(c)
real(kind=8), intent(in) :: x, a, b
real(kind=8) :: c
end function
end interface
! pointers to the reconstruction and limiter procedures
!
procedure(interfaces_iface) , pointer, save :: interfaces => null()
procedure(reconstruct_iface) , pointer, save :: reconstruct_states => null()
procedure(limiter_iface) , pointer, save :: limiter_tvd => null()
procedure(limiter_iface) , pointer, save :: limiter_prol => null()
procedure(limiter_iface) , pointer, save :: limiter_clip => null()
! method names
!
character(len=255), save :: name_rec = ""
character(len=255), save :: name_tlim = ""
character(len=255), save :: name_plim = ""
character(len=255), save :: name_clim = ""
! module parameters
!
real(kind=8), save :: eps = epsilon(1.0d+00)
real(kind=8), save :: rad = 0.5d+00
! monotonicity preserving reconstruction coefficients
!
real(kind=8), save :: kappa = 1.0d+00
real(kind=8), save :: kbeta = 1.0d+00
! number of ghost zones (required for compact schemes)
!
integer , save :: ng = 2
! order of the reconstruction
!
integer , save :: order = 1
! number of cells used in the Gaussian process reconstruction
!
integer , save :: ngp = 5
integer , save :: mgp = 1
integer , save :: dgp = 9
! normal distribution width in the Gaussian process reconstruction
!
real(kind=8), save :: sgp = 9.0d+00
! PPM constant
!
real(kind=8), save :: ppm_const = 1.25d+00
! weight toward central scheme for low-dissipation methods
!
real(kind=8), save :: cweight = 0.0d+00
! Gaussian process reconstruction coefficients vector
!
real(kind=8), dimension(:) , allocatable, save :: cgp
real(kind=8), dimension(:,:,:), allocatable, save :: ugp
! flags for reconstruction corrections
!
logical , save :: mlp = .false.
logical , save :: positivity = .true.
logical , save :: clip = .false.
! interpolation coefficients
!
real(kind=8), dimension(10), save :: ce9a
real(kind=8), dimension( 8), save :: ce7a
real(kind=8), dimension( 6), save :: ce5a
real(kind=8), dimension( 3), save :: di5a, di7a
real(kind=8), dimension( 5), save :: di9a
real(kind=8), dimension( 4), save :: ci5a
real(kind=8), dimension( 6), save :: ci7a, ci9a
real(kind=8), dimension(9), parameter :: &
ce9 = [ 4.000d+00,-4.100d+01, 1.990d+02,-6.410d+02, 1.879d+03, &
1.375d+03,-3.050d+02, 5.500d+01,-5.000d+00 ] / 2.520d+03
real(kind=8), dimension(7), parameter :: &
ce7 = [-3.000d+00, 2.500d+01,-1.010d+02, 3.190d+02, &
2.140d+02,-3.800d+01, 4.000d+00 ] / 4.200d+02
real(kind=8), dimension(5), parameter :: &
ce5 = [ 2.0d+00,-1.3d+01, 4.7d+01, 2.7d+01,-3.0d+00 ] / 6.0d+01
real(kind=8), dimension(3), parameter :: &
ce3 = [-1.0d+00, 5.0d+00, 2.0d+00 ] / 6.0d+00
real(kind=8), dimension(2), parameter :: &
ce2 = [ 5.0d-01, 5.0d-01 ]
! by default everything is private
!
private
! declare public subroutines
!
public :: initialize_interpolations, finalize_interpolations
public :: print_interpolations
public :: interfaces, reconstruct, limiter_prol
public :: fix_positivity
public :: order
!- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
!
contains
!
!===============================================================================
!
! subroutine INITIALIZE_INTERPOLATIONS:
! ------------------------------------
!
! Subroutine initializes the interpolation module by reading the module
! parameters.
!
! Arguments:
!
! nghosts - the number of ghosts cells at each side of a block;
! verbose - a logical flag turning the information printing;
! status - an integer flag for error return value;
!
!===============================================================================
!
subroutine initialize_interpolations(nghosts, verbose, status)
! include external procedures
!
use iso_fortran_env, only : error_unit
use parameters , only : get_parameter
! local variables are not implicit by default
!
implicit none
! subroutine arguments
!
integer, intent(inout) :: nghosts
logical, intent(in) :: verbose
integer, intent(out) :: status
! local variables
!
character(len=255) :: sreconstruction = "tvd"
character(len=255) :: tlimiter = "mm"
character(len=255) :: plimiter = "mm"
character(len=255) :: climiter = "mm"
character(len=255) :: mlp_limiting = "off"
character(len=255) :: positivity_fix = "on"
character(len=255) :: clip_extrema = "off"
character(len= 16) :: stmp
real(kind=8) :: cfl = 0.5d+00
! local parameters
!
character(len=*), parameter :: loc = 'INTERPOLATIONS:initialize_interpolation()'
!
!-------------------------------------------------------------------------------
!
#ifdef PROFILE
! set timer descriptions
!
call set_timer('interpolations:: initialization', imi)
call set_timer('interpolations:: reconstruction', imr)
call set_timer('interpolations:: fix positivity', imf)
call set_timer('interpolations:: clip extrema' , imc)
! start accounting time for module initialization/finalization
!
call start_timer(imi)
#endif /* PROFILE */
! reset the status flag
!
status = 0
! obtain the user defined interpolation methods and coefficients
!
call get_parameter("reconstruction" , sreconstruction)
call get_parameter("limiter" , tlimiter )
call get_parameter("fix_positivity" , positivity_fix )
call get_parameter("clip_extrema" , clip_extrema )
call get_parameter("extrema_limiter" , climiter )
call get_parameter("prolongation_limiter", plimiter )
call get_parameter("mlp_limiting" , mlp_limiting )
call get_parameter("ngp" , ngp )
call get_parameter("sgp" , sgp )
call get_parameter("eps" , eps )
call get_parameter("limo3_rad" , rad )
call get_parameter("kappa" , kappa )
call get_parameter("kbeta" , kbeta )
call get_parameter("ppm_const" , ppm_const )
call get_parameter("central_weight" , cweight )
call get_parameter("cfl" , cfl )
! calculate κ = (1 - ν) / ν
!
kappa = min(kappa, (1.0d+00 - cfl) / cfl)
! correct central weight
!
cweight = max(0.0d+00, min(1.0d+00, cweight))
! check ngp
!
if (mod(ngp,2) == 0 .or. ngp < 3) then
if (verbose) then
write(error_unit,"('[', a, ']: ', a)") trim(loc), &
"The parameter ngp has to be an odd integer >= 3. "// &
"Resetting to default value of ngp = 5."
end if
ngp = 5
end if
! calculate mgp
!
mgp = (ngp - 1) / 2
dgp = ngp**NDIMS
! select the reconstruction method
!
select case(trim(sreconstruction))
case ("tvd", "TVD")
name_rec = "2nd order TVD"
interfaces => interfaces_tvd
reconstruct_states => reconstruct_tvd
case ("weno3", "WENO3")
name_rec = "3rd order WENO"
interfaces => interfaces_dir
reconstruct_states => reconstruct_weno3
order = 3
case ("limo3", "LIMO3", "LimO3")
name_rec = "3rd order logarithmic limited"
interfaces => interfaces_dir
reconstruct_states => reconstruct_limo3
order = 3
eps = max(1.0d-12, eps)
case ("ppm", "PPM")
name_rec = "3rd order PPM"
interfaces => interfaces_dir
reconstruct_states => reconstruct_ppm
order = 3
nghosts = max(nghosts, 4)
case ("weno5z", "weno5-z", "WENO5Z", "WENO5-Z")
name_rec = "5th order WENO-Z (Borges et al. 2008)"
interfaces => interfaces_dir
reconstruct_states => reconstruct_weno5z
order = 5
nghosts = max(nghosts, 4)
case ("weno5yc", "weno5-yc", "WENO5YC", "WENO5-YC")
name_rec = "5th order WENO-YC (Yamaleev & Carpenter 2009)"
interfaces => interfaces_dir
reconstruct_states => reconstruct_weno5yc
order = 5
nghosts = max(nghosts, 4)
case ("weno5ns", "weno5-ns", "WENO5NS", "WENO5-NS")
name_rec = "5th order WENO-NS (Ha et al. 2013)"
interfaces => interfaces_dir
reconstruct_states => reconstruct_weno5ns
order = 5
nghosts = max(nghosts, 4)
case ("crweno5z", "crweno5-z", "CRWENO5Z", "CRWENO5-Z")
name_rec = "5th order Compact WENO-Z"
interfaces => interfaces_dir
reconstruct_states => reconstruct_crweno5z
order = 5
nghosts = max(nghosts, 4)
case ("crweno5yc", "crweno5-yc", "CRWENO5YC", "CRWENO5-YC")
name_rec = "5th order Compact WENO-YC"
interfaces => interfaces_dir
reconstruct_states => reconstruct_crweno5yc
order = 5
nghosts = max(nghosts, 4)
case ("crweno5ns", "crweno5-ns", "CRWENO5NS", "CRWENO5-NS")
name_rec = "5th order Compact WENO-NS"
interfaces => interfaces_dir
reconstruct_states => reconstruct_crweno5ns
order = 5
nghosts = max(nghosts, 4)
case ("mp5", "MP5")
name_rec = "5th order Monotonicity Preserving"
interfaces => interfaces_dir
reconstruct_states => reconstruct_mp5
order = 5
nghosts = max(nghosts, 4)
case ("mp7", "MP7")
name_rec = "7th order Monotonicity Preserving"
interfaces => interfaces_dir
reconstruct_states => reconstruct_mp7
order = 7
nghosts = max(nghosts, 4)
case ("mp9", "MP9")
name_rec = "9th order Monotonicity Preserving"
interfaces => interfaces_dir
reconstruct_states => reconstruct_mp9
order = 9
nghosts = max(nghosts, 6)
case ("crmp5", "CRMP5")
name_rec = "5th order Compact Monotonicity Preserving"
interfaces => interfaces_dir
reconstruct_states => reconstruct_crmp5
order = 5
nghosts = max(nghosts, 4)
case ("crmp7", "CRMP7")
name_rec = "7th order Compact Monotonicity Preserving"
interfaces => interfaces_dir
reconstruct_states => reconstruct_crmp7
order = 7
nghosts = max(nghosts, 4)
case ("crmp9", "CRMP9")
name_rec = "9th order Compact Monotonicity Preserving"
interfaces => interfaces_dir
reconstruct_states => reconstruct_crmp9
order = 9
nghosts = max(nghosts, 6)
case ("ocmp5", "OCMP5")
name_rec = "5th order Optimized Compact Monotonicity Preserving"
interfaces => interfaces_dir
reconstruct_states => reconstruct_ocmp5
order = 5
nghosts = max(nghosts, 4)
case ("ocmp7", "OCMP7")
name_rec = "7th order Optimized Compact Monotonicity Preserving"
interfaces => interfaces_dir
reconstruct_states => reconstruct_ocmp7
order = 7
nghosts = max(nghosts, 6)
case ("ocmp9", "OCMP9")
name_rec = "9th order Optimized Compact Monotonicity Preserving"
interfaces => interfaces_dir
reconstruct_states => reconstruct_ocmp9
order = 9
nghosts = max(nghosts, 6)
case ("gp", "GP")
write(stmp, '(f16.1)') sgp
write(name_rec, '("Gaussian Process (",i1,"-point, δ=",a,")")') ngp &
, trim(adjustl(stmp))
! allocate the Gaussian process reconstruction matrix and position vector
!
allocate(cgp(ngp), stat = status)
! prepare matrix coefficients
!
if (status == 0) call prepare_gp(status)
interfaces => interfaces_dir
reconstruct_states => reconstruct_gp
order = ngp
ng = 2
do while(ng < (ngp + 1) / 2)
ng = ng + 2
end do
nghosts = max(nghosts, ng)
case ("mgp", "MGP")
write(stmp, '(f16.1)') sgp
write(name_rec, &
'("Multidimensional Gaussian Process (",i1,"-point, δ=",a,")")') &
ngp, trim(adjustl(stmp))
! allocate the Gaussian process reconstruction matrix and position vector
!
allocate(ugp(dgp,2,NDIMS), stat = status)
! prepare matrix coefficients
!
if (status == 0) call prepare_mgp(status)
interfaces => interfaces_mgp
ng = 2
do while(ng < (ngp + 1) / 2)
ng = ng + 2
end do
nghosts = max(nghosts, ng)
case default
if (verbose) then
write(error_unit,"('[', a, ']: ', a)") trim(loc), &
"The selected reconstruction method is not " // &
"implemented: " // trim(sreconstruction) // "." // &
"Available methods: 'tvd' 'limo3', 'ppm'," // &
" 'weno3', 'weno5z', 'weno5yc', 'weno5ns'," // &
" 'crweno5z', 'crweno5yc', 'crweno5ns','mp5', " // &
" 'mp7', 'mp9', 'crmp5', 'crmp5ld', 'crmp7', 'gp', 'mgp'."
end if
status = 1
end select
! select the TVD limiter
!
select case(trim(tlimiter))
case ("mm", "minmod")
name_tlim = "minmod"
limiter_tvd => limiter_minmod
order = max(2, order)
case ("mc", "monotonized_central")
name_tlim = "monotonized central"
limiter_tvd => limiter_monotonized_central
order = max(2, order)
case ("sb", "superbee")
name_tlim = "superbee"
limiter_tvd => limiter_superbee
order = max(2, order)
case ("vl", "vanleer")
name_tlim = "van Leer"
limiter_tvd => limiter_vanleer
order = max(2, order)
case ("va", "vanalbada")
name_tlim = "van Albada"
limiter_tvd => limiter_vanalbada
order = max(2, order)
case default
name_tlim = "zero derivative"
limiter_tvd => limiter_zero
order = max(1, order)
end select
! select the prolongation limiter
!
select case(trim(plimiter))
case ("mm", "minmod")
name_plim = "minmod"
limiter_prol => limiter_minmod
case ("mc", "monotonized_central")
name_plim = "monotonized central"
limiter_prol => limiter_monotonized_central
case ("sb", "superbee")
name_plim = "superbee"
limiter_prol => limiter_superbee
case ("vl", "vanleer")
name_plim = "van Leer"
limiter_prol => limiter_vanleer
case default
name_plim = "zero derivative"
limiter_prol => limiter_zero
end select
! select the clipping limiter
!
select case(trim(climiter))
case ("mm", "minmod")
name_clim = "minmod"
limiter_clip => limiter_minmod
case ("mc", "monotonized_central")
name_clim = "monotonized central"
limiter_clip => limiter_monotonized_central
case ("sb", "superbee")
name_clim = "superbee"
limiter_clip => limiter_superbee
case ("vl", "vanleer")
name_clim = "van Leer"
limiter_clip => limiter_vanleer
case default
name_clim = "zero derivative"
limiter_clip => limiter_zero
end select
! check additional reconstruction limiting
!
select case(trim(mlp_limiting))
case ("on", "ON", "t", "T", "y", "Y", "true", "TRUE", "yes", "YES")
mlp = .true.
case default
mlp = .false.
end select
select case(trim(positivity_fix))
case ("on", "ON", "t", "T", "y", "Y", "true", "TRUE", "yes", "YES")
positivity = .true.
case default
positivity = .false.
end select
select case(trim(clip_extrema))
case ("on", "ON", "t", "T", "y", "Y", "true", "TRUE", "yes", "YES")
clip = .true.
case default
clip = .false.
end select
! set the internal number of ghost cells
!
ng = nghosts
! calculate coefficients of the low-dissipation methods
!
ce5a = [ - cweight +2.000d+00, 5.00d+00 * cweight -1.300d+01, &
-1.00d+01 * cweight +4.700d+01, 1.00d+01 * cweight +2.700d+01, &
-5.00d+00 * cweight -3.000d+00, cweight ] / 6.00d+01
ce7a = [ 3.00d+00 * cweight -6.000d+00, -2.10d+01 * cweight +5.000d+01, &
6.30d+01 * cweight -2.020d+02, -1.05d+02 * cweight +6.380d+02, &
1.05d+02 * cweight +4.280d+02, -6.30d+01 * cweight -7.600d+01, &
2.10d+01 * cweight +8.000d+00, -3.00d+00 * cweight ] / 8.40d+02
ce9a = [ -2.00d+00 * cweight +4.000d+00, 1.80d+01 * cweight -4.100d+01, &
-7.20d+01 * cweight +1.990d+02, 1.68d+02 * cweight -6.410d+02, &
-2.52d+02 * cweight +1.879d+03, 2.52d+02 * cweight +1.375d+03, &
-1.68d+02 * cweight -3.050d+02, 7.20d+01 * cweight +5.500d+01, &
-1.80d+01 * cweight -5.000d+00, 2.00d+00 * cweight ] / 2.52d+03
di5a = [ -(cweight -3.0d+00) / 6.0d+00, 1.0d+00, &
(cweight +1.0d+00) / 6.0d+00 ]
ci5a = [ - cweight +2.0d+00, -9.0d+00 * cweight +3.8d+01, &
9.0d+00 * cweight +2.0d+01, cweight ] / 3.6d+01
di7a = [ -(cweight -4.0d+00) / 8.0d+00, 1.0d+00, &
(cweight +2.0d+00) / 8.0d+00 ]
ci7a = [ cweight -2.0d+00, -1.50d+01 * cweight +3.8d+01, &
-8.0d+01 * cweight +4.78d+02, 8.0d+01 * cweight +3.18d+02, &
1.5d+01 * cweight +8.00d+00, -cweight ] / 4.8d+02
di9a = [ -2.0d+00 * cweight +5.0d+00, -1.0d+01 * cweight +4.0d+01, &
6.0d+01, 1.0d+01 * cweight +2.0d+01, &
2.0d+00 * cweight +1.0d+00 ] / 6.0d+01
ci9a = [ -3.00d+00 * cweight +6.000d+00,-1.75d+02 * cweight +4.810d+02, &
-3.00d+02 * cweight +1.881d+03, 3.00d+02 * cweight +1.281d+03, &
1.75d+02 * cweight +1.310d+02, 3.00d+00 * cweight ] / 1.8d+03
#ifdef PROFILE
! stop accounting time for module initialization/finalization
!
call stop_timer(imi)
#endif /* PROFILE */
!-------------------------------------------------------------------------------
!
end subroutine initialize_interpolations
!
!===============================================================================
!
! subroutine FINALIZE_INTERPOLATIONS:
! ----------------------------------
!
! Subroutine finalizes the interpolation module by releasing all memory used
! by its module variables.
!
! Arguments:
!
! status - an integer flag for error return value;
!
!===============================================================================
!
subroutine finalize_interpolations(status)
! local variables are not implicit by default
!
implicit none
! subroutine arguments
!
integer, intent(out) :: status
!
!-------------------------------------------------------------------------------
!
#ifdef PROFILE
! start accounting time for module initialization/finalization
!
call start_timer(imi)
#endif /* PROFILE */
! reset the status flag
!
status = 0
! deallocate Gaussian process reconstruction coefficient vector if used
!
if (allocated(cgp)) deallocate(cgp, stat = status)
if (allocated(ugp)) deallocate(ugp, stat = status)
! release the procedure pointers
!
nullify(reconstruct_states)
nullify(limiter_tvd)
nullify(limiter_prol)
nullify(limiter_clip)
#ifdef PROFILE
! stop accounting time for module initialization/finalization
!
call stop_timer(imi)
#endif /* PROFILE */
!-------------------------------------------------------------------------------
!
end subroutine finalize_interpolations
!
!===============================================================================
!
! subroutine PRINT_INTERPOLATIONS:
! -------------------------------
!
! Subroutine prints module parameters and settings.
!
! Arguments:
!
! verbose - a logical flag turning the information printing;
!
!===============================================================================
!
subroutine print_interpolations(verbose)
! import external procedures and variables
!
use helpers, only : print_section, print_parameter
! local variables are not implicit by default
!
implicit none
! subroutine arguments
!
logical, intent(in) :: verbose
!
!-------------------------------------------------------------------------------
!
if (verbose) then
call print_section(verbose, "Interpolations")
call print_parameter(verbose, "reconstruction" , name_rec )
call print_parameter(verbose, "TVD limiter" , name_tlim)
call print_parameter(verbose, "prolongation limiter", name_plim)
if (mlp) then
call print_parameter(verbose, "MLP limiting" , "on" )
else
call print_parameter(verbose, "MLP limiting" , "off" )
end if
if (positivity) then
call print_parameter(verbose, "fix positivity" , "on" )
else
call print_parameter(verbose, "fix positivity" , "off" )
end if
if (clip) then
call print_parameter(verbose, "clip extrema" , "on" )
call print_parameter(verbose, "extrema limiter" , name_clim)
else
call print_parameter(verbose, "clip extrema" , "off" )
end if
call print_parameter(verbose, "central weight", cweight)
end if
!-------------------------------------------------------------------------------
!
end subroutine print_interpolations
!
!===============================================================================
!
! subroutine PREPARE_MGP:
! ---------------------
!
! Subroutine prepares matrixes for the multidimensional
! Gaussian Process (GP) method.
!
!===============================================================================
!
subroutine prepare_mgp(iret)
! include external procedures
!
use algebra , only : max_prec, invert
use constants , only : pi
use iso_fortran_env, only : error_unit
! local variables are not implicit by default
!
implicit none
! subroutine arguments
!
integer, intent(inout) :: iret
! local variables
!
logical :: flag
integer :: i, j, i1, j1, i2, j2
#if NDIMS == 3
integer :: k1, k2
#endif /* NDIMS == 3 */
real(kind=max_prec) :: sig, fc, fx, fy, xl, xr, yl, yr
#if NDIMS == 3
real(kind=max_prec) :: fz, zl, zr
#endif /* NDIMS == 3 */
! local arrays for derivatives
!
real(kind=max_prec), dimension(:,:) , allocatable :: cov, inv
real(kind=max_prec), dimension(:,:,:), allocatable :: xgp
! local parameters
!
character(len=*), parameter :: loc = 'INTERPOLATIONS::prepare_mgp()'
!
!-------------------------------------------------------------------------------
!
! calculate normal distribution sigma
!
sig = sqrt(2.0d+00) * sgp
! allocate the convariance matrix and interpolation position vector
!
allocate(cov(dgp,dgp))
allocate(inv(dgp,dgp))
allocate(xgp(dgp,2,NDIMS))
! prepare the covariance matrix
!
fc = 0.5d+00 * sqrt(pi) * sig
i = 0
#if NDIMS == 3
do k1 = - mgp, mgp
#endif /* NDIMS == 3 */
do j1 = - mgp, mgp
do i1 = - mgp, mgp
i = i + 1
j = 0
#if NDIMS == 3
do k2 = - mgp, mgp
#endif /* NDIMS == 3 */
do j2 = - mgp, mgp
do i2 = - mgp, mgp
j = j + 1
xl = (1.0d+00 * (i1 - i2) - 0.5d+00) / sig
xr = (1.0d+00 * (i1 - i2) + 0.5d+00) / sig
yl = (1.0d+00 * (j1 - j2) - 0.5d+00) / sig
yr = (1.0d+00 * (j1 - j2) + 0.5d+00) / sig
#if NDIMS == 3
zl = (1.0d+00 * (k1 - k2) - 0.5d+00) / sig
zr = (1.0d+00 * (k1 - k2) + 0.5d+00) / sig
#endif /* NDIMS == 3 */
cov(i,j) = fc * (erf(xr) - erf(xl)) * (erf(yr) - erf(yl))
#if NDIMS == 3
cov(i,j) = cov(i,j) * (erf(zr) - erf(zl))
#endif /* NDIMS == 3 */
end do
end do
end do
end do
#if NDIMS == 3
end do
end do
#endif /* NDIMS == 3 */
! prepare the interpolation position vector
!
i = 0
#if NDIMS == 3
do k1 = - mgp, mgp
#endif /* NDIMS == 3 */
do j1 = - mgp, mgp
do i1 = - mgp, mgp
i = i + 1
xl = (1.0d+00 * i1 - 0.5d+00) / sig
xr = (1.0d+00 * i1 + 0.5d+00) / sig
yl = (1.0d+00 * j1 - 0.5d+00) / sig
yr = (1.0d+00 * j1 + 0.5d+00) / sig
#if NDIMS == 3
zl = (1.0d+00 * k1 - 0.5d+00) / sig
zr = (1.0d+00 * k1 + 0.5d+00) / sig
#endif /* NDIMS == 3 */
fx = erf(xr) - erf(xl)
fy = erf(yr) - erf(yl)
#if NDIMS == 3
fz = erf(zr) - erf(zl)
xgp(i,1,1) = exp(- xl**2) * fy * fz
xgp(i,2,1) = exp(- xr**2) * fy * fz
xgp(i,1,2) = exp(- yl**2) * fx * fz
xgp(i,2,2) = exp(- yr**2) * fx * fz
xgp(i,1,3) = exp(- zl**2) * fx * fy
xgp(i,2,3) = exp(- zr**2) * fx * fy
#else /* NDIMS == 3 */
xgp(i,1,1) = exp(- xl**2) * fy
xgp(i,2,1) = exp(- xr**2) * fy
xgp(i,1,2) = exp(- yl**2) * fx
xgp(i,2,2) = exp(- yr**2) * fx
#endif /* NDIMS == 3 */
end do
end do
#if NDIMS == 3
end do
#endif /* NDIMS == 3 */
! invert the matrix
!
call invert(dgp, cov(1:dgp,1:dgp), inv(1:dgp,1:dgp), flag)
! prepare the interpolation coefficients vector
!
do j = 1, NDIMS
do i = 1, 2
ugp(1:dgp,i,j) = real(matmul(xgp(1:dgp,i,j), inv(1:dgp,1:dgp)), kind=8)
end do
end do
! deallocate the convariance matrix and interpolation position vector
!
deallocate(cov)
deallocate(inv)
deallocate(xgp)
! check if the matrix was inverted successfully
!
if (.not. flag) then
write(error_unit,"('[',a,']: ',a)") trim(loc) &
, "Could not invert the covariance matrix!"
iret = 201
end if
!-------------------------------------------------------------------------------
!
end subroutine prepare_mgp
!
!===============================================================================
!
! subroutine INTERFACES_TVD:
! -------------------------
!
! Subroutine reconstructs both side interfaces of variable using TVD methods.
!
! Arguments:
!
! positive - the variable positivity flag;
! h - the spatial step;
! q - the variable array;
! qi - the array of reconstructed interfaces (2 in each direction);
!
!===============================================================================
!
subroutine interfaces_tvd(positive, h, q, qi)
! include external procedures
!
use coordinates , only : nb, ne, nbl, neu
use iso_fortran_env, only : error_unit
! local variables are not implicit by default
!
implicit none
! subroutine arguments
!
logical , intent(in) :: positive
real(kind=8), dimension(:) , intent(in) :: h
real(kind=8), dimension(:,:,:) , intent(in) :: q
real(kind=8), dimension(:,:,:,:,:), intent(out) :: qi
! local variables
!
integer :: i , j , k = 1
integer :: im1, jm1, ip1, jp1
#if NDIMS == 3
integer :: km1, kp1
#endif /* NDIMS == 3 */
! local vectors
!
real(kind=8), dimension(NDIMS) :: dql, dqr, dq
! local parameters
!
character(len=*), parameter :: loc = 'INTERPOLATIONS::interfaces_tvd()'
!
!-------------------------------------------------------------------------------
!
! copy ghost zones
!
do j = 1, NDIMS
do i = 1, 2
qi( :nb, : , : ,i,j) = q( :nb, : , : )
qi(ne: , : , : ,i,j) = q(ne: , : , : )
qi(nb:ne, :nb, : ,i,j) = q(nb:ne, :nb, : )
qi(nb:ne,ne: , : ,i,j) = q(nb:ne,ne: , : )
#if NDIMS == 3
qi(nb:ne,nb:ne, :nb,i,j) = q(nb:ne,nb:ne, :nb)
qi(nb:ne,nb:ne,ne: ,i,j) = q(nb:ne,nb:ne,ne: )
#endif /* NDIMS == 3 */
end do
end do
! interpolate interfaces
!
#if NDIMS == 3
do k = nbl, neu
km1 = k - 1
kp1 = k + 1
#endif /* NDIMS == 3 */
do j = nbl, neu
jm1 = j - 1
jp1 = j + 1
do i = nbl, neu
im1 = i - 1
ip1 = i + 1
! calculate the TVD derivatives
!
dql(1) = q(i ,j,k) - q(im1,j,k)
dqr(1) = q(ip1,j,k) - q(i ,j,k)
dq (1) = limiter_tvd(0.5d+00, dql(1), dqr(1))
dql(2) = q(i,j ,k) - q(i,jm1,k)
dqr(2) = q(i,jp1,k) - q(i,j ,k)
dq (2) = limiter_tvd(0.5d+00, dql(2), dqr(2))
#if NDIMS == 3
dql(3) = q(i,j,k ) - q(i,j,km1)
dqr(3) = q(i,j,kp1) - q(i,j,k )
dq (3) = limiter_tvd(0.5d+00, dql(3), dqr(3))
#endif /* NDIMS == 3 */
! limit the derivatives if they produce negative interpolation for positive
! variables
!
if (positive) then
if (q(i,j,k) > 0.0d+00) then
do while (q(i,j,k) <= sum(abs(dq(1:NDIMS))))
dq(:) = 0.5d+00 * dq(:)
end do
else
write(error_unit,"('[',a,']: ',a,3i4,a)") trim(loc) &
, "Positive variable is not positive at ( ", i, j, k, " )"
dq(:) = 0.0d+00
end if
end if
! interpolate states
!
qi(i ,j,k,1,1) = q(i,j,k) + dq(1)
qi(im1,j,k,2,1) = q(i,j,k) - dq(1)
qi(i,j ,k,1,2) = q(i,j,k) + dq(2)
qi(i,jm1,k,2,2) = q(i,j,k) - dq(2)
#if NDIMS == 3
qi(i,j,k ,1,3) = q(i,j,k) + dq(3)
qi(i,j,km1,2,3) = q(i,j,k) - dq(3)
#endif /* NDIMS == 3 */
end do ! i = nbl, neu
end do ! j = nbl, neu
#if NDIMS == 3
end do ! k = nbl, neu
#endif /* NDIMS == 3 */
! apply Multi-dimensional Limiting Process
!
if (mlp) call mlp_limiting(q(:,:,:), qi(:,:,:,:,:))
!-------------------------------------------------------------------------------
!
end subroutine interfaces_tvd
!
!===============================================================================
!
! subroutine INTERFACES_DIR:
! -------------------------
!
! Subroutine reconstructs both side interfaces of variable separately
! along each direction.
!
! Arguments:
!
! positive - the variable positivity flag;
! h - the spatial step;
! q - the variable array;
! qi - the array of reconstructed interfaces (2 in each direction);
!
!===============================================================================
!
subroutine interfaces_dir(positive, h, q, qi)
! include external procedures
!
use coordinates, only : nb, ne, nbl, neu
! local variables are not implicit by default
!
implicit none
! subroutine arguments
!
logical , intent(in) :: positive
real(kind=8), dimension(:) , intent(in) :: h
real(kind=8), dimension(:,:,:) , intent(in) :: q
real(kind=8), dimension(:,:,:,:,:), intent(out) :: qi
! local variables
!
integer :: i, j, k = 1
!
!-------------------------------------------------------------------------------
!
! copy ghost zones
!
do j = 1, NDIMS
do i = 1, 2
qi( :nb, : , : ,i,j) = q( :nb, : , : )
qi(ne: , : , : ,i,j) = q(ne: , : , : )
qi(nb:ne, :nb, : ,i,j) = q(nb:ne, :nb, : )
qi(nb:ne,ne: , : ,i,j) = q(nb:ne,ne: , : )
#if NDIMS == 3
qi(nb:ne,nb:ne, :nb,i,j) = q(nb:ne,nb:ne, :nb)
qi(nb:ne,nb:ne,ne: ,i,j) = q(nb:ne,nb:ne,ne: )
#endif /* NDIMS == 3 */
end do
end do
! interpolate interfaces
!
#if NDIMS == 3
do k = nbl, neu
#endif /* NDIMS == 3 */
do j = nbl, neu
call reconstruct(h(1), q(:,j,k), qi(:,j,k,1,1), qi(:,j,k,2,1))
end do ! j = nbl, neu
do i = nbl, neu
call reconstruct(h(2), q(i,:,k), qi(i,:,k,1,2), qi(i,:,k,2,2))
end do ! i = nbl, neu
#if NDIMS == 3
end do ! k = nbl, neu
do j = nbl, neu
do i = nbl, neu
call reconstruct(h(3), q(i,j,:), qi(i,j,:,1,3), qi(i,j,:,2,3))
end do ! i = nbl, neu
end do ! j = nbl, neu
#endif /* NDIMS == 3 */
! make sure the interface states are positive for positive variables
!
if (positive) then
#if NDIMS == 3
do k = nbl, neu
#endif /* NDIMS == 3 */
do j = nbl, neu
call fix_positivity(q(:,j,k), qi(:,j,k,1,1), qi(:,j,k,2,1))
end do ! j = nbl, neu
do i = nbl, neu
call fix_positivity(q(i,:,k), qi(i,:,k,1,2), qi(i,:,k,2,2))
end do ! i = nbl, neu
#if NDIMS == 3
end do ! k = nbl, neu
do j = nbl, neu
do i = nbl, neu
call fix_positivity(q(i,j,:), qi(i,j,:,1,3), qi(i,j,:,2,3))
end do ! i = nbl, neu
end do ! j = nbl, neu
#endif /* NDIMS == 3 */
end if
! apply Multi-dimensional Limiting Process
!
if (mlp) call mlp_limiting(q(:,:,:), qi(:,:,:,:,:))
!-------------------------------------------------------------------------------
!
end subroutine interfaces_dir
!
!===============================================================================
!
! subroutine INTERFACES_MGP:
! -------------------------
!
! Subroutine reconstructs both side interfaces of variable using
! multidimensional Gaussian Process method.
!
! Arguments:
!
! positive - the variable positivity flag;
! h - the spatial step;
! q - the variable array;
! qi - the array of reconstructed interfaces (2 in each direction);
!
!===============================================================================
!
subroutine interfaces_mgp(positive, h, q, qi)
! include external procedures
!
use coordinates , only : nb, ne, nbl, neu
use iso_fortran_env, only : error_unit
! local variables are not implicit by default
!
implicit none
! subroutine arguments
!
logical , intent(in) :: positive
real(kind=8), dimension(:) , intent(in) :: h
real(kind=8), dimension(:,:,:) , intent(in) :: q
real(kind=8), dimension(:,:,:,:,:), intent(out) :: qi
! local variables
!
logical :: flag
integer :: i, il, iu, im1, ip1
integer :: j, jl, ju, jm1, jp1
integer :: k = 1
#if NDIMS == 3
integer :: kl, ku, km1, kp1
#endif /* NDIMS == 3 */
! local arrays for derivatives
!
real(kind=8), dimension(NDIMS) :: dql, dqr, dq
real(kind=8), dimension(dgp) :: u
! local parameters
!
character(len=*), parameter :: loc = 'INTERPOLATIONS::interfaces_mgp()'
!
!-------------------------------------------------------------------------------
!
! copy ghost zones
!
do j = 1, NDIMS
do i = 1, 2
qi( :nb, : , : ,i,j) = q( :nb, : , : )
qi(ne: , : , : ,i,j) = q(ne: , : , : )
qi(nb:ne, :nb, : ,i,j) = q(nb:ne, :nb, : )
qi(nb:ne,ne: , : ,i,j) = q(nb:ne,ne: , : )
#if NDIMS == 3
qi(nb:ne,nb:ne, :nb,i,j) = q(nb:ne,nb:ne, :nb)
qi(nb:ne,nb:ne,ne: ,i,j) = q(nb:ne,nb:ne,ne: )
#endif /* NDIMS == 3 */
end do
end do
! interpolate interfaces using precomputed interpolation vectors
!
#if NDIMS == 3
do k = nbl, neu
kl = k - mgp
ku = k + mgp
km1 = k - 1
kp1 = k + 1
#endif /* NDIMS == 3 */
do j = nbl, neu
jl = j - mgp
ju = j + mgp
jm1 = j - 1
jp1 = j + 1
do i = nbl, neu
il = i - mgp
iu = i + mgp
im1 = i - 1
ip1 = i + 1
#if NDIMS == 3
u(:) = reshape(q(il:iu,jl:ju,kl:ku), (/ dgp /)) - q(i,j,k)
qi(i ,j,k,1,1) = sum(ugp(1:dgp,1,1) * u(1:dgp)) + q(i,j,k)
qi(im1,j,k,2,1) = sum(ugp(1:dgp,2,1) * u(1:dgp)) + q(i,j,k)
qi(i,j ,k,1,2) = sum(ugp(1:dgp,1,2) * u(1:dgp)) + q(i,j,k)
qi(i,jm1,k,2,2) = sum(ugp(1:dgp,2,2) * u(1:dgp)) + q(i,j,k)
qi(i,j,k ,1,3) = sum(ugp(1:dgp,1,3) * u(1:dgp)) + q(i,j,k)
qi(i,j,km1,2,3) = sum(ugp(1:dgp,2,3) * u(1:dgp)) + q(i,j,k)
#else /* NDIMS == 3 */
u(:) = reshape(q(il:iu,jl:ju,k ), (/ dgp /)) - q(i,j,k)
qi(i ,j,k,1,1) = sum(ugp(1:dgp,1,1) * u(1:dgp)) + q(i,j,k)
qi(im1,j,k,2,1) = sum(ugp(1:dgp,2,1) * u(1:dgp)) + q(i,j,k)
qi(i,j ,k,1,2) = sum(ugp(1:dgp,1,2) * u(1:dgp)) + q(i,j,k)
qi(i,jm1,k,2,2) = sum(ugp(1:dgp,2,2) * u(1:dgp)) + q(i,j,k)
#endif /* NDIMS == 3 */
! if the interpolation is not monotonic, apply a TVD slope
!
flag = ((qi(i ,j,k,1,1) - q(ip1,j,k)) &
* (qi(i ,j,k,1,1) - q(i ,j,k)) > eps)
flag = flag .or. ((qi(im1,j,k,2,1) - q(im1,j,k)) &
* (qi(im1,j,k,2,1) - q(i ,j,k)) > eps)
flag = flag .or. ((qi(i,j ,k,1,2) - q(i,jp1,k)) &
* (qi(i,j ,k,1,2) - q(i,j ,k)) > eps)
flag = flag .or. ((qi(i,jm1,k,2,2) - q(i,jm1,k)) &
* (qi(i,jm1,k,2,2) - q(i,j ,k)) > eps)
#if NDIMS == 3
flag = flag .or. ((qi(i,j,k ,1,3) - q(i,j,kp1)) &
* (qi(i,j,k ,1,3) - q(i,j,k )) > eps)
flag = flag .or. ((qi(i,j,km1,2,3) - q(i,j,km1)) &
* (qi(i,j,km1,2,3) - q(i,j,k )) > eps)
#endif /* NDIMS == 3 */
if (flag) then
! calculate the TVD derivatives
!
dql(1) = q(i ,j,k) - q(im1,j,k)
dqr(1) = q(ip1,j,k) - q(i ,j,k)
dq (1) = limiter_tvd(0.5d+00, dql(1), dqr(1))
dql(2) = q(i,j ,k) - q(i,jm1,k)
dqr(2) = q(i,jp1,k) - q(i,j ,k)
dq (2) = limiter_tvd(0.5d+00, dql(2), dqr(2))
#if NDIMS == 3
dql(3) = q(i,j,k ) - q(i,j,km1)
dqr(3) = q(i,j,kp1) - q(i,j,k )
dq (3) = limiter_tvd(0.5d+00, dql(3), dqr(3))
#endif /* NDIMS == 3 */
! limit the derivatives if they produce negative interpolation for positive
! variables
!
if (positive) then
if (q(i,j,k) > 0.0d+00) then
do while (q(i,j,k) <= sum(abs(dq(1:NDIMS))))
dq(:) = 0.5d+00 * dq(:)
end do
else
write(error_unit,"('[',a,']: ',a,3i4,a)") trim(loc) &
, "Positive variable is not positive at ( ", i, j, k, " )"
dq(:) = 0.0d+00
end if
end if
! interpolate states
!
qi(i ,j,k,1,1) = q(i,j,k) + dq(1)
qi(im1,j,k,2,1) = q(i,j,k) - dq(1)
qi(i,j ,k,1,2) = q(i,j,k) + dq(2)
qi(i,jm1,k,2,2) = q(i,j,k) - dq(2)
#if NDIMS == 3
qi(i,j,k ,1,3) = q(i,j,k) + dq(3)
qi(i,j,km1,2,3) = q(i,j,k) - dq(3)
#endif /* NDIMS == 3 */
end if
end do ! i = nbl, neu
end do ! j = nbl, neu
#if NDIMS == 3
end do ! k = nbl, neu
#endif /* NDIMS == 3 */
! apply Multi-dimensional Limiting Process
!
if (mlp) call mlp_limiting(q(:,:,:), qi(:,:,:,:,:))
!-------------------------------------------------------------------------------
!
end subroutine interfaces_mgp
!
!===============================================================================
!
! subroutine MLP_LIMITING:
! -----------------------
!
! Subroutine applies the multi-dimensional limiting process to
! the reconstructed states in order to control oscillations due to
! the Gibbs phenomena near discontinuities.
!
! Arguments:
!
! q - the variable array;
! qi - the array of reconstructed interfaces (2 in each direction);
!
! References:
!
! [1] Gerlinger, P.,
! "Multi-dimensional limiting for high-order schemes including
! turbulence and combustion",
! Journal of Computational Physics,
! 2012, vol. 231, pp. 2199-2228,
! http://dx.doi.org/10.1016/j.jcp.2011.10.024
!
!===============================================================================
!
subroutine mlp_limiting(q, qi)
! include external procedures
!
use coordinates, only : nn => bcells
! local variables are not implicit by default
!
implicit none
! subroutine arguments
!
real(kind=8), dimension(:,:,:) , intent(in) :: q
real(kind=8), dimension(:,:,:,:,:), intent(inout) :: qi
! local variables
!
integer :: i, im1, ip1
integer :: j, jm1, jp1
integer :: k = 1
#if NDIMS == 3
integer :: km1, kp1
#endif /* NDIMS == 3 */
integer :: m
#if NDIMS == 3
integer :: n, np1, np2
#endif /* NDIMS == 3 */
real(kind=8) :: qmn, qmx, dqc
real(kind=8) :: fc, fl
! local vectors
!
real(kind=8), dimension(NDIMS) :: dql, dqr, dq
real(kind=8), dimension(NDIMS) :: dqm, ap
#if NDIMS == 3
real(kind=8), dimension(NDIMS) :: hh, uu
#endif /* NDIMS == 3 */
!
!-------------------------------------------------------------------------------
!
#if NDIMS == 3
do k = 1, nn
km1 = max( 1, k - 1)
kp1 = min(nn, k + 1)
#endif /* NDIMS == 3 */
do j = 1, nn
jm1 = max( 1, j - 1)
jp1 = min(nn, j + 1)
do i = 1, nn
im1 = max( 1, i - 1)
ip1 = min(nn, i + 1)
! calculate the minmod TVD derivatives
!
dql(1) = q(i ,j,k) - q(im1,j,k)
dqr(1) = q(ip1,j,k) - q(i ,j,k)
dq (1) = limiter_minmod(0.5d+00, dql(1), dqr(1))
dql(2) = q(i,j ,k) - q(i,jm1,k)
dqr(2) = q(i,jp1,k) - q(i,j ,k)
dq (2) = limiter_minmod(0.5d+00, dql(2), dqr(2))
#if NDIMS == 3
dql(3) = q(i,j,k ) - q(i,j,km1)
dqr(3) = q(i,j,kp1) - q(i,j,k )
dq (3) = limiter_minmod(0.5d+00, dql(3), dqr(3))
#endif /* NDIMS == 3 */
! calculate dqc
!
#if NDIMS == 3
qmn = minval(q(im1:ip1,jm1:jp1,km1:kp1))
qmx = maxval(q(im1:ip1,jm1:jp1,km1:kp1))
#else /* NDIMS == 3 */
qmn = minval(q(im1:ip1,jm1:jp1,k))
qmx = maxval(q(im1:ip1,jm1:jp1,k))
#endif /* NDIMS == 3 */
dqc = min(qmx - q(i,j,k), q(i,j,k) - qmn)
! if needed, apply the multi-dimensional limiting process
!
if (sum(abs(dq(1:NDIMS))) > dqc) then
dqm(1) = abs(q(ip1,j,k) - q(im1,j,k))
dqm(2) = abs(q(i,jp1,k) - q(i,jm1,k))
#if NDIMS == 3
dqm(3) = abs(q(i,j,kp1) - q(i,j,km1))
#endif /* NDIMS == 3 */
fc = dqc / max(1.0d-16, sum(abs(dqm(1:NDIMS))))
do m = 1, NDIMS
ap(m) = fc * abs(dqm(m))
end do
#if NDIMS == 3
do n = 1, NDIMS
hh(n) = max(ap(n) - abs(dq(n)), 0.0d+00)
np1 = mod(n , NDIMS) + 1
np2 = mod(n + 1, NDIMS) + 1
uu(n) = ap(n) - hh(n)
uu(np1) = ap(np1) + 0.5d+00 * hh(n)
uu(np2) = ap(np2) + 0.5d+00 * hh(n)
fc = hh(n) / (hh(n) + 1.0d-16)
fl = fc * (max(ap(np1) - abs(dq(np1)), 0.0d+00) &
- max(ap(np2) - abs(dq(np2)), 0.0d+00))
ap(n ) = uu(n)
ap(np1) = uu(np1) - fl
ap(np2) = uu(np2) + fl
end do
#else /* NDIMS == 3 */
fl = max(ap(1) - abs(dq(1)), 0.0d+00) &
- max(ap(2) - abs(dq(2)), 0.0d+00)
ap(1) = ap(1) - fl
ap(2) = ap(2) + fl
#endif /* NDIMS == 3 */
do m = 1, NDIMS
dq(m) = sign(ap(m), dq(m))
end do
end if
! update the interpolated states
!
dql(1) = qi(i ,j,k,1,1) - q(i,j,k)
dqr(1) = qi(im1,j,k,2,1) - q(i,j,k)
if (max(abs(dql(1)), abs(dqr(1))) > abs(dq(1))) then
qi(i ,j,k,1,1) = q(i,j,k) + dq(1)
qi(im1,j,k,2,1) = q(i,j,k) - dq(1)
end if
dql(2) = qi(i,j ,k,1,2) - q(i,j,k)
dqr(2) = qi(i,jm1,k,2,2) - q(i,j,k)
if (max(abs(dql(2)), abs(dqr(2))) > abs(dq(2))) then
qi(i,j ,k,1,2) = q(i,j,k) + dq(2)
qi(i,jm1,k,2,2) = q(i,j,k) - dq(2)
end if
#if NDIMS == 3
dql(3) = qi(i,j,k ,1,3) - q(i,j,k)
dqr(3) = qi(i,j,km1,2,3) - q(i,j,k)
if (max(abs(dql(3)), abs(dqr(3))) > abs(dq(3))) then
qi(i,j,k ,1,3) = q(i,j,k) + dq(3)
qi(i,j,km1,2,3) = q(i,j,k) - dq(3)
end if
#endif /* NDIMS == 3 */
end do ! i = 1, nn
end do ! j = 1, nn
#if NDIMS == 3
end do ! k = 1, nn
#endif /* NDIMS == 3 */
!-------------------------------------------------------------------------------
!
end subroutine mlp_limiting
!
!===============================================================================
!
! subroutine RECONSTRUCT:
! ----------------------
!
! Subroutine calls a reconstruction procedure, depending on the compilation
! flag SPACE, in order to interpolate the left and right states from their
! cell integrals. These states are required by any approximate Riemann
! solver.
!
! Arguments:
!
! h - the spatial step; this is required for some reconstruction methods;
! f - the input vector of cell averaged values;
! fl - the left side state reconstructed for location (i+1/2);
! fr - the right side state reconstructed for location (i+1/2);
!
!===============================================================================
!
subroutine reconstruct(h, f, fl, fr)
! local variables are not implicit by default
!
implicit none
! subroutine arguments
!
real(kind=8) , intent(in) :: h
real(kind=8), dimension(:), intent(in) :: f
real(kind=8), dimension(:), intent(out) :: fl, fr
!
!-------------------------------------------------------------------------------
!
#ifdef PROFILE
! start accounting time for reconstruction
!
call start_timer(imr)
#endif /* PROFILE */
! reconstruct the states using the selected subroutine
!
call reconstruct_states(h, f(:), fl(:), fr(:))
! correct the reconstruction near extrema by clipping them in order to improve
! the stability of scheme
!
if (clip) call clip_extrema(f(:), fl(:), fr(:))
#ifdef PROFILE
! stop accounting time for reconstruction
!
call stop_timer(imr)
#endif /* PROFILE */
!-------------------------------------------------------------------------------
!
end subroutine reconstruct
!
!===============================================================================
!
! subroutine RECONSTRUCT_TVD:
! --------------------------
!
! Subroutine reconstructs the interface states using the second order TVD
! method with a selected limiter.
!
! Arguments are described in subroutine reconstruct().
!
!
!===============================================================================
!
subroutine reconstruct_tvd(h, fc, fl, fr)
! local variables are not implicit by default
!
implicit none
! subroutine arguments
!
real(kind=8) , intent(in) :: h
real(kind=8), dimension(:), intent(in) :: fc
real(kind=8), dimension(:), intent(out) :: fl, fr
! local variables
!
integer :: n, i, im1, ip1
real(kind=8) :: df, dfl, dfr
!
!-------------------------------------------------------------------------------
!
! get the input vector length
!
n = size(fc)
! calculate the left- and right-side interface interpolations
!
do i = 2, n - 1
! calculate left and right indices
!
im1 = i - 1
ip1 = i + 1
! calculate left and right side derivatives
!
dfl = fc(i ) - fc(im1)
dfr = fc(ip1) - fc(i )
! obtain the TVD limited derivative
!
df = limiter_tvd(0.5d+00, dfl, dfr)
! update the left and right-side interpolation states
!
fl(i ) = fc(i) + df
fr(im1) = fc(i) - df
end do ! i = 2, n - 1
! update the interpolation of the first and last points
!
i = n - 1
fl(1) = 0.5d+00 * (fc(1) + fc(2))
fr(i) = 0.5d+00 * (fc(i) + fc(n))
fl(n) = fc(n)
fr(n) = fc(n)
!-------------------------------------------------------------------------------
!
end subroutine reconstruct_tvd
!
!===============================================================================
!
! subroutine RECONSTRUCT_WENO3:
! ----------------------------
!
! Subroutine reconstructs the interface states using the third order
! Weighted Essentially Non-Oscillatory (WENO) method.
!
! Arguments are described in subroutine reconstruct().
!
! References:
!
! [1] Yamaleev & Carpenter, 2009, J. Comput. Phys., 228, 3025
!
!===============================================================================
!
subroutine reconstruct_weno3(h, fc, fl, fr)
! local variables are not implicit by default
!
implicit none
! subroutine arguments
!
real(kind=8) , intent(in) :: h
real(kind=8), dimension(:), intent(in) :: fc
real(kind=8), dimension(:), intent(out) :: fl, fr
! local variables
!
integer :: n, i, im1, ip1
real(kind=8) :: bp, bm, ap, am, wp, wm, ww
real(kind=8) :: dfl, dfr, fp, fm, h2
! selection weights
!
real(kind=8), parameter :: dp = 2.0d+00 / 3.0d+00, dm = 1.0d+00 / 3.0d+00
!
!-------------------------------------------------------------------------------
!
! get the input vector length
!
n = size(fc)
! prepare common parameters
!
h2 = h * h
! iterate along the vector
!
do i = 2, n - 1
! prepare neighbour indices
!
im1 = i - 1
ip1 = i + 1
! calculate the left and right derivatives
!
dfl = fc(i ) - fc(im1)
dfr = fc(ip1) - fc(i )
! calculate coefficient omega
!
ww = (dfr - dfl)**2
! calculate corresponding betas
!
bp = dfr * dfr
bm = dfl * dfl
! calculate improved alphas
!
ap = 1.0d+00 + ww / (bp + h2)
am = 1.0d+00 + ww / (bm + h2)
! calculate weights
!
wp = dp * ap
wm = dm * am
ww = 2.0d+00 * (wp + wm)
! calculate central interpolation
!
fp = fc(i ) + fc(ip1)
! calculate left side interpolation
!
fm = - fc(im1) + 3.0d+00 * fc(i )
! calculate the left state
!
fl( i ) = (wp * fp + wm * fm) / ww
! calculate weights
!
wp = dp * am
wm = dm * ap
ww = 2.0d+00 * (wp + wm)
! calculate central interpolation
!
fp = fc(i ) + fc(im1)
! calculate right side interpolation
!
fm = - fc(ip1) + 3.0d+00 * fc(i )
! calculate the right state
!
fr(im1) = (wp * fp + wm * fm) / ww
end do ! i = 2, n - 1
! update the interpolation of the first and last points
!
i = n - 1
fl(1) = 0.5d+00 * (fc(1) + fc(2))
fr(i) = 0.5d+00 * (fc(i) + fc(n))
fl(n) = fc(n)
fr(n) = fc(n)
!-------------------------------------------------------------------------------
!
end subroutine reconstruct_weno3
!
!===============================================================================
!
! subroutine RECONSTRUCT_LIMO3:
! ----------------------------
!
! Subroutine reconstructs the interface states using the third order method
! with a limiter function LimO3.
!
! Arguments are described in subroutine reconstruct().
!
! References:
!
! [1] Cada, M. & Torrilhon, M.,
! "Compact third-order limiter functions for finite volume methods",
! Journal of Computational Physics, 2009, 228, 4118-4145
! [2] Mignone, A., Tzeferacos, P., & Bodo, G.,
! "High-order conservative finite divergence GLM-MHD schemes for
! cell-centered MHD",
! Journal of Computational Physics, 2010, 229, 5896-5920
!
!===============================================================================
!
subroutine reconstruct_limo3(h, fc, fl, fr)
! local variables are not implicit by default
!
implicit none
! subroutine arguments
!
real(kind=8) , intent(in) :: h
real(kind=8), dimension(:), intent(in) :: fc
real(kind=8), dimension(:), intent(out) :: fl, fr
! local variables
!
integer :: n, i, im1, ip1
real(kind=8) :: dfl, dfr
real(kind=8) :: th, et, f1, f2, xl, xi, rdx, rdx2
!
!-------------------------------------------------------------------------------
!
! get the input vector length
!
n = size(fc)
! prepare parameters
!
rdx = rad * h
rdx2 = rdx * rdx
! iterate over positions and interpolate states
!
do i = 2, n - 1
! prepare neighbour indices
!
im1 = i - 1
ip1 = i + 1
! prepare left and right differences
!
dfl = fc(i ) - fc(im1)
dfr = fc(ip1) - fc(i )
! calculate the indicator function (eq. 3.17 in [1])
!
et = (dfl * dfl + dfr * dfr) / rdx2
! the switching function (embedded in eq. 3.22 in [1], eq. 32 in [2])
!
xi = max(0.0d+00, 0.5d+00 * min(2.0d+00, 1.0d+00 + (et - 1.0d+00) / eps))
xl = 1.0d+00 - xi
! calculate values at i + ½
!
if (abs(dfr) > eps) then
! calculate the slope ratio (eq. 2.8 in [1])
!
th = dfl / dfr
! calculate the quadratic reconstruction (eq. 3.8 in [1], divided by 2)
!
f1 = (2.0d+00 + th) / 6.0d+00
! calculate the third order limiter (eq. 3.13 in [1], cofficients divided by 2)
!
if (th >= 0.0d+00) then
f2 = max(0.0d+00, min(f1, th, 0.8d+00))
else
f2 = max(0.0d+00, min(f1, - 0.25d+00 * th))
end if
! interpolate the left state (eq. 3.5 in [1], eq. 30 in [2])
!
fl(i) = fc(i) + dfr * (xl * f1 + xi * f2)
else
fl(i) = fc(i)
end if
! calculate values at i - ½
!
if (abs(dfl) > eps) then
! calculate the slope ratio (eq. 2.8 in [1])
!
th = dfr / dfl
! calculate the quadratic reconstruction (eq. 3.8 in [1], divided by 2)
!
f1 = (2.0d+00 + th) / 6.0d+00
! calculate the third order limiter (eq. 3.13 in [1], cofficients divided by 2)
!
if (th >= 0.0d+00) then
f2 = max(0.0d+00, min(f1, th, 0.8d+00))
else
f2 = max(0.0d+00, min(f1, - 0.25d+00 * th))
end if
! interpolate the right state (eq. 3.5 in [1], eq. 30 in [2])
!
fr(im1) = fc(i) - dfl * (xl * f1 + xi * f2)
else
fr(im1) = fc(i)
end if
end do ! i = 2, n - 1
! update the interpolation of the first and last points
!
i = n - 1
fl(1) = 0.5d+00 * (fc(1) + fc(2))
fr(i) = 0.5d+00 * (fc(i) + fc(n))
fl(n) = fc(n)
fr(n) = fc(n)
!-------------------------------------------------------------------------------
!
end subroutine reconstruct_limo3
!
!===============================================================================
!
! subroutine RECONSTRUCT_PPM:
! --------------------------
!
! Subroutine reconstructs the interface states using the third order
! Piecewise Parabolic Method (PPM) with new limiters. This version lacks
! the support for flattening important for keeping the spurious oscillations
! near strong shocks/discontinuties under control.
!
! Arguments are described in subroutine reconstruct().
!
! References:
!
! [1] Colella, P., Woodward, P. R.,
! "The Piecewise Parabolic Method (PPM) for Gas-Dynamical Simulations",
! Journal of Computational Physics, 1984, vol. 54, pp. 174-201,
! https://dx.doi.org/10.1016/0021-9991(84)90143-8
! [2] Colella, P., Sekora, M. D.,
! "A limiter for PPM that preserves accuracy at smooth extrema",
! Journal of Computational Physics, 2008, vol. 227, pp. 7069-7076,
! https://doi.org/10.1016/j.jcp.2008.03.034
!
!===============================================================================
!
subroutine reconstruct_ppm(h, fc, fl, fr)
! local variables are not implicit by default
!
implicit none
! subroutine arguments
!
real(kind=8) , intent(in) :: h
real(kind=8), dimension(:), intent(in) :: fc
real(kind=8), dimension(:), intent(out) :: fl, fr
! local variables
!
logical :: cm, cp, ext
integer :: n, i, im1, ip1, im2
real(kind=8) :: df2c, df2m, df2p, df2s, df2l
real(kind=8) :: dfm, dfp, dcm, dcp
real(kind=8) :: alm, alp, amx, sgn, del
! local arrays
!
real(kind=8), dimension(size(fc)) :: fi, df2
!
!-------------------------------------------------------------------------------
!
! get the input vector length
!
n = size(fc)
! calculate the high-order interface interpolation; eq. (16) in [2]
!
fi(1 ) = 5.0d-01 * (fc(1) + fc(2))
do i = 2, n - 2
fi(i) = (7.0d+00 * (fc(i) + fc(i+1)) - (fc(i-1) + fc(i+2))) / 1.2d+01
end do
fi(n-1) = 5.0d-01 * (fc(n-1) + fc(n))
fi(n ) = fc(n)
! calculate second-order central derivative
!
df2(1) = 0.0d+00
do i = 2, n - 1
df2(i) = (fc(i+1) + fc(i-1)) - 2.0d+00 * fc(i)
end do
df2(n) = 0.0d+00
! limit the interpolation; eqs. (18) and (19) in [2]
!
do i = 2, n - 2
im1 = i - 1
ip1 = i + 1
if ((fc(ip1) - fi(i)) * (fi(i) - fc(i)) < 0.0d+00) then
df2c = 3.0d+00 * ((fc(ip1) + fc(i )) - 2.0d+00 * fi(i))
df2m = df2(i )
df2p = df2(ip1)
if (min(df2c, df2m, df2p) * max(df2c, df2m, df2p) > 0.0d+00) then
df2l = sign(min(ppm_const * min(abs(df2m), abs(df2p)), abs(df2c)), df2c)
else
df2l = 0.0d+00
end if
fi(i) = 5.0d-01 * (fc(i) + fc(ip1)) - df2l / 6.0d+00
end if
end do
! iterate along the vector
!
do i = 2, n - 1
im1 = i - 1
ip1 = i + 1
! limit states if local extremum is detected or the interpolation is not
! monotone
!
alm = fi(im1) - fc(i)
alp = fi(i ) - fc(i)
cm = abs(alm) >= 2.0d+00 * abs(alp)
cp = abs(alp) >= 2.0d+00 * abs(alm)
ext = .false.
! check if we have local extremum here
!
if (alm * alp > 0.0d+00) then
ext = .true.
else if (cm .or. cp) then
im2 = max(1, i - 1)
dfm = fi(im1) - fi(im2)
dfp = fi(ip1) - fi(i )
dcm = fc(i ) - fc(im1)
dcp = fc(ip1) - fc(i )
if (min(abs(dfm),abs(dfp)) >= min(abs(dcm),abs(dcp))) then
ext = dfm * dfp < 0.0d+00
else
ext = dcm * dcp < 0.0d+00
end if
end if
! limit states if the local extremum is detected
!
if (ext) then
df2s = 6.0d+00 * (alm + alp)
df2m = df2(im1)
df2c = df2(i )
df2p = df2(ip1)
if (min(df2s, df2c, df2m, df2p) &
* max(df2s, df2c, df2m, df2p) > 0.0d+00) then
df2l = sign(min(ppm_const * min(abs(df2m), abs(df2c), abs(df2p)) &
, abs(df2s)), df2s)
if (abs(df2l) > 0.0d+00) then
alm = alm * df2l / df2s
alp = alp * df2l / df2s
else
alm = 0.0d+00
alp = 0.0d+00
end if
else
alm = 0.0d+00
alp = 0.0d+00
end if
else
! the interpolation is not monotonic so apply additional limiter
!
if (cp) then
sgn = sign(1.0d+00, alp)
amx = - 2.5d-01 * alp**2 / (alp + alm)
dfp = fc(ip1) - fc(i)
if (sgn * amx >= sgn * dfp) then
del = dfp * (dfp - alm)
if (del >= 0.0d+00) then
alp = - 2.0d+00 * (dfp + sgn * sqrt(del))
else
alp = - 2.0d+00 * alm
end if
end if
end if
if (cm) then
sgn = sign(1.0d+00, alm)
amx = - 2.5d-01 * alm**2 / (alp + alm)
dfm = fc(im1) - fc(i)
if (sgn * amx >= sgn * dfm) then
del = dfm * (dfm - alp)
if (del >= 0.0d+00) then
alm = - 2.0d+00 * (dfm + sgn * sqrt(del))
else
alm = - 2.0d+00 * alp
end if
end if
end if
end if
! update the states
!
fr(im1) = fc(i) + alm
fl(i ) = fc(i) + alp
end do ! i = 2, n
! update the interpolation of the first and last points
!
fl(1 ) = fi(1)
fr(n-1) = fi(n)
fl(n ) = fi(n)
fr(n ) = fc(n)
!-------------------------------------------------------------------------------
!
end subroutine reconstruct_ppm
!
!===============================================================================
!
! subroutine RECONSTRUCT_WENO5Z:
! -----------------------------
!
! Subroutine reconstructs the interface states using the fifth order
! Explicit Weighted Essentially Non-Oscillatory (WENO5) method with
! stencil weights by Borges et al. (2008).
!
! Arguments are described in subroutine reconstruct().
!
! References:
!
! [1] Borges, R., Carmona, M., Costa, B., & Don, W.-S.,
! "An improved weighted essentially non-oscillatory scheme for
! hyperbolic conservation laws"
! Journal of Computational Physics,
! 2008, vol. 227, pp. 3191-3211,
! http://dx.doi.org/10.1016/j.jcp.2007.11.038
!
!===============================================================================
!
subroutine reconstruct_weno5z(h, fc, fl, fr)
! local variables are not implicit by default
!
implicit none
! subroutine arguments
!
real(kind=8) , intent(in) :: h
real(kind=8), dimension(:), intent(in) :: fc
real(kind=8), dimension(:), intent(out) :: fl, fr
! local variables
!
integer :: n, i, im1, ip1, im2, ip2
real(kind=8) :: bl, bc, br, tt, df
real(kind=8) :: al, ac, ar
real(kind=8) :: wl, wc, wr, ww
real(kind=8) :: ql, qc, qr
! local arrays for derivatives
!
real(kind=8), dimension(size(fc)) :: dfm, dfp, df2
! smoothness indicator coefficients
!
real(kind=8), parameter :: c1 = 1.3d+01 / 1.2d+01, c2 = 2.5d-01
! weight coefficients
!
real(kind=8), parameter :: dl = 1.0d-01, dc = 6.0d-01, dr = 3.0d-01
! interpolation coefficients
!
real(kind=8), parameter :: a11 = 2.0d+00 / 6.0d+00 &
, a12 = - 7.0d+00 / 6.0d+00 &
, a13 = 1.1d+01 / 6.0d+00
real(kind=8), parameter :: a21 = - 1.0d+00 / 6.0d+00 &
, a22 = 5.0d+00 / 6.0d+00 &
, a23 = 2.0d+00 / 6.0d+00
real(kind=8), parameter :: a31 = 2.0d+00 / 6.0d+00 &
, a32 = 5.0d+00 / 6.0d+00 &
, a33 = - 1.0d+00 / 6.0d+00
!
!-------------------------------------------------------------------------------
!
! get the input vector length
!
n = size(fc)
! calculate the left and right derivatives
!
do i = 1, n - 1
ip1 = i + 1
dfp(i ) = fc(ip1) - fc(i)
dfm(ip1) = dfp(i)
end do
dfm(1) = dfp(1)
dfp(n) = dfm(n)
! calculate the absolute value of the second derivative
!
df2(:) = c1 * (dfp(:) - dfm(:))**2
! iterate along the vector
!
do i = 3, n - 2
! prepare neighbour indices
!
im2 = i - 2
im1 = i - 1
ip1 = i + 1
ip2 = i + 2
! calculate βₖ (eqs. 9-11 in [1])
!
bl = df2(im1) + c2 * (3.0d+00 * dfm(i ) - dfm(im1))**2
bc = df2(i ) + c2 * ( dfp(i ) + dfm(i ))**2
br = df2(ip1) + c2 * (3.0d+00 * dfp(i ) - dfp(ip1))**2
! calculate τ (below eq. 25 in [1])
!
tt = abs(br - bl)
! calculate αₖ (eq. 28 in [1])
!
al = 1.0d+00 + tt / (bl + eps)
ac = 1.0d+00 + tt / (bc + eps)
ar = 1.0d+00 + tt / (br + eps)
! calculate weights
!
wl = dl * al
wc = dc * ac
wr = dr * ar
ww = (wl + wr) + wc
wl = wl / ww
wr = wr / ww
wc = 1.0d+00 - (wl + wr)
! calculate the interpolations of the left state
!
ql = a11 * fc(im2) + a12 * fc(im1) + a13 * fc(i )
qc = a21 * fc(im1) + a22 * fc(i ) + a23 * fc(ip1)
qr = a31 * fc(i ) + a32 * fc(ip1) + a33 * fc(ip2)
! calculate the left state
!
fl(i ) = (wl * ql + wr * qr) + wc * qc
! normalize weights
!
wl = dl * ar
wc = dc * ac
wr = dr * al
ww = (wl + wr) + wc
wl = wl / ww
wr = wr / ww
wc = 1.0d+00 - (wl + wr)
! calculate the interpolations of the right state
!
ql = a11 * fc(ip2) + a12 * fc(ip1) + a13 * fc(i )
qc = a21 * fc(ip1) + a22 * fc(i ) + a23 * fc(im1)
qr = a31 * fc(i ) + a32 * fc(im1) + a33 * fc(im2)
! calculate the right state
!
fr(im1) = (wl * ql + wr * qr) + wc * qc
end do ! i = 3, n - 2
! update the interpolation of the first and last two points
!
fl(1) = 0.5d+00 * (fc(1) + fc(2))
df = limiter_tvd(0.5d+00, dfm(2), dfp(2))
fr(1) = fc(2) - df
fl(2) = fc(2) + df
i = n - 1
df = limiter_tvd(0.5d+00, dfm(i), dfp(i))
fr(i-1) = fc(i) - df
fl(i) = fc(i) + df
fr(i) = 0.5d+00 * (fc(i) + fc(n))
fl(n) = fc(n)
fr(n) = fc(n)
!-------------------------------------------------------------------------------
!
end subroutine reconstruct_weno5z
!
!===============================================================================
!
! subroutine RECONSTRUCT_WENO5YC:
! ------------------------------
!
! Subroutine reconstructs the interface states using the fifth order
! Explicit Weighted Essentially Non-Oscillatory (WENO5) method with
! stencil weights by Yamaleev & Carpenter (2009).
!
! Arguments are described in subroutine reconstruct().
!
! References:
!
! [1] Yamaleev, N. K. & Carpenter, H. C.,
! "A Systematic Methodology for Constructing High-Order Energy Stable
! WENO Schemes"
! Journal of Computational Physics,
! 2009, vol. 228, pp. 4248-4272,
! http://dx.doi.org/10.1016/j.jcp.2009.03.002
!
!===============================================================================
!
subroutine reconstruct_weno5yc(h, fc, fl, fr)
! local variables are not implicit by default
!
implicit none
! subroutine arguments
!
real(kind=8) , intent(in) :: h
real(kind=8), dimension(:), intent(in) :: fc
real(kind=8), dimension(:), intent(out) :: fl, fr
! local variables
!
integer :: n, i, im1, ip1, im2, ip2
real(kind=8) :: bl, bc, br, tt, df
real(kind=8) :: al, ac, ar
real(kind=8) :: wl, wc, wr, ww
real(kind=8) :: ql, qc, qr
! local arrays for derivatives
!
real(kind=8), dimension(size(fc)) :: dfm, dfp, df2
! smoothness indicator coefficients
!
real(kind=8), parameter :: c1 = 1.3d+01 / 1.2d+01, c2 = 2.5d-01
! weight coefficients
!
real(kind=8), parameter :: dl = 1.0d-01, dc = 6.0d-01, dr = 3.0d-01
! interpolation coefficients
!
real(kind=8), parameter :: a11 = 2.0d+00 / 6.0d+00 &
, a12 = - 7.0d+00 / 6.0d+00 &
, a13 = 1.1d+01 / 6.0d+00
real(kind=8), parameter :: a21 = - 1.0d+00 / 6.0d+00 &
, a22 = 5.0d+00 / 6.0d+00 &
, a23 = 2.0d+00 / 6.0d+00
real(kind=8), parameter :: a31 = 2.0d+00 / 6.0d+00 &
, a32 = 5.0d+00 / 6.0d+00 &
, a33 = - 1.0d+00 / 6.0d+00
!
!-------------------------------------------------------------------------------
!
! get the input vector length
!
n = size(fc)
! calculate the left and right derivatives
!
do i = 1, n - 1
ip1 = i + 1
dfp(i ) = fc(ip1) - fc(i)
dfm(ip1) = dfp(i)
end do
dfm(1) = dfp(1)
dfp(n) = dfm(n)
! calculate the absolute value of the second derivative
!
df2(:) = c1 * (dfp(:) - dfm(:))**2
! iterate along the vector
!
do i = 3, n - 2
! prepare neighbour indices
!
im2 = i - 2
im1 = i - 1
ip1 = i + 1
ip2 = i + 2
! calculate βₖ (eq. 19 in [1])
!
bl = df2(im1) + c2 * (3.0d+00 * dfm(i ) - dfm(im1))**2
bc = df2(i ) + c2 * ( dfp(i ) + dfm(i ))**2
br = df2(ip1) + c2 * (3.0d+00 * dfp(i ) - dfp(ip1))**2
! calculate τ (below eq. 20 in [1])
!
tt = (6.0d+00 * fc(i) - 4.0d+00 * (fc(im1) + fc(ip1)) &
+ (fc(im2) + fc(ip2)))**2
! calculate αₖ (eqs. 18 or 58 in [1])
!
al = 1.0d+00 + tt / (bl + eps)
ac = 1.0d+00 + tt / (bc + eps)
ar = 1.0d+00 + tt / (br + eps)
! calculate weights
!
wl = dl * al
wc = dc * ac
wr = dr * ar
ww = (wl + wr) + wc
wl = wl / ww
wr = wr / ww
wc = 1.0d+00 - (wl + wr)
! calculate the interpolations of the left state
!
ql = a11 * fc(im2) + a12 * fc(im1) + a13 * fc(i )
qc = a21 * fc(im1) + a22 * fc(i ) + a23 * fc(ip1)
qr = a31 * fc(i ) + a32 * fc(ip1) + a33 * fc(ip2)
! calculate the left state
!
fl(i ) = (wl * ql + wr * qr) + wc * qc
! normalize weights
!
wl = dl * ar
wc = dc * ac
wr = dr * al
ww = (wl + wr) + wc
wl = wl / ww
wr = wr / ww
wc = 1.0d+00 - (wl + wr)
! calculate the interpolations of the right state
!
ql = a11 * fc(ip2) + a12 * fc(ip1) + a13 * fc(i )
qc = a21 * fc(ip1) + a22 * fc(i ) + a23 * fc(im1)
qr = a31 * fc(i ) + a32 * fc(im1) + a33 * fc(im2)
! calculate the right state
!
fr(im1) = (wl * ql + wr * qr) + wc * qc
end do ! i = 3, n - 2
! update the interpolation of the first and last two points
!
fl(1) = 0.5d+00 * (fc(1) + fc(2))
df = limiter_tvd(0.5d+00, dfm(2), dfp(2))
fr(1) = fc(2) - df
fl(2) = fc(2) + df
i = n - 1
df = limiter_tvd(0.5d+00, dfm(i), dfp(i))
fr(i-1) = fc(i) - df
fl(i) = fc(i) + df
fr(i) = 0.5d+00 * (fc(i) + fc(n))
fl(n) = fc(n)
fr(n) = fc(n)
!-------------------------------------------------------------------------------
!
end subroutine reconstruct_weno5yc
!
!===============================================================================
!
! subroutine RECONSTRUCT_WENO5NS:
! ------------------------------
!
! Subroutine reconstructs the interface states using the fifth order
! Explicit Weighted Essentially Non-Oscillatory (WENO5) method with new
! smoothness indicators and stencil weights by Ha et al. (2013).
!
! Arguments are described in subroutine reconstruct().
!
! References:
!
! [1] Ha, Y., Kim, C. H., Lee, Y. J., & Yoon, J.,
! "An improved weighted essentially non-oscillatory scheme with a new
! smoothness indicator",
! Journal of Computational Physics,
! 2013, vol. 232, pp. 68-86
! http://dx.doi.org/10.1016/j.jcp.2012.06.016
!
!===============================================================================
!
subroutine reconstruct_weno5ns(h, fc, fl, fr)
! local variables are not implicit by default
!
implicit none
! subroutine arguments
!
real(kind=8) , intent(in) :: h
real(kind=8), dimension(:), intent(in) :: fc
real(kind=8), dimension(:), intent(out) :: fl, fr
! local variables
!
integer :: n, i, im1, ip1, im2, ip2
real(kind=8) :: bl, bc, br
real(kind=8) :: al, ac, ar, aa
real(kind=8) :: wl, wc, wr
real(kind=8) :: df, lq, l3, zt
real(kind=8) :: ql, qc, qr
! local arrays for derivatives
!
real(kind=8), dimension(size(fc)) :: dfm, dfp, df2
! weight coefficients
!
real(kind=8), parameter :: dl = 1.0d-01, dc = 6.0d-01, dr = 3.0d-01
! interpolation coefficients
!
real(kind=8), parameter :: a11 = 2.0d+00 / 6.0d+00 &
, a12 = - 7.0d+00 / 6.0d+00 &
, a13 = 1.1d+01 / 6.0d+00
real(kind=8), parameter :: a21 = - 1.0d+00 / 6.0d+00 &
, a22 = 5.0d+00 / 6.0d+00 &
, a23 = 2.0d+00 / 6.0d+00
real(kind=8), parameter :: a31 = 2.0d+00 / 6.0d+00 &
, a32 = 5.0d+00 / 6.0d+00 &
, a33 = - 1.0d+00 / 6.0d+00
! the free parameter for smoothness indicators (see Eq. 3.6 in [1])
!
real(kind=8), parameter :: xi = 4.0d-01
!
!-------------------------------------------------------------------------------
!
! get the input vector length
!
n = size(fc)
! calculate the left and right derivatives
!
do i = 1, n - 1
ip1 = i + 1
dfp(i ) = fc(ip1) - fc(i)
dfm(ip1) = dfp(i)
end do
dfm(1) = dfp(1)
dfp(n) = dfm(n)
! calculate the absolute value of the second derivative
!
df2(:) = 0.5d+00 * abs(dfp(:) - dfm(:))
! iterate along the vector
!
do i = 3, n - 2
! prepare neighbour indices
!
im2 = i - 2
im1 = i - 1
ip1 = i + 1
ip2 = i + 2
! calculate βₖ (eq. 3.6 in [1])
!
df = abs(dfp(i))
lq = xi * df
bl = df2(im1) + xi * abs(2.0d+00 * dfm(i) - dfm(im1))
bc = df2(i ) + lq
br = df2(ip1) + lq
! calculate ζ (below eq. 3.6 in [1])
!
l3 = df**3
zt = 0.5d+00 * ((bl - br)**2 + (l3 / (1.0d+00 + l3))**2)
! calculate αₖ (eq. 3.9 in [4])
!
al = dl * (1.0d+00 + zt / (bl + eps)**2)
ac = dc * (1.0d+00 + zt / (bc + eps)**2)
ar = dr * (1.0d+00 + zt / (br + eps)**2)
! calculate weights
!
aa = (al + ar) + ac
wl = al / aa
wr = ar / aa
wc = 1.0d+00 - (wl + wr)
! calculate the interpolations of the left state
!
ql = a11 * fc(im2) + a12 * fc(im1) + a13 * fc(i )
qc = a21 * fc(im1) + a22 * fc(i ) + a23 * fc(ip1)
qr = a31 * fc(i ) + a32 * fc(ip1) + a33 * fc(ip2)
! calculate the left state
!
fl(i ) = (wl * ql + wr * qr) + wc * qc
! calculate βₖ (eq. 3.6 in [1])
!
df = abs(dfm(i))
lq = xi * df
bl = df2(ip1) + xi * abs(2.0d+00 * dfp(i) - dfp(ip1))
bc = df2(i ) + lq
br = df2(im1) + lq
! calculate ζ (below eq. 3.6 in [1])
l3 = df**3
zt = 0.5d+00 * ((bl - br)**2 + (l3 / (1.0d+00 + l3))**2)
! calculate αₖ (eq. 3.9 in [4])
!
al = dl * (1.0d+00 + zt / (bl + eps)**2)
ac = dc * (1.0d+00 + zt / (bc + eps)**2)
ar = dr * (1.0d+00 + zt / (br + eps)**2)
! normalize weights
!
aa = (al + ar) + ac
wl = al / aa
wr = ar / aa
wc = 1.0d+00 - (wl + wr)
! calculate the interpolations of the right state
!
ql = a11 * fc(ip2) + a12 * fc(ip1) + a13 * fc(i )
qc = a21 * fc(ip1) + a22 * fc(i ) + a23 * fc(im1)
qr = a31 * fc(i ) + a32 * fc(im1) + a33 * fc(im2)
! calculate the right state
!
fr(im1) = (wl * ql + wr * qr) + wc * qc
end do ! i = 3, n - 2
! update the interpolation of the first and last two points
!
fl(1) = 0.5d+00 * (fc(1) + fc(2))
df = limiter_tvd(0.5d+00, dfm(2), dfp(2))
fr(1) = fc(2) - df
fl(2) = fc(2) + df
i = n - 1
df = limiter_tvd(0.5d+00, dfm(i), dfp(i))
fr(i-1) = fc(i) - df
fl(i) = fc(i) + df
fr(i) = 0.5d+00 * (fc(i) + fc(n))
fl(n) = fc(n)
fr(n) = fc(n)
!-------------------------------------------------------------------------------
!
end subroutine reconstruct_weno5ns
!
!===============================================================================
!
! subroutine RECONSTRUCT_CRWENO5Z:
! -------------------------------
!
! Subroutine reconstructs the interface states using the fifth order
! Compact-Reconstruction Weighted Essentially Non-Oscillatory (CRWENO)
! method and smoothness indicators by Borges et al. (2008).
!
! Arguments are described in subroutine reconstruct().
!
! References:
!
! [1] Ghosh, D. & Baeder, J. D.,
! "Compact Reconstruction Schemes with Weighted ENO Limiting for
! Hyperbolic Conservation Laws"
! SIAM Journal on Scientific Computing,
! 2012, vol. 34, no. 3, pp. A1678-A1706,
! http://dx.doi.org/10.1137/110857659
! [2] Ghosh, D. & Baeder, J. D.,
! "Weighted Non-linear Compact Schemes for the Direct Numerical
! Simulation of Compressible, Turbulent Flows"
! Journal on Scientific Computing,
! 2014,
! http://dx.doi.org/10.1007/s10915-014-9818-0
! [3] Borges, R., Carmona, M., Costa, B., & Don, W.-S.,
! "An improved weighted essentially non-oscillatory scheme for
! hyperbolic conservation laws"
! Journal of Computational Physics,
! 2008, vol. 227, pp. 3191-3211,
! http://dx.doi.org/10.1016/j.jcp.2007.11.038
!
!===============================================================================
!
subroutine reconstruct_crweno5z(h, fc, fl, fr)
! include external procedures
!
use algebra , only : tridiag
! local variables are not implicit by default
!
implicit none
! subroutine arguments
!
real(kind=8) , intent(in) :: h
real(kind=8), dimension(:), intent(in) :: fc
real(kind=8), dimension(:), intent(out) :: fl, fr
! local variables
!
integer :: n, i, im1, ip1, im2, ip2
real(kind=8) :: bl, bc, br, tt
real(kind=8) :: wl, wc, wr, ww
real(kind=8) :: ql, qc, qr
! local arrays for derivatives
!
real(kind=8), dimension(size(fc)) :: dfm, dfp, df2
real(kind=8), dimension(size(fc)) :: al, ac, ar
real(kind=8), dimension(size(fc)) :: u
real(kind=8), dimension(size(fc),2) :: a, b, c, r
! smoothness indicator coefficients
!
real(kind=8), parameter :: c1 = 1.3d+01 / 1.2d+01, c2 = 2.5d-01
! weight coefficients for implicit (c) and explicit (d) interpolations
!
real(kind=8), parameter :: cl = 1.0d+00 / 9.0d+00
real(kind=8), parameter :: cc = 5.0d+00 / 9.0d+00
real(kind=8), parameter :: cr = 1.0d+00 / 3.0d+00
real(kind=8), parameter :: dl = 1.0d-01, dc = 6.0d-01, dr = 3.0d-01
! implicit method coefficients
!
real(kind=8), parameter :: dq = 5.0d-01
! interpolation coefficients
!
real(kind=8), parameter :: a11 = 2.0d+00 / 6.0d+00 &
, a12 = - 7.0d+00 / 6.0d+00 &
, a13 = 1.1d+01 / 6.0d+00
real(kind=8), parameter :: a21 = - 1.0d+00 / 6.0d+00 &
, a22 = 5.0d+00 / 6.0d+00 &
, a23 = 2.0d+00 / 6.0d+00
real(kind=8), parameter :: a31 = 2.0d+00 / 6.0d+00 &
, a32 = 5.0d+00 / 6.0d+00 &
, a33 = - 1.0d+00 / 6.0d+00
!
!-------------------------------------------------------------------------------
!
! get the input vector length
!
n = size(fc)
! calculate the left and right derivatives
!
do i = 1, n - 1
ip1 = i + 1
dfp(i ) = fc(ip1) - fc(i)
dfm(ip1) = dfp(i)
end do
dfm(1) = dfp(1)
dfp(n) = dfm(n)
! calculate the absolute value of the second derivative
!
df2(:) = c1 * (dfp(:) - dfm(:))**2
! prepare smoothness indicators
!
do i = 2, n - 1
! prepare neighbour indices
!
im1 = i - 1
ip1 = i + 1
! calculate βₖ (eqs. 9-11 in [1])
!
bl = df2(im1) + c2 * (3.0d+00 * dfm(i ) - dfm(im1))**2
bc = df2(i ) + c2 * ( dfp(i ) + dfm(i ))**2
br = df2(ip1) + c2 * (3.0d+00 * dfp(i ) - dfp(ip1))**2
! calculate τ (below eq. 25 in [1])
!
tt = abs(br - bl)
! calculate αₖ (eq. 28 in [1])
!
al(i) = 1.0d+00 + tt / (bl + eps)
ac(i) = 1.0d+00 + tt / (bc + eps)
ar(i) = 1.0d+00 + tt / (br + eps)
end do ! i = 2, n - 1
! prepare tridiagonal system coefficients
!
do i = ng, n - ng + 1
! prepare neighbour indices
!
im1 = i - 1
ip1 = i + 1
! calculate weights
!
wl = cl * al(i)
wc = cc * ac(i)
wr = cr * ar(i)
ww = (wl + wr) + wc
wl = wl / ww
wr = wr / ww
wc = 1.0d+00 - (wl + wr)
! calculate tridiagonal matrix coefficients
!
a(i,1) = 2.0d+00 * wl + wc
b(i,1) = wl + 2.0d+00 * (wc + wr)
c(i,1) = wr
! prepare right hand side of tridiagonal equation
!
r(i,1) = (wl * fc(im1) + (5.0d+00 * (wl + wc) + wr) * fc(i ) &
+ (wc + 5.0d+00 * wr) * fc(ip1)) * dq
! calculate weights
!
wl = cl * ar(i)
wc = cc * ac(i)
wr = cr * al(i)
ww = (wl + wr) + wc
wl = wl / ww
wr = wr / ww
wc = 1.0d+00 - (wl + wr)
! calculate tridiagonal matrix coefficients
!
a(i,2) = wr
b(i,2) = wl + 2.0d+00 * (wc + wr)
c(i,2) = 2.0d+00 * wl + wc
! prepare right hand side of tridiagonal equation
!
r(i,2) = (wl * fc(ip1) + (5.0d+00 * (wl + wc) + wr) * fc(i ) &
+ (wc + 5.0d+00 * wr) * fc(im1)) * dq
end do ! i = ng, n - ng + 1
! interpolate ghost zones using explicit solver (left-side reconstruction)
!
do i = 2, ng
! prepare neighbour indices
!
im2 = max(1, i - 2)
im1 = i - 1
ip1 = i + 1
ip2 = i + 2
! calculate weights
!
wl = dl * al(i)
wc = dc * ac(i)
wr = dr * ar(i)
ww = (wl + wr) + wc
wl = wl / ww
wr = wr / ww
wc = 1.0d+00 - (wl + wr)
! calculate the interpolations of the left state
!
ql = a11 * fc(im2) + a12 * fc(im1) + a13 * fc(i )
qc = a21 * fc(im1) + a22 * fc(i ) + a23 * fc(ip1)
qr = a31 * fc(i ) + a32 * fc(ip1) + a33 * fc(ip2)
! calculate the left state
!
fl(i) = (wl * ql + wr * qr) + wc * qc
! prepare coefficients of the tridiagonal system
!
a(i,1) = 0.0d+00
b(i,1) = 1.0d+00
c(i,1) = 0.0d+00
r(i,1) = fl(i)
end do ! i = 2, ng
a(1,1) = 0.0d+00
b(1,1) = 1.0d+00
c(1,1) = 0.0d+00
r(1,1) = 0.5d+00 * (fc(1) + fc(2))
! interpolate ghost zones using explicit solver (left-side reconstruction)
!
do i = n - ng, n - 1
! prepare neighbour indices
!
im2 = i - 2
im1 = i - 1
ip1 = i + 1
ip2 = min(n, i + 2)
! calculate weights
!
wl = dl * al(i)
wc = dc * ac(i)
wr = dr * ar(i)
ww = (wl + wr) + wc
wl = wl / ww
wr = wr / ww
wc = 1.0d+00 - (wl + wr)
! calculate the interpolations of the left state
!
ql = a11 * fc(im2) + a12 * fc(im1) + a13 * fc(i )
qc = a21 * fc(im1) + a22 * fc(i ) + a23 * fc(ip1)
qr = a31 * fc(i ) + a32 * fc(ip1) + a33 * fc(ip2)
! calculate the left state
!
fl(i) = (wl * ql + wr * qr) + wc * qc
! prepare coefficients of the tridiagonal system
!
a(i,1) = 0.0d+00
b(i,1) = 1.0d+00
c(i,1) = 0.0d+00
r(i,1) = fl(i)
end do ! i = n - ng, n - 1
a(n,1) = 0.0d+00
b(n,1) = 1.0d+00
c(n,1) = 0.0d+00
r(n,1) = fc(n)
! interpolate ghost zones using explicit solver (right-side reconstruction)
!
do i = 2, ng + 1
! prepare neighbour indices
!
im2 = max(1, i - 2)
im1 = i - 1
ip1 = i + 1
ip2 = i + 2
! normalize weights
!
wl = dl * ar(i)
wc = dc * ac(i)
wr = dr * al(i)
ww = (wl + wr) + wc
wl = wl / ww
wr = wr / ww
wc = 1.0d+00 - (wl + wr)
! calculate the interpolations of the right state
!
ql = a11 * fc(ip2) + a12 * fc(ip1) + a13 * fc(i )
qc = a21 * fc(ip1) + a22 * fc(i ) + a23 * fc(im1)
qr = a31 * fc(i ) + a32 * fc(im1) + a33 * fc(im2)
! calculate the right state
!
fr(i) = (wl * ql + wr * qr) + wc * qc
! prepare coefficients of the tridiagonal system
!
a(i,2) = 0.0d+00
b(i,2) = 1.0d+00
c(i,2) = 0.0d+00
r(i,2) = fr(i)
end do ! i = 2, ng + 1
a(1,2) = 0.0d+00
b(1,2) = 1.0d+00
c(1,2) = 0.0d+00
r(1,2) = fc(1)
! interpolate ghost zones using explicit solver (right-side reconstruction)
!
do i = n - ng + 1, n - 1
! prepare neighbour indices
!
im2 = max(1, i - 2)
im1 = max(1, i - 1)
ip1 = min(n, i + 1)
ip2 = min(n, i + 2)
! normalize weights
!
wl = dl * ar(i)
wc = dc * ac(i)
wr = dr * al(i)
ww = (wl + wr) + wc
wl = wl / ww
wr = wr / ww
wc = 1.0d+00 - (wl + wr)
! calculate the interpolations of the right state
!
ql = a11 * fc(ip2) + a12 * fc(ip1) + a13 * fc(i )
qc = a21 * fc(ip1) + a22 * fc(i ) + a23 * fc(im1)
qr = a31 * fc(i ) + a32 * fc(im1) + a33 * fc(im2)
! calculate the right state
!
fr(i) = (wl * ql + wr * qr) + wc * qc
! prepare coefficients of the tridiagonal system
!
a(i,2) = 0.0d+00
b(i,2) = 1.0d+00
c(i,2) = 0.0d+00
r(i,2) = fr(i)
end do ! i = n - ng + 1, n - 1
a(n,2) = 0.0d+00
b(n,2) = 1.0d+00
c(n,2) = 0.0d+00
r(n,2) = 0.5d+00 * (fc(n-1) + fc(n))
! solve the tridiagonal system of equations for the left-side interpolation
!
call tridiag(n, a(1:n,1), b(1:n,1), c(1:n,1), r(1:n,1), u(1:n))
! substitute the left-side values
!
fl(1:n ) = u(1:n)
! solve the tridiagonal system of equations for the left-side interpolation
!
call tridiag(n, a(1:n,2), b(1:n,2), c(1:n,2), r(1:n,2), u(1:n))
! substitute the right-side values
!
fr(1:n-1) = u(2:n)
! update the interpolation of the first and last points
!
i = n - 1
fl(1) = 0.5d+00 * (fc(1) + fc(2))
fr(i) = 0.5d+00 * (fc(i) + fc(n))
fl(n) = fc(n)
fr(n) = fc(n)
!-------------------------------------------------------------------------------
!
end subroutine reconstruct_crweno5z
!
!===============================================================================
!
! subroutine RECONSTRUCT_CRWENO5YC:
! --------------------------------
!
! Subroutine reconstructs the interface states using the fifth order
! Compact-Reconstruction Weighted Essentially Non-Oscillatory (CRWENO)
! method and smoothness indicators by Yamaleev & Carpenter (2009).
!
! Arguments are described in subroutine reconstruct().
!
! References:
!
! [1] Ghosh, D. & Baeder, J. D.,
! "Compact Reconstruction Schemes with Weighted ENO Limiting for
! Hyperbolic Conservation Laws"
! SIAM Journal on Scientific Computing,
! 2012, vol. 34, no. 3, pp. A1678-A1706,
! http://dx.doi.org/10.1137/110857659
! [2] Ghosh, D. & Baeder, J. D.,
! "Weighted Non-linear Compact Schemes for the Direct Numerical
! Simulation of Compressible, Turbulent Flows"
! Journal on Scientific Computing,
! 2014,
! http://dx.doi.org/10.1007/s10915-014-9818-0
! [3] Yamaleev, N. K. & Carpenter, H. C.,
! "A Systematic Methodology for Constructing High-Order Energy Stable
! WENO Schemes"
! Journal of Computational Physics,
! 2009, vol. 228, pp. 4248-4272,
! http://dx.doi.org/10.1016/j.jcp.2009.03.002
!
!===============================================================================
!
subroutine reconstruct_crweno5yc(h, fc, fl, fr)
! include external procedures
!
use algebra , only : tridiag
! local variables are not implicit by default
!
implicit none
! subroutine arguments
!
real(kind=8) , intent(in) :: h
real(kind=8), dimension(:), intent(in) :: fc
real(kind=8), dimension(:), intent(out) :: fl, fr
! local variables
!
integer :: n, i, im1, ip1, im2, ip2
real(kind=8) :: bl, bc, br, tt
real(kind=8) :: wl, wc, wr, ww
real(kind=8) :: ql, qc, qr
! local arrays for derivatives
!
real(kind=8), dimension(size(fc)) :: dfm, dfp, df2
real(kind=8), dimension(size(fc)) :: al, ac, ar
real(kind=8), dimension(size(fc)) :: u
real(kind=8), dimension(size(fc),2) :: a, b, c, r
! smoothness indicator coefficients
!
real(kind=8), parameter :: c1 = 1.3d+01 / 1.2d+01, c2 = 2.5d-01
! weight coefficients for implicit (c) and explicit (d) interpolations
!
real(kind=8), parameter :: cl = 1.0d+00 / 9.0d+00
real(kind=8), parameter :: cc = 5.0d+00 / 9.0d+00
real(kind=8), parameter :: cr = 1.0d+00 / 3.0d+00
real(kind=8), parameter :: dl = 1.0d-01, dc = 6.0d-01, dr = 3.0d-01
! implicit method coefficients
!
real(kind=8), parameter :: dq = 5.0d-01
! interpolation coefficients
!
real(kind=8), parameter :: a11 = 2.0d+00 / 6.0d+00 &
, a12 = - 7.0d+00 / 6.0d+00 &
, a13 = 1.1d+01 / 6.0d+00
real(kind=8), parameter :: a21 = - 1.0d+00 / 6.0d+00 &
, a22 = 5.0d+00 / 6.0d+00 &
, a23 = 2.0d+00 / 6.0d+00
real(kind=8), parameter :: a31 = 2.0d+00 / 6.0d+00 &
, a32 = 5.0d+00 / 6.0d+00 &
, a33 = - 1.0d+00 / 6.0d+00
!
!-------------------------------------------------------------------------------
!
! get the input vector length
!
n = size(fc)
! calculate the left and right derivatives
!
do i = 1, n - 1
ip1 = i + 1
dfp(i ) = fc(ip1) - fc(i)
dfm(ip1) = dfp(i)
end do
dfm(1) = dfp(1)
dfp(n) = dfm(n)
! calculate the absolute value of the second derivative
!
df2(:) = c1 * (dfp(:) - dfm(:))**2
! prepare smoothness indicators
!
do i = 2, n - 1
! prepare neighbour indices
!
im2 = max(1, i - 2)
im1 = i - 1
ip1 = i + 1
ip2 = min(n, i + 2)
! calculate βₖ (eqs. 9-11 in [1])
!
bl = df2(im1) + c2 * (3.0d+00 * dfm(i ) - dfm(im1))**2
bc = df2(i ) + c2 * ( dfp(i ) + dfm(i ))**2
br = df2(ip1) + c2 * (3.0d+00 * dfp(i ) - dfp(ip1))**2
! calculate τ (below eq. 64 in [3])
!
tt = (6.0d+00 * fc(i) + (fc(im2) + fc(ip2)) &
- 4.0d+00 * (fc(im1) + fc(ip1)))**2
! calculate αₖ (eq. 28 in [1])
!
al(i) = 1.0d+00 + tt / (bl + eps)
ac(i) = 1.0d+00 + tt / (bc + eps)
ar(i) = 1.0d+00 + tt / (br + eps)
end do ! i = 2, n - 1
! prepare tridiagonal system coefficients
!
do i = ng, n - ng + 1
! prepare neighbour indices
!
im1 = i - 1
ip1 = i + 1
! calculate weights
!
wl = cl * al(i)
wc = cc * ac(i)
wr = cr * ar(i)
ww = (wl + wr) + wc
wl = wl / ww
wr = wr / ww
wc = 1.0d+00 - (wl + wr)
! calculate tridiagonal matrix coefficients
!
a(i,1) = 2.0d+00 * wl + wc
b(i,1) = wl + 2.0d+00 * (wc + wr)
c(i,1) = wr
! prepare right hand side of tridiagonal equation
!
r(i,1) = (wl * fc(im1) + (5.0d+00 * (wl + wc) + wr) * fc(i ) &
+ (wc + 5.0d+00 * wr) * fc(ip1)) * dq
! calculate weights
!
wl = cl * ar(i)
wc = cc * ac(i)
wr = cr * al(i)
ww = (wl + wr) + wc
wl = wl / ww
wr = wr / ww
wc = 1.0d+00 - (wl + wr)
! calculate tridiagonal matrix coefficients
!
a(i,2) = wr
b(i,2) = wl + 2.0d+00 * (wc + wr)
c(i,2) = 2.0d+00 * wl + wc
! prepare right hand side of tridiagonal equation
!
r(i,2) = (wl * fc(ip1) + (5.0d+00 * (wl + wc) + wr) * fc(i ) &
+ (wc + 5.0d+00 * wr) * fc(im1)) * dq
end do ! i = ng, n - ng + 1
! interpolate ghost zones using explicit solver (left-side reconstruction)
!
do i = 2, ng
! prepare neighbour indices
!
im2 = max(1, i - 2)
im1 = i - 1
ip1 = i + 1
ip2 = i + 2
! calculate weights
!
wl = dl * al(i)
wc = dc * ac(i)
wr = dr * ar(i)
ww = (wl + wr) + wc
wl = wl / ww
wr = wr / ww
wc = 1.0d+00 - (wl + wr)
! calculate the interpolations of the left state
!
ql = a11 * fc(im2) + a12 * fc(im1) + a13 * fc(i )
qc = a21 * fc(im1) + a22 * fc(i ) + a23 * fc(ip1)
qr = a31 * fc(i ) + a32 * fc(ip1) + a33 * fc(ip2)
! calculate the left state
!
fl(i) = (wl * ql + wr * qr) + wc * qc
! prepare coefficients of the tridiagonal system
!
a(i,1) = 0.0d+00
b(i,1) = 1.0d+00
c(i,1) = 0.0d+00
r(i,1) = fl(i)
end do ! i = 2, ng
a(1,1) = 0.0d+00
b(1,1) = 1.0d+00
c(1,1) = 0.0d+00
r(1,1) = 0.5d+00 * (fc(1) + fc(2))
! interpolate ghost zones using explicit solver (left-side reconstruction)
!
do i = n - ng, n - 1
! prepare neighbour indices
!
im2 = i - 2
im1 = i - 1
ip1 = i + 1
ip2 = min(n, i + 2)
! calculate weights
!
wl = dl * al(i)
wc = dc * ac(i)
wr = dr * ar(i)
ww = (wl + wr) + wc
wl = wl / ww
wr = wr / ww
wc = 1.0d+00 - (wl + wr)
! calculate the interpolations of the left state
!
ql = a11 * fc(im2) + a12 * fc(im1) + a13 * fc(i )
qc = a21 * fc(im1) + a22 * fc(i ) + a23 * fc(ip1)
qr = a31 * fc(i ) + a32 * fc(ip1) + a33 * fc(ip2)
! calculate the left state
!
fl(i) = (wl * ql + wr * qr) + wc * qc
! prepare coefficients of the tridiagonal system
!
a(i,1) = 0.0d+00
b(i,1) = 1.0d+00
c(i,1) = 0.0d+00
r(i,1) = fl(i)
end do ! i = n - ng, n - 1
a(n,1) = 0.0d+00
b(n,1) = 1.0d+00
c(n,1) = 0.0d+00
r(n,1) = fc(n)
! interpolate ghost zones using explicit solver (right-side reconstruction)
!
do i = 2, ng + 1
! prepare neighbour indices
!
im2 = max(1, i - 2)
im1 = i - 1
ip1 = i + 1
ip2 = i + 2
! normalize weights
!
wl = dl * ar(i)
wc = dc * ac(i)
wr = dr * al(i)
ww = (wl + wr) + wc
wl = wl / ww
wr = wr / ww
wc = 1.0d+00 - (wl + wr)
! calculate the interpolations of the right state
!
ql = a11 * fc(ip2) + a12 * fc(ip1) + a13 * fc(i )
qc = a21 * fc(ip1) + a22 * fc(i ) + a23 * fc(im1)
qr = a31 * fc(i ) + a32 * fc(im1) + a33 * fc(im2)
! calculate the right state
!
fr(i) = (wl * ql + wr * qr) + wc * qc
! prepare coefficients of the tridiagonal system
!
a(i,2) = 0.0d+00
b(i,2) = 1.0d+00
c(i,2) = 0.0d+00
r(i,2) = fr(i)
end do ! i = 2, ng + 1
a(1,2) = 0.0d+00
b(1,2) = 1.0d+00
c(1,2) = 0.0d+00
r(1,2) = fc(1)
! interpolate ghost zones using explicit solver (right-side reconstruction)
!
do i = n - ng + 1, n - 1
! prepare neighbour indices
!
im2 = i - 2
im1 = i - 1
ip1 = i + 1
ip2 = min(n, i + 2)
! normalize weights
!
wl = dl * ar(i)
wc = dc * ac(i)
wr = dr * al(i)
ww = (wl + wr) + wc
wl = wl / ww
wr = wr / ww
wc = 1.0d+00 - (wl + wr)
! calculate the interpolations of the right state
!
ql = a11 * fc(ip2) + a12 * fc(ip1) + a13 * fc(i )
qc = a21 * fc(ip1) + a22 * fc(i ) + a23 * fc(im1)
qr = a31 * fc(i ) + a32 * fc(im1) + a33 * fc(im2)
! calculate the right state
!
fr(i) = (wl * ql + wr * qr) + wc * qc
! prepare coefficients of the tridiagonal system
!
a(i,2) = 0.0d+00
b(i,2) = 1.0d+00
c(i,2) = 0.0d+00
r(i,2) = fr(i)
end do ! i = n - ng + 1, n - 1
a(n,2) = 0.0d+00
b(n,2) = 1.0d+00
c(n,2) = 0.0d+00
r(n,2) = 0.5d+00 * (fc(n-1) + fc(n))
! solve the tridiagonal system of equations for the left-side interpolation
!
call tridiag(n, a(1:n,1), b(1:n,1), c(1:n,1), r(1:n,1), u(1:n))
! substitute the left-side values
!
fl(1:n ) = u(1:n)
! solve the tridiagonal system of equations for the left-side interpolation
!
call tridiag(n, a(1:n,2), b(1:n,2), c(1:n,2), r(1:n,2), u(1:n))
! substitute the right-side values
!
fr(1:n-1) = u(2:n)
! update the interpolation of the first and last points
!
i = n - 1
fl(1) = 0.5d+00 * (fc(1) + fc(2))
fr(i) = 0.5d+00 * (fc(i) + fc(n))
fl(n) = fc(n)
fr(n) = fc(n)
!-------------------------------------------------------------------------------
!
end subroutine reconstruct_crweno5yc
!
!===============================================================================
!
! subroutine RECONSTRUCT_CRWENO5NS:
! --------------------------------
!
! Subroutine reconstructs the interface states using the fifth order
! Compact-Reconstruction Weighted Essentially Non-Oscillatory (CRWENO)
! method combined with the smoothness indicators by Ha et al. (2013).
!
! Arguments are described in subroutine reconstruct().
!
! References:
!
! [1] Ghosh, D. & Baeder, J. D.,
! "Compact Reconstruction Schemes with Weighted ENO Limiting for
! Hyperbolic Conservation Laws"
! SIAM Journal on Scientific Computing,
! 2012, vol. 34, no. 3, pp. A1678-A1706,
! http://dx.doi.org/10.1137/110857659
! [2] Ghosh, D. & Baeder, J. D.,
! "Weighted Non-linear Compact Schemes for the Direct Numerical
! Simulation of Compressible, Turbulent Flows"
! Journal on Scientific Computing,
! 2014,
! http://dx.doi.org/10.1007/s10915-014-9818-0
! [3] Ha, Y., Kim, C. H., Lee, Y. J., & Yoon, J.,
! "An improved weighted essentially non-oscillatory scheme with a new
! smoothness indicator",
! Journal of Computational Physics,
! 2013, vol. 232, pp. 68-86
! http://dx.doi.org/10.1016/j.jcp.2012.06.016
!
!===============================================================================
!
subroutine reconstruct_crweno5ns(h, fc, fl, fr)
! include external procedures
!
use algebra , only : tridiag
! local variables are not implicit by default
!
implicit none
! subroutine arguments
!
real(kind=8) , intent(in) :: h
real(kind=8), dimension(:), intent(in) :: fc
real(kind=8), dimension(:), intent(out) :: fl, fr
! local variables
!
integer :: n, i, im1, ip1, im2, ip2
real(kind=8) :: bl, bc, br
real(kind=8) :: wl, wc, wr, ww
real(kind=8) :: df, lq, l3, zt
real(kind=8) :: ql, qc, qr
! local arrays for derivatives
!
real(kind=8), dimension(size(fc)) :: dfm, dfp, df2
real(kind=8), dimension(size(fc),2) :: al, ac, ar
real(kind=8), dimension(size(fc)) :: u
real(kind=8), dimension(size(fc),2) :: a, b, c, r
! the free parameter for smoothness indicators (see eq. 3.6 in [3])
!
real(kind=8), parameter :: xi = 4.0d-01
! weight coefficients for implicit (c) and explicit (d) interpolations
!
real(kind=8), parameter :: cl = 1.0d+00 / 9.0d+00
real(kind=8), parameter :: cc = 5.0d+00 / 9.0d+00
real(kind=8), parameter :: cr = 1.0d+00 / 3.0d+00
real(kind=8), parameter :: dl = 1.0d-01, dc = 6.0d-01, dr = 3.0d-01
! implicit method coefficients
!
real(kind=8), parameter :: dq = 5.0d-01
! 3rd order interpolation coefficients for three stencils
!
real(kind=8), parameter :: a11 = 2.0d+00 / 6.0d+00 &
, a12 = - 7.0d+00 / 6.0d+00 &
, a13 = 1.1d+01 / 6.0d+00
real(kind=8), parameter :: a21 = - 1.0d+00 / 6.0d+00 &
, a22 = 5.0d+00 / 6.0d+00 &
, a23 = 2.0d+00 / 6.0d+00
real(kind=8), parameter :: a31 = 2.0d+00 / 6.0d+00 &
, a32 = 5.0d+00 / 6.0d+00 &
, a33 = - 1.0d+00 / 6.0d+00
!
!-------------------------------------------------------------------------------
!
! get the input vector length
!
n = size(fc)
! calculate the left and right derivatives
!
do i = 1, n - 1
ip1 = i + 1
dfp(i ) = fc(ip1) - fc(i)
dfm(ip1) = dfp(i)
end do
dfm(1) = dfp(1)
dfp(n) = dfm(n)
! calculate the absolute value of the second derivative
!
df2(:) = 0.5d+00 * abs(dfp(:) - dfm(:))
! prepare smoothness indicators
!
do i = 2, n - 1
! prepare neighbour indices
!
im1 = i - 1
ip1 = i + 1
! calculate βₖ
!
df = abs(dfp(i))
lq = xi * df
bl = df2(im1) + xi * abs(2.0d+00 * dfm(i) - dfm(im1))
bc = df2(i ) + lq
br = df2(ip1) + lq
! calculate ζ
!
l3 = df**3
zt = 0.5d+00 * ((bl - br)**2 + (l3 / (1.0d+00 + l3))**2)
! calculate αₖ
!
al(i,1) = 1.0d+00 + zt / (bl + eps)**2
ac(i,1) = 1.0d+00 + zt / (bc + eps)**2
ar(i,1) = 1.0d+00 + zt / (br + eps)**2
! calculate βₖ
!
df = abs(dfm(i))
lq = xi * df
bl = df2(im1) + lq
bc = df2(i ) + lq
br = df2(ip1) + xi * abs(2.0d+00 * dfp(i) - dfp(ip1))
! calculate ζ
l3 = df**3
zt = 0.5d+00 * ((bl - br)**2 + (l3 / (1.0d+00 + l3))**2)
! calculate αₖ
!
al(i,2) = 1.0d+00 + zt / (bl + eps)**2
ac(i,2) = 1.0d+00 + zt / (bc + eps)**2
ar(i,2) = 1.0d+00 + zt / (br + eps)**2
end do ! i = 2, n - 1
! prepare tridiagonal system coefficients
!
do i = ng, n - ng + 1
! prepare neighbour indices
!
im1 = i - 1
ip1 = i + 1
! calculate weights
!
wl = cl * al(i,1)
wc = cc * ac(i,1)
wr = cr * ar(i,1)
ww = (wl + wr) + wc
wl = wl / ww
wr = wr / ww
wc = 1.0d+00 - (wl + wr)
! calculate tridiagonal matrix coefficients
!
a(i,1) = 2.0d+00 * wl + wc
b(i,1) = wl + 2.0d+00 * (wc + wr)
c(i,1) = wr
! prepare right hand side of tridiagonal equation
!
r(i,1) = (wl * fc(im1) + (5.0d+00 * (wl + wc) + wr) * fc(i ) &
+ (wc + 5.0d+00 * wr) * fc(ip1)) * dq
! calculate weights
!
wl = cl * ar(i,2)
wc = cc * ac(i,2)
wr = cr * al(i,2)
ww = (wl + wr) + wc
wl = wl / ww
wr = wr / ww
wc = 1.0d+00 - (wl + wr)
! calculate tridiagonal matrix coefficients
!
a(i,2) = wr
b(i,2) = wl + 2.0d+00 * (wc + wr)
c(i,2) = 2.0d+00 * wl + wc
! prepare right hand side of tridiagonal equation
!
r(i,2) = (wl * fc(ip1) + (5.0d+00 * (wl + wc) + wr) * fc(i ) &
+ (wc + 5.0d+00 * wr) * fc(im1)) * dq
end do ! i = ng, n - ng + 1
! interpolate ghost zones using explicit solver (left-side reconstruction)
!
do i = 2, ng
! prepare neighbour indices
!
im2 = max(1, i - 2)
im1 = i - 1
ip1 = i + 1
ip2 = i + 2
! calculate weights
!
wl = dl * al(i,1)
wc = dc * ac(i,1)
wr = dr * ar(i,1)
ww = (wl + wr) + wc
wl = wl / ww
wr = wr / ww
wc = 1.0d+00 - (wl + wr)
! calculate the interpolations of the left state
!
ql = a11 * fc(im2) + a12 * fc(im1) + a13 * fc(i )
qc = a21 * fc(im1) + a22 * fc(i ) + a23 * fc(ip1)
qr = a31 * fc(i ) + a32 * fc(ip1) + a33 * fc(ip2)
! calculate the left state
!
fl(i) = (wl * ql + wr * qr) + wc * qc
! prepare coefficients of the tridiagonal system
!
a(i,1) = 0.0d+00
b(i,1) = 1.0d+00
c(i,1) = 0.0d+00
r(i,1) = fl(i)
end do ! i = 2, ng
a(1,1) = 0.0d+00
b(1,1) = 1.0d+00
c(1,1) = 0.0d+00
r(1,1) = 0.5d+00 * (fc(1) + fc(2))
! interpolate ghost zones using explicit solver (left-side reconstruction)
!
do i = n - ng, n - 1
! prepare neighbour indices
!
im2 = i - 2
im1 = i - 1
ip1 = i + 1
ip2 = min(n, i + 2)
! calculate weights
!
wl = dl * al(i,1)
wc = dc * ac(i,1)
wr = dr * ar(i,1)
ww = (wl + wr) + wc
wl = wl / ww
wr = wr / ww
wc = 1.0d+00 - (wl + wr)
! calculate the interpolations of the left state
!
ql = a11 * fc(im2) + a12 * fc(im1) + a13 * fc(i )
qc = a21 * fc(im1) + a22 * fc(i ) + a23 * fc(ip1)
qr = a31 * fc(i ) + a32 * fc(ip1) + a33 * fc(ip2)
! calculate the left state
!
fl(i) = (wl * ql + wr * qr) + wc * qc
! prepare coefficients of the tridiagonal system
!
a(i,1) = 0.0d+00
b(i,1) = 1.0d+00
c(i,1) = 0.0d+00
r(i,1) = fl(i)
end do ! i = n - ng, n - 1
a(n,1) = 0.0d+00
b(n,1) = 1.0d+00
c(n,1) = 0.0d+00
r(n,1) = fc(n)
! interpolate ghost zones using explicit solver (right-side reconstruction)
!
do i = 2, ng + 1
! prepare neighbour indices
!
im2 = max(1, i - 2)
im1 = i - 1
ip1 = i + 1
ip2 = i + 2
! normalize weights
!
wl = dl * ar(i,2)
wc = dc * ac(i,2)
wr = dr * al(i,2)
ww = (wl + wr) + wc
wl = wl / ww
wr = wr / ww
wc = 1.0d+00 - (wl + wr)
! calculate the interpolations of the right state
!
ql = a11 * fc(ip2) + a12 * fc(ip1) + a13 * fc(i )
qc = a21 * fc(ip1) + a22 * fc(i ) + a23 * fc(im1)
qr = a31 * fc(i ) + a32 * fc(im1) + a33 * fc(im2)
! calculate the right state
!
fr(i) = (wl * ql + wr * qr) + wc * qc
! prepare coefficients of the tridiagonal system
!
a(i,2) = 0.0d+00
b(i,2) = 1.0d+00
c(i,2) = 0.0d+00
r(i,2) = fr(i)
end do ! i = 2, ng + 1
a(1,2) = 0.0d+00
b(1,2) = 1.0d+00
c(1,2) = 0.0d+00
r(1,2) = fc(1)
! interpolate ghost zones using explicit solver (right-side reconstruction)
!
do i = n - ng + 1, n - 1
! prepare neighbour indices
!
im2 = i - 2
im1 = i - 1
ip1 = i + 1
ip2 = min(n, i + 2)
! normalize weights
!
wl = dl * ar(i,2)
wc = dc * ac(i,2)
wr = dr * al(i,2)
ww = (wl + wr) + wc
wl = wl / ww
wr = wr / ww
wc = 1.0d+00 - (wl + wr)
! calculate the interpolations of the right state
!
ql = a11 * fc(ip2) + a12 * fc(ip1) + a13 * fc(i )
qc = a21 * fc(ip1) + a22 * fc(i ) + a23 * fc(im1)
qr = a31 * fc(i ) + a32 * fc(im1) + a33 * fc(im2)
! calculate the right state
!
fr(i) = (wl * ql + wr * qr) + wc * qc
! prepare coefficients of the tridiagonal system
!
a(i,2) = 0.0d+00
b(i,2) = 1.0d+00
c(i,2) = 0.0d+00
r(i,2) = fr(i)
end do ! i = n - ng + 1, n - 1
a(n,2) = 0.0d+00
b(n,2) = 1.0d+00
c(n,2) = 0.0d+00
r(n,2) = 0.5d+00 * (fc(n-1) + fc(n))
! solve the tridiagonal system of equations for the left-side interpolation
!
call tridiag(n, a(1:n,1), b(1:n,1), c(1:n,1), r(1:n,1), u(1:n))
! substitute the left-side values
!
fl(1:n ) = u(1:n)
! solve the tridiagonal system of equations for the left-side interpolation
!
call tridiag(n, a(1:n,2), b(1:n,2), c(1:n,2), r(1:n,2), u(1:n))
! substitute the right-side values
!
fr(1:n-1) = u(2:n)
! update the interpolation of the first and last points
!
i = n - 1
fl(1) = 0.5d+00 * (fc(1) + fc(2))
fr(i) = 0.5d+00 * (fc(i) + fc(n))
fl(n) = fc(n)
fr(n) = fc(n)
!-------------------------------------------------------------------------------
!
end subroutine reconstruct_crweno5ns
!
!===============================================================================
!
! subroutine RECONSTRUCT_MP5:
! --------------------------
!
! Subroutine reconstructs the interface states using the 5th order
! Monotonicity Preserving (MP) method with adjustable dissipation.
!
! Arguments are described in subroutine reconstruct().
!
! References:
!
! [1] Suresh, A. & Huynh, H. T.,
! "Accurate Monotonicity-Preserving Schemes with Runge-Kutta
! Time Stepping"
! Journal on Computational Physics,
! 1997, vol. 136, pp. 83-99,
! http://dx.doi.org/10.1006/jcph.1997.5745
! [2] Jian Fang, Yufeng Yao, Zhaorui Li, Lipeng Lu,
! "Investigation of low-dissipation monotonicity-preserving scheme
! for direct numerical simulation of compressible turbulent flows",
! Computers & Fluids,
! 2014, vol. 104, pp. 55-72,
! http://dx.doi.org/10.1016/j.compfluid.2014.07.024
!
!===============================================================================
!
subroutine reconstruct_mp5(h, fc, fl, fr)
implicit none
real(kind=8) , intent(in) :: h
real(kind=8), dimension(:), intent(in) :: fc
real(kind=8), dimension(:), intent(out) :: fl, fr
integer :: n, i
real(kind=8), dimension(size(fc)) :: fi
real(kind=8), dimension(size(fc)) :: u
!
!-------------------------------------------------------------------------------
!
n = size(fc)
!! === left-side interpolation ===
!!
do i = 3, n - 3
u(i) = sum(ce5a(:) * fc(i-2:i+3))
end do
u( 1) = sum(ce2(:) * fc( 1:2))
u( 2) = sum(ce3(:) * fc( 1:3))
u(n-2) = sum(ce5(:) * fc(n-4:n))
u(n-1) = sum(ce3(:) * fc(n-2:n))
u(n ) = fc(n )
call mp_limiting(fc(:), u(:))
fl(1:n) = u(1:n)
!! === right-side interpolation ===
!!
fi(1:n) = fc(n:1:-1)
do i = 3, n - 3
u(i) = sum(ce5a(:) * fi(i-2:i+3))
end do
u( 1) = sum(ce2(:) * fi( 1:2))
u( 2) = sum(ce3(:) * fi( 1:3))
u(n-2) = sum(ce5(:) * fi(n-4:n))
u(n-1) = sum(ce3(:) * fi(n-2:n))
u(n ) = fi(n )
call mp_limiting(fi(:), u(:))
fr(1:n-1) = u(n-1:1:-1)
i = n - 1
fl(1) = 0.5d+00 * (fc(1) + fc(2))
fr(i) = 0.5d+00 * (fc(i) + fc(n))
fl(n) = fc(n)
fr(n) = fc(n)
!-------------------------------------------------------------------------------
!
end subroutine reconstruct_mp5
!
!===============================================================================
!
! subroutine RECONSTRUCT_MP7:
! --------------------------
!
! Subroutine reconstructs the interface states using the 7th order
! Monotonicity Preserving (MP) method with adjustable dissipation.
!
! Arguments are described in subroutine reconstruct().
!
! References:
!
! - See RECONSTRUCT_MP5
!
!===============================================================================
!
subroutine reconstruct_mp7(h, fc, fl, fr)
implicit none
real(kind=8) , intent(in) :: h
real(kind=8), dimension(:), intent(in) :: fc
real(kind=8), dimension(:), intent(out) :: fl, fr
integer :: n, i
real(kind=8), dimension(size(fc)) :: fi
real(kind=8), dimension(size(fc)) :: u
!
!-------------------------------------------------------------------------------
!
n = size(fc)
!! === left-side interpolation ===
!!
do i = 4, n - 4
u(i) = sum(ce7a(:) * fc(i-3:i+4))
end do
u( 1) = sum(ce2(:) * fc( 1:2))
u( 2) = sum(ce3(:) * fc( 1:3))
u( 3) = sum(ce5(:) * fc( 1:5))
u(n-3) = sum(ce7(:) * fc(n-6:n))
u(n-2) = sum(ce5(:) * fc(n-4:n))
u(n-1) = sum(ce3(:) * fc(n-2:n))
u(n ) = fc(n )
call mp_limiting(fc(:), u(:))
fl(1:n) = u(1:n)
!! === right-side interpolation ===
!!
fi(1:n) = fc(n:1:-1)
do i = 4, n - 4
u(i) = sum(ce7a(:) * fi(i-3:i+4))
end do
u( 1) = sum(ce2(:) * fi( 1:2))
u( 2) = sum(ce3(:) * fi( 1:3))
u( 3) = sum(ce5(:) * fi( 1:5))
u(n-3) = sum(ce7(:) * fi(n-6:n))
u(n-2) = sum(ce5(:) * fi(n-4:n))
u(n-1) = sum(ce3(:) * fi(n-2:n))
u(n ) = fi(n )
call mp_limiting(fi(:), u(:))
fr(1:n-1) = u(n-1:1:-1)
i = n - 1
fl(1) = 0.5d+00 * (fc(1) + fc(2))
fr(i) = 0.5d+00 * (fc(i) + fc(n))
fl(n) = fc(n)
fr(n) = fc(n)
!-------------------------------------------------------------------------------
!
end subroutine reconstruct_mp7
!
!===============================================================================
!
! subroutine RECONSTRUCT_MP9:
! --------------------------
!
! Subroutine reconstructs the interface states using the 9th order
! Monotonicity Preserving (MP) method with adjustable dissipation.
!
! Arguments are described in subroutine reconstruct().
!
! References:
!
! - See RECONSTRUCT_MP5LD
!
!===============================================================================
!
subroutine reconstruct_mp9(h, fc, fl, fr)
implicit none
real(kind=8) , intent(in) :: h
real(kind=8), dimension(:), intent(in) :: fc
real(kind=8), dimension(:), intent(out) :: fl, fr
integer :: n, i
real(kind=8), dimension(size(fc)) :: fi
real(kind=8), dimension(size(fc)) :: u
!
!-------------------------------------------------------------------------------
!
n = size(fc)
!! === left-side interpolation ===
!!
do i = 5, n - 5
u(i) = sum(ce9a(:) * fc(i-4:i+5))
end do
u( 1) = sum(ce2(:) * fc( 1:2))
u( 2) = sum(ce3(:) * fc( 1:3))
u( 3) = sum(ce5(:) * fc( 1:5))
u( 4) = sum(ce7(:) * fc( 1:7))
u(n-4) = sum(ce9(:) * fc(n-8:n))
u(n-3) = sum(ce7(:) * fc(n-6:n))
u(n-2) = sum(ce5(:) * fc(n-4:n))
u(n-1) = sum(ce3(:) * fc(n-2:n))
u(n ) = fc(n )
call mp_limiting(fc(:), u(:))
fl(1:n) = u(1:n)
!! === right-side interpolation ===
!!
fi(1:n) = fc(n:1:-1)
do i = 5, n - 5
u(i) = sum(ce9a(:) * fi(i-4:i+5))
end do
u( 1) = sum(ce2(:) * fi( 1:2))
u( 2) = sum(ce3(:) * fi( 1:3))
u( 3) = sum(ce5(:) * fi( 1:5))
u( 4) = sum(ce7(:) * fi( 1:7))
u(n-4) = sum(ce9(:) * fi(n-8:n))
u(n-3) = sum(ce7(:) * fi(n-6:n))
u(n-2) = sum(ce5(:) * fi(n-4:n))
u(n-1) = sum(ce3(:) * fi(n-2:n))
u(n ) = fi(n )
call mp_limiting(fi(:), u(:))
fr(1:n-1) = u(n-1:1:-1)
i = n - 1
fl(1) = 0.5d+00 * (fc(1) + fc(2))
fr(i) = 0.5d+00 * (fc(i) + fc(n))
fl(n) = fc(n)
fr(n) = fc(n)
!-------------------------------------------------------------------------------
!
end subroutine reconstruct_mp9
!
!===============================================================================
!
! subroutine RECONSTRUCT_CRMP5:
! ----------------------------
!
! Subroutine reconstructs the interface states using the 5th order
! Compact Reconstruction Monotonicity Preserving (CRMP) method with
! adjustable dissipation.
!
! Arguments are described in subroutine reconstruct().
!
! References:
!
! [1] Suresh, A. & Huynh, H. T.,
! "Accurate Monotonicity-Preserving Schemes with Runge-Kutta
! Time Stepping"
! Journal on Computational Physics,
! 1997, vol. 136, pp. 83-99,
! http://dx.doi.org/10.1006/jcph.1997.5745
! [2] Jian Fang, Yufeng Yao, Zhaorui Li, Lipeng Lu,
! "Investigation of low-dissipation monotonicity-preserving scheme
! for direct numerical simulation of compressible turbulent flows",
! Computers & Fluids,
! 2014, vol. 104, pp. 55-72,
! http://dx.doi.org/10.1016/j.compfluid.2014.07.024
!
!===============================================================================
!
subroutine reconstruct_crmp5(h, fc, fl, fr)
use algebra, only : tridiag
implicit none
real(kind=8) , intent(in) :: h
real(kind=8), dimension(:), intent(in) :: fc
real(kind=8), dimension(:), intent(out) :: fl, fr
integer :: n, i
real(kind=8), dimension(size(fc)) :: fi
real(kind=8), dimension(size(fc)) :: a, b, c
real(kind=8), dimension(size(fc)) :: r
real(kind=8), dimension(size(fc)) :: u
!
!-------------------------------------------------------------------------------
!
n = size(fc)
do i = 1, ng
a(i) = 0.0d+00
b(i) = 1.0d+00
c(i) = 0.0d+00
end do
do i = ng + 1, n - ng - 1
a(i) = di5a(1)
b(i) = di5a(2)
c(i) = di5a(3)
end do
do i = n - ng, n
a(i) = 0.0d+00
b(i) = 1.0d+00
c(i) = 0.0d+00
end do
!! === left-side interpolation ===
!!
do i = ng, n - ng + 1
r(i) = sum(ci5a(:) * fc(i-1:i+2))
end do
r( 1) = sum(ce2(:) * fc( 1: 2))
r( 2) = sum(ce3(:) * fc( 1: 3))
do i = 3, ng
r(i) = sum(ce5(:) * fc(i-2:i+2))
end do
do i = n - ng, n - 2
r(i) = sum(ce5(:) * fc(i-2:i+2))
end do
r(n-1) = sum(ce3(:) * fc(n-2: n))
r(n ) = fc(n )
call tridiag(n, a(1:n), b(1:n), c(1:n), r(1:n), u(1:n))
call mp_limiting(fc(:), u(:))
fl(1:n) = u(1:n)
!! === right-side interpolation ===
!!
fi(1:n) = fc(n:1:-1)
do i = ng, n - ng + 1
r(i) = sum(ci5a(:) * fi(i-1:i+2))
end do ! i = ng, n - ng + 1
r( 1) = sum(ce2(:) * fi( 1: 2))
r( 2) = sum(ce3(:) * fi( 1: 3))
do i = 3, ng
r(i) = sum(ce5(:) * fi(i-2:i+2))
end do
do i = n - ng, n - 2
r(i) = sum(ce5(:) * fi(i-2:i+2))
end do
r(n-1) = sum(ce3(:) * fi(n-2: n))
r(n ) = fi(n )
call tridiag(n, a(1:n), b(1:n), c(1:n), r(1:n), u(1:n))
call mp_limiting(fi(:), u(:))
fr(1:n-1) = u(n-1:1:-1)
i = n - 1
fl(1) = 0.5d+00 * (fc(1) + fc(2))
fr(i) = 0.5d+00 * (fc(i) + fc(n))
fl(n) = fc(n)
fr(n) = fc(n)
!-------------------------------------------------------------------------------
!
end subroutine reconstruct_crmp5
!
!===============================================================================
!
! subroutine RECONSTRUCT_CRMP7:
! ----------------------------
!
! Subroutine reconstructs the interface states using the 7th order
! Compact Reconstruction Monotonicity Preserving (CRMP) method with
! adjustable dissipation.
!
! Arguments are described in subroutine reconstruct().
!
! References:
!
! - See RECONSTRUCT_CRMP5
!
!===============================================================================
!
subroutine reconstruct_crmp7(h, fc, fl, fr)
use algebra, only : tridiag
implicit none
real(kind=8) , intent(in) :: h
real(kind=8), dimension(:), intent(in) :: fc
real(kind=8), dimension(:), intent(out) :: fl, fr
integer :: n, i
real(kind=8), dimension(size(fc)) :: fi
real(kind=8), dimension(size(fc)) :: a, b, c
real(kind=8), dimension(size(fc)) :: r
real(kind=8), dimension(size(fc)) :: u
!
!-------------------------------------------------------------------------------
!
n = size(fc)
do i = 1, ng
a(i) = 0.0d+00
b(i) = 1.0d+00
c(i) = 0.0d+00
end do
do i = ng + 1, n - ng - 1
a(i) = di7a(1)
b(i) = di7a(2)
c(i) = di7a(3)
end do
do i = n - ng, n
a(i) = 0.0d+00
b(i) = 1.0d+00
c(i) = 0.0d+00
end do
!! === left-side interpolation ===
!!
do i = ng, n - ng + 1
r(i) = sum(ci7a(:) * fc(i-2:i+3))
end do
r( 1) = sum(ce2(:) * fc( 1: 2))
r( 2) = sum(ce3(:) * fc( 1: 3))
r( 3) = sum(ce5(:) * fc( 1: 5))
do i = 4, ng
r(i) = sum(ce7(:) * fc(i-3:i+3))
end do
do i = n - ng, n - 3
r(i) = sum(ce7(:) * fc(i-3:i+3))
end do
r(n-2) = sum(ce5(:) * fc(n-4: n))
r(n-1) = sum(ce3(:) * fc(n-2: n))
r(n ) = fc(n )
call tridiag(n, a(1:n), b(1:n), c(1:n), r(1:n), u(1:n))
call mp_limiting(fc(:), u(:))
fl(1:n) = u(1:n)
!! === right-side interpolation ===
!!
fi(1:n) = fc(n:1:-1)
do i = ng, n - ng + 1
r(i) = sum(ci7a(:) * fi(i-2:i+3))
end do ! i = ng, n - ng + 1
r( 1) = sum(ce2(:) * fi( 1: 2))
r( 2) = sum(ce3(:) * fi( 1: 3))
r( 3) = sum(ce5(:) * fi( 1: 5))
do i = 4, ng
r(i) = sum(ce7(:) * fi(i-3:i+3))
end do
do i = n - ng, n - 3
r(i) = sum(ce7(:) * fi(i-3:i+3))
end do
r(n-2) = sum(ce5(:) * fi(n-4: n))
r(n-1) = sum(ce3(:) * fi(n-2: n))
r(n ) = fi(n )
call tridiag(n, a(1:n), b(1:n), c(1:n), r(1:n), u(1:n))
call mp_limiting(fi(:), u(:))
fr(1:n-1) = u(n-1:1:-1)
i = n - 1
fl(1) = 0.5d+00 * (fc(1) + fc(2))
fr(i) = 0.5d+00 * (fc(i) + fc(n))
fl(n) = fc(n)
fr(n) = fc(n)
!-------------------------------------------------------------------------------
!
end subroutine reconstruct_crmp7
!
!===============================================================================
!
! subroutine RECONSTRUCT_CRMP9:
! ----------------------------
!
! Subroutine reconstructs the interface states using the 9th order
! Compact Reconstruction Monotonicity Preserving (CRMP) method with
! adjustable dissipation.
!
! Arguments are described in subroutine reconstruct().
!
! References:
!
! - See RECONSTRUCT_CRMP5
!
!===============================================================================
!
subroutine reconstruct_crmp9(h, fc, fl, fr)
use algebra, only : pentadiag
implicit none
real(kind=8) , intent(in) :: h
real(kind=8), dimension(:), intent(in) :: fc
real(kind=8), dimension(:), intent(out) :: fl, fr
integer :: n, i
real(kind=8), dimension(size(fc)) :: fi
real(kind=8), dimension(size(fc)) :: e, c, d, a, b
real(kind=8), dimension(size(fc)) :: r
real(kind=8), dimension(size(fc)) :: u
!
!-------------------------------------------------------------------------------
!
n = size(fc)
do i = 1, ng
e(i) = 0.0d+00
c(i) = 0.0d+00
d(i) = 1.0d+00
a(i) = 0.0d+00
b(i) = 0.0d+00
end do
do i = ng + 1, n - ng - 1
e(i) = di9a(1)
c(i) = di9a(2)
d(i) = di9a(3)
a(i) = di9a(4)
b(i) = di9a(5)
end do
do i = n - ng, n
e(i) = 0.0d+00
c(i) = 0.0d+00
d(i) = 1.0d+00
a(i) = 0.0d+00
b(i) = 0.0d+00
end do
!! === left-side interpolation ===
!!
do i = ng, n - ng + 1
r(i) = sum(ci9a(:) * fc(i-2:i+3))
end do
r( 1) = sum(ce2(:) * fc( 1: 2))
r( 2) = sum(ce3(:) * fc( 1: 3))
r( 3) = sum(ce5(:) * fc( 1: 5))
r( 4) = sum(ce7(:) * fc( 1: 7))
do i = 5, ng
r(i) = sum(ce9(:) * fc(i-4:i+4))
end do
do i = n - ng, n - 4
r(i) = sum(ce9(:) * fc(i-4:i+4))
end do
r(n-3) = sum(ce7(:) * fc(n-6: n))
r(n-2) = sum(ce5(:) * fc(n-4: n))
r(n-1) = sum(ce3(:) * fc(n-2: n))
r(n ) = fc(n )
call pentadiag(n, e(:), c(:), d(:), a(:), b(:), r(:), u(:))
call mp_limiting(fc(:), u(:))
fl(1:n) = u(1:n)
!! === right-side interpolation ===
!!
fi(1:n) = fc(n:1:-1)
do i = ng, n - ng + 1
r(i) = sum(ci9a(:) * fi(i-2:i+3))
end do ! i = ng, n - ng + 1
r( 1) = sum(ce2(:) * fi( 1: 2))
r( 2) = sum(ce3(:) * fi( 1: 3))
r( 3) = sum(ce5(:) * fi( 1: 5))
r( 4) = sum(ce7(:) * fi( 1: 7))
do i = 5, ng
r(i) = sum(ce9(:) * fi(i-4:i+4))
end do
do i = n - ng, n - 4
r(i) = sum(ce9(:) * fi(i-4:i+4))
end do
r(n-3) = sum(ce7(:) * fi(n-6: n))
r(n-2) = sum(ce5(:) * fi(n-4: n))
r(n-1) = sum(ce3(:) * fi(n-2: n))
r(n ) = fi(n )
call pentadiag(n, e(:), c(:), d(:), a(:), b(:), r(:), u(:))
call mp_limiting(fi(:), u(:))
fr(1:n-1) = u(n-1:1:-1)
i = n - 1
fl(1) = 0.5d+00 * (fc(1) + fc(2))
fr(i) = 0.5d+00 * (fc(i) + fc(n))
fl(n) = fc(n)
fr(n) = fc(n)
!-------------------------------------------------------------------------------
!
end subroutine reconstruct_crmp9
!
!===============================================================================
!
! subroutine RECONSTRUCT_OCMP5:
! -----------------------------
!
! Subroutine reconstructs the interface states using the 5th order Optimized
! Compact Reconstruction Monotonicity Preserving (CRMP) method.
!
! Arguments are described in subroutine reconstruct().
!
! References:
!
! [1] Myeong-Hwan Ahn, Duck-Joo Lee,
! "Modified Monotonicity Preserving Constraints for High-Resolution
! Optimized Compact Scheme",
! Journal of Scientific Computing,
! 2020, vol. 83, p. 34
! https://doi.org/10.1007/s10915-020-01221-0
!
!===============================================================================
!
subroutine reconstruct_ocmp5(h, fc, fl, fr)
use algebra, only : tridiag
implicit none
real(kind=8) , intent(in) :: h
real(kind=8), dimension(:), intent(in) :: fc
real(kind=8), dimension(:), intent(out) :: fl, fr
integer :: n, i
real(kind=8), dimension(size(fc)) :: fi
real(kind=8), dimension(size(fc)) :: a, b, c
real(kind=8), dimension(size(fc)) :: r
real(kind=8), dimension(size(fc)) :: u
real(kind=8), parameter :: a1 = 5.0160152430504783780454277648572d-01
real(kind=8), parameter :: a2 = 2.5395800542237252167985944322018d-01
real(kind=8), dimension(3), parameter :: &
di5 = [ a1, 1.0d+00, a2 ]
real(kind=8), dimension(5), parameter :: &
ci5 = [- 3.0d+00 * a1 - 3.0d+00 * a2 + 2.0d+00, &
2.7d+01 * a1 + 1.7d+01 * a2 - 1.3d+01, &
4.7d+01 * a1 - 4.3d+01 * a2 + 4.7d+01, &
- 1.3d+01 * a1 + 7.7d+01 * a2 + 2.7d+01, &
2.0d+00 * a1 + 1.2d+01 * a2 - 3.0d+00 ] / 6.0d+01
!
!-------------------------------------------------------------------------------
!
n = size(fc)
do i = 1, ng
a(i) = 0.0d+00
b(i) = 1.0d+00
c(i) = 0.0d+00
end do
do i = ng + 1, n - ng - 1
a(i) = di5(1)
b(i) = di5(2)
c(i) = di5(3)
end do
do i = n - ng, n
a(i) = 0.0d+00
b(i) = 1.0d+00
c(i) = 0.0d+00
end do
!! === left-side interpolation ===
!!
do i = ng, n - ng + 1
r(i) = sum(ci5(:) * fc(i-2:i+2))
end do
r( 1) = sum(ce2(:) * fc( 1: 2))
r( 2) = sum(ce3(:) * fc( 1: 3))
do i = 3, ng
r(i) = sum(ce5(:) * fc(i-2:i+2))
end do
do i = n - ng, n - 2
r(i) = sum(ce5(:) * fc(i-2:i+2))
end do
r(n-1) = sum(ce3(:) * fc(n-2: n))
r(n ) = fc(n )
call tridiag(n, a(1:n), b(1:n), c(1:n), r(1:n), u(1:n))
call mp_limiting(fc(:), u(:))
fl(1:n) = u(1:n)
!! === right-side interpolation ===
!!
fi(1:n) = fc(n:1:-1)
do i = ng, n - ng + 1
r(i) = sum(ci5(:) * fi(i-2:i+2))
end do ! i = ng, n - ng + 1
r( 1) = sum(ce2(:) * fi( 1: 2))
r( 2) = sum(ce3(:) * fi( 1: 3))
do i = 3, ng
r(i) = sum(ce5(:) * fi(i-2:i+2))
end do
do i = n - ng, n - 2
r(i) = sum(ce5(:) * fi(i-2:i+2))
end do
r(n-1) = sum(ce3(:) * fi(n-2: n))
r(n ) = fi(n )
call tridiag(n, a(1:n), b(1:n), c(1:n), r(1:n), u(1:n))
call mp_limiting(fi(:), u(:))
fr(1:n-1) = u(n-1:1:-1)
i = n - 1
fl(1) = 0.5d+00 * (fc(1) + fc(2))
fr(i) = 0.5d+00 * (fc(i) + fc(n))
fl(n) = fc(n)
fr(n) = fc(n)
!-------------------------------------------------------------------------------
!
end subroutine reconstruct_ocmp5
!
!===============================================================================
!
! subroutine RECONSTRUCT_OCMP7:
! -----------------------------
!
! Subroutine reconstructs the interface states using the 7th order Optimized
! Compact Reconstruction Monotonicity Preserving (CRMP) method.
!
! Arguments are described in subroutine reconstruct().
!
! References:
!
! [1] Myeong-Hwan Ahn, Duck-Joo Lee,
! "Modified Monotonicity Preserving Constraints for High-Resolution
! Optimized Compact Scheme",
! Journal of Scientific Computing,
! 2020, vol. 83, p. 34
! https://doi.org/10.1007/s10915-020-01221-0
!
!===============================================================================
!
subroutine reconstruct_ocmp7(h, fc, fl, fr)
use algebra, only : pentadiag
implicit none
real(kind=8) , intent(in) :: h
real(kind=8), dimension(:), intent(in) :: fc
real(kind=8), dimension(:), intent(out) :: fl, fr
integer :: n, i
real(kind=8), dimension(size(fc)) :: fi
real(kind=8), dimension(size(fc)) :: e, c, d, a, b
real(kind=8), dimension(size(fc)) :: r
real(kind=8), dimension(size(fc)) :: u
real(kind=8), parameter :: a1 = 6.7080731007136045597206649140123d-01
real(kind=8), parameter :: a2 = 3.4031334443871704940876966367699d-01
real(kind=8), dimension(5), parameter :: &
di7 = [ (3.0d+00 * a1 + 2.0d+00 * a2 - 2.0d+00) / 8.0d+00, &
a1, 1.0d+00, a2, &
( a1 + 6.0d+00 * a2 - 2.0d+00) / 4.0d+01 ]
real(kind=8), dimension(5), parameter :: &
ci7 = [ 1.80d+01 * a1 + 1.80d+01 * a2 - 1.60d+01, &
5.43d+02 * a1 + 2.68d+02 * a2 - 2.91d+02, &
3.43d+02 * a1 - 3.32d+02 * a2 + 5.09d+02, &
-1.07d+02 * a1 + 5.68d+02 * a2 + 3.09d+02, &
4.30d+01 * a1 + 3.18d+02 * a2 - 9.10d+01 ] / 6.0d+02
!
!-------------------------------------------------------------------------------
!
n = size(fc)
! prepare the diagonals of the tridiagonal matrix
!
do i = 1, ng
e(i) = 0.0d+00
c(i) = 0.0d+00
d(i) = 1.0d+00
a(i) = 0.0d+00
b(i) = 0.0d+00
end do
do i = ng + 1, n - ng - 1
e(i) = di7(1)
c(i) = di7(2)
d(i) = di7(3)
a(i) = di7(4)
b(i) = di7(5)
end do
do i = n - ng, n
e(i) = 0.0d+00
c(i) = 0.0d+00
d(i) = 1.0d+00
a(i) = 0.0d+00
b(i) = 0.0d+00
end do
!! === left-side interpolation ===
!!
do i = ng, n - ng + 1
r(i) = sum(ci7(:) * fc(i-2:i+2))
end do
r( 1) = sum(ce2(:) * fc( 1: 2))
r( 2) = sum(ce3(:) * fc( 1: 3))
r( 3) = sum(ce5(:) * fc( 1: 5))
do i = 4, ng
r(i) = sum(ce7(:) * fc(i-3:i+3))
end do
do i = n - ng, n - 3
r(i) = sum(ce7(:) * fc(i-3:i+3))
end do
r(n-2) = sum(ce5(:) * fc(n-4: n))
r(n-1) = sum(ce3(:) * fc(n-2: n))
r(n ) = fc(n )
call pentadiag(n, e(:), c(:), d(:), a(:), b(:), r(:), u(:))
call mp_limiting(fc(:), u(:))
fl(1:n) = u(1:n)
!! === right-side interpolation ===
!!
fi(1:n) = fc(n:1:-1)
do i = ng, n - ng + 1
r(i) = sum(ci7(:) * fi(i-2:i+2))
end do ! i = ng, n - ng + 1
r( 1) = sum(ce2(:) * fi( 1: 2))
r( 2) = sum(ce3(:) * fi( 1: 3))
r( 3) = sum(ce5(:) * fi( 1: 5))
do i = 4, ng
r(i) = sum(ce7(:) * fi(i-3:i+3))
end do
do i = n - ng, n - 3
r(i) = sum(ce7(:) * fi(i-3:i+3))
end do
r(n-2) = sum(ce5(:) * fi(n-4: n))
r(n-1) = sum(ce3(:) * fi(n-2: n))
r(n ) = fi(n )
call pentadiag(n, e(:), c(:), d(:), a(:), b(:), r(:), u(:))
call mp_limiting(fi(:), u(:))
fr(1:n-1) = u(n-1:1:-1)
i = n - 1
fl(1) = 0.5d+00 * (fc(1) + fc(2))
fr(i) = 0.5d+00 * (fc(i) + fc(n))
fl(n) = fc(n)
fr(n) = fc(n)
!-------------------------------------------------------------------------------
!
end subroutine reconstruct_ocmp7
!
!===============================================================================
!
! subroutine RECONSTRUCT_OCMP9:
! -----------------------------
!
! Subroutine reconstructs the interface states using the 9th order Optimized
! Compact Reconstruction Monotonicity Preserving (CRMP) method.
!
! Arguments are described in subroutine reconstruct().
!
! References:
!
! [1] Myeong-Hwan Ahn, Duck-Joo Lee,
! "Modified Monotonicity Preserving Constraints for High-Resolution
! Optimized Compact Scheme",
! Journal of Scientific Computing,
! 2020, vol. 83, p. 34
! https://doi.org/10.1007/s10915-020-01221-0
!
!===============================================================================
!
subroutine reconstruct_ocmp9(h, fc, fl, fr)
use algebra, only : pentadiag
implicit none
real(kind=8) , intent(in) :: h
real(kind=8), dimension(:), intent(in) :: fc
real(kind=8), dimension(:), intent(out) :: fl, fr
integer :: n, i
real(kind=8), dimension(size(fc)) :: fi
real(kind=8), dimension(size(fc)) :: e, c, d, a, b
real(kind=8), dimension(size(fc)) :: r
real(kind=8), dimension(size(fc)) :: u
real(kind=8), parameter :: a1 = 6.7049430606778809680492458975703d-01
real(kind=8), parameter :: a2 = 4.0910274527161221589360057231066d-01
real(kind=8), dimension(5), parameter :: &
di9 = [ (9.0d+00 * a1 + 5.0d+00 * a2 - 6.0d+00) / 2.0d+01, &
a1, 1.0d+00, a2, &
( a1 + 5.0d+00 * a2 - 2.0d+00) / 2.0d+01 ]
real(kind=8), dimension(7), parameter :: &
ci9 = [-1.000d+01 * a1 -1.000d+01 * a2 +1.000d+01, &
2.420d+02 * a1 +2.000d+02 * a2 -2.140d+02, &
4.085d+03 * a1 +1.635d+03 * a2 -2.146d+03, &
2.335d+03 * a1 -1.865d+03 * a2 +3.454d+03, &
-8.150d+02 * a1 +3.385d+03 * a2 +2.404d+03, &
4.450d+02 * a1 +2.895d+03 * a2 -9.560d+02, &
1.800d+01 * a1 +6.000d+01 * a2 -3.200d+01 ] / 4.2d+03
!
!-------------------------------------------------------------------------------
!
n = size(fc)
! prepare the diagonals of the tridiagonal matrix
!
do i = 1, ng
e(i) = 0.0d+00
c(i) = 0.0d+00
d(i) = 1.0d+00
a(i) = 0.0d+00
b(i) = 0.0d+00
end do
do i = ng + 1, n - ng - 1
e(i) = di9(1)
c(i) = di9(2)
d(i) = di9(3)
a(i) = di9(4)
b(i) = di9(5)
end do
do i = n - ng, n
e(i) = 0.0d+00
c(i) = 0.0d+00
d(i) = 1.0d+00
a(i) = 0.0d+00
b(i) = 0.0d+00
end do
!! === left-side interpolation ===
!!
do i = ng, n - ng + 1
r(i) = sum(ci9(:) * fc(i-3:i+3))
end do
r( 1) = sum(ce2(:) * fc( 1: 2))
r( 2) = sum(ce3(:) * fc( 1: 3))
r( 3) = sum(ce5(:) * fc( 1: 5))
r( 4) = sum(ce7(:) * fc( 1: 7))
do i = 5, ng
r(i) = sum(ce9(:) * fc(i-4:i+4))
end do
do i = n - ng, n - 4
r(i) = sum(ce9(:) * fc(i-4:i+4))
end do
r(n-3) = sum(ce7(:) * fc(n-6: n))
r(n-2) = sum(ce5(:) * fc(n-4: n))
r(n-1) = sum(ce3(:) * fc(n-2: n))
r(n ) = fc(n )
call pentadiag(n, e(:), c(:), d(:), a(:), b(:), r(:), u(:))
call mp_limiting(fc(:), u(:))
fl(1:n) = u(1:n)
!! === right-side interpolation ===
!!
fi(1:n) = fc(n:1:-1)
do i = ng, n - ng + 1
r(i) = sum(ci9(:) * fi(i-3:i+3))
end do ! i = ng, n - ng + 1
r( 1) = sum(ce2(:) * fi( 1: 2))
r( 2) = sum(ce3(:) * fi( 1: 3))
r( 3) = sum(ce5(:) * fi( 1: 5))
r( 4) = sum(ce7(:) * fi( 1: 7))
do i = 5, ng
r(i) = sum(ce9(:) * fi(i-4:i+4))
end do
do i = n - ng, n - 4
r(i) = sum(ce9(:) * fi(i-4:i+4))
end do
r(n-3) = sum(ce7(:) * fi(n-6: n))
r(n-2) = sum(ce5(:) * fi(n-4: n))
r(n-1) = sum(ce3(:) * fi(n-2: n))
r(n ) = fi(n )
call pentadiag(n, e(:), c(:), d(:), a(:), b(:), r(:), u(:))
call mp_limiting(fi(:), u(:))
fr(1:n-1) = u(n-1:1:-1)
i = n - 1
fl(1) = 0.5d+00 * (fc(1) + fc(2))
fr(i) = 0.5d+00 * (fc(i) + fc(n))
fl(n) = fc(n)
fr(n) = fc(n)
!-------------------------------------------------------------------------------
!
end subroutine reconstruct_ocmp9
!
!===============================================================================
!
! subroutine PREPARE_GP:
! ---------------------
!
! Subroutine prepares matrixes for the Gaussian Process (GP) method.
!
!===============================================================================
!
subroutine prepare_gp(iret)
! include external procedures
!
use algebra , only : max_prec, invert
use constants , only : pi
use iso_fortran_env, only : error_unit
! local variables are not implicit by default
!
implicit none
! subroutine arguments
!
integer, intent(inout) :: iret
! local variables
!
logical :: flag
integer :: i, j, ip, jp
real(kind=max_prec) :: sig, zl, zr, fc
! local arrays for derivatives
!
real(kind=max_prec), dimension(:,:), allocatable :: cov, agp
real(kind=max_prec), dimension(:) , allocatable :: xgp
! local parameters
!
character(len=*), parameter :: loc = 'INTERPOLATIONS::prepare_gp()'
!
!-------------------------------------------------------------------------------
!
! calculate normal distribution sigma
!
sig = sqrt(2.0d+00) * sgp
! allocate the convariance matrix and interpolation position vector
!
allocate(cov(ngp,ngp))
allocate(agp(ngp,ngp))
allocate(xgp(ngp))
! prepare the covariance matrix
!
fc = 0.5d+00 * sqrt(pi) * sig
i = 0
do ip = - mgp, mgp
i = i + 1
j = 0
do jp = - mgp, mgp
j = j + 1
zl = (1.0d+00 * (ip - jp) - 0.5d+00) / sig
zr = (1.0d+00 * (ip - jp) + 0.5d+00) / sig
cov(i,j) = fc * (erf(zr) - erf(zl))
end do
end do
! invert the matrix
!
call invert(ngp, cov(:,:), agp(:,:), flag)
! continue if the matrix inversion was successful
!
if (flag) then
! make the inversed matrix symmetric
!
do j = 1, ngp
do i = 1, ngp
if (i /= j) then
fc = 0.5d+00 * (agp(i,j) + agp(j,i))
agp(i,j) = fc
agp(j,i) = fc
end if
end do
end do
! prepare the interpolation position vector
!
j = 0
do jp = - mgp, mgp
j = j + 1
zr = (0.5d+00 - 1.0d+00 * jp) / sig
xgp(j) = exp(- zr**2)
end do
! prepare the interpolation coefficients vector
!
cgp(1:ngp) = real(matmul(xgp(1:ngp), agp(1:ngp,1:ngp)), kind=8)
end if
! deallocate the convariance matrix and interpolation position vector
!
deallocate(cov)
deallocate(agp)
deallocate(xgp)
! check if the matrix was inverted successfully
!
if (.not. flag) then
write(error_unit,"('[',a,']: ',a)") trim(loc) &
, "Could not invert the covariance matrix!"
iret = 202
end if
!-------------------------------------------------------------------------------
!
end subroutine prepare_gp
!
!===============================================================================
!
! subroutine RECONSTRUCT_GP:
! -------------------------
!
! Subroutine reconstructs the interface states using one dimensional
! high order Gaussian Process (GP) method.
!
! Arguments are described in subroutine reconstruct().
!
!===============================================================================
!
subroutine reconstruct_gp(h, fc, fl, fr)
! local variables are not implicit by default
!
implicit none
! subroutine arguments
!
real(kind=8) , intent(in) :: h
real(kind=8), dimension(:), intent(in) :: fc
real(kind=8), dimension(:), intent(out) :: fl, fr
! local variables
!
integer :: n, i
! local arrays for derivatives
!
real(kind=8), dimension(size(fc)) :: fi
real(kind=8), dimension(size(fc)) :: u
!
!-------------------------------------------------------------------------------
!
! get the input vector length
!
n = size(fc)
!! === left-side interpolation ===
!!
! interpolate the interface state of the ghost zones using the interpolations
! of lower orders
!
u( 1) = sum(ce2(:) * fc( 1: 2))
u( 2) = sum(ce3(:) * fc( 1: 3))
do i = 3, mgp
u(i) = sum(ce5(:) * fc(i-2:i+2))
end do
do i = n + 1 - mgp, n - 2
u(i) = sum(ce5(:) * fc(i-2:i+2))
end do
u(n-1) = sum(ce3(:) * fc(n-2: n))
u(n ) = fc(n )
! reconstruct the interface state using the Gauss process interpolation
!
do i = 1 + mgp, n - mgp
u(i) = sum(cgp(1:ngp) * (fc(i-mgp:i+mgp) - fc(i))) + fc(i)
end do
! apply the monotonicity preserving limiting
!
call mp_limiting(fc(:), u(:))
! copy the interpolation to the respective vector
!
fl(1:n) = u(1:n)
!! === right-side interpolation ===
!!
! invert the cell-centered value vector
!
fi(1:n) = fc(n:1:-1)
! interpolate the interface state of the ghost zones using the interpolations
! of lower orders
!
u( 1) = sum(ce2(:) * fi( 1: 2))
u( 2) = sum(ce3(:) * fi( 1: 3))
do i = 3, mgp
u(i) = sum(ce5(:) * fi(i-2:i+2))
end do
do i = n + 1 - mgp, n - 2
u(i) = sum(ce5(:) * fi(i-2:i+2))
end do
u(n-1) = sum(ce3(:) * fi(n-2: n))
u(n ) = fi(n )
! reconstruct the interface state using the Gauss process interpolation
!
do i = 1 + mgp, n - mgp
u(i) = sum(cgp(1:ngp) * (fi(i-mgp:i+mgp) - fi(i))) + fi(i)
end do
! apply the monotonicity preserving limiting
!
call mp_limiting(fi(:), u(:))
! copy the interpolation to the respective vector
!
fr(1:n-1) = u(n-1:1:-1)
! update the interpolation of the first and last points
!
i = n - 1
fl(1) = 0.5d+00 * (fc(1) + fc(2))
fr(i) = 0.5d+00 * (fc(i) + fc(n))
fl(n) = fc(n)
fr(n) = fc(n)
!-------------------------------------------------------------------------------
!
end subroutine reconstruct_gp
!
!===============================================================================
!
! function LIMITER_ZERO:
! ---------------------
!
! Function returns zero.
!
! Arguments:
!
! x - scaling factor;
! a, b - the input values;
!
!===============================================================================
!
function limiter_zero(x, a, b) result(c)
! local variables are not implicit by default
!
implicit none
! input arguments
!
real(kind=8), intent(in) :: x, a, b
real(kind=8) :: c
!
!-------------------------------------------------------------------------------
!
c = 0.0d+00
!-------------------------------------------------------------------------------
!
end function limiter_zero
!
!===============================================================================
!
! function LIMITER_MINMOD:
! -----------------------
!
! Function returns the minimum module value among two arguments using
! minmod limiter.
!
! Arguments:
!
! x - scaling factor;
! a, b - the input values;
!
!===============================================================================
!
function limiter_minmod(x, a, b) result(c)
! local variables are not implicit by default
!
implicit none
! input arguments
!
real(kind=8), intent(in) :: x, a, b
real(kind=8) :: c
!
!-------------------------------------------------------------------------------
!
c = 0.5d+00 * (sign(x, a) + sign(x, b)) * min(abs(a), abs(b))
!-------------------------------------------------------------------------------
!
end function limiter_minmod
!
!===============================================================================
!
! function LIMITER_MONOTONIZED_CENTRAL:
! ------------------------------------
!
! Function returns the minimum module value among two arguments using
! the monotonized central TVD limiter.
!
! Arguments:
!
! x - scaling factor;
! a, b - the input values;
!
!===============================================================================
!
function limiter_monotonized_central(x, a, b) result(c)
! local variables are not implicit by default
!
implicit none
! input arguments
!
real(kind=8), intent(in) :: x, a, b
real(kind=8) :: c
!
!-------------------------------------------------------------------------------
!
c = (sign(x, a) + sign(x, b)) * min(abs(a), abs(b), 2.5d-01 * abs(a + b))
!-------------------------------------------------------------------------------
!
end function limiter_monotonized_central
!
!===============================================================================
!
! function LIMITER_SUPERBEE:
! -------------------------
!
! Function returns the minimum module value among two arguments using
! superbee limiter.
!
! Arguments:
!
! x - scaling factor;
! a, b - the input values;
!
!===============================================================================
!
function limiter_superbee(x, a, b) result(c)
! local variables are not implicit by default
!
implicit none
! input arguments
!
real(kind=8), intent(in) :: x, a, b
real(kind=8) :: c
!
!-------------------------------------------------------------------------------
!
c = 0.5d+00 * (sign(x, a) + sign(x, b)) &
* max(min(2.0d+00 * abs(a), abs(b)), min(abs(a), 2.0d+00 * abs(b)))
!-------------------------------------------------------------------------------
!
end function limiter_superbee
!
!===============================================================================
!
! function LIMITER_VANLEER:
! ------------------------
!
! Function returns the minimum module value among two arguments using
! van Leer's limiter.
!
! Arguments:
!
! x - scaling factor;
! a, b - the input values;
!
!===============================================================================
!
function limiter_vanleer(x, a, b) result(c)
! local variables are not implicit by default
!
implicit none
! input arguments
!
real(kind=8), intent(in) :: x, a, b
real(kind=8) :: c
!
!-------------------------------------------------------------------------------
!
c = a * b
if (c > 0.0d+00) then
c = 2.0d+00 * x * c / (a + b)
else
c = 0.0d+00
end if
!-------------------------------------------------------------------------------
!
end function limiter_vanleer
!
!===============================================================================
!
! function LIMITER_VANALBADA:
! --------------------------
!
! Function returns the minimum module value among two arguments using
! van Albada's limiter.
!
! Arguments:
!
! x - scaling factor;
! a, b - the input values;
!
!===============================================================================
!
function limiter_vanalbada(x, a, b) result(c)
! local variables are not implicit by default
!
implicit none
! input arguments
!
real(kind=8), intent(in) :: x, a, b
real(kind=8) :: c
!
!-------------------------------------------------------------------------------
!
c = x * a * b * (a + b) / max(eps, a * a + b * b)
!-------------------------------------------------------------------------------
!
end function limiter_vanalbada
!
!===============================================================================
!
! function MINMOD:
! ===============
!
! Function returns the minimum module value among two arguments.
!
! Arguments:
!
! a, b - the input values;
!
!===============================================================================
!
real(kind=8) function minmod(a, b)
! local variables are not implicit by default
!
implicit none
! input arguments
!
real(kind=8), intent(in) :: a, b
!
!-------------------------------------------------------------------------------
!
minmod = (sign(0.5d+00, a) + sign(0.5d+00, b)) * min(abs(a), abs(b))
return
!-------------------------------------------------------------------------------
!
end function minmod
!
!===============================================================================
!
! function MINMOD4:
! ================
!
! Function returns the minimum module value among four arguments.
!
! Arguments:
!
! a, b, c, d - the input values;
!
!===============================================================================
!
real(kind=8) function minmod4(a, b, c, d)
! local variables are not implicit by default
!
implicit none
! input arguments
!
real(kind=8), intent(in) :: a, b, c, d
!
!-------------------------------------------------------------------------------
!
minmod4 = minmod(minmod(a, b), minmod(c, d))
return
!-------------------------------------------------------------------------------
!
end function minmod4
!
!===============================================================================
!
! function MEDIAN:
! ===============
!
! Function returns the median of three argument values.
!
! Arguments:
!
! a, b, c - the input values;
!
!===============================================================================
!
real(kind=8) function median(a, b, c)
! local variables are not implicit by default
!
implicit none
! input arguments
!
real(kind=8), intent(in) :: a, b, c
!
!-------------------------------------------------------------------------------
!
median = a + minmod(b - a, c - a)
return
end function median
!
!===============================================================================
!
! subroutine FIX_POSITIVITY:
! -------------------------
!
! Subroutine scans the input arrays of the left and right states for
! negative values. If it finds one, it repeates the state reconstruction
! the integrated cell-centered values using the zeroth order interpolation.
!
! Arguments:
!
! qi - the cell centered integrals of variable;
! ql, qr - the left and right states of variable;
!
!===============================================================================
!
subroutine fix_positivity(qi, ql, qr)
! local variables are not implicit by default
!
implicit none
! input/output arguments
!
real(kind=8), dimension(:), intent(in) :: qi
real(kind=8), dimension(:), intent(inout) :: ql, qr
! local variables
!
integer :: n, i, im1, ip1
!
!------------------------------------------------------------------------------
!
#ifdef PROFILE
! start accounting time for positivity fix
!
call start_timer(imf)
#endif /* PROFILE */
! check positivity only if desired
!
if (positivity) then
! get the input vector size
!
n = size(qi)
! look for negative values in the states along the vector
!
do i = 1, n
! check if the left state has a negative value
!
if (ql(i) <= 0.0d+00) then
! calculate the left neighbour index
!
im1 = max(1, i - 1)
! limit the states using the zeroth-order reconstruction
!
ql(i ) = qi(i)
qr(im1) = qi(i)
end if ! fl ≤ 0
! check if the right state has a negative value
!
if (qr(i) <= 0.0d+00) then
! calculate the right neighbour index
!
ip1 = min(n, i + 1)
! limit the states using the zeroth-order reconstruction
!
ql(ip1) = qi(ip1)
qr(i ) = qi(ip1)
end if ! fr ≤ 0
end do ! i = 1, n
end if ! positivity == .true.
#ifdef PROFILE
! stop accounting time for positivity fix
!
call stop_timer(imf)
#endif /* PROFILE */
!-------------------------------------------------------------------------------
!
end subroutine fix_positivity
!
!===============================================================================
!
! subroutine CLIP_EXTREMA:
! -----------------------
!
! Subroutine scans the reconstructed states and check if they didn't leave
! the allowed limits. In the case where the limits where exceeded,
! the states are limited using constant reconstruction.
!
! Arguments:
!
! qi - the cell centered integrals of variable;
! ql, qr - the left and right states of variable;
!
!===============================================================================
!
subroutine clip_extrema(qi, ql, qr)
! local variables are not implicit by default
!
implicit none
! subroutine arguments
!
real(kind=8), dimension(:), intent(in) :: qi
real(kind=8), dimension(:), intent(inout) :: ql, qr
! local variables
!
integer :: n, i, im1, ip1, ip2
real(kind=8) :: qmn, qmx
real(kind=8) :: dql, dqr, dq
!
!------------------------------------------------------------------------------
!
#ifdef PROFILE
! start accounting time for extrema clipping
!
call start_timer(imc)
#endif /* PROFILE */
! get the input vector size
!
n = size(qi)
! iterate over all points
!
do i = 1, n
! calculate indices
!
im1 = max(1, i - 1)
ip1 = min(n, i + 1)
! estimate the bounds of the allowed interval for reconstructed states
!
qmn = min(qi(i), qi(ip1))
qmx = max(qi(i), qi(ip1))
! check if the left state lays in the allowed range
!
if (ql(i) < qmn .or. ql(i) > qmx) then
! calculate the left and right derivatives
!
dql = qi(i ) - qi(im1)
dqr = qi(ip1) - qi(i )
! get the limited slope
!
dq = limiter_clip(0.5d+00, dql, dqr)
! calculate new states
!
ql(i ) = qi(i) + dq
qr(im1) = qi(i) - dq
end if
! check if the right state lays in the allowed range
!
if (qr(i) < qmn .or. qr(i) > qmx) then
! calculate the missing index
!
ip2 = min(n, i + 2)
! calculate the left and right derivatives
!
dql = qi(ip1) - qi(i )
dqr = qi(ip2) - qi(ip1)
! get the limited slope
!
dq = limiter_clip(0.5d+00, dql, dqr)
! calculate new states
!
ql(ip1) = qi(ip1) + dq
qr(i ) = qi(ip1) - dq
end if
end do ! i = 1, n
#ifdef PROFILE
! stop accounting time for extrema clipping
!
call stop_timer(imc)
#endif /* PROFILE */
!-------------------------------------------------------------------------------
!
end subroutine clip_extrema
!
!===============================================================================
!
! subroutine MP_LIMITING:
! ----------------------
!
! Subroutine applies the monotonicity preserving (MP) limiter to a vector of
! high order reconstructed interface values.
!
! Arguments:
!
! qc - the vector of cell-centered values;
! qi - the vector of interface values obtained from the high order
! interpolation as input and its monotonicity limited values as output;
!
! References:
!
! [1] Suresh, A. & Huynh, H. T.,
! "Accurate Monotonicity-Preserving Schemes with Runge-Kutta
! Time Stepping"
! Journal on Computational Physics,
! 1997, vol. 136, pp. 83-99,
! http://dx.doi.org/10.1006/jcph.1997.5745
! [2] He, ZhiWei, Li, XinLiang, Fu, DeXun, & Ma, YanWen,
! "A 5th order monotonicity-preserving upwind compact difference
! scheme",
! Science China Physics, Mechanics and Astronomy,
! Volume 54, Issue 3, pp. 511-522,
! http://dx.doi.org/10.1007/s11433-010-4220-x
!
!===============================================================================
!
subroutine mp_limiting(qc, qi)
! local variables are not implicit by default
!
implicit none
! subroutine arguments
!
real(kind=8), dimension(:), intent(in) :: qc
real(kind=8), dimension(:), intent(inout) :: qi
! local variables
!
integer :: n, i, im1, ip1, ip2
real(kind=8) :: dq, ds, dc0, dc4, dm1, dp1, dml, dmr
real(kind=8) :: qlc, qmd, qmp, qmn, qmx, qul
! local vectors
!
real(kind=8), dimension(0:size(qc)+2) :: dm
!
!-------------------------------------------------------------------------------
!
! get the input vector size
!
n = size(qc)
! calculate derivatives
!
dm(0 ) = 0.0d+00
dm(1 ) = 0.0d+00
dm(2:n) = qc(2:n) - qc(1:n-1)
dm(n+1) = 0.0d+00
dm(n+2) = 0.0d+00
! check monotonicity condition for all elements and apply limiting if required
!
do i = 1, n - 1
ip1 = i + 1
if (dm(i) * dm(ip1) >= 0.0d+00) then
dq = kappa * dm(i)
else
dq = kbeta * dm(i)
end if
qmp = qc(i) + minmod(dm(ip1), dq)
ds = (qi(i) - qc(i)) * (qi(i) - qmp)
if (ds > eps) then
im1 = i - 1
ip2 = i + 2
dm1 = dm(i ) - dm(im1)
dc0 = dm(ip1) - dm(i )
dp1 = dm(ip2) - dm(ip1)
dc4 = 4.0d+00 * dc0
dml = 0.5d+00 * minmod4(dc4 - dm1, 4.0d+00 * dm1 - dc0, dc0, dm1)
dmr = 0.5d+00 * minmod4(dc4 - dp1, 4.0d+00 * dp1 - dc0, dc0, dp1)
qmd = qc(i) + 0.5d+00 * dm(ip1) - dmr
qul = qc(i) + dq
qlc = qc(i) + 0.5d+00 * dq + dml
qmx = max(min(qc(i), qc(ip1), qmd), min(qc(i), qul, qlc))
qmn = min(max(qc(i), qc(ip1), qmd), max(qc(i), qul, qlc))
qi(i) = median(qi(i), qmn, qmx)
end if
end do ! i = 1, n - 1
!-------------------------------------------------------------------------------
!
end subroutine mp_limiting
!===============================================================================
!
end module interpolations