4535 lines
140 KiB
Fortran
4535 lines
140 KiB
Fortran
!!******************************************************************************
|
||
!!
|
||
!! 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-2024 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: EVOLUTION
|
||
!!
|
||
!! This module provides an interface for temporal integration with
|
||
!! the stability handling. New integration methods can be added by
|
||
!! implementing more evolve_* subroutines.
|
||
!!
|
||
!!******************************************************************************
|
||
!
|
||
module evolution
|
||
|
||
implicit none
|
||
|
||
! interfaces for procedure pointers
|
||
!
|
||
abstract interface
|
||
subroutine evolve_iface()
|
||
end subroutine
|
||
subroutine update_errors_iface(n, m)
|
||
integer, intent(in) :: n, m
|
||
end subroutine
|
||
end interface
|
||
|
||
! pointer to the temporal integration subroutine
|
||
!
|
||
procedure(evolve_iface), pointer, save :: evolve => null()
|
||
|
||
! pointer to the error update subroutine
|
||
!
|
||
procedure(update_errors_iface), pointer, save :: update_errors => null()
|
||
|
||
! evolution parameters
|
||
!
|
||
logical , save :: error_control = .false.
|
||
logical , save :: fsal = .false.
|
||
logical , save :: fsal_update = .true.
|
||
character(len=255), save :: name_int = ""
|
||
character(len=255), save :: name_norm = ""
|
||
integer , save :: order = 2
|
||
integer , save :: stages = 2
|
||
integer , save :: registers = 1
|
||
real(kind=8) , save :: cfl = 5.0d-01
|
||
|
||
! coefficients controlling the decay of scalar potential ѱ
|
||
!
|
||
real(kind=8) , save :: glm_alpha = 5.0d-01
|
||
|
||
! time variables
|
||
!
|
||
integer , save :: step = 0
|
||
real(kind=8) , save :: time = 0.0d+00
|
||
real(kind=8) , save :: dt = 1.0d+00
|
||
real(kind=8) , save :: dth = 1.0d+00
|
||
real(kind=8) , save :: dte = 0.0d+00
|
||
real(kind=8) , save :: dtp = huge(dt) ! dt for precise snapshots
|
||
real(kind=8) , save :: dtsafe = 1.0d-02
|
||
real(kind=8) , save :: facjmp = 1.05d+00
|
||
|
||
! the absolute and relative tolerances, limiting factors, the maximum error,
|
||
! the maximum number of passes for the adaptive step,
|
||
! the total number of integration iterations, the number of rejected iterations
|
||
!
|
||
real(kind=8) , save :: atol = 1.0d-04
|
||
real(kind=8) , save :: rtol = 1.0d-04
|
||
real(kind=8) , save :: fac = 8.1d-01
|
||
real(kind=8) , save :: facmin = 1.0d-01
|
||
real(kind=8) , save :: facmax = 5.0d+00
|
||
real(kind=8) , save :: errtol = 1.0d+00
|
||
real(kind=8) , save :: chi = 1.0d+00
|
||
integer , save :: mrej = 5
|
||
integer , save :: niterations = 0
|
||
integer , save :: nrejections = 0
|
||
|
||
! coefficients of Runge-Kutta methods
|
||
!
|
||
real(kind=8), dimension(:) , allocatable, save :: c, bt, dl, bh
|
||
real(kind=8), dimension(:,:), allocatable, save :: gm
|
||
|
||
! errors in three recent steps
|
||
!
|
||
real(kind=8), dimension(3), save :: betas, errs
|
||
|
||
! GLM variables
|
||
!
|
||
real(kind=8), dimension(:), allocatable, save :: adecay, aglm
|
||
|
||
! by default everything is private
|
||
!
|
||
private
|
||
|
||
! declare public subroutines
|
||
!
|
||
public :: initialize_evolution, finalize_evolution, print_evolution
|
||
public :: initialize_time_step, new_time_step, advance
|
||
|
||
! declare public variables
|
||
!
|
||
public :: step, time, dt, dth, dte, dtp, cfl, glm_alpha, registers
|
||
public :: atol, rtol, mrej, niterations, nrejections, errs, errtol
|
||
public :: error_control
|
||
|
||
!- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||
!
|
||
contains
|
||
!
|
||
!===============================================================================
|
||
!!
|
||
!!*** PUBLIC SUBROUTINES *****************************************************
|
||
!!
|
||
!===============================================================================
|
||
!
|
||
!===============================================================================
|
||
!
|
||
! subroutine INITIALIZE_EVOLUTION:
|
||
! -------------------------------
|
||
!
|
||
! Subroutine initializes module EVOLUTION by setting its parameters.
|
||
!
|
||
! Arguments:
|
||
!
|
||
! verbose - a logical flag turning the information printing;
|
||
! status - an integer flag for error return value;
|
||
!
|
||
!===============================================================================
|
||
!
|
||
subroutine initialize_evolution(verbose, status)
|
||
|
||
use coordinates, only : toplev, adx, ady
|
||
#if NDIMS == 3
|
||
use coordinates, only : adz
|
||
#endif /* NDIMS == 3 */
|
||
use forcing , only : initialize_forcing
|
||
use gravity , only : initialize_gravity
|
||
use helpers , only : print_message, uppercase
|
||
use mpitools , only : check_status
|
||
use parameters , only : get_parameter
|
||
use schemes , only : initialize_schemes
|
||
use shapes , only : initialize_shapes
|
||
use sources , only : initialize_sources
|
||
|
||
implicit none
|
||
|
||
logical, intent(in) :: verbose
|
||
integer, intent(out) :: status
|
||
|
||
character(len=255) :: integration = "rk2", error_norm = "l2"
|
||
integer :: n
|
||
|
||
character(len=512) :: msg
|
||
|
||
character(len=*), parameter :: fmt = "('The selected time advance " // &
|
||
"method is not implemented: ',a,'.'" // &
|
||
",a,4x,'Available methods are: ', a, '.'" // &
|
||
",a,4x,'Available embedded methods are: ', a, '.')"
|
||
character(len=*), parameter :: loc = 'EVOLUTION::initialize_evolution()'
|
||
|
||
!-------------------------------------------------------------------------------
|
||
!
|
||
status = 0
|
||
|
||
! get the integration method and the value of the CFL coefficient
|
||
!
|
||
call get_parameter("time_advance", integration)
|
||
call get_parameter("stages" , stages )
|
||
call get_parameter("cfl" , cfl )
|
||
call get_parameter("glm_alpha" , glm_alpha )
|
||
|
||
! get the absolute and relative tolerances, the maximum number of passes for
|
||
! the adaptive step, and limiting factors
|
||
!
|
||
call get_parameter("absolute_tolerance", atol)
|
||
call get_parameter("relative_tolerance", rtol)
|
||
call get_parameter("maximum_rejections", mrej)
|
||
call get_parameter("chi" , chi)
|
||
call get_parameter("factor" , fac )
|
||
call get_parameter("minimum_factor" , facmin)
|
||
call get_parameter("maximum_factor" , facmax)
|
||
call get_parameter("dt_safe_factor" , dtsafe)
|
||
call get_parameter("dt_jump_factor" , facjmp)
|
||
|
||
! select the integration method, check the correctness of the integration
|
||
! parameters and adjust the CFL coefficient if necessary
|
||
!
|
||
select case(trim(integration))
|
||
|
||
case ("euler", "EULER")
|
||
|
||
evolve => evolve_euler
|
||
order = 1
|
||
registers = 2
|
||
name_int = "1st order Euler"
|
||
|
||
case ("ssprk(2,2)", "SSPRK(2,2)", "rk2", "RK2")
|
||
|
||
evolve => evolve_ssprk2
|
||
order = 2
|
||
registers = 2
|
||
name_int = "2nd order SSPRK(2,2)"
|
||
|
||
case ("ssprk(3,3)", "SSPRK(3,3)", "rk3", "RK3")
|
||
|
||
evolve => evolve_ssprk3
|
||
order = 3
|
||
registers = 2
|
||
name_int = "3ʳᵈ order SSPRK(3,3)"
|
||
|
||
case ("ssprk(4,3)", "SSPRK(4,3)", "rk3.4", "RK3.4")
|
||
|
||
evolve => evolve_ssprk34
|
||
order = 3
|
||
registers = 2
|
||
name_int = "3ʳᵈ order 4-step SSPRK(4,3)"
|
||
|
||
case ("ssprk(5,3)", "SSPRK(5,3)", "rk3.5", "RK3.5")
|
||
|
||
evolve => evolve_ssprk35
|
||
order = 3
|
||
registers = 3
|
||
name_int = "3ʳᵈ order 5-step SSPRK(5,3)"
|
||
|
||
case ("ssprk(5,4)", "SSPRK(5,4)", "rk4.5", "RK4.5")
|
||
|
||
evolve => evolve_ssprk45
|
||
order = 4
|
||
registers = 3
|
||
name_int = "4th order 5-step SSPRK(5,4)"
|
||
|
||
case ("ssprk(10,4)", "SSPRK(10,4)", "rk4.10", "RK4.10")
|
||
|
||
evolve => evolve_ssprk410
|
||
order = 4
|
||
registers = 3
|
||
name_int = "4th order 10-step SSPRK(10,4)"
|
||
|
||
case ("ssprk(m,2)", "SSPRK(m,2)", "ssprk2(1)m", "SSPRK2(1)M")
|
||
|
||
error_control = .true.
|
||
evolve => evolve_ssprk21m
|
||
order = 2
|
||
registers = 3
|
||
stages = max(2, min(9, stages))
|
||
write(name_int, "('2ⁿᵈ-order ',i0,'-step embedded " // &
|
||
"SSPRK(',i0,',2) method')") stages, stages
|
||
|
||
allocate(c(stages), dl(stages), bt(stages), bh(stages))
|
||
|
||
do n = 1, stages
|
||
c(n) = n - 1.0d+00
|
||
end do
|
||
c (:) = c(:) / (stages - 1)
|
||
bt(:) = 1.0d+00 / (stages - 1)
|
||
bt(stages) = 1.0d+00 / stages
|
||
bh(:) = 1.0d+00 / stages
|
||
bh(1) = (stages + 1.0d+00) / stages**2
|
||
bh(stages) = (stages - 1.0d+00) / stages**2
|
||
dl(1) = (stages - 1.0d+00) / stages
|
||
dl(2) = 1.0d+00 - dl(1)
|
||
|
||
betas(:) = [ 5.8d-01, -2.1d-01, 1.0d-01 ]
|
||
|
||
call get_parameter("beta(1)", betas(1))
|
||
call get_parameter("beta(2)", betas(2))
|
||
call get_parameter("beta(3)", betas(3))
|
||
|
||
betas(:) = - betas(:) / 2.0d+00
|
||
|
||
case ("ssprk3(2)4", "ssp3(2)4", "SSPRK3(2)4", "SSP3(2)4")
|
||
|
||
error_control = .true.
|
||
evolve => evolve_ssp324
|
||
order = 3
|
||
registers = 3
|
||
stages = 4
|
||
name_int = "3ʳᵈ-order 4-step embedded SSP3(2)4 method"
|
||
|
||
betas(:) = [ 5.5d-01, -2.7d-01, 5.0d-02 ]
|
||
|
||
call get_parameter("beta(1)", betas(1))
|
||
call get_parameter("beta(2)", betas(2))
|
||
call get_parameter("beta(3)", betas(3))
|
||
|
||
betas(:) = - betas(:) / 3.0d+00
|
||
|
||
case ("ssprk3(2)m", "ssp3(2)m", "ssprk(m,3)", "SSPRK3(2)M", "SSP3(2)M", "SSPRK(M,3)")
|
||
|
||
error_control = .true.
|
||
evolve => evolve_ssprk32m
|
||
order = 3
|
||
registers = 4
|
||
n = 2
|
||
do while(n**2 <= stages)
|
||
n = n + 1
|
||
end do
|
||
n = n - 1
|
||
stages = max(4, n**2)
|
||
write(name_int, "('3ʳᵈ-order order ',i0,'-step embedded SSPRK3(2)n² method')") stages
|
||
|
||
betas(:) = [ 5.5d-01, -2.7d-01, 5.0d-02 ]
|
||
|
||
call get_parameter("beta(1)", betas(1))
|
||
call get_parameter("beta(2)", betas(2))
|
||
call get_parameter("beta(3)", betas(3))
|
||
|
||
betas(:) = - betas(:) / 3.0d+00
|
||
|
||
if (stages == 4 .and. verbose) then
|
||
write(*,*)
|
||
write(*,*) "ADVICE:"
|
||
write(*,*) "The method 'SSPRK3(2)m' is primarily designed for n²," // &
|
||
" where n > 2. Since you intend to use 4 stages with" // &
|
||
" this method, it is highly advised to use method" // &
|
||
" 'SSPRK3(2)4', since it slightly better optimized and" // &
|
||
" significantly used less memory."
|
||
end if
|
||
|
||
case ("rk3(2)5", "RK3(2)5")
|
||
|
||
! References:
|
||
!
|
||
! [1] Ranocha, H., Dalcin, L., Parsani, M., Ketcheson, D. I.
|
||
! "Coefficients of Optimized Runge-Kutta Methods with Automatic
|
||
! Step Size Control for Compressible Computational Fluid Dynamics",
|
||
! 2021, DOI:10.5281/zenodo.4671927,
|
||
! https://github.com/ranocha/Optimized-RK-CFD
|
||
!
|
||
error_control = .true.
|
||
evolve => evolve_3sstarplus
|
||
registers = 4
|
||
order = 3
|
||
stages = 5
|
||
name_int = "Optimized 3ʳᵈ-order 5-step embedded RK3(2)5"
|
||
|
||
allocate(c(stages+1), dl(stages), bt(stages), bh(stages+1), gm(3,stages))
|
||
c (:) = [ 0.000000000000000000000000000000000000d+00, &
|
||
2.300285062878154351930669430512780706d-01, &
|
||
4.050049049262914975700372321130661410d-01, &
|
||
8.947823877926760224705450466361360720d-01, &
|
||
7.235108137218888081489570284485201518d-01, &
|
||
1.000000000000000000000000000000000000d+00 ]
|
||
dl(:) = [ 1.000000000000000000000000000000000000d+00, &
|
||
3.407687209321455242558804921815861422d-01, &
|
||
3.414399280584625023244387687873774697d-01, &
|
||
7.229302732875589702087936723400941329d-01, &
|
||
0.000000000000000000000000000000000000d+00 ]
|
||
bt(:) = [ 2.300285062878154351930669430512780706d-01, &
|
||
3.021457892454169700189445968126242994d-01, &
|
||
8.025601039472704213300183888573974531d-01, &
|
||
4.362158997637629844305216319994356355d-01, &
|
||
1.129268494470295369172265188216779157d-01 ]
|
||
bh(:) = [ 1.046363371354093758897668305991705199d-01, &
|
||
9.520431574956758809511173383346476348d-02, &
|
||
4.482446645568668405072421350300379357d-01, &
|
||
2.449030295461310135957132640369862245d-01, &
|
||
1.070116530120251819121660365003405564d-01, &
|
||
0.000000000000000000000000000000000000d+00 ]
|
||
gm(1,:) = [ 0.000000000000000000000000000000000000d+00, &
|
||
2.587669070352079020144955303389306026d-01, &
|
||
-1.324366873994502973977035353758550057d-01, &
|
||
5.055601231460399101814291350373559483d-02, &
|
||
5.670552807902877312521811889846000976d-01 ]
|
||
gm(2,:) = [ 1.000000000000000000000000000000000000d+00, &
|
||
5.528418745102160639901976698795928733d-01, &
|
||
6.731844400389673824374042790213570079d-01, &
|
||
2.803103804507635075215805236096803381d-01, &
|
||
5.521508873507393276457754945308880998d-01 ]
|
||
gm(3,:) = [ 0.000000000000000000000000000000000000d+00, &
|
||
0.000000000000000000000000000000000000d+00, &
|
||
0.000000000000000000000000000000000000d+00, &
|
||
2.752585813446636957256614568573008811d-01, &
|
||
-8.950548709279785077579454232514633376d-01 ]
|
||
|
||
betas(:) = [ 6.4d-01, -3.1d-01, 4.0d-02 ]
|
||
|
||
call get_parameter("beta(1)", betas(1))
|
||
call get_parameter("beta(2)", betas(2))
|
||
call get_parameter("beta(3)", betas(3))
|
||
|
||
betas(:) = - betas(:) / 3.0d+00
|
||
|
||
case ("rk3(2)5f", "RK3(2)5F")
|
||
|
||
! References:
|
||
!
|
||
! [1] Ranocha, H., Dalcin, L., Parsani, M., Ketcheson, D. I.
|
||
! "Coefficients of Optimized Runge-Kutta Methods with Automatic
|
||
! Step Size Control for Compressible Computational Fluid Dynamics",
|
||
! 2021, DOI:10.5281/zenodo.4671927,
|
||
! https://github.com/ranocha/Optimized-RK-CFD
|
||
!
|
||
error_control = .true.
|
||
fsal = .true.
|
||
evolve => evolve_3sstarplus
|
||
registers = 4
|
||
order = 3
|
||
stages = 5
|
||
name_int = "Optimized 3ʳᵈ-order 5-step embedded RK3(2)5 FSAL"
|
||
|
||
allocate(c(stages+1), dl(stages), bt(stages), bh(stages+1), gm(3,stages))
|
||
c (:) = [ 0.000000000000000000000000000000000000d+00, &
|
||
2.300298624518076223899418286314123354d-01, &
|
||
4.050046072094990912268498160116125481d-01, &
|
||
8.947822893693433545220710894560512805d-01, &
|
||
7.235136928826589010272834603680114769d-01, &
|
||
1.000000000000000000000000000000000000d+00 ]
|
||
dl(:) = [ 1.000000000000000000000000000000000000d+00, &
|
||
3.407655879334525365094815965895763636d-01, &
|
||
3.414382655003386206551709871126405331d-01, &
|
||
7.229275366787987419692007421895451953d-01, &
|
||
0.000000000000000000000000000000000000d+00 ]
|
||
bt(:) = [ 2.300298624518076223899418286314123354d-01, &
|
||
3.021434166948288809034402119555380003d-01, &
|
||
8.025606185416310937583009085873554681d-01, &
|
||
4.362158943603440930655148245148766471d-01, &
|
||
1.129272530455059129782111662594436580d-01 ]
|
||
bh(:) = [ 9.484166705035703392326247283838082847d-02, &
|
||
1.726371339430353766966762629176676070d-01, &
|
||
3.998243189084371024483169698618455770d-01, &
|
||
1.718016807580178450618829007973835152d-01, &
|
||
5.881914422155740300718268359027168467d-02, &
|
||
1.020760551185952388626787099944507877d-01 ]
|
||
gm(1,:) = [ 0.000000000000000000000000000000000000d+00, &
|
||
2.587771979725733308135192812685323706d-01, &
|
||
-1.324380360140723382965420909764953437d-01, &
|
||
5.056033948190826045833606441415585735d-02, &
|
||
5.670532000739313812633197158607642990d-01 ]
|
||
gm(2,:) = [ 1.000000000000000000000000000000000000d+00, &
|
||
5.528354909301389892439698870483746541d-01, &
|
||
6.731871608203061824849561782794643600d-01, &
|
||
2.803103963297672407841316576323901761d-01, &
|
||
5.521525447020610386070346724931300367d-01 ]
|
||
gm(3,:) = [ 0.000000000000000000000000000000000000d+00, &
|
||
0.000000000000000000000000000000000000d+00, &
|
||
0.000000000000000000000000000000000000d+00, &
|
||
2.752563273304676380891217287572780582d-01, &
|
||
-8.950526174674033822276061734289327568d-01 ]
|
||
|
||
betas(:) = [ 7.0d-01, -2.3d-01, 0.0d+00 ]
|
||
|
||
call get_parameter("beta(1)", betas(1))
|
||
call get_parameter("beta(2)", betas(2))
|
||
call get_parameter("beta(3)", betas(3))
|
||
|
||
betas(:) = - betas(:) / 3.0d+00
|
||
|
||
case ("rk4(3)9", "RK4(3)9")
|
||
|
||
! References:
|
||
!
|
||
! [1] Ranocha, H., Dalcin, L., Parsani, M., Ketcheson, D. I.
|
||
! "Coefficients of Optimized Runge-Kutta Methods with Automatic
|
||
! Step Size Control for Compressible Computational Fluid Dynamics",
|
||
! 2021, DOI:10.5281/zenodo.4671927,
|
||
! https://github.com/ranocha/Optimized-RK-CFD
|
||
!
|
||
error_control = .true.
|
||
evolve => evolve_3sstarplus
|
||
registers = 4
|
||
order = 4
|
||
stages = 9
|
||
name_int = "Optimized 4ᵗʰ-order 9-step embedded RK4(3)9"
|
||
|
||
allocate(c(stages+1), dl(stages), bt(stages), bh(stages+1), gm(3,stages))
|
||
c (:) = [ 0.000000000000000000000000000000000000d+00, &
|
||
2.836343531977826022543660465926414772d-01, &
|
||
5.484073767552486705240014599676811834d-01, &
|
||
3.687229456675706936558667052479014150d-01, &
|
||
-6.806119916032093175251948474173648331d-01, &
|
||
3.518526451892056368706593492732753284d-01, &
|
||
1.665941920204672094647868254892387293d+00, &
|
||
9.715276989307335935187466054546761665d-01, &
|
||
9.051569554420045339601721625247585643d-01, &
|
||
1.000000000000000000000000000000000000d+00 ]
|
||
dl(:) = [ 1.000000000000000000000000000000000000d+00, &
|
||
1.262923854387806460989545005598562667d+00, &
|
||
7.574967177560872438940839460448329992d-01, &
|
||
5.163591158111222863455531895152351544d-01, &
|
||
-2.746333792042827389548936599648122146d-02, &
|
||
-4.382674653941770848797864513655752318d-01, &
|
||
1.273587103668392811985704533534301656d+00, &
|
||
-6.294740045442794829622796613103492913d-01, &
|
||
0.000000000000000000000000000000000000d+00 ]
|
||
bt(:) = [ 2.836343531977826022543660465926414772d-01, &
|
||
9.736497978646965372894268287659773644d-01, &
|
||
3.382358566377620380505126936670933370d-01, &
|
||
-3.584937820217850715182820651063453804d-01, &
|
||
-4.113955814725134294322006403954822487d-03, &
|
||
1.427968962196019024010757034274849198d+00, &
|
||
1.808467712038743032991177525728915926d-02, &
|
||
1.605771316794521018947553625079465692d-01, &
|
||
2.952226811394310028003810072027839487d-01 ]
|
||
bh(:) = [ 4.550655927970944948340364817140593012d-02, &
|
||
1.175968310492638562142460384341959193d-01, &
|
||
3.658257330515213200375475084421083608d-02, &
|
||
-5.311555834355629559010061596928357525d-03, &
|
||
5.178250012713127329531367677410650996d-03, &
|
||
4.954639022118682638697706200022961443d-01, &
|
||
-5.999303132737865921441409466809521699d-03, &
|
||
9.405093434568315929035250835218733824d-02, &
|
||
2.169318087627035072893925375820310602d-01, &
|
||
0.000000000000000000000000000000000000d+00 ]
|
||
gm(1,:) = [ 0.000000000000000000000000000000000000d+00, &
|
||
-4.655641301259180308677051498071354582d+00, &
|
||
-7.720264924836063859141482018013692338d-01, &
|
||
-4.024423213419724605695005429153112050d+00, &
|
||
-2.129685246739018613087466942802498152d-02, &
|
||
-2.435022519234470128602335652131234586d+00, &
|
||
1.985627480986167686791439120784668251d-02, &
|
||
-2.810790112885283952929218377438668784d-01, &
|
||
1.689434895835535695524003319503844110d-01 ]
|
||
gm(2,:) = [ 1.000000000000000000000000000000000000d+00, &
|
||
2.499262752607825957145627300817258023d+00, &
|
||
5.866820365436136799319929406678132638d-01, &
|
||
1.205141365412670762568835277881144391d+00, &
|
||
3.474793796700868848597960521248007941d-01, &
|
||
1.321346140128723105871355808477092220d+00, &
|
||
3.119636324379370564023292317172847140d-01, &
|
||
4.351419055894087609560896967082486864d-01, &
|
||
2.359698299440788299161958168555704234d-01 ]
|
||
gm(3,:) = [ 0.000000000000000000000000000000000000d+00, &
|
||
0.000000000000000000000000000000000000d+00, &
|
||
0.000000000000000000000000000000000000d+00, &
|
||
7.621037111138170045618771082985664430d-01, &
|
||
-1.981182159087218433914909510116664154d-01, &
|
||
-6.228960706317566993192689455719570179d-01, &
|
||
-3.752246993432626328289874575355102038d-01, &
|
||
-3.355436539000946543242869676125143358d-01, &
|
||
-4.560963110717484359015342341157302403d-02 ]
|
||
|
||
betas(:) = [ 2.5d-01, -1.2d-01, 0.0d+00 ]
|
||
|
||
call get_parameter("beta(1)", betas(1))
|
||
call get_parameter("beta(2)", betas(2))
|
||
call get_parameter("beta(3)", betas(3))
|
||
|
||
betas(:) = - betas(:) / 4.0d+00
|
||
|
||
case ("rk4(3)9f", "RK4(3)9F")
|
||
|
||
! References:
|
||
!
|
||
! [1] Ranocha, H., Dalcin, L., Parsani, M., Ketcheson, D. I.
|
||
! "Coefficients of Optimized Runge-Kutta Methods with Automatic
|
||
! Step Size Control for Compressible Computational Fluid Dynamics",
|
||
! 2021, DOI:10.5281/zenodo.4671927,
|
||
! https://github.com/ranocha/Optimized-RK-CFD
|
||
!
|
||
error_control = .true.
|
||
fsal = .true.
|
||
evolve => evolve_3sstarplus
|
||
registers = 4
|
||
order = 4
|
||
stages = 9
|
||
name_int = "Optimized 4ᵗʰ-order 9-step embedded RK4(3)9 FSAL"
|
||
|
||
allocate(c(stages+1), dl(stages), bt(stages), bh(stages+1), gm(3,stages))
|
||
c (:) = [ 0.000000000000000000000000000000000000d+00, &
|
||
2.836343005184365275160654678626695428d-01, &
|
||
5.484076570002894365286665352032296535d-01, &
|
||
3.687228761669438493478872632332010073d-01, &
|
||
-6.806126440140844191258463830024463902d-01, &
|
||
3.518526124230705801739919476290327750d-01, &
|
||
1.665941994879593315477304663913129942d+00, &
|
||
9.715279295934715835299192116436237065d-01, &
|
||
9.051569840159589594903399929316959062d-01, &
|
||
1.000000000000000000000000000000000000d+00 ]
|
||
dl(:) = [ 1.000000000000000000000000000000000000d+00, &
|
||
1.262923876648114432874834923838556100d+00, &
|
||
7.574967189685911558308119415539596711d-01, &
|
||
5.163589453140728104667573195005629833d-01, &
|
||
-2.746327421802609557034437892013640319d-02, &
|
||
-4.382673178127944142238606608356542890d-01, &
|
||
1.273587294602656522645691372699677063d+00, &
|
||
-6.294740283927400326554066998751383342d-01, &
|
||
0.000000000000000000000000000000000000d+00 ]
|
||
bt(:) = [ 2.836343005184365275160654678626695428d-01, &
|
||
9.736500104654741223716056170419660217d-01, &
|
||
3.382359225242515288768487569778320563d-01, &
|
||
-3.584943611106183357043212309791897386d-01, &
|
||
-4.113944068471528211627210454497620358d-03, &
|
||
1.427968894048586363415504654313371031d+00, &
|
||
1.808470948394314017665968411915568633d-02, &
|
||
1.605770645946802213926893453819236685d-01, &
|
||
2.952227015964591648775833803635147962d-01 ]
|
||
bh(:) = [ 2.483675912451591196775756814283216443d-02, &
|
||
1.866327774562103796990092260942180726d-01, &
|
||
5.671080795936984495604436622517631183d-02, &
|
||
-3.447695439149287702616943808570747099d-03, &
|
||
3.602245056516636472203469198006404016d-03, &
|
||
4.545570622145088936800484247980581766d-01, &
|
||
-2.434665289427612407531544765622888855d-04, &
|
||
6.642755361103549971517945063138312147d-02, &
|
||
1.613697079523505006226025497715177578d-01, &
|
||
4.955424859358438183052504342394102722d-02 ]
|
||
gm(1,:) = [ 0.000000000000000000000000000000000000d+00, &
|
||
-4.655641447335068552684422206224169103d+00, &
|
||
-7.720265099645871829248487209517314217d-01, &
|
||
-4.024436690519806086742256154738379161d+00, &
|
||
-2.129676284018530966221583708648634733d-02, &
|
||
-2.435022509790109546199372365866450709d+00, &
|
||
1.985627297131987000579523283542615256d-02, &
|
||
-2.810791146791038566946663374735713961d-01, &
|
||
1.689434168754859644351230590422137972d-01 ]
|
||
gm(2,:) = [ 1.000000000000000000000000000000000000d+00, &
|
||
2.499262792574495009336242992898153462d+00, &
|
||
5.866820377718875577451517985847920081d-01, &
|
||
1.205146086523094569925592464380295241d+00, &
|
||
3.474793722186732780030762737753849272d-01, &
|
||
1.321346060965113109321230804210670518d+00, &
|
||
3.119636464694193615946633676950358444d-01, &
|
||
4.351419539684379261368971206040518552d-01, &
|
||
2.359698130028753572503744518147537768d-01 ]
|
||
gm(3,:) = [ 0.000000000000000000000000000000000000d+00, &
|
||
0.000000000000000000000000000000000000d+00, &
|
||
0.000000000000000000000000000000000000d+00, &
|
||
7.621006678721315291614677352949377871d-01, &
|
||
-1.981182504339400567765766904309673119d-01, &
|
||
-6.228959218699007450469629366684127462d-01, &
|
||
-3.752248380775956442989480369774937099d-01, &
|
||
-3.355438309135169811915662336248989661d-01, &
|
||
-4.560955005031121479972862973705108039d-02 ]
|
||
|
||
betas(:) = [ 3.8d-01, -1.8d-01, 1.0d-02 ]
|
||
|
||
call get_parameter("beta(1)", betas(1))
|
||
call get_parameter("beta(2)", betas(2))
|
||
call get_parameter("beta(3)", betas(3))
|
||
|
||
betas(:) = - betas(:) / 4.0d+00
|
||
|
||
case ("rk5(4)10", "RK5(4)10")
|
||
|
||
! References:
|
||
!
|
||
! [1] Ranocha, H., Dalcin, L., Parsani, M., Ketcheson, D. I.
|
||
! "Coefficients of Optimized Runge-Kutta Methods with Automatic
|
||
! Step Size Control for Compressible Computational Fluid Dynamics",
|
||
! 2021, DOI:10.5281/zenodo.4671927,
|
||
! https://github.com/ranocha/Optimized-RK-CFD
|
||
!
|
||
error_control = .true.
|
||
evolve => evolve_3sstarplus
|
||
registers = 4
|
||
order = 5
|
||
stages = 10
|
||
name_int = "Optimized 5ᵗʰ-order 10-step embedded RK5(4)10"
|
||
|
||
allocate(c(stages+1), dl(stages), bt(stages), bh(stages+1), gm(3,stages))
|
||
c (:) = [ 0.000000000000000000000000000000000000d+00, &
|
||
2.597883575710995826783320802193635406d-01, &
|
||
9.904573115730917688557891428202061598d-02, &
|
||
2.155511882303785204133426661931565216d-01, &
|
||
5.007950078421880417512789524851012021d-01, &
|
||
5.592251914858131230054392022144328176d-01, &
|
||
5.449986973408778242805929551952000165d-01, &
|
||
7.615224662599497796472095353126697300d-01, &
|
||
8.427062083059167761623893618875787414d-01, &
|
||
9.152209807185253394871325258038753352d-01, &
|
||
1.000000000000000000000000000000000000d+00 ]
|
||
dl(:) = [ 1.000000000000000000000000000000000000d+00, &
|
||
-1.331778409133849616712007380176762548d-01, &
|
||
8.260422785246030254485064732649153253d-01, &
|
||
1.513700430513332405798616943654007796d+00, &
|
||
-1.305810063177048110528482211982726539d+00, &
|
||
3.036678789342507704281817524408221954d+00, &
|
||
-1.449458267074592489788800461540171106d+00, &
|
||
3.834313873320957483471400258279635203d+00, &
|
||
4.122293971923324492772059928094971199d+00, &
|
||
0.000000000000000000000000000000000000d+00 ]
|
||
bt(:) = [ 2.597883575710995826783320802193635406d-01, &
|
||
1.777008800169541694837687556103565007d-02, &
|
||
2.481636637328140606807905234325691851d-01, &
|
||
7.941736827560429420202759490815682546d-01, &
|
||
3.885391296871822541486945325814526190d-01, &
|
||
1.455051664264339366757555740296587660d-01, &
|
||
1.587517379462528932413419955691782412d-01, &
|
||
1.650605631567659573994022720500446501d-01, &
|
||
2.118093299943235065178000892467421832d-01, &
|
||
1.559392340339606299335442956580114440d-01 ]
|
||
bh(:) = [ 5.734588484676193812418453938089759359d-02, &
|
||
1.971447518039733870541652912891291496d-02, &
|
||
7.215296605683716720707226840456658773d-02, &
|
||
1.739659489807939956977075317768151880d-01, &
|
||
3.703693600445487815015171515640585668d-01, &
|
||
-1.215599039055065009827765147821222534d-01, &
|
||
1.180372945491121604465067725859678821d-01, &
|
||
4.155688823364870056536983972605056553d-02, &
|
||
1.227886627910379901351569893551486490d-01, &
|
||
1.456284232223684285998448928597043056d-01, &
|
||
0.000000000000000000000000000000000000d+00 ]
|
||
gm(1,:) = [ 0.000000000000000000000000000000000000d+00, &
|
||
4.043660078504695837542588769963326988d-01, &
|
||
-8.503427464263185087039788184485627962d-01, &
|
||
-6.950894167072419998080989313353063399d+00, &
|
||
9.238765225328278557805080247596562995d-01, &
|
||
-2.563178039957404359875124580586147888d+00, &
|
||
2.545744869966347362604059848503340890d-01, &
|
||
3.125831733863168874151935287174374515d-01, &
|
||
-7.007114800567584871263283872289072079d-01, &
|
||
4.839620970980726631935174740648996010d-01 ]
|
||
gm(2,:) = [ 1.000000000000000000000000000000000000d+00, &
|
||
6.871467069752345566001768382316915820d-01, &
|
||
1.093024760468898686510433898645775908d+00, &
|
||
3.225975382330161123625348062949430509d+00, &
|
||
1.041153700841396427100436517666787823d+00, &
|
||
1.292821488864702752767390075072674807d+00, &
|
||
7.391462769297006312785029455392854586d-01, &
|
||
1.239129257039300081860496157739352186d-01, &
|
||
1.842753479366766790220633908793933781d-01, &
|
||
5.712788942697077644959290025755003720d-02 ]
|
||
gm(3,:) = [ 0.000000000000000000000000000000000000d+00, &
|
||
0.000000000000000000000000000000000000d+00, &
|
||
0.000000000000000000000000000000000000d+00, &
|
||
-2.393405159342139386425044844626597490d+00, &
|
||
-1.902854422095986544338294743445530533d+00, &
|
||
-2.820042210583207174321941694153843259d+00, &
|
||
-1.832698464130564949123807896975136336d+00, &
|
||
-2.199094510750697865007677774395365522d-01, &
|
||
-4.082430660384876496971887725512427800d-01, &
|
||
-1.377669791121207993339861855818881150d-01 ]
|
||
|
||
betas(:) = [ 4.7d-01, -2.0d-01, 6.0d-02 ]
|
||
|
||
call get_parameter("beta(1)", betas(1))
|
||
call get_parameter("beta(2)", betas(2))
|
||
call get_parameter("beta(3)", betas(3))
|
||
|
||
betas(:) = - betas(:) / 5.0d+00
|
||
|
||
case ("rk5(4)10f", "RK5(4)10F")
|
||
|
||
! References:
|
||
!
|
||
! [1] Ranocha, H., Dalcin, L., Parsani, M., Ketcheson, D. I.
|
||
! "Coefficients of Optimized Runge-Kutta Methods with Automatic
|
||
! Step Size Control for Compressible Computational Fluid Dynamics",
|
||
! 2021, DOI:10.5281/zenodo.4671927,
|
||
! https://github.com/ranocha/Optimized-RK-CFD
|
||
!
|
||
error_control = .true.
|
||
fsal = .true.
|
||
evolve => evolve_3sstarplus
|
||
registers = 4
|
||
order = 5
|
||
stages = 10
|
||
name_int = "Optimized 5ᵗʰ-order 10-step embedded RK5(4)10 FSAL"
|
||
|
||
allocate(c(stages+1), dl(stages), bt(stages), bh(stages+1), gm(3,stages))
|
||
c (:) = [ 0.000000000000000000000000000000000000d+00, &
|
||
2.597883554788674084039539165398464630d-01, &
|
||
9.904573247592460887087003212056568980d-02, &
|
||
2.155511890524058691860390281856497503d-01, &
|
||
5.007950088969676776844289399972611534d-01, &
|
||
5.592251911688643533787800688765883636d-01, &
|
||
5.449986978853637084972622392134732553d-01, &
|
||
7.615224694532590139829150720490417596d-01, &
|
||
8.427062083267360939805493320684741215d-01, &
|
||
9.152209805057669959657927210873423883d-01, &
|
||
1.000000000000000000000000000000000000d+00 ]
|
||
dl(:) = [ 1.000000000000000000000000000000000000d+00, &
|
||
-1.331778419508803397033287009506932673d-01, &
|
||
8.260422814750207498262063505871077303d-01, &
|
||
1.513700425755728332485300719652378197d+00, &
|
||
-1.305810059935023735972298885749903694d+00, &
|
||
3.036678802924163246003321318996156380d+00, &
|
||
-1.449458274398895177922690618003584514d+00, &
|
||
3.834313899176362315089976408899373409d+00, &
|
||
4.122293760012985409330881631526514714d+00, &
|
||
0.000000000000000000000000000000000000d+00 ]
|
||
bt(:) = [ 2.597883554788674084039539165398464630d-01, &
|
||
1.777008889438867858759149597539211023d-02, &
|
||
2.481636629715501931294746189266601496d-01, &
|
||
7.941736871152005775821844297293296135d-01, &
|
||
3.885391285642019129575902994397298066d-01, &
|
||
1.455051657916305055730603387469193768d-01, &
|
||
1.587517385964749337690916959584348979d-01, &
|
||
1.650605617880053419242434594242509601d-01, &
|
||
2.118093284937153836908655490906875007d-01, &
|
||
1.559392342362059886106995325687547506d-01 ]
|
||
bh(:) = [ -2.019255440012066080909442770590267512d-02, &
|
||
2.737903480959184339932730854141598275d-02, &
|
||
3.028818636145965534365173822296811090d-01, &
|
||
-3.656843880622222190071445247906780540d-02, &
|
||
3.982664774676767729863101188528827405d-01, &
|
||
-5.715959421140685436681459970502471634d-02, &
|
||
9.849855103848558320961101178888983150d-02, &
|
||
6.654601552456084978615342374581437947d-02, &
|
||
9.073479542748112726465375642050504556d-02, &
|
||
8.432289325330803924891866923939606351d-02, &
|
||
4.529095628204896774513180907141004447d-02 ]
|
||
gm(1,:) = [ 0.000000000000000000000000000000000000d+00, &
|
||
4.043660121685749695640462197806189975d-01, &
|
||
-8.503427289575839690883191973980814832d-01, &
|
||
-6.950894175262117526410215315179482885d+00, &
|
||
9.238765192731084931855438934978371889d-01, &
|
||
-2.563178056509891340215942413817786020d+00, &
|
||
2.545744879365226143946122067064118430d-01, &
|
||
3.125831707411998258746812355492206137d-01, &
|
||
-7.007114414440507927791249989236719346d-01, &
|
||
4.839621016023833375810172323297465039d-01 ]
|
||
gm(2,:) = [ 1.000000000000000000000000000000000000d+00, &
|
||
6.871467028161416909922221357014564412d-01, &
|
||
1.093024748914750833700799552463885117d+00, &
|
||
3.225975379607193001678365742708874597d+00, &
|
||
1.041153702510101386914019859778740444d+00, &
|
||
1.292821487912164945157744726076279306d+00, &
|
||
7.391462755788122847651304143259254381d-01, &
|
||
1.239129251371800313941948224441873274d-01, &
|
||
1.842753472370123193132193302369345580d-01, &
|
||
5.712788998796583446479387686662738843d-02 ]
|
||
gm(3,:) = [ 0.000000000000000000000000000000000000d+00, &
|
||
0.000000000000000000000000000000000000d+00, &
|
||
0.000000000000000000000000000000000000d+00, &
|
||
-2.393405133244194727221124311276648940d+00, &
|
||
-1.902854422421760920850597670305403139d+00, &
|
||
-2.820042207399977261483046412236557428d+00, &
|
||
-1.832698465277380999601896111079977378d+00, &
|
||
-2.199094483084671192328083958346519535d-01, &
|
||
-4.082430635847870963724591602173546218d-01, &
|
||
-1.377669797880289713535665985132703979d-01 ]
|
||
|
||
betas(:) = [ 4.5d-01, -1.3d-01, 0.0d+00 ]
|
||
|
||
call get_parameter("beta(1)", betas(1))
|
||
call get_parameter("beta(2)", betas(2))
|
||
call get_parameter("beta(3)", betas(3))
|
||
|
||
betas(:) = - betas(:) / 5.0d+00
|
||
|
||
case default
|
||
|
||
if (verbose) then
|
||
write(msg,fmt) "'" // uppercase(trim(integration)) // "'", &
|
||
new_line('a'), &
|
||
"'EULER', 'SSPRK(2,2)', 'SSPRK(3,3)', 'SSPRK(4,3)', " // &
|
||
"'SSPRK(5,3)', 'SSPRK(5,4)', 'SSPRK(10,4)'", &
|
||
new_line('a'), &
|
||
"'SSPRK2(1)M', 'SSPRK3(2)4', 'SSPRK3(2)M', " // &
|
||
"'RK3(2)5', 'RK4(3)9', 'RK5(4)10', "// &
|
||
"'RK3(2)5F', 'RK4(3)9F', 'RK5(4)10F'"
|
||
call print_message(loc, msg)
|
||
end if
|
||
status = 1
|
||
return
|
||
|
||
end select
|
||
|
||
! select error norm
|
||
!
|
||
call get_parameter("error_norm", error_norm)
|
||
|
||
select case(trim(error_norm))
|
||
case("Lmax", "lmax", "max", "maximum", "infinity")
|
||
update_errors => update_errors_lmax
|
||
name_norm = "Lmax-norm"
|
||
case("L1", "l1", "Manhattan", "manhattan")
|
||
update_errors => update_errors_l1
|
||
name_norm = "L1-norm"
|
||
case default
|
||
update_errors => update_errors_l2
|
||
name_norm = "L2-norm"
|
||
end select
|
||
|
||
! reset recent error history
|
||
!
|
||
errs = 1.0d+00
|
||
|
||
! GLM coefficients for all refinement levels
|
||
!
|
||
allocate(adecay(toplev), aglm(toplev))
|
||
#if NDIMS == 3
|
||
aglm(:) = - glm_alpha / min(adx(:), ady(:), adz(:))
|
||
#else /* NDIMS == 3 */
|
||
aglm(:) = - glm_alpha / min(adx(:), ady(:))
|
||
#endif /* NDIMS == 3 */
|
||
|
||
! initialize other modules
|
||
!
|
||
call initialize_schemes(verbose, status)
|
||
if (status /=0) &
|
||
call print_message(loc, "Could not initialize module SCHEMES!")
|
||
if (check_status(status /= 0)) return
|
||
|
||
call initialize_sources(verbose, status)
|
||
if (status /=0) &
|
||
call print_message(loc, "Could not initialize module SOURCES!")
|
||
if (check_status(status /= 0)) return
|
||
|
||
call initialize_forcing(verbose, status)
|
||
if (status /=0) &
|
||
call print_message(loc, "Could not initialize module FORCING!")
|
||
if (check_status(status /= 0)) return
|
||
|
||
call initialize_gravity(verbose, status)
|
||
if (status /=0) &
|
||
call print_message(loc, "Could not initialize module GRAVITY!")
|
||
if (check_status(status /= 0)) return
|
||
|
||
call initialize_shapes(status)
|
||
if (status /=0) &
|
||
call print_message(loc, "Could not initialize module SHAPES!")
|
||
if (check_status(status /= 0)) return
|
||
|
||
!-------------------------------------------------------------------------------
|
||
!
|
||
end subroutine initialize_evolution
|
||
!
|
||
!===============================================================================
|
||
!
|
||
! subroutine FINALIZE_EVOLUTION:
|
||
! -----------------------------
|
||
!
|
||
! Subroutine releases memory used by the module.
|
||
!
|
||
! Arguments:
|
||
!
|
||
! status - an integer flag for error return value;
|
||
!
|
||
!===============================================================================
|
||
!
|
||
subroutine finalize_evolution(verbose, status)
|
||
|
||
use forcing, only : finalize_forcing
|
||
use gravity, only : finalize_gravity
|
||
use helpers, only : print_section, print_parameter, print_message
|
||
use schemes, only : finalize_schemes
|
||
use shapes , only : finalize_shapes
|
||
use sources, only : finalize_sources
|
||
|
||
implicit none
|
||
|
||
logical, intent(in) :: verbose
|
||
integer, intent(out) :: status
|
||
|
||
character(len=*), parameter :: loc = 'EVOLUTION::finalize_evolution()'
|
||
|
||
!-------------------------------------------------------------------------------
|
||
!
|
||
status = 0
|
||
|
||
call finalize_shapes(status)
|
||
if (status /=0) &
|
||
call print_message(loc, "Could not finalize module SHAPES!")
|
||
|
||
call finalize_gravity(status)
|
||
if (status /=0) &
|
||
call print_message(loc, "Could not finalize module GRAVITY!")
|
||
|
||
call finalize_forcing(status)
|
||
if (status /=0) &
|
||
call print_message(loc, "Could not finalize module FORCING!")
|
||
|
||
call finalize_sources(status)
|
||
if (status /=0) &
|
||
call print_message(loc, "Could not finalize module SOURCES!")
|
||
|
||
call finalize_schemes(status)
|
||
if (status /=0) &
|
||
call print_message(loc, "Could not finalize module SCHEMES!")
|
||
|
||
if (allocated(adecay)) deallocate(adecay)
|
||
if (allocated(aglm)) deallocate(aglm)
|
||
if (allocated(c)) deallocate(c)
|
||
if (allocated(dl)) deallocate(dl)
|
||
if (allocated(bt)) deallocate(bt)
|
||
if (allocated(bh)) deallocate(bh)
|
||
if (allocated(gm)) deallocate(gm)
|
||
|
||
! nullify pointers
|
||
!
|
||
nullify(evolve)
|
||
nullify(update_errors)
|
||
|
||
! print integration summary
|
||
!
|
||
if (niterations > 0) then
|
||
call print_section(verbose, "Integration summary")
|
||
call print_parameter(verbose, "Number of iterations", niterations)
|
||
call print_parameter(verbose, "Number of rejections", nrejections)
|
||
end if
|
||
|
||
!-------------------------------------------------------------------------------
|
||
!
|
||
end subroutine finalize_evolution
|
||
!
|
||
!===============================================================================
|
||
!
|
||
! subroutine PRINT_EVOLUTION:
|
||
! --------------------------
|
||
!
|
||
! Subroutine prints module parameters.
|
||
!
|
||
! Arguments:
|
||
!
|
||
! verbose - a logical flag turning the information printing;
|
||
!
|
||
!===============================================================================
|
||
!
|
||
subroutine print_evolution(verbose)
|
||
|
||
use equations, only : magnetized
|
||
use forcing , only : print_forcing
|
||
use helpers , only : print_section, print_parameter
|
||
use schemes , only : print_schemes
|
||
use shapes , only : print_shapes
|
||
use sources , only : print_sources
|
||
|
||
implicit none
|
||
|
||
logical, intent(in) :: verbose
|
||
|
||
!-------------------------------------------------------------------------------
|
||
!
|
||
call print_sources(verbose)
|
||
call print_forcing(verbose)
|
||
|
||
if (verbose) then
|
||
|
||
call print_section(verbose, "Evolution")
|
||
call print_parameter(verbose, "time advance", name_int)
|
||
call print_parameter(verbose, "no. of registers", registers)
|
||
call print_parameter(verbose, "CFL coefficient", cfl)
|
||
call print_parameter(verbose, "timestep jump factor", facjmp)
|
||
if (magnetized) then
|
||
call print_parameter(verbose, "GLM alpha coefficient", glm_alpha)
|
||
end if
|
||
if (error_control) then
|
||
call print_parameter(verbose, "absolute tolerance", atol)
|
||
call print_parameter(verbose, "relative tolerance", rtol)
|
||
call print_parameter(verbose, "error norm" , name_norm)
|
||
call print_parameter(verbose, "maximum rejections", mrej)
|
||
call print_parameter(verbose, "chi" , chi)
|
||
call print_parameter(verbose, "factor" , fac)
|
||
call print_parameter(verbose, "minimum factor" , facmin)
|
||
call print_parameter(verbose, "maximum factor" , facmax)
|
||
end if
|
||
|
||
end if
|
||
|
||
call print_shapes(verbose)
|
||
call print_schemes(verbose)
|
||
|
||
!-------------------------------------------------------------------------------
|
||
!
|
||
end subroutine print_evolution
|
||
!
|
||
!===============================================================================
|
||
!
|
||
! subroutine ADVANCE:
|
||
! ------------------
|
||
!
|
||
! Subroutine advances the solution by one time step using the selected time
|
||
! integration method.
|
||
!
|
||
! Arguments:
|
||
!
|
||
! status - the subroutine call status: 0 for success, otherwise failure;
|
||
!
|
||
!===============================================================================
|
||
!
|
||
subroutine advance(status)
|
||
|
||
use blocks , only : set_blocks_update
|
||
use coordinates, only : toplev
|
||
use forcing , only : update_forcing, forcing_enabled
|
||
use mesh , only : update_mesh
|
||
|
||
implicit none
|
||
|
||
integer, intent(out) :: status
|
||
|
||
logical :: injected
|
||
|
||
!-------------------------------------------------------------------------------
|
||
!
|
||
! advance the solution using the selected method
|
||
!
|
||
call evolve()
|
||
|
||
! add forcing contribution, requires the boundary and primitive variable update
|
||
!
|
||
if (forcing_enabled) then
|
||
call update_forcing(time, dt, injected)
|
||
|
||
if (injected) then
|
||
call update_variables(time + dt, 0.0d+00, status)
|
||
if (status /= 0) go to 100
|
||
end if
|
||
end if
|
||
|
||
! check if we need to perform the refinement step
|
||
!
|
||
if (toplev > 1) then
|
||
|
||
! set all meta blocks to not be updated
|
||
!
|
||
call set_blocks_update(.false.)
|
||
|
||
! check refinement and refine
|
||
!
|
||
call update_mesh(status)
|
||
if (status /= 0) go to 100
|
||
|
||
! update primitive variables
|
||
!
|
||
call update_variables(time + dt, 0.0d+00, status)
|
||
if (status /= 0) go to 100
|
||
|
||
! set all meta blocks to be updated
|
||
!
|
||
call set_blocks_update(.true.)
|
||
|
||
end if ! toplev > 1
|
||
|
||
! error entry point
|
||
!
|
||
100 continue
|
||
|
||
!-------------------------------------------------------------------------------
|
||
!
|
||
end subroutine advance
|
||
!
|
||
!===============================================================================
|
||
!
|
||
! subroutine INITIALIZE_TIME_STEP:
|
||
! -------------------------------
|
||
!
|
||
! Subroutine estimates the initial time step.
|
||
!
|
||
! References:
|
||
!
|
||
! [1] Courant, R., Friedrichs, K., Lewy, H.,
|
||
! "Über die partiellen Differenzengleichungen der mathematischen Physik",
|
||
! Mathematische Annalen, 1928, volume 100, pages 32–74,
|
||
! DOI: 10.1007/BF01448839
|
||
! [2] Hairer, E., Nørsett, S. P., Wanner, G.,
|
||
! "Solving Ordinary Differential Equations I: Nonstiff Problems",
|
||
! Springer-Verlag Berlin Heidelberg, 1993,
|
||
! ISBN: 978-3-540-56670-0, DOI: 10.1007/978-3-540-78862-1
|
||
!
|
||
!===============================================================================
|
||
!
|
||
subroutine initialize_time_step()
|
||
|
||
use blocks , only : block_data, data_blocks, get_nleafs, get_dblocks
|
||
use coordinates, only : nc => ncells, nb, ne, adx, ady
|
||
#if NDIMS == 3
|
||
use coordinates, only : adz
|
||
#endif /* NDIMS == 3 */
|
||
use equations , only : nf, get_maximum_speeds, cmax2, cmax, umax, cglm
|
||
use helpers , only : print_message
|
||
#ifdef MPI
|
||
use mpitools , only : reduce_maximum, reduce_sum
|
||
#endif /* MPI */
|
||
use sources , only : viscosity, resistivity, update_sources
|
||
|
||
implicit none
|
||
|
||
type(block_data), pointer :: pdata
|
||
|
||
logical :: flag
|
||
integer :: l, m, n, status
|
||
real(kind=8) :: um, cm, dx_min, fnorm, h0, h1
|
||
real(kind=8), dimension(3) :: d
|
||
|
||
real(kind=8), dimension(:,:), allocatable :: s
|
||
|
||
#if NDIMS == 3
|
||
real(kind=8), dimension(nf,nc,nc,nc) :: sc, df
|
||
#else /* NDIMS == 3 */
|
||
real(kind=8), dimension(nf,nc,nc, 1) :: sc, df
|
||
#endif /* NDIMS == 3 */
|
||
|
||
real(kind=8), parameter :: eps = tiny(cmax)
|
||
|
||
character(len=*), parameter :: loc = 'EVOLUTION:initialize_time_step()'
|
||
!
|
||
!-------------------------------------------------------------------------------
|
||
!
|
||
umax = 0.0d+00
|
||
cmax = eps
|
||
m = 1
|
||
n = get_dblocks()
|
||
|
||
!$omp parallel do default(shared) private(pdata,um,cm)
|
||
do l = 1, n
|
||
pdata => data_blocks(l)%ptr
|
||
|
||
call get_maximum_speeds(pdata%q, um, cm)
|
||
!$omp atomic update
|
||
umax = max(umax, um)
|
||
!$omp atomic update
|
||
cmax = max(cmax, cm)
|
||
!$omp atomic update
|
||
m = max(m, pdata%meta%level)
|
||
end do
|
||
!$omp end parallel do
|
||
|
||
#ifdef MPI
|
||
call reduce_maximum(umax)
|
||
call reduce_maximum(cmax)
|
||
call reduce_maximum(m)
|
||
#endif /* MPI */
|
||
|
||
cglm = cmax - umax
|
||
cmax2 = cmax * cmax
|
||
|
||
#if NDIMS == 2
|
||
dx_min = min(adx(m), ady(m))
|
||
#endif /* NDIMS == 2 */
|
||
#if NDIMS == 3
|
||
dx_min = min(adx(m), ady(m), adz(m))
|
||
#endif /* NDIMS == 3 */
|
||
|
||
dth = dx_min / max(cmax &
|
||
+ 2.0d+00 * max(viscosity, resistivity) / dx_min, eps)
|
||
dt = cfl * dth
|
||
|
||
! determine the time step due to the error
|
||
!
|
||
if (error_control) then
|
||
allocate(s(n,3))
|
||
s(:,:) = 0.0d+00
|
||
|
||
fnorm = (1.0d+00 / nc)**NDIMS / nf / get_nleafs()
|
||
|
||
d(:) = 0.0d+00
|
||
|
||
!$omp parallel do default(shared) private(pdata,sc)
|
||
do l = 1, n
|
||
pdata => data_blocks(l)%ptr
|
||
|
||
call update_increment(pdata)
|
||
call update_sources(0.0d+00, 0.0d+00, pdata)
|
||
|
||
#if NDIMS == 3
|
||
sc(:,:,:,:) = atol + rtol * abs(pdata%uu(1:nf,nb:ne,nb:ne,nb:ne,1))
|
||
|
||
s(l,1) = sum(fnorm * (pdata%uu(1:nf,nb:ne,nb:ne,nb:ne,1) / sc(:,:,:,:))**2)
|
||
s(l,2) = sum(fnorm * (pdata%du(1:nf,nb:ne,nb:ne,nb:ne) / sc(:,:,:,:))**2)
|
||
#else /* NDIMS == 3 */
|
||
sc(:,:,:,:) = atol + rtol * abs(pdata%uu(1:nf,nb:ne,nb:ne, : ,1))
|
||
|
||
s(l,1) = sum(fnorm * (pdata%uu(1:nf,nb:ne,nb:ne, : ,1) / sc(:,:,:,:))**2)
|
||
s(l,2) = sum(fnorm * (pdata%du(1:nf,nb:ne,nb:ne, : ) / sc(:,:,:,:))**2)
|
||
#endif /* NDIMS == 3 */
|
||
|
||
pdata%u => pdata%uu(:,:,:,:,2)
|
||
end do
|
||
!$omp end parallel do
|
||
d(1) = sum(s(:,1))
|
||
d(2) = sum(s(:,2))
|
||
|
||
#ifdef MPI
|
||
call reduce_sum(d(1:2))
|
||
#endif /* MPI */
|
||
|
||
d(1:2) = sqrt(d(1:2))
|
||
|
||
if (minval(d(1:2)) >= 1.0d-05) then
|
||
h0 = min(dt, 1.0d-02 * d(1) / d(2))
|
||
else
|
||
h0 = dt
|
||
end if
|
||
|
||
m = 10
|
||
flag = .true.
|
||
|
||
do while(flag)
|
||
|
||
!$omp parallel do default(shared) private(pdata)
|
||
do l = 1, n
|
||
pdata => data_blocks(l)%ptr
|
||
|
||
pdata%uu(:,:,:,:,2) = pdata%uu(:,:,:,:,1) + h0 * pdata%du(:,:,:,:)
|
||
end do
|
||
!$omp end parallel do
|
||
|
||
call update_variables(time + h0, h0, status)
|
||
|
||
if (status /= 0) then
|
||
h0 = 2.5d-01 * h0
|
||
flag = m > 0
|
||
m = m - 1
|
||
else
|
||
flag = .false.
|
||
end if
|
||
|
||
end do
|
||
|
||
if (status /= 0) then
|
||
call print_message(loc, "Could not estimate the initial time step " // &
|
||
"due to the error. Setting it to the CFL time step.")
|
||
dte = dt
|
||
else
|
||
!$omp parallel do default(shared) private(pdata,df,sc)
|
||
do l = 1, n
|
||
pdata => data_blocks(l)%ptr
|
||
|
||
#if NDIMS == 3
|
||
df(:,:,:,:) = pdata%du(1:nf,nb:ne,nb:ne,nb:ne)
|
||
sc(:,:,:,:) = atol + rtol * abs(pdata%uu(1:nf,nb:ne,nb:ne,nb:ne,1))
|
||
#else /* NDIMS == 3 */
|
||
df(:,:,:,:) = pdata%du(1:nf,nb:ne,nb:ne, : )
|
||
sc(:,:,:,:) = atol + rtol * abs(pdata%uu(1:nf,nb:ne,nb:ne, : ,1))
|
||
#endif /* NDIMS == 3 */
|
||
|
||
call update_increment(pdata)
|
||
call update_sources(time + h0, 0.0d+00, pdata)
|
||
|
||
#if NDIMS == 3
|
||
df(:,:,:,:) = df(:,:,:,:) - pdata%du(1:nf,nb:ne,nb:ne,nb:ne)
|
||
#else /* NDIMS == 3 */
|
||
df(:,:,:,:) = df(:,:,:,:) - pdata%du(1:nf,nb:ne,nb:ne, : )
|
||
#endif /* NDIMS == 3 */
|
||
s(l,3) = sum(fnorm * (df(:,:,:,:) / sc(:,:,:,:))**2)
|
||
end do
|
||
!$omp end parallel do
|
||
d(3) = sum(s(:,3))
|
||
deallocate(s)
|
||
|
||
#ifdef MPI
|
||
call reduce_sum(d(3:3))
|
||
#endif /* MPI */
|
||
|
||
d(3) = sqrt(d(3)) / h0
|
||
|
||
h1 = max(d(2), d(3))
|
||
if (h1 > 1.0d-15) then
|
||
h1 = (1.0d-02 / h1)**(1.0d+00 / 3.0d+00)
|
||
else
|
||
h1 = max(dt, 1.0d-03 * h0)
|
||
end if
|
||
|
||
dte = min(1.0d+02 * h0, h1)
|
||
dt = min(dt, dte)
|
||
|
||
end if
|
||
|
||
! revert the initial state
|
||
!
|
||
!$omp parallel do default(shared) private(pdata,df,sc)
|
||
do l = 1, n
|
||
pdata => data_blocks(l)%ptr
|
||
pdata%uu(:,:,:,:,2) = pdata%uu(:,:,:,:,1)
|
||
|
||
pdata%u => pdata%uu(:,:,:,:,1)
|
||
end do
|
||
!$omp end parallel do
|
||
|
||
call update_variables(time, 0.0d+00, status)
|
||
|
||
end if
|
||
|
||
!-------------------------------------------------------------------------------
|
||
!
|
||
end subroutine initialize_time_step
|
||
!
|
||
!===============================================================================
|
||
!
|
||
! subroutine NEW_TIME_STEP:
|
||
! ------------------------
|
||
!
|
||
! Subroutine estimates the new time step from the maximum speed in the system
|
||
! and source term constraints.
|
||
!
|
||
! References:
|
||
!
|
||
! [1] Courant, R., Friedrichs, K., Lewy, H.,
|
||
! "Über die partiellen Differenzengleichungen der mathematischen Physik",
|
||
! Mathematische Annalen, 1928, volume 100, pages 32–74,
|
||
! DOI: 10.1007/BF01448839
|
||
!
|
||
!===============================================================================
|
||
!
|
||
subroutine new_time_step()
|
||
|
||
use blocks , only : block_data, data_blocks, get_dblocks
|
||
use coordinates , only : adx, ady
|
||
#if NDIMS == 3
|
||
use coordinates , only : adz
|
||
#endif /* NDIMS == 3 */
|
||
use equations , only : get_maximum_speeds, cmax, cmax2, umax, cglm
|
||
#ifdef MPI
|
||
use mpitools , only : reduce_maximum
|
||
#endif /* MPI */
|
||
use sources , only : viscosity, resistivity
|
||
|
||
implicit none
|
||
|
||
type(block_data), pointer :: pdata
|
||
|
||
integer :: l, n, m
|
||
real(kind=8) :: um, cm, dx_min
|
||
|
||
real(kind=8), parameter :: eps = tiny(cmax)
|
||
|
||
!-------------------------------------------------------------------------------
|
||
!
|
||
umax = 0.0d+00
|
||
cmax = eps
|
||
m = 1
|
||
n = get_dblocks()
|
||
|
||
!$omp parallel do default(shared) private(pdata,um,cm)
|
||
do l = 1, n
|
||
pdata => data_blocks(l)%ptr
|
||
|
||
call get_maximum_speeds(pdata%q, um, cm)
|
||
!$omp atomic update
|
||
umax = max(umax, um)
|
||
!$omp atomic update
|
||
cmax = max(cmax, cm)
|
||
!$omp atomic update
|
||
m = max(m, pdata%meta%level)
|
||
end do
|
||
!$omp end parallel do
|
||
|
||
#ifdef MPI
|
||
call reduce_maximum(umax)
|
||
call reduce_maximum(cmax)
|
||
call reduce_maximum(m)
|
||
#endif /* MPI */
|
||
|
||
cglm = cmax - umax
|
||
cmax2 = cmax * cmax
|
||
|
||
#if NDIMS == 2
|
||
dx_min = min(adx(m), ady(m))
|
||
#endif /* NDIMS == 2 */
|
||
#if NDIMS == 3
|
||
dx_min = min(adx(m), ady(m), adz(m))
|
||
#endif /* NDIMS == 3 */
|
||
|
||
dth = dx_min / max(cmax &
|
||
+ 2.0d+00 * max(viscosity, resistivity) / dx_min, eps)
|
||
dt = min(facjmp * dt, cfl * dth)
|
||
dt = min(dt, dtp)
|
||
if (error_control) dt = min(dt, dte)
|
||
|
||
!-------------------------------------------------------------------------------
|
||
!
|
||
end subroutine new_time_step
|
||
!
|
||
!===============================================================================
|
||
!!
|
||
!!*** PRIVATE SUBROUTINES ****************************************************
|
||
!!
|
||
!===============================================================================
|
||
!
|
||
!===============================================================================
|
||
!
|
||
! subroutine EVOLVE_EULER:
|
||
! -----------------------
|
||
!
|
||
! Subroutine advances the solution by one time step using the 1st order
|
||
! Euler integration method.
|
||
!
|
||
! References:
|
||
!
|
||
! [1] Press, W. H, Teukolsky, S. A., Vetterling, W. T., Flannery, B. P.,
|
||
! "Numerical Recipes in Fortran",
|
||
! Cambridge University Press, Cambridge, 1992
|
||
!
|
||
!===============================================================================
|
||
!
|
||
subroutine evolve_euler()
|
||
|
||
use blocks , only : block_data, data_blocks, get_dblocks
|
||
use boundaries, only : boundary_fluxes
|
||
use equations , only : ibp, cmax
|
||
use sources , only : update_sources
|
||
|
||
implicit none
|
||
|
||
type(block_data), pointer :: pdata
|
||
|
||
integer :: l, n, status
|
||
real(kind=8) :: t
|
||
|
||
!-------------------------------------------------------------------------------
|
||
!
|
||
status = 1
|
||
|
||
n = get_dblocks()
|
||
|
||
do while(status /= 0)
|
||
|
||
t = time + dt
|
||
|
||
!$omp parallel do default(shared) private(pdata)
|
||
do l = 1, n
|
||
pdata => data_blocks(l)%ptr
|
||
|
||
pdata%uu(:,:,:,:,2) = pdata%uu(:,:,:,:,1)
|
||
|
||
pdata%u => pdata%uu(:,:,:,:,2)
|
||
end do
|
||
!$omp end parallel do
|
||
|
||
!$omp parallel do default(shared) private(pdata)
|
||
do l = 1, n
|
||
pdata => data_blocks(l)%ptr
|
||
|
||
call update_increment(pdata)
|
||
call update_sources(t, dt, pdata)
|
||
end do
|
||
!$omp end parallel do
|
||
|
||
call boundary_fluxes(status)
|
||
|
||
if (status /= 0) return
|
||
|
||
!$omp parallel do default(shared) private(pdata)
|
||
do l = 1, n
|
||
pdata => data_blocks(l)%ptr
|
||
|
||
pdata%uu(:,:,:,:,2) = pdata%uu(:,:,:,:,2) + dt * pdata%du(:,:,:,:)
|
||
end do
|
||
!$omp end parallel do
|
||
|
||
if (ibp > 0) then
|
||
adecay(:) = exp(aglm(:) * cmax * dt)
|
||
|
||
!$omp parallel do default(shared) private(pdata)
|
||
do l = 1, n
|
||
pdata => data_blocks(l)%ptr
|
||
|
||
pdata%u(ibp,:,:,:) = adecay(pdata%meta%level) * pdata%u(ibp,:,:,:)
|
||
end do
|
||
!$omp end parallel do
|
||
end if
|
||
|
||
call update_variables(t, dt, status)
|
||
|
||
if (status /= 0) dt = 2.5d-01 * dt
|
||
|
||
end do
|
||
|
||
!$omp parallel do default(shared) private(pdata)
|
||
do l = 1, n
|
||
pdata => data_blocks(l)%ptr
|
||
|
||
pdata%uu(:,:,:,:,1) = pdata%uu(:,:,:,:,2)
|
||
|
||
pdata%u => pdata%uu(:,:,:,:,1)
|
||
end do
|
||
!$omp end parallel do
|
||
|
||
!-------------------------------------------------------------------------------
|
||
!
|
||
end subroutine evolve_euler
|
||
!
|
||
!===============================================================================
|
||
!
|
||
! subroutine EVOLVE_SSPRK2:
|
||
! ------------------------
|
||
!
|
||
! Subroutine advances the solution by one time step using the 2nd order
|
||
! Strong Stability Preserving Runge-Kutta time integration method.
|
||
!
|
||
! References:
|
||
!
|
||
! [1] Press, W. H, Teukolsky, S. A., Vetterling, W. T., Flannery, B. P.,
|
||
! "Numerical Recipes in Fortran",
|
||
! Cambridge University Press, Cambridge, 1992
|
||
!
|
||
!===============================================================================
|
||
!
|
||
subroutine evolve_ssprk2()
|
||
|
||
use blocks , only : block_data, data_blocks, get_dblocks
|
||
use boundaries, only : boundary_fluxes
|
||
use equations , only : ibp, cmax
|
||
use sources , only : update_sources
|
||
|
||
implicit none
|
||
|
||
type(block_data), pointer :: pdata
|
||
|
||
integer :: l, n, status
|
||
real(kind=8) :: t, ds
|
||
|
||
!-------------------------------------------------------------------------------
|
||
!
|
||
status = 1
|
||
|
||
n = get_dblocks()
|
||
|
||
do while(status /= 0)
|
||
|
||
ds = 5.0d-01 * dt
|
||
|
||
!= 1st step: U(1) = U(n) + dt * F[U(n)]
|
||
!
|
||
t = time + dt
|
||
|
||
!$omp parallel do default(shared) private(pdata)
|
||
do l = 1, n
|
||
pdata => data_blocks(l)%ptr
|
||
|
||
call update_increment(pdata)
|
||
call update_sources(t, 0.0d+00, pdata)
|
||
end do
|
||
!$omp end parallel do
|
||
|
||
call boundary_fluxes(status)
|
||
|
||
if (status /= 0) go to 100
|
||
|
||
!$omp parallel do default(shared) private(pdata)
|
||
do l = 1, n
|
||
pdata => data_blocks(l)%ptr
|
||
|
||
pdata%uu(:,:,:,:,2) = pdata%uu(:,:,:,:,1) + dt * pdata%du(:,:,:,:)
|
||
|
||
pdata%u => pdata%uu(:,:,:,:,2)
|
||
end do
|
||
!$omp end parallel do
|
||
|
||
call update_variables(t, dt, status)
|
||
|
||
if (status /= 0) go to 100
|
||
|
||
!= 2nd step: U(n+1) = 1/2 U(n) + 1/2 U(1) + 1/2 dt * F[U(1)]
|
||
!
|
||
!$omp parallel do default(shared) private(pdata)
|
||
do l = 1, n
|
||
pdata => data_blocks(l)%ptr
|
||
|
||
call update_increment(pdata)
|
||
call update_sources(t, ds, pdata)
|
||
end do
|
||
!$omp end parallel do
|
||
|
||
call boundary_fluxes(status)
|
||
|
||
if (status /= 0) go to 100
|
||
|
||
!$omp parallel do default(shared) private(pdata)
|
||
do l = 1, n
|
||
pdata => data_blocks(l)%ptr
|
||
|
||
pdata%uu(:,:,:,:,2) = 5.0d-01 * (pdata%uu(:,:,:,:,1) &
|
||
+ pdata%uu(:,:,:,:,2)) &
|
||
+ ds * pdata%du(:,:,:,:)
|
||
end do
|
||
!$omp end parallel do
|
||
|
||
if (ibp > 0) then
|
||
adecay(:) = exp(aglm(:) * cmax * dt)
|
||
|
||
!$omp parallel do default(shared) private(pdata)
|
||
do l = 1, n
|
||
pdata => data_blocks(l)%ptr
|
||
|
||
pdata%u(ibp,:,:,:) = adecay(pdata%meta%level) * pdata%u(ibp,:,:,:)
|
||
end do
|
||
!$omp end parallel do
|
||
end if
|
||
|
||
call update_variables(t, ds, status)
|
||
|
||
100 continue
|
||
|
||
if (status /= 0) dt = 2.5d-01 * dt
|
||
|
||
end do
|
||
|
||
!$omp parallel do default(shared) private(pdata)
|
||
do l = 1, n
|
||
pdata => data_blocks(l)%ptr
|
||
|
||
pdata%uu(:,:,:,:,1) = pdata%uu(:,:,:,:,2)
|
||
|
||
pdata%u => pdata%uu(:,:,:,:,1)
|
||
end do
|
||
!$omp end parallel do
|
||
|
||
!-------------------------------------------------------------------------------
|
||
!
|
||
end subroutine evolve_ssprk2
|
||
!
|
||
!===============================================================================
|
||
!
|
||
! subroutine EVOLVE_SSPRK3:
|
||
! ------------------------
|
||
!
|
||
! Subroutine advances the solution by one time step using the 3rd order
|
||
! Strong Stability Preserving Runge-Kutta time integration method.
|
||
!
|
||
! References:
|
||
!
|
||
! [1] Press, W. H, Teukolsky, S. A., Vetterling, W. T., Flannery, B. P.,
|
||
! "Numerical Recipes in Fortran",
|
||
! Cambridge University Press, Cambridge, 1992
|
||
!
|
||
!===============================================================================
|
||
!
|
||
subroutine evolve_ssprk3()
|
||
|
||
use blocks , only : block_data, data_blocks, get_dblocks
|
||
use boundaries, only : boundary_fluxes
|
||
use equations , only : ibp, cmax
|
||
use sources , only : update_sources
|
||
|
||
implicit none
|
||
|
||
type(block_data), pointer :: pdata
|
||
|
||
integer :: l, n, status
|
||
real(kind=8) :: t, ds
|
||
|
||
!-------------------------------------------------------------------------------
|
||
!
|
||
status = 1
|
||
|
||
n = get_dblocks()
|
||
|
||
do while(status /= 0)
|
||
|
||
!= 1st substep: U(1) = U(n) + dt F[U(n)]
|
||
!
|
||
t = time + dt
|
||
|
||
!$omp parallel do default(shared) private(pdata)
|
||
do l = 1, n
|
||
pdata => data_blocks(l)%ptr
|
||
|
||
call update_increment(pdata)
|
||
call update_sources(t, 0.0d+00, pdata)
|
||
end do
|
||
!$omp end parallel do
|
||
|
||
call boundary_fluxes(status)
|
||
|
||
if (status /= 0) go to 100
|
||
|
||
!$omp parallel do default(shared) private(pdata)
|
||
do l = 1, n
|
||
pdata => data_blocks(l)%ptr
|
||
|
||
pdata%uu(:,:,:,:,2) = pdata%uu(:,:,:,:,1) + dt * pdata%du(:,:,:,:)
|
||
|
||
pdata%u => pdata%uu(:,:,:,:,2)
|
||
end do
|
||
!$omp end parallel do
|
||
|
||
call update_variables(t, dt, status)
|
||
|
||
if (status /= 0) go to 100
|
||
|
||
!= 2nd step: U(2) = 3/4 U(n) + 1/4 U(1) + 1/4 dt F[U(1)]
|
||
!
|
||
ds = dt / 4.0d+00
|
||
t = time + 5.0d-01 * dt
|
||
|
||
!$omp parallel do default(shared) private(pdata)
|
||
do l = 1, n
|
||
pdata => data_blocks(l)%ptr
|
||
|
||
call update_increment(pdata)
|
||
call update_sources(t, ds, pdata)
|
||
end do
|
||
!$omp end parallel do
|
||
|
||
call boundary_fluxes(status)
|
||
|
||
if (status /= 0) go to 100
|
||
|
||
!$omp parallel do default(shared) private(pdata)
|
||
do l = 1, n
|
||
pdata => data_blocks(l)%ptr
|
||
|
||
pdata%uu(:,:,:,:,2) = (3.0d+00 * pdata%uu(:,:,:,:,1) &
|
||
+ pdata%uu(:,:,:,:,2) &
|
||
+ ds * pdata%du(:,:,:,:)) / 4.0d+00
|
||
end do
|
||
!$omp end parallel do
|
||
|
||
call update_variables(t, ds, status)
|
||
|
||
if (status /= 0) go to 100
|
||
|
||
!= 3rd step: U(n+1) = 1/3 U(n) + 2/3 U(2) + 2/3 dt F[U(2)]
|
||
!
|
||
ds = 2.0d+00 * dt / 3.0d+00
|
||
t = time + dt
|
||
|
||
!$omp parallel do default(shared) private(pdata)
|
||
do l = 1, n
|
||
pdata => data_blocks(l)%ptr
|
||
|
||
call update_increment(pdata)
|
||
call update_sources(t, ds, pdata)
|
||
end do
|
||
!$omp end parallel do
|
||
|
||
call boundary_fluxes(status)
|
||
|
||
if (status /= 0) go to 100
|
||
|
||
!$omp parallel do default(shared) private(pdata)
|
||
do l = 1, n
|
||
pdata => data_blocks(l)%ptr
|
||
|
||
pdata%uu(:,:,:,:,2) = ( pdata%uu(:,:,:,:,1) &
|
||
+ 2.0d+00 * (pdata%uu(:,:,:,:,2) &
|
||
+ ds * pdata%du(:,:,:,:))) / 3.0d+00
|
||
|
||
pdata%u => pdata%uu(:,:,:,:,1)
|
||
end do
|
||
!$omp end parallel do
|
||
|
||
if (ibp > 0) then
|
||
adecay(:) = exp(aglm(:) * cmax * dt)
|
||
|
||
!$omp parallel do default(shared) private(pdata)
|
||
do l = 1, n
|
||
pdata => data_blocks(l)%ptr
|
||
|
||
pdata%u(ibp,:,:,:) = adecay(pdata%meta%level) * pdata%u(ibp,:,:,:)
|
||
end do
|
||
!$omp end parallel do
|
||
end if
|
||
|
||
call update_variables(t, dt, status)
|
||
|
||
100 continue
|
||
|
||
if (status /= 0) dt = dt / 4.0d+00
|
||
|
||
end do
|
||
|
||
!$omp parallel do default(shared) private(pdata)
|
||
do l = 1, n
|
||
pdata => data_blocks(l)%ptr
|
||
|
||
pdata%uu(:,:,:,:,1) = pdata%uu(:,:,:,:,2)
|
||
|
||
pdata%u => pdata%uu(:,:,:,:,1)
|
||
end do
|
||
!$omp end parallel do
|
||
|
||
!-------------------------------------------------------------------------------
|
||
!
|
||
end subroutine evolve_ssprk3
|
||
!
|
||
!===============================================================================
|
||
!
|
||
! subroutine EVOLVE_SSPRK34:
|
||
! -------------------------
|
||
!
|
||
! Subroutine advances the solution by one time step using the 3rd order
|
||
! 4-stage Strong Stability Preserving Runge-Kutta time integration method.
|
||
!
|
||
! References:
|
||
!
|
||
! [1] Ruuth, S. J.,
|
||
! "Global Optimization of Explicit Strong-Stability-Preserving
|
||
! Runge-Kutta methods",
|
||
! Mathematics of Computation,
|
||
! 2006, vol. 75, no. 253, pp. 183-207
|
||
!
|
||
!===============================================================================
|
||
!
|
||
subroutine evolve_ssprk34()
|
||
|
||
use blocks , only : block_data, data_blocks, get_dblocks
|
||
use boundaries, only : boundary_fluxes
|
||
use equations , only : ibp, cmax
|
||
use sources , only : update_sources
|
||
|
||
implicit none
|
||
|
||
type(block_data), pointer :: pdata
|
||
|
||
integer :: l, n, status
|
||
real(kind=8) :: t, ds
|
||
|
||
!-------------------------------------------------------------------------------
|
||
!
|
||
status = 1
|
||
|
||
n = get_dblocks()
|
||
|
||
do while(status /= 0)
|
||
|
||
!= 1st step: U(1) = U(n) + 1/2 dt F[U(n)]
|
||
!
|
||
ds = 5.0d-01 * dt
|
||
t = time + ds
|
||
|
||
!$omp parallel do default(shared) private(pdata)
|
||
do l = 1, n
|
||
pdata => data_blocks(l)%ptr
|
||
|
||
call update_increment(pdata)
|
||
call update_sources(t, 0.0d+00, pdata)
|
||
end do
|
||
!$omp end parallel do
|
||
|
||
call boundary_fluxes(status)
|
||
|
||
if (status /= 0) go to 100
|
||
|
||
!$omp parallel do default(shared) private(pdata)
|
||
do l = 1, n
|
||
pdata => data_blocks(l)%ptr
|
||
|
||
pdata%uu(:,:,:,:,2) = pdata%uu(:,:,:,:,1) + ds * pdata%du(:,:,:,:)
|
||
|
||
pdata%u => pdata%uu(:,:,:,:,2)
|
||
end do
|
||
!$omp end parallel do
|
||
|
||
call update_variables(t, ds, status)
|
||
|
||
if (status /= 0) go to 100
|
||
|
||
!= 2nd step: U(2) = U(2) + 1/2 dt F[U(1)]
|
||
!
|
||
t = time + dt
|
||
|
||
!$omp parallel do default(shared) private(pdata)
|
||
do l = 1, n
|
||
pdata => data_blocks(l)%ptr
|
||
|
||
call update_increment(pdata)
|
||
call update_sources(t, ds, pdata)
|
||
end do
|
||
!$omp end parallel do
|
||
|
||
call boundary_fluxes(status)
|
||
|
||
if (status /= 0) go to 100
|
||
|
||
!$omp parallel do default(shared) private(pdata)
|
||
do l = 1, n
|
||
pdata => data_blocks(l)%ptr
|
||
|
||
pdata%uu(:,:,:,:,2) = pdata%uu(:,:,:,:,2) + ds * pdata%du(:,:,:,:)
|
||
end do
|
||
!$omp end parallel do
|
||
|
||
call update_variables(t, ds, status)
|
||
|
||
if (status /= 0) go to 100
|
||
|
||
!= 3rd step: U(3) = 2/3 U(n) + 1/3 (U(2) + 1/6 dt F[U(2)])
|
||
!
|
||
t = time + ds
|
||
|
||
!$omp parallel do default(shared) private(pdata)
|
||
do l = 1, n
|
||
pdata => data_blocks(l)%ptr
|
||
|
||
call update_increment(pdata)
|
||
call update_sources(t, ds, pdata)
|
||
end do
|
||
!$omp end parallel do
|
||
|
||
call boundary_fluxes(status)
|
||
|
||
if (status /= 0) go to 100
|
||
|
||
!$omp parallel do default(shared) private(pdata)
|
||
do l = 1, n
|
||
pdata => data_blocks(l)%ptr
|
||
|
||
pdata%uu(:,:,:,:,2) = (2.0d+00 * pdata%uu(:,:,:,:,1) &
|
||
+ pdata%uu(:,:,:,:,2) &
|
||
+ 5.0d-01 * dt * pdata%du(:,:,:,:)) / 3.0d+00
|
||
end do
|
||
!$omp end parallel do
|
||
|
||
call update_variables(t, ds, status)
|
||
|
||
if (status /= 0) go to 100
|
||
|
||
!= the final step: U(n+1) = U(3) + 1/2 dt F[U(3)]
|
||
!
|
||
t = time + dt
|
||
|
||
!$omp parallel do default(shared) private(pdata)
|
||
do l = 1, n
|
||
pdata => data_blocks(l)%ptr
|
||
|
||
call update_increment(pdata)
|
||
call update_sources(t, ds, pdata)
|
||
end do
|
||
!$omp end parallel do
|
||
|
||
call boundary_fluxes(status)
|
||
|
||
if (status /= 0) go to 100
|
||
|
||
!$omp parallel do default(shared) private(pdata)
|
||
do l = 1, n
|
||
pdata => data_blocks(l)%ptr
|
||
|
||
pdata%uu(:,:,:,:,2) = pdata%uu(:,:,:,:,2) + ds * pdata%du(:,:,:,:)
|
||
end do
|
||
!$omp end parallel do
|
||
|
||
if (ibp > 0) then
|
||
adecay(:) = exp(aglm(:) * cmax * dt)
|
||
|
||
!$omp parallel do default(shared) private(pdata)
|
||
do l = 1, n
|
||
pdata => data_blocks(l)%ptr
|
||
|
||
pdata%u(ibp,:,:,:) = adecay(pdata%meta%level) * pdata%u(ibp,:,:,:)
|
||
end do
|
||
!$omp end parallel do
|
||
end if
|
||
|
||
call update_variables(t, dt, status)
|
||
|
||
100 continue
|
||
|
||
if (status /= 0) dt = 2.5d-01 * dt
|
||
|
||
end do
|
||
|
||
!$omp parallel do default(shared) private(pdata)
|
||
do l = 1, n
|
||
pdata => data_blocks(l)%ptr
|
||
|
||
pdata%uu(:,:,:,:,1) = pdata%uu(:,:,:,:,2)
|
||
|
||
pdata%u => pdata%uu(:,:,:,:,1)
|
||
end do
|
||
!$omp end parallel do
|
||
|
||
!-------------------------------------------------------------------------------
|
||
!
|
||
end subroutine evolve_ssprk34
|
||
!
|
||
!===============================================================================
|
||
!
|
||
! subroutine EVOLVE_SSPRK35:
|
||
! -------------------------
|
||
!
|
||
! Subroutine advances the solution by one time step using the 3rd order
|
||
! 5-stage Strong Stability Preserving Runge-Kutta time integration method.
|
||
!
|
||
! References:
|
||
!
|
||
! [1] Ruuth, S. J.,
|
||
! "Global Optimization of Explicit Strong-Stability-Preserving
|
||
! Runge-Kutta methods",
|
||
! Mathematics of Computation,
|
||
! 2006, vol. 75, no. 253, pp. 183-207
|
||
!
|
||
!===============================================================================
|
||
!
|
||
subroutine evolve_ssprk35()
|
||
|
||
use blocks , only : block_data, data_blocks, get_dblocks
|
||
use boundaries, only : boundary_fluxes
|
||
use equations , only : ibp, cmax
|
||
use sources , only : update_sources
|
||
|
||
implicit none
|
||
|
||
type(block_data), pointer :: pdata
|
||
|
||
integer :: l, n, status
|
||
real(kind=8) :: t, ds
|
||
|
||
real(kind=8), parameter :: b1 = 3.77268915331368d-01
|
||
real(kind=8), parameter :: b3 = 2.42995220537396d-01
|
||
real(kind=8), parameter :: b4 = 2.38458932846290d-01
|
||
real(kind=8), parameter :: b5 = 2.87632146308408d-01
|
||
real(kind=8), parameter :: a31 = 3.55909775063327d-01
|
||
real(kind=8), parameter :: a33 = 6.44090224936673d-01
|
||
real(kind=8), parameter :: a41 = 3.67933791638137d-01
|
||
real(kind=8), parameter :: a44 = 6.32066208361863d-01
|
||
real(kind=8), parameter :: a53 = 2.37593836598569d-01
|
||
real(kind=8), parameter :: a55 = 7.62406163401431d-01
|
||
!
|
||
!-------------------------------------------------------------------------------
|
||
!
|
||
status = 1
|
||
|
||
n = get_dblocks()
|
||
|
||
do while(status /= 0)
|
||
|
||
!= 1st step: U(1) = U(n) + b1 dt F[U(n)]
|
||
!
|
||
ds = b1 * dt
|
||
t = time + ds
|
||
|
||
!$omp parallel do default(shared) private(pdata)
|
||
do l = 1, n
|
||
pdata => data_blocks(l)%ptr
|
||
|
||
call update_increment(pdata)
|
||
call update_sources(t, 0.0d+00, pdata)
|
||
end do
|
||
!$omp end parallel do
|
||
|
||
call boundary_fluxes(status)
|
||
|
||
if (status /= 0) go to 100
|
||
|
||
!$omp parallel do default(shared) private(pdata)
|
||
do l = 1, n
|
||
pdata => data_blocks(l)%ptr
|
||
|
||
pdata%uu(:,:,:,:,2) = pdata%uu(:,:,:,:,1) + ds * pdata%du(:,:,:,:)
|
||
|
||
pdata%u => pdata%uu(:,:,:,:,2)
|
||
end do
|
||
!$omp end parallel do
|
||
|
||
call update_variables(t, ds, status)
|
||
|
||
if (status /= 0) go to 100
|
||
|
||
!= 2nd step: U(2) = U(1) + b1 dt F[U(1)]
|
||
!
|
||
t = time + 2.0d+00 * ds
|
||
|
||
!$omp parallel do default(shared) private(pdata)
|
||
do l = 1, n
|
||
pdata => data_blocks(l)%ptr
|
||
|
||
call update_increment(pdata)
|
||
call update_sources(t, ds, pdata)
|
||
end do
|
||
!$omp end parallel do
|
||
|
||
call boundary_fluxes(status)
|
||
|
||
if (status /= 0) go to 100
|
||
|
||
!$omp parallel do default(shared) private(pdata)
|
||
do l = 1, n
|
||
pdata => data_blocks(l)%ptr
|
||
|
||
pdata%uu(:,:,:,:,2) = pdata%uu(:,:,:,:,2) + ds * pdata%du(:,:,:,:)
|
||
end do
|
||
!$omp end parallel do
|
||
|
||
call update_variables(t, ds, status)
|
||
|
||
if (status /= 0) go to 100
|
||
|
||
!= 3rd step: U(3) = a31 U(n) + a33 U(2) + b3 dt F[U(2)]
|
||
!
|
||
ds = b3 * dt
|
||
t = time + (2.0d+00 * a33 * b1 + b3) * dt
|
||
|
||
!$omp parallel do default(shared) private(pdata)
|
||
do l = 1, n
|
||
pdata => data_blocks(l)%ptr
|
||
|
||
call update_increment(pdata)
|
||
call update_sources(t, ds, pdata)
|
||
end do
|
||
!$omp end parallel do
|
||
|
||
call boundary_fluxes(status)
|
||
|
||
if (status /= 0) go to 100
|
||
|
||
!$omp parallel do default(shared) private(pdata)
|
||
do l = 1, n
|
||
pdata => data_blocks(l)%ptr
|
||
|
||
pdata%uu(:,:,:,:,2) = a31 * pdata%uu(:,:,:,:,1) &
|
||
+ a33 * pdata%uu(:,:,:,:,2) + ds * pdata%du(:,:,:,:)
|
||
end do
|
||
!$omp end parallel do
|
||
|
||
call update_variables(t, ds, status)
|
||
|
||
if (status /= 0) go to 100
|
||
|
||
!= 4th step: U(4) = a41 U(n) + a44 U(3) + b4 dt F[U(3)]
|
||
!
|
||
ds = b4 * dt
|
||
t = time + ((2.0d+00 * b1 * a33 + b3) * a44 + b4) * dt
|
||
|
||
!$omp parallel do default(shared) private(pdata)
|
||
do l = 1, n
|
||
pdata => data_blocks(l)%ptr
|
||
|
||
call update_increment(pdata)
|
||
call update_sources(t, ds, pdata)
|
||
end do
|
||
!$omp end parallel do
|
||
|
||
call boundary_fluxes(status)
|
||
|
||
if (status /= 0) go to 100
|
||
|
||
!$omp parallel do default(shared) private(pdata)
|
||
do l = 1, n
|
||
pdata => data_blocks(l)%ptr
|
||
|
||
pdata%uu(:,:,:,:,3) = a41 * pdata%uu(:,:,:,:,1) &
|
||
+ a44 * pdata%uu(:,:,:,:,2) + ds * pdata%du(:,:,:,:)
|
||
|
||
pdata%u => pdata%uu(:,:,:,:,3)
|
||
end do
|
||
!$omp end parallel do
|
||
|
||
call update_variables(t, ds, status)
|
||
|
||
if (status /= 0) go to 100
|
||
|
||
!= the final step: U(n+1) = a53 U(2) + a55 U(4) + b5 dt F[U(4)]
|
||
!
|
||
ds = b5 * dt
|
||
t = time + dt
|
||
|
||
!$omp parallel do default(shared) private(pdata)
|
||
do l = 1, n
|
||
pdata => data_blocks(l)%ptr
|
||
|
||
call update_increment(pdata)
|
||
call update_sources(t, ds, pdata)
|
||
end do
|
||
!$omp end parallel do
|
||
|
||
call boundary_fluxes(status)
|
||
|
||
if (status /= 0) go to 100
|
||
|
||
!$omp parallel do default(shared) private(pdata)
|
||
do l = 1, n
|
||
pdata => data_blocks(l)%ptr
|
||
|
||
pdata%uu(:,:,:,:,2) = a53 * pdata%uu(:,:,:,:,2) &
|
||
+ a55 * pdata%uu(:,:,:,:,3) + ds * pdata%du(:,:,:,:)
|
||
|
||
pdata%u => pdata%uu(:,:,:,:,2)
|
||
end do
|
||
!$omp end parallel do
|
||
|
||
if (ibp > 0) then
|
||
adecay(:) = exp(aglm(:) * cmax * dt)
|
||
|
||
!$omp parallel do default(shared) private(pdata)
|
||
do l = 1, n
|
||
pdata => data_blocks(l)%ptr
|
||
|
||
pdata%u(ibp,:,:,:) = adecay(pdata%meta%level) * pdata%u(ibp,:,:,:)
|
||
end do
|
||
!$omp end parallel do
|
||
end if
|
||
|
||
call update_variables(t, dt, status)
|
||
|
||
100 continue
|
||
|
||
if (status /= 0) dt = 2.5d-01 * dt
|
||
|
||
end do
|
||
|
||
!$omp parallel do default(shared) private(pdata)
|
||
do l = 1, n
|
||
pdata => data_blocks(l)%ptr
|
||
|
||
pdata%uu(:,:,:,:,1) = pdata%uu(:,:,:,:,2)
|
||
|
||
pdata%u => pdata%uu(:,:,:,:,1)
|
||
end do
|
||
!$omp end parallel do
|
||
|
||
!-------------------------------------------------------------------------------
|
||
!
|
||
end subroutine evolve_ssprk35
|
||
!
|
||
!===============================================================================
|
||
!
|
||
! subroutine EVOLVE_SSPRK45:
|
||
! -------------------------
|
||
!
|
||
! Subroutine advances the solution by one time step using the 4th order
|
||
! 5-stage Strong Stability Preserving Runge-Kutta time integration method.
|
||
!
|
||
! References:
|
||
!
|
||
! [1] Ruuth, S. J.,
|
||
! "Global Optimization of Explicit Strong-Stability-Preserving
|
||
! Runge-Kutta methods",
|
||
! Mathematics of Computation,
|
||
! 2006, vol. 75, no. 253, pp. 183-207
|
||
!
|
||
!===============================================================================
|
||
!
|
||
subroutine evolve_ssprk45()
|
||
|
||
use blocks , only : block_data, data_blocks, get_dblocks
|
||
use boundaries, only : boundary_fluxes
|
||
use equations , only : ibp, cmax
|
||
use sources , only : update_sources
|
||
|
||
implicit none
|
||
|
||
type(block_data), pointer :: pdata
|
||
|
||
integer :: l, n, status
|
||
real(kind=8) :: t, ds
|
||
|
||
real(kind=8), parameter :: b11 = 3.91752226571890d-01, &
|
||
b22 = 3.68410593050371d-01, &
|
||
b33 = 2.51891774271694d-01, &
|
||
b44 = 5.44974750228521d-01, &
|
||
b54 = 6.36924686662900d-02, &
|
||
b55 = 2.26007483236906d-01
|
||
real(kind=8), parameter :: a21 = 4.44370493651235d-01, &
|
||
a22 = 5.55629506348765d-01
|
||
real(kind=8), parameter :: a31 = 6.20101851488403d-01, &
|
||
a33 = 3.79898148511597d-01
|
||
real(kind=8), parameter :: a41 = 1.78079954393132d-01, &
|
||
a44 = 8.21920045606868d-01
|
||
real(kind=8), parameter :: a53 = 5.17231671970585d-01, &
|
||
a54 = 9.60597105261470d-02, &
|
||
a55 = 3.86708617503269d-01
|
||
real(kind=8), parameter :: c2 = 3.91752226571890d-01, &
|
||
c3 = 5.86079689311541d-01, &
|
||
c4 = 4.74542363121399d-01, &
|
||
c5 = 9.35010630967652d-01
|
||
|
||
!-------------------------------------------------------------------------------
|
||
!
|
||
status = 1
|
||
|
||
n = get_dblocks()
|
||
|
||
do while(status /= 0)
|
||
|
||
!= 1st step: U(1) = U(n) + b11 dt F[U(n)]
|
||
!
|
||
ds = b11 * dt
|
||
t = time
|
||
|
||
!$omp parallel do default(shared) private(pdata)
|
||
do l = 1, n
|
||
pdata => data_blocks(l)%ptr
|
||
|
||
call update_increment(pdata)
|
||
call update_sources(t, 0.0d+00, pdata)
|
||
end do
|
||
!$omp end parallel do
|
||
|
||
call boundary_fluxes(status)
|
||
|
||
if (status /= 0) go to 100
|
||
|
||
!$omp parallel do default(shared) private(pdata)
|
||
do l = 1, n
|
||
pdata => data_blocks(l)%ptr
|
||
|
||
pdata%uu(:,:,:,:,2) = pdata%uu(:,:,:,:,1) + ds * pdata%du(:,:,:,:)
|
||
|
||
pdata%u => pdata%uu(:,:,:,:,2)
|
||
end do
|
||
!$omp end parallel do
|
||
|
||
call update_variables(t, ds, status)
|
||
|
||
if (status /= 0) go to 100
|
||
|
||
!= 2nd step: U(2) = a21 U(n) + a22 U(1) + b22 dt F[U(1)]
|
||
!
|
||
ds = b22 * dt
|
||
t = time + c2 * dt
|
||
|
||
!$omp parallel do default(shared) private(pdata)
|
||
do l = 1, n
|
||
pdata => data_blocks(l)%ptr
|
||
|
||
call update_increment(pdata)
|
||
call update_sources(t, ds, pdata)
|
||
end do
|
||
!$omp end parallel do
|
||
|
||
call boundary_fluxes(status)
|
||
|
||
if (status /= 0) go to 100
|
||
|
||
!$omp parallel do default(shared) private(pdata)
|
||
do l = 1, n
|
||
pdata => data_blocks(l)%ptr
|
||
|
||
pdata%uu(:,:,:,:,2) = a21 * pdata%uu(:,:,:,:,1) &
|
||
+ a22 * pdata%uu(:,:,:,:,2) &
|
||
+ ds * pdata%du(:,:,:,:)
|
||
end do
|
||
!$omp end parallel do
|
||
|
||
call update_variables(t, ds, status)
|
||
|
||
if (status /= 0) go to 100
|
||
|
||
!= 3rd step: U(3) = a31 U(n) + a33 U(2) + b33 dt F[U(2)]
|
||
!
|
||
ds = b33 * dt
|
||
t = time + c3 * dt
|
||
|
||
!$omp parallel do default(shared) private(pdata)
|
||
do l = 1, n
|
||
pdata => data_blocks(l)%ptr
|
||
|
||
call update_increment(pdata)
|
||
call update_sources(t, ds, pdata)
|
||
end do
|
||
!$omp end parallel do
|
||
|
||
call boundary_fluxes(status)
|
||
|
||
if (status /= 0) go to 100
|
||
|
||
!$omp parallel do default(shared) private(pdata)
|
||
do l = 1, n
|
||
pdata => data_blocks(l)%ptr
|
||
|
||
pdata%uu(:,:,:,:,3) = a53 * pdata%uu(:,:,:,:,2)
|
||
pdata%uu(:,:,:,:,2) = a31 * pdata%uu(:,:,:,:,1) &
|
||
+ a33 * pdata%uu(:,:,:,:,2) &
|
||
+ ds * pdata%du(:,:,:,:)
|
||
end do
|
||
!$omp end parallel do
|
||
|
||
call update_variables(t, ds, status)
|
||
|
||
if (status /= 0) go to 100
|
||
|
||
!= 4th step: U(4) = a41 U(n) + a44 U(3) + b44 dt F[U(3)]
|
||
!
|
||
ds = b44 * dt
|
||
t = time + c4 * dt
|
||
|
||
!$omp parallel do default(shared) private(pdata)
|
||
do l = 1, n
|
||
pdata => data_blocks(l)%ptr
|
||
|
||
call update_increment(pdata)
|
||
call update_sources(t, ds, pdata)
|
||
end do
|
||
!$omp end parallel do
|
||
|
||
call boundary_fluxes(status)
|
||
|
||
if (status /= 0) go to 100
|
||
|
||
!$omp parallel do default(shared) private(pdata)
|
||
do l = 1, n
|
||
pdata => data_blocks(l)%ptr
|
||
|
||
pdata%uu(:,:,:,:,3) = pdata%uu(:,:,:,:,3) &
|
||
+ a54 * pdata%uu(:,:,:,:,2) &
|
||
+ b54 * dt * pdata%du(:,:,:,:)
|
||
pdata%uu(:,:,:,:,2) = a41 * pdata%uu(:,:,:,:,1) &
|
||
+ a44 * pdata%uu(:,:,:,:,2) &
|
||
+ ds * pdata%du(:,:,:,:)
|
||
end do
|
||
!$omp end parallel do
|
||
|
||
call update_variables(t, ds, status)
|
||
|
||
if (status /= 0) go to 100
|
||
|
||
!= the final step: U(n+1) = a54 U(3) + a55 U(4) + b54 dt F[U(3)] + b55 dt F[U(4)]
|
||
!
|
||
ds = b55 * dt
|
||
t = time + c5 * dt
|
||
|
||
!$omp parallel do default(shared) private(pdata)
|
||
do l = 1, n
|
||
pdata => data_blocks(l)%ptr
|
||
|
||
call update_increment(pdata)
|
||
call update_sources(t, ds, pdata)
|
||
end do
|
||
!$omp end parallel do
|
||
|
||
call boundary_fluxes(status)
|
||
|
||
if (status /= 0) go to 100
|
||
|
||
!$omp parallel do default(shared) private(pdata)
|
||
do l = 1, n
|
||
pdata => data_blocks(l)%ptr
|
||
|
||
pdata%uu(:,:,:,:,2) = pdata%uu(:,:,:,:,3) &
|
||
+ a55 * pdata%uu(:,:,:,:,2) &
|
||
+ ds * pdata%du(:,:,:,:)
|
||
|
||
pdata%u => pdata%uu(:,:,:,:,2)
|
||
end do
|
||
!$omp end parallel do
|
||
|
||
if (ibp > 0) then
|
||
adecay(:) = exp(aglm(:) * cmax * dt)
|
||
|
||
!$omp parallel do default(shared) private(pdata)
|
||
do l = 1, n
|
||
pdata => data_blocks(l)%ptr
|
||
|
||
pdata%u(ibp,:,:,:) = adecay(pdata%meta%level) * pdata%u(ibp,:,:,:)
|
||
end do
|
||
!$omp end parallel do
|
||
end if
|
||
|
||
call update_variables(t, dt, status)
|
||
|
||
100 continue
|
||
|
||
if (status /= 0) dt = 2.5d-01 * dt
|
||
|
||
end do
|
||
|
||
!$omp parallel do default(shared) private(pdata)
|
||
do l = 1, n
|
||
pdata => data_blocks(l)%ptr
|
||
|
||
pdata%uu(:,:,:,:,1) = pdata%uu(:,:,:,:,2)
|
||
|
||
pdata%u => pdata%uu(:,:,:,:,1)
|
||
end do
|
||
!$omp end parallel do
|
||
|
||
!-------------------------------------------------------------------------------
|
||
!
|
||
end subroutine evolve_ssprk45
|
||
!
|
||
!===============================================================================
|
||
!
|
||
! subroutine EVOLVE_SSPRK410:
|
||
! --------------------------
|
||
!
|
||
! Subroutine advances the solution by one time step using the 4th order
|
||
! 10-stage Strong Stability Preserving Runge-Kutta time integration method.
|
||
!
|
||
! References:
|
||
!
|
||
! [1] Gottlieb, S., Ketcheson, D., Shu C. - W.,
|
||
! "Strong stability preserving Runge-Kutta and multistep
|
||
! time discretizations",
|
||
! World Scientific Publishing, 2011
|
||
!
|
||
!===============================================================================
|
||
!
|
||
subroutine evolve_ssprk410()
|
||
|
||
use blocks , only : block_data, data_blocks, get_dblocks
|
||
use boundaries, only : boundary_fluxes
|
||
use equations , only : ibp, cmax
|
||
use sources , only : update_sources
|
||
|
||
implicit none
|
||
|
||
type(block_data), pointer :: pdata
|
||
|
||
integer :: i, l, n, status
|
||
real(kind=8) :: t
|
||
|
||
real(kind=8), dimension(9) :: ds
|
||
|
||
real(kind=8), dimension(9), parameter :: cc = &
|
||
[ 1.0d+00, 2.0d+00, 3.0d+00, 4.0d+00, 2.0d+00, &
|
||
3.0d+00, 4.0d+00, 5.0d+00, 6.0d+00 ] / 6.0d+00
|
||
|
||
!-------------------------------------------------------------------------------
|
||
!
|
||
ds(:) = cc(:) * dt
|
||
|
||
status = 1
|
||
|
||
n = get_dblocks()
|
||
|
||
do while(status /= 0)
|
||
|
||
!= 1st step: U(2) = U(1)
|
||
!
|
||
!$omp parallel do default(shared) private(pdata)
|
||
do l = 1, n
|
||
pdata => data_blocks(l)%ptr
|
||
|
||
pdata%uu(:,:,:,:,2) = pdata%uu(:,:,:,:,1)
|
||
pdata%uu(:,:,:,:,3) = pdata%uu(:,:,:,:,1)
|
||
|
||
pdata%u => pdata%uu(:,:,:,:,2)
|
||
end do
|
||
!$omp end parallel do
|
||
|
||
!= 2nd step: U(1) = [1 + dt/6 L] U(1), for i = 1, ..., 5
|
||
!
|
||
do i = 1, 5
|
||
|
||
t = time + ds(i)
|
||
|
||
!$omp parallel do default(shared) private(pdata)
|
||
do l = 1, n
|
||
pdata => data_blocks(l)%ptr
|
||
|
||
call update_increment(pdata)
|
||
call update_sources(t, 0.0d+00, pdata)
|
||
end do
|
||
!$omp end parallel do
|
||
|
||
call boundary_fluxes(status)
|
||
|
||
if (status /= 0) go to 100
|
||
|
||
!$omp parallel do default(shared) private(pdata)
|
||
do l = 1, n
|
||
pdata => data_blocks(l)%ptr
|
||
|
||
pdata%uu(:,:,:,:,2) = pdata%uu(:,:,:,:,2) + ds(1) * pdata%du(:,:,:,:)
|
||
end do
|
||
!$omp end parallel do
|
||
|
||
call update_variables(t, ds(1), status)
|
||
|
||
if (status /= 0) go to 100
|
||
|
||
end do ! i = 1, 5
|
||
|
||
!= 3rd step: U(2) = U(2)/25 + 9/25 U(1), U(1) = 15 U(2) - 5 U(1)
|
||
!
|
||
!$omp parallel do default(shared) private(pdata)
|
||
do l = 1, n
|
||
pdata => data_blocks(l)%ptr
|
||
|
||
pdata%uu(:,:,:,:,3) = (pdata%uu(:,:,:,:,3) &
|
||
+ 9.0d+00 * pdata%uu(:,:,:,:,2)) / 2.5d+01
|
||
pdata%uu(:,:,:,:,2) = 1.5d+01 * pdata%uu(:,:,:,:,3) &
|
||
- 5.0d+00 * pdata%uu(:,:,:,:,2)
|
||
end do
|
||
!$omp end parallel do
|
||
|
||
!= 4th step: U(1) = [1 + dt/6 L] U(1), for i = 6, ..., 9
|
||
!
|
||
! integrate the intermediate steps
|
||
!
|
||
do i = 6, 9
|
||
|
||
t = time + ds(i)
|
||
|
||
!$omp parallel do default(shared) private(pdata)
|
||
do l = 1, n
|
||
pdata => data_blocks(l)%ptr
|
||
|
||
call update_increment(pdata)
|
||
call update_sources(t, ds(1), pdata)
|
||
end do
|
||
!$omp end parallel do
|
||
|
||
call boundary_fluxes(status)
|
||
|
||
if (status /= 0) go to 100
|
||
|
||
!$omp parallel do default(shared) private(pdata)
|
||
do l = 1, n
|
||
pdata => data_blocks(l)%ptr
|
||
|
||
pdata%uu(:,:,:,:,2) = pdata%uu(:,:,:,:,2) + ds(1) * pdata%du(:,:,:,:)
|
||
end do
|
||
!$omp end parallel do
|
||
|
||
call update_variables(t, ds(1), status)
|
||
|
||
if (status /= 0) go to 100
|
||
|
||
end do ! i = 6, 9
|
||
|
||
!= the final step: U(n+1) = U(2) + 3/5 U(1) + 1/10 dt F[U(1)]
|
||
!
|
||
t = time + dt
|
||
|
||
!$omp parallel do default(shared) private(pdata)
|
||
do l = 1, n
|
||
pdata => data_blocks(l)%ptr
|
||
|
||
call update_increment(pdata)
|
||
call update_sources(t, 1.0d-01 * dt, pdata)
|
||
end do
|
||
!$omp end parallel do
|
||
|
||
call boundary_fluxes(status)
|
||
|
||
if (status /= 0) go to 100
|
||
|
||
!$omp parallel do default(shared) private(pdata)
|
||
do l = 1, n
|
||
pdata => data_blocks(l)%ptr
|
||
|
||
pdata%uu(:,:,:,:,2) = (1.0d+01 * pdata%uu(:,:,:,:,3) &
|
||
+ 6.0d+00 * pdata%uu(:,:,:,:,2) &
|
||
+ dt * pdata%du(:,:,:,:)) / 1.0d+01
|
||
end do
|
||
!$omp end parallel do
|
||
|
||
if (ibp > 0) then
|
||
adecay(:) = exp(aglm(:) * cmax * dt)
|
||
|
||
!$omp parallel do default(shared) private(pdata)
|
||
do l = 1, n
|
||
pdata => data_blocks(l)%ptr
|
||
|
||
pdata%u(ibp,:,:,:) = adecay(pdata%meta%level) * pdata%u(ibp,:,:,:)
|
||
end do
|
||
!$omp end parallel do
|
||
end if
|
||
|
||
call update_variables(t, dt, status)
|
||
|
||
100 continue
|
||
|
||
if (status /= 0) dt = 2.5d-01 * dt
|
||
|
||
end do
|
||
|
||
!$omp parallel do default(shared) private(pdata)
|
||
do l = 1, n
|
||
pdata => data_blocks(l)%ptr
|
||
|
||
pdata%uu(:,:,:,:,1) = pdata%uu(:,:,:,:,2)
|
||
|
||
pdata%u => pdata%uu(:,:,:,:,1)
|
||
end do
|
||
!$omp end parallel do
|
||
|
||
!-------------------------------------------------------------------------------
|
||
!
|
||
end subroutine evolve_ssprk410
|
||
!
|
||
!===============================================================================
|
||
!
|
||
! EMBEDDED METHODS
|
||
!
|
||
!===============================================================================
|
||
!
|
||
! subroutine EVOLVE_SSPRK21M:
|
||
! --------------------------
|
||
!
|
||
! Subroutine advances the solution by one time step using the 2nd order
|
||
! m-stage Strong Stability Preserving Runge-Kutta time integration method.
|
||
! Up to 9 stages are allowed, due to stability problems with more stages.
|
||
!
|
||
! References:
|
||
!
|
||
! [1] Conde, S., Fekete, I., Shadid, J. N.,
|
||
! "Embedded error estimation and adaptive step-size control for
|
||
! optimal explicit strong stability preserving Runge–Kutta methods"
|
||
! 2018, arXiv:1806.08693v1
|
||
! [2] Gottlieb, S. and Gottlieb, L.-A., J.
|
||
! "Strong Stability Preserving Properties of Runge-Kutta Time
|
||
! Discretization Methods for Linear Constant Coefficient Operators",
|
||
! Journal of Scientific Computing,
|
||
! 2003, vol. 18, no. 1, pp. 83-109
|
||
!
|
||
!===============================================================================
|
||
!
|
||
subroutine evolve_ssprk21m()
|
||
|
||
use blocks , only : block_data, data_blocks, get_dblocks
|
||
use boundaries, only : boundary_fluxes
|
||
use equations , only : errors, ibp, cmax
|
||
use helpers , only : print_message
|
||
use sources , only : update_sources
|
||
|
||
implicit none
|
||
|
||
type(block_data), pointer :: pdata
|
||
|
||
logical :: test, cond
|
||
integer :: i, l, n, nrej, status
|
||
real(kind=8) :: tm, dtm, fc
|
||
|
||
character(len=*), parameter :: loc = 'EVOLUTION:evolve_ssprk21m()'
|
||
|
||
!-------------------------------------------------------------------------------
|
||
!
|
||
test = .true.
|
||
cond = .true.
|
||
nrej = 0
|
||
n = get_dblocks()
|
||
|
||
! at the entry point we assume the previous solution of conserved variables U(n)
|
||
! is stored in pdata%u(:,:,:,:,1) and the primitive variables are already
|
||
! updated from this array;
|
||
!
|
||
! pdata%uu(:,:,:,:,1) - the previous solution, U(n)
|
||
! pdata%uu(:,:,:,:,2) - the new 2nd order solution, U(1)
|
||
! pdata%uu(:,:,:,:,3) - the new 1st order solution, U(2)
|
||
!
|
||
do while(test)
|
||
|
||
!= preparatory step: U(1) = U(n), U(2) = 0, U(3) = U(n)
|
||
!
|
||
!$omp parallel do default(shared) private(pdata)
|
||
do l = 1, n
|
||
pdata => data_blocks(l)%ptr
|
||
|
||
pdata%uu(:,:,:,:,2) = pdata%uu(:,:,:,:,1)
|
||
pdata%uu(:,:,:,:,3) = pdata%uu(:,:,:,:,1)
|
||
|
||
pdata%u => pdata%uu(:,:,:,:,2)
|
||
end do
|
||
!$omp end parallel do
|
||
|
||
!= 1st step: U(1) = U(1) + dt/(m-1) F[U(1)], for i = 1, ..., m-1
|
||
!
|
||
do i = 1, stages - 1
|
||
|
||
dtm = c(i) * dt
|
||
tm = time + dtm
|
||
|
||
!$omp parallel do default(shared) private(pdata)
|
||
do l = 1, n
|
||
pdata => data_blocks(l)%ptr
|
||
|
||
call update_increment(pdata)
|
||
call update_sources(tm, dtm, pdata)
|
||
end do
|
||
!$omp end parallel do
|
||
|
||
call boundary_fluxes(status)
|
||
|
||
if (status /= 0) go to 100
|
||
|
||
!$omp parallel do default(shared) private(pdata)
|
||
do l = 1, n
|
||
pdata => data_blocks(l)%ptr
|
||
|
||
pdata%uu(:,:,:,:,2) = pdata%uu(:,:,:,:,2) &
|
||
+ bt(i) * dt * pdata%du(:,:,:,:)
|
||
pdata%uu(:,:,:,:,3) = pdata%uu(:,:,:,:,3) &
|
||
+ bh(i) * dt * pdata%du(:,:,:,:)
|
||
end do
|
||
!$omp end parallel do
|
||
|
||
call update_variables(tm, dtm, status)
|
||
if (status /= 0) go to 100
|
||
|
||
end do ! i = 1, stages - 1
|
||
|
||
!= 2nd step: U(1) = (m-1)/m U(1) + 1/m U(2) + dt/m F[U(1)]
|
||
!
|
||
i = stages
|
||
dtm = c(i) * dt
|
||
tm = time + dtm
|
||
|
||
!$omp parallel do default(shared) private(pdata)
|
||
do l = 1, n
|
||
pdata => data_blocks(l)%ptr
|
||
|
||
call update_increment(pdata)
|
||
call update_sources(tm, dtm, pdata)
|
||
end do
|
||
!$omp end parallel do
|
||
|
||
call boundary_fluxes(status)
|
||
|
||
if (status /= 0) go to 100
|
||
|
||
!$omp parallel do default(shared) private(pdata)
|
||
do l = 1, n
|
||
pdata => data_blocks(l)%ptr
|
||
|
||
pdata%uu(:,:,:,:,2) = dl(1) * pdata%uu(:,:,:,:,2) &
|
||
+ dl(2) * pdata%uu(:,:,:,:,1) &
|
||
+ bt(i) * dt * pdata%du(:,:,:,:)
|
||
pdata%uu(:,:,:,:,3) = pdata%uu(:,:,:,:,3) &
|
||
+ bh(i) * dt * pdata%du(:,:,:,:)
|
||
end do
|
||
!$omp end parallel do
|
||
|
||
call update_variables(tm, dtm, status)
|
||
if (status /= 0) go to 100
|
||
|
||
!= 3rd step: decay the magnetic divergence potential of both solutions
|
||
!
|
||
if (ibp > 0) then
|
||
adecay(:) = exp(aglm(:) * cmax * dt)
|
||
|
||
!$omp parallel do default(shared) private(pdata)
|
||
do l = 1, n
|
||
pdata => data_blocks(l)%ptr
|
||
|
||
pdata%uu(ibp,:,:,:,2) = adecay(pdata%meta%level) &
|
||
* pdata%uu(ibp,:,:,:,2)
|
||
pdata%uu(ibp,:,:,:,3) = adecay(pdata%meta%level) &
|
||
* pdata%uu(ibp,:,:,:,3)
|
||
end do
|
||
!$omp end parallel do
|
||
end if
|
||
|
||
! update the vector of errors
|
||
!
|
||
call update_errors(2, 3)
|
||
|
||
! calculate the tolerance and estimate the next time step due to the error
|
||
!
|
||
errtol = maxval(errors)
|
||
errs(1) = errtol
|
||
fc = product(errs(:)**betas(:))
|
||
fc = 1.0d+00 + chi * atan((fc - 1.0d+00) / chi)
|
||
dte = dt * fc
|
||
cond = errtol <= 1.0d+00 .or. fc > fac .or. nrej >= mrej
|
||
|
||
100 continue
|
||
cond = cond .and. status == 0
|
||
|
||
if (cond) then
|
||
test = .false.
|
||
|
||
errs(3) = errs(2)
|
||
errs(2) = errs(1)
|
||
|
||
else
|
||
if (status == 0) then
|
||
dt = max(dte, dtsafe * dth)
|
||
nrej = nrej + 1 ! rejection count in the current step
|
||
else
|
||
dt = 2.5d-01 * dt
|
||
end if
|
||
nrejections = nrejections + 1
|
||
|
||
! since the solution was rejected, we have to revert the primitive variables
|
||
! to the previous state
|
||
!
|
||
!$omp parallel do default(shared) private(pdata)
|
||
do l = 1, n
|
||
pdata => data_blocks(l)%ptr
|
||
|
||
pdata%u => pdata%uu(:,:,:,:,1)
|
||
end do
|
||
!$omp end parallel do
|
||
|
||
call update_variables(tm, dtm, status)
|
||
if (status /= 0) &
|
||
call print_message(loc, "Possible bug: the revert to " // &
|
||
"the previous state found it unphysical.")
|
||
|
||
end if
|
||
|
||
niterations = niterations + 1
|
||
|
||
end do
|
||
|
||
!= final step: U(n+1) = U(1) - update the accepted solution
|
||
!
|
||
!$omp parallel do default(shared) private(pdata)
|
||
do l = 1, n
|
||
pdata => data_blocks(l)%ptr
|
||
|
||
pdata%uu(:,:,:,:,1) = pdata%uu(:,:,:,:,2)
|
||
|
||
pdata%u => pdata%uu(:,:,:,:,1)
|
||
end do
|
||
!$omp end parallel do
|
||
|
||
!-------------------------------------------------------------------------------
|
||
!
|
||
end subroutine evolve_ssprk21m
|
||
!
|
||
!===============================================================================
|
||
!
|
||
! subroutine EVOLVE_SSP324:
|
||
! --------------------------
|
||
!
|
||
! Subroutine advances the solution by one time step using the 3ʳᵈ-order
|
||
! 4-stage embedded Strong Stability Preserving Runge-Kutta time integration
|
||
! method SSP3(2)4 with the error control.
|
||
!
|
||
! References:
|
||
!
|
||
! [1] Ranocha, H., Dalcin, L., Parsani, M., Ketcheson, D. I.,
|
||
! "Optimized Runge-Kutta Methods with Automatic Step Size Control
|
||
! for Compressible Computational Fluid Dynamics",
|
||
! 2021, arXiv:2104.06836v2
|
||
! [2] Conde, S., Fekete, I., Shadid, J. N.,
|
||
! "Embedded error estimation and adaptive step-size control for
|
||
! optimal explicit strong stability preserving Runge–Kutta methods"
|
||
! 2018, arXiv:1806.08693v1
|
||
! [3] Gottlieb, S., Ketcheson, D., Shu, C.-W.,
|
||
! "Strong stability preserving Runge-Kutta and multistep time
|
||
! discretizations",
|
||
! 2011, World Scientific Publishing
|
||
!
|
||
!===============================================================================
|
||
!
|
||
subroutine evolve_ssp324()
|
||
|
||
use blocks , only : block_data, data_blocks, get_dblocks
|
||
use boundaries, only : boundary_fluxes
|
||
use equations , only : errors, ibp, cmax
|
||
use helpers , only : print_message
|
||
use sources , only : update_sources
|
||
|
||
implicit none
|
||
|
||
type(block_data), pointer :: pdata
|
||
|
||
logical :: test, cond
|
||
integer :: i, l, n, nrej, status
|
||
real(kind=8) :: tm, dtm, dh, fc
|
||
|
||
character(len=*), parameter :: loc = 'EVOLUTION:evolve_ssp324()'
|
||
|
||
!-------------------------------------------------------------------------------
|
||
!
|
||
test = .true.
|
||
cond = .true.
|
||
nrej = 0
|
||
n = get_dblocks()
|
||
|
||
! at the entry point we assume the previous solution of conserved variables U(n)
|
||
! is stored in pdata%u(:,:,:,:,1) and the primitive variables are already
|
||
! updated from this array;
|
||
!
|
||
! pdata%uu(:,:,:,:,1) - the previous solution, U(n)
|
||
! pdata%uu(:,:,:,:,2) - the new 3rd order solution, U(1)
|
||
! pdata%uu(:,:,:,:,3) - the new 2nd order solution, U(2)
|
||
!
|
||
do while(test)
|
||
|
||
! initiate the fractional time step
|
||
!
|
||
dh = 5.0d-01 * dt
|
||
|
||
!= preparation step: U(1) = U(n)
|
||
!
|
||
!$omp parallel do default(shared) private(pdata)
|
||
do l = 1, n
|
||
pdata => data_blocks(l)%ptr
|
||
|
||
pdata%uu(:,:,:,:,2) = pdata%uu(:,:,:,:,1)
|
||
|
||
pdata%u => pdata%uu(:,:,:,:,2)
|
||
end do
|
||
!$omp end parallel do
|
||
|
||
!= 1st to 3rd steps: U(1) = U(1) + ½ dt F[U(1)], for i = 1...3
|
||
!
|
||
do i = 1, 3
|
||
|
||
tm = time + (i - 1) * dh
|
||
dtm = dh
|
||
|
||
!$omp parallel do default(shared) private(pdata)
|
||
do l = 1, n
|
||
pdata => data_blocks(l)%ptr
|
||
|
||
call update_increment(pdata)
|
||
call update_sources(tm, dtm, pdata)
|
||
end do
|
||
!$omp end parallel do
|
||
|
||
call boundary_fluxes(status)
|
||
|
||
if (status /= 0) go to 100
|
||
|
||
!$omp parallel do default(shared) private(pdata)
|
||
do l = 1, n
|
||
pdata => data_blocks(l)%ptr
|
||
|
||
pdata%uu(:,:,:,:,2) = pdata%uu(:,:,:,:,2) + dh * pdata%du(:,:,:,:)
|
||
end do
|
||
!$omp end parallel do
|
||
|
||
call update_variables(tm, dtm, status)
|
||
if (status /= 0) go to 100
|
||
|
||
end do ! i = 1, 3
|
||
|
||
!= 4th step: U(1) = ⅔ U(n) + ⅓ U(1), U(2) = ⅓ U(n) + ⅔ U(1)
|
||
!
|
||
!$omp parallel do default(shared) private(pdata)
|
||
do l = 1, n
|
||
pdata => data_blocks(l)%ptr
|
||
|
||
pdata%uu(:,:,:,:,3) = ( pdata%uu(:,:,:,:,1) &
|
||
+ 2.0d+00 * pdata%uu(:,:,:,:,2)) / 3.0d+00
|
||
pdata%uu(:,:,:,:,2) = (2.0d+00 * pdata%uu(:,:,:,:,1) &
|
||
+ pdata%uu(:,:,:,:,2)) / 3.0d+00
|
||
end do
|
||
!$omp end parallel do
|
||
|
||
call update_variables(tm, dtm, status)
|
||
if (status /= 0) go to 100
|
||
|
||
!= 5th step: U(1) = U(1) + ½ dt F[U(1)] <- 3ʳᵈ-order candidate
|
||
!
|
||
tm = time + dh
|
||
dtm = dh
|
||
|
||
!$omp parallel do default(shared) private(pdata)
|
||
do l = 1, n
|
||
pdata => data_blocks(l)%ptr
|
||
|
||
call update_increment(pdata)
|
||
call update_sources(tm, dtm, pdata)
|
||
end do
|
||
!$omp end parallel do
|
||
|
||
call boundary_fluxes(status)
|
||
|
||
if (status /= 0) go to 100
|
||
|
||
!$omp parallel do default(shared) private(pdata)
|
||
do l = 1, n
|
||
pdata => data_blocks(l)%ptr
|
||
|
||
pdata%uu(:,:,:,:,2) = pdata%uu(:,:,:,:,2) + dh * pdata%du(:,:,:,:)
|
||
end do
|
||
!$omp end parallel do
|
||
|
||
call update_variables(tm, dtm, status)
|
||
if (status /= 0) go to 100
|
||
|
||
!= 6th step: U(2) = ½ (U(1) + U(2)) <- 2ⁿᵈ-order approximation
|
||
!
|
||
!$omp parallel do default(shared) private(pdata)
|
||
do l = 1, n
|
||
pdata => data_blocks(l)%ptr
|
||
|
||
pdata%uu(:,:,:,:,3) = 5.0d-01 * (pdata%uu(:,:,:,:,3) &
|
||
+ pdata%uu(:,:,:,:,2))
|
||
end do
|
||
!$omp end parallel do
|
||
|
||
!= 7th step: decay the magnetic divergence potential of both solutions
|
||
!
|
||
if (ibp > 0) then
|
||
adecay(:) = exp(aglm(:) * cmax * dt)
|
||
|
||
!$omp parallel do default(shared) private(pdata)
|
||
do l = 1, n
|
||
pdata => data_blocks(l)%ptr
|
||
|
||
pdata%uu(ibp,:,:,:,2) = adecay(pdata%meta%level) &
|
||
* pdata%uu(ibp,:,:,:,2)
|
||
pdata%uu(ibp,:,:,:,3) = adecay(pdata%meta%level) &
|
||
* pdata%uu(ibp,:,:,:,3)
|
||
end do
|
||
!$omp end parallel do
|
||
end if
|
||
|
||
! update the vector of errors
|
||
!
|
||
call update_errors(2, 3)
|
||
|
||
! calculate the tolerance and estimate the next time step due to the error
|
||
!
|
||
errtol = maxval(errors)
|
||
errs(1) = errtol
|
||
fc = product(errs(:)**betas(:))
|
||
fc = 1.0d+00 + chi * atan((fc - 1.0d+00) / chi)
|
||
dte = dt * fc
|
||
cond = errtol <= 1.0d+00 .or. fc > fac .or. nrej >= mrej
|
||
|
||
100 continue
|
||
cond = cond .and. status == 0
|
||
|
||
if (cond) then
|
||
test = .false.
|
||
|
||
errs(3) = errs(2)
|
||
errs(2) = errs(1)
|
||
|
||
else
|
||
if (status == 0) then
|
||
dt = max(dte, dtsafe * dth)
|
||
nrej = nrej + 1 ! rejection count in the current step
|
||
else
|
||
dt = 2.5d-01 * dt
|
||
end if
|
||
nrejections = nrejections + 1
|
||
|
||
! since the solution was rejected, we have to revert the primitive variables
|
||
! to the previous state
|
||
!
|
||
!$omp parallel do default(shared) private(pdata)
|
||
do l = 1, n
|
||
pdata => data_blocks(l)%ptr
|
||
|
||
pdata%u => pdata%uu(:,:,:,:,1)
|
||
end do
|
||
!$omp end parallel do
|
||
|
||
call update_variables(tm, dtm, status)
|
||
if (status /= 0) &
|
||
call print_message(loc, "Possible bug: " // &
|
||
"the previous state seems unphysical.")
|
||
end if
|
||
|
||
niterations = niterations + 1
|
||
|
||
end do
|
||
|
||
!= final step: U(n+1) = U(1) - update the accepted solution
|
||
!
|
||
!$omp parallel do default(shared) private(pdata)
|
||
do l = 1, n
|
||
pdata => data_blocks(l)%ptr
|
||
|
||
pdata%uu(:,:,:,:,1) = pdata%uu(:,:,:,:,2)
|
||
|
||
pdata%u => pdata%uu(:,:,:,:,1)
|
||
end do
|
||
!$omp end parallel do
|
||
|
||
!-------------------------------------------------------------------------------
|
||
!
|
||
end subroutine evolve_ssp324
|
||
!
|
||
!===============================================================================
|
||
!
|
||
! subroutine EVOLVE_SSPRK32M:
|
||
! --------------------------
|
||
!
|
||
! Subroutine advances the solution by one time step using the 3ʳᵈ-order
|
||
! m-stage (m=n²) embedded Strong Stability Preserving Runge-Kutta time
|
||
! integration method SSP3(2)m with the error control.
|
||
!
|
||
! References:
|
||
!
|
||
! [1] Conde, S., Fekete, I., Shadid, J. N.,
|
||
! "Embedded error estimation and adaptive step-size control for
|
||
! optimal explicit strong stability preserving Runge–Kutta methods"
|
||
! 2018, arXiv:1806.08693v1
|
||
! [2] Gottlieb, S., Ketcheson, D., Shu, C.-W.,
|
||
! "Strong stability preserving Runge-Kutta and multistep time
|
||
! discretizations",
|
||
! 2011, World Scientific Publishing
|
||
!
|
||
!===============================================================================
|
||
!
|
||
subroutine evolve_ssprk32m()
|
||
|
||
use blocks , only : block_data, data_blocks, get_dblocks
|
||
use boundaries, only : boundary_fluxes
|
||
use equations , only : errors, ibp, cmax
|
||
use helpers , only : print_message
|
||
use sources , only : update_sources
|
||
|
||
implicit none
|
||
|
||
type(block_data), pointer :: pdata
|
||
|
||
logical , save :: first = .true.
|
||
integer , save :: i1, i2, i3, i4, n, m
|
||
real(kind=8), save :: f1, f2, f3, f4
|
||
|
||
logical :: test, cond
|
||
integer :: i, l, nrej, status
|
||
real(kind=8) :: tm, dtm, dh, fc
|
||
|
||
character(len=*), parameter :: loc = 'EVOLUTION:evolve_ssprk32m()'
|
||
|
||
!-------------------------------------------------------------------------------
|
||
!
|
||
if (first) then
|
||
|
||
n = 2
|
||
do while(n**2 < stages)
|
||
n = n + 1
|
||
end do
|
||
m = stages - n
|
||
i1 = (n - 1) * (n - 2) / 2
|
||
i2 = i1 + 1
|
||
i3 = n * (n + 1) / 2
|
||
i4 = i3 + 1
|
||
|
||
fc = real(2 * n - 1, kind=8)
|
||
f1 = real(n - 1, kind=8) / fc
|
||
f2 = real(n , kind=8) / fc
|
||
f4 = real(m , kind=8) / stages
|
||
f3 = 1.0d+00 - f4
|
||
|
||
first = .false.
|
||
|
||
end if
|
||
|
||
test = .true.
|
||
cond = .true.
|
||
nrej = 0
|
||
n = get_dblocks()
|
||
|
||
! at the entry point we assume the previous solution of conserved variables U(n)
|
||
! is stored in pdata%u(:,:,:,:,1) and the primitive variables are already
|
||
! updated from this array;
|
||
!
|
||
! pdata%uu(:,:,:,:,1) - the previous solution, U(n)
|
||
! pdata%uu(:,:,:,:,2) - the new 3rd order solution, U(1)
|
||
! pdata%uu(:,:,:,:,3) - the intermediate solution, U(2)
|
||
! pdata%uu(:,:,:,:,4) - the new 2nd order solution, U(3)
|
||
!
|
||
do while(test)
|
||
|
||
! initiate the fractional time step
|
||
!
|
||
dh = dt / m
|
||
|
||
!= preparation step: U(1) = U(n)
|
||
!
|
||
!$omp parallel do default(shared) private(pdata)
|
||
do l = 1, n
|
||
pdata => data_blocks(l)%ptr
|
||
|
||
pdata%uu(:,:,:,:,2) = pdata%uu(:,:,:,:,1)
|
||
|
||
pdata%u => pdata%uu(:,:,:,:,2)
|
||
end do
|
||
!$omp end parallel do
|
||
|
||
!= 1st step: U(1) = U(1) + dt/r F[U(1)], for i = 1...(n-1)*(n-2)/2
|
||
!
|
||
do i = 1, i1
|
||
|
||
tm = time + (i - 1) * dh
|
||
dtm = dh
|
||
|
||
!$omp parallel do default(shared) private(pdata)
|
||
do l = 1, n
|
||
pdata => data_blocks(l)%ptr
|
||
|
||
call update_increment(pdata)
|
||
call update_sources(tm, dtm, pdata)
|
||
end do
|
||
!$omp end parallel do
|
||
|
||
call boundary_fluxes(status)
|
||
|
||
if (status /= 0) go to 100
|
||
|
||
!$omp parallel do default(shared) private(pdata)
|
||
do l = 1, n
|
||
pdata => data_blocks(l)%ptr
|
||
|
||
pdata%uu(:,:,:,:,2) = pdata%uu(:,:,:,:,2) + dh * pdata%du(:,:,:,:)
|
||
end do
|
||
!$omp end parallel do
|
||
|
||
call update_variables(tm, dtm, status)
|
||
if (status /= 0) go to 100
|
||
|
||
end do ! i = 1, i1
|
||
|
||
!= 2nd step: U(2) = U(1)
|
||
!
|
||
!$omp parallel do default(shared) private(pdata)
|
||
do l = 1, n
|
||
pdata => data_blocks(l)%ptr
|
||
|
||
pdata%uu(:,:,:,:,3) = pdata%uu(:,:,:,:,2)
|
||
end do
|
||
!$omp end parallel do
|
||
|
||
!= 3rd step: U(1) = U(1) + dt/r F[U(1)], for i = (n-1)*(n-2)/2+1...n*(n+1)/2
|
||
!
|
||
do i = i2, i3
|
||
|
||
tm = time + (i - 1) * dh
|
||
dtm = dh
|
||
|
||
!$omp parallel do default(shared) private(pdata)
|
||
do l = 1, n
|
||
pdata => data_blocks(l)%ptr
|
||
|
||
call update_increment(pdata)
|
||
call update_sources(tm, dtm, pdata)
|
||
end do
|
||
!$omp end parallel do
|
||
|
||
call boundary_fluxes(status)
|
||
|
||
if (status /= 0) go to 100
|
||
|
||
!$omp parallel do default(shared) private(pdata)
|
||
do l = 1, n
|
||
pdata => data_blocks(l)%ptr
|
||
|
||
pdata%uu(:,:,:,:,2) = pdata%uu(:,:,:,:,2) + dh * pdata%du(:,:,:,:)
|
||
end do
|
||
!$omp end parallel do
|
||
|
||
call update_variables(tm, dtm, status)
|
||
if (status /= 0) go to 100
|
||
|
||
end do ! i = i2, i3
|
||
|
||
!= 4th step: U(3) = (1 - r/s) * U(n) + r/s * U(1),
|
||
! U(1) = [(n - 1) * U(1) + n * U(2)] / (2*n - 1),
|
||
! U(3) = U(3) - r/s * U(1)
|
||
!
|
||
!$omp parallel do default(shared) private(pdata)
|
||
do l = 1, n
|
||
pdata => data_blocks(l)%ptr
|
||
|
||
pdata%uu(:,:,:,:,4) = f3 * pdata%uu(:,:,:,:,1) &
|
||
+ f4 * pdata%uu(:,:,:,:,2)
|
||
pdata%uu(:,:,:,:,2) = f1 * pdata%uu(:,:,:,:,2) &
|
||
+ f2 * pdata%uu(:,:,:,:,3)
|
||
pdata%uu(:,:,:,:,4) = pdata%uu(:,:,:,:,4) &
|
||
- f4 * pdata%uu(:,:,:,:,2)
|
||
end do
|
||
!$omp end parallel do
|
||
|
||
call update_variables(tm, dtm, status)
|
||
if (status /= 0) go to 100
|
||
|
||
!= 6th step: U(1) = U(1) + dt/r F[U(1)], for i = n*(n+1)/2+1...stages
|
||
!
|
||
do i = i4, stages
|
||
|
||
tm = time + (i - 1 - n) * dh
|
||
dtm = dh
|
||
|
||
!$omp parallel do default(shared) private(pdata)
|
||
do l = 1, n
|
||
pdata => data_blocks(l)%ptr
|
||
|
||
call update_increment(pdata)
|
||
call update_sources(tm, dtm, pdata)
|
||
end do
|
||
!$omp end parallel do
|
||
|
||
call boundary_fluxes(status)
|
||
|
||
if (status /= 0) go to 100
|
||
|
||
!$omp parallel do default(shared) private(pdata)
|
||
do l = 1, n
|
||
pdata => data_blocks(l)%ptr
|
||
|
||
pdata%uu(:,:,:,:,2) = pdata%uu(:,:,:,:,2) + dh * pdata%du(:,:,:,:)
|
||
end do
|
||
!$omp end parallel do
|
||
|
||
call update_variables(tm, dtm, status)
|
||
if (status /= 0) go to 100
|
||
|
||
end do ! i = i4, stages
|
||
|
||
!= 7th step: U(3) = U(3) + r/s * U(1)
|
||
!
|
||
!$omp parallel do default(shared) private(pdata)
|
||
do l = 1, n
|
||
pdata => data_blocks(l)%ptr
|
||
|
||
pdata%uu(:,:,:,:,4) = pdata%uu(:,:,:,:,4) + f4 * pdata%uu(:,:,:,:,2)
|
||
end do
|
||
!$omp end parallel do
|
||
|
||
!= 8th step: decay the magnetic divergence potential of both solutions
|
||
!
|
||
if (ibp > 0) then
|
||
adecay(:) = exp(aglm(:) * cmax * dt)
|
||
|
||
!$omp parallel do default(shared) private(pdata)
|
||
do l = 1, n
|
||
pdata => data_blocks(l)%ptr
|
||
|
||
pdata%uu(ibp,:,:,:,2) = adecay(pdata%meta%level) &
|
||
* pdata%uu(ibp,:,:,:,2)
|
||
pdata%uu(ibp,:,:,:,4) = adecay(pdata%meta%level) &
|
||
* pdata%uu(ibp,:,:,:,4)
|
||
end do
|
||
!$omp end parallel do
|
||
end if
|
||
|
||
! update the vector of errors
|
||
!
|
||
call update_errors(2, 4)
|
||
|
||
! calculate the tolerance and estimate the next time step due to the error
|
||
!
|
||
errtol = maxval(errors)
|
||
errs(1) = errtol
|
||
fc = product(errs(:)**betas(:))
|
||
fc = 1.0d+00 + chi * atan((fc - 1.0d+00) / chi)
|
||
dte = dt * fc
|
||
cond = errtol <= 1.0d+00 .or. fc > fac .or. nrej >= mrej
|
||
|
||
100 continue
|
||
cond = cond .and. status == 0
|
||
|
||
if (cond) then
|
||
test = .false.
|
||
|
||
errs(3) = errs(2)
|
||
errs(2) = errs(1)
|
||
else
|
||
if (status == 0) then
|
||
dt = max(dte, dtsafe * dth)
|
||
nrej = nrej + 1 ! rejection count in the current step
|
||
else
|
||
dt = 2.5d-01 * dt
|
||
end if
|
||
nrejections = nrejections + 1
|
||
|
||
! since the solution was rejected, we have to revert the primitive variables
|
||
! to the previous state
|
||
!
|
||
!$omp parallel do default(shared) private(pdata)
|
||
do l = 1, n
|
||
pdata => data_blocks(l)%ptr
|
||
|
||
pdata%u => pdata%uu(:,:,:,:,1)
|
||
end do
|
||
!$omp end parallel do
|
||
|
||
call update_variables(tm, dtm, status)
|
||
if (status /= 0) &
|
||
call print_message(loc, "Possible bug: the revert to " // &
|
||
"the previous state found it unphysical.")
|
||
end if
|
||
|
||
niterations = niterations + 1
|
||
|
||
end do
|
||
|
||
!= final step: U(n+1) = U(1) - update the accepted solution
|
||
!
|
||
!$omp parallel do default(shared) private(pdata)
|
||
do l = 1, n
|
||
pdata => data_blocks(l)%ptr
|
||
|
||
pdata%uu(:,:,:,:,1) = pdata%uu(:,:,:,:,2)
|
||
|
||
pdata%u => pdata%uu(:,:,:,:,1)
|
||
end do
|
||
!$omp end parallel do
|
||
|
||
!-------------------------------------------------------------------------------
|
||
!
|
||
end subroutine evolve_ssprk32m
|
||
!
|
||
!===============================================================================
|
||
!
|
||
! subroutine EVOLVE_3SSTARPLUS:
|
||
! ----------------------------
|
||
!
|
||
! Subroutine advances the solution by one time step using the minimum
|
||
! storage implementation of 3S*+ methods.
|
||
!
|
||
! References:
|
||
!
|
||
! [1] Ranocha, H., Dalcin, L., Parsani, M., Ketcheson, D. I.
|
||
! "Optimized Runge-Kutta Methods with Automatic Step Size Control
|
||
! for Compressible Computational Fluid Dynamics",
|
||
! 2021, arXiv:2104.06836
|
||
! [2] Gottlieb, S., Ketcheson, D., Shu C. - W.,
|
||
! "Strong stability preserving Runge-Kutta and multistep
|
||
! time discretizations",
|
||
! World Scientific Publishing, 2011
|
||
!
|
||
!===============================================================================
|
||
!
|
||
subroutine evolve_3sstarplus()
|
||
|
||
use blocks , only : block_data, data_blocks, get_dblocks
|
||
use boundaries, only : boundary_fluxes
|
||
use equations , only : errors, ibp, cmax
|
||
use helpers , only : print_message
|
||
use sources , only : update_sources
|
||
|
||
implicit none
|
||
|
||
type(block_data), pointer :: pdata
|
||
|
||
logical :: test, cond
|
||
integer :: i, l, n, nrej, status
|
||
real(kind=8) :: tm, dtm, fc
|
||
|
||
character(len=*), parameter :: loc = 'EVOLUTION:evolve_3sstarplus()'
|
||
|
||
!-------------------------------------------------------------------------------
|
||
!
|
||
test = .true.
|
||
cond = .true.
|
||
nrej = 0
|
||
n = get_dblocks()
|
||
|
||
! at the entry point we assume the previous solution of conserved variables U(n)
|
||
! is stored in pdata%u(:,:,:,:,1) and the primitive variables are already
|
||
! updated from this array;
|
||
!
|
||
! pdata%uu(:,:,:,:,1) - the previous solution, U(n)
|
||
! pdata%uu(:,:,:,:,2) - the new 3rd order solution, U(1)
|
||
! pdata%uu(:,:,:,:,3) - the intermediate solution, U(2)
|
||
! pdata%uu(:,:,:,:,4) - the new 2nd order solution, U(3)
|
||
!
|
||
do while(test)
|
||
|
||
!= preparatory step: U(1) = U(n), U(2) = 0, U(3) = U(n)
|
||
!
|
||
!$omp parallel do default(shared) private(pdata)
|
||
do l = 1, n
|
||
pdata => data_blocks(l)%ptr
|
||
|
||
pdata%uu(:,:,:,:,2) = pdata%uu(:,:,:,:,1)
|
||
pdata%uu(:,:,:,:,3) = pdata%uu(:,:,:,:,1)
|
||
pdata%uu(:,:,:,:,4) = pdata%uu(:,:,:,:,1)
|
||
|
||
pdata%u => pdata%uu(:,:,:,:,2)
|
||
end do
|
||
!$omp end parallel do
|
||
|
||
!= 1st stage
|
||
!
|
||
if (fsal_update) then
|
||
!$omp parallel do default(shared) private(pdata)
|
||
do l = 1, n
|
||
pdata => data_blocks(l)%ptr
|
||
|
||
call update_increment(pdata)
|
||
call update_sources(time, 0.0d+00, pdata)
|
||
|
||
end do
|
||
!$omp end parallel do
|
||
|
||
call boundary_fluxes(status)
|
||
|
||
if (status /= 0) go to 100
|
||
end if
|
||
|
||
!$omp parallel do default(shared) private(pdata)
|
||
do l = 1, n
|
||
pdata => data_blocks(l)%ptr
|
||
|
||
pdata%uu(:,:,:,:,2) = pdata%uu(:,:,:,:,1) &
|
||
+ bt(1) * dt * pdata%du(:,:,:,:)
|
||
pdata%uu(:,:,:,:,4) = pdata%uu(:,:,:,:,4) &
|
||
+ bh(1) * dt * pdata%du(:,:,:,:)
|
||
end do
|
||
!$omp end parallel do
|
||
|
||
dtm = c(2) * dt
|
||
call update_variables(time, dtm, status)
|
||
if (status /= 0) go to 100
|
||
|
||
!= remaining stages
|
||
!
|
||
do i = 2, stages
|
||
|
||
dtm = c(i) * dt
|
||
tm = time + dtm
|
||
|
||
!$omp parallel do default(shared) private(pdata)
|
||
do l = 1, n
|
||
pdata => data_blocks(l)%ptr
|
||
|
||
call update_increment(pdata)
|
||
call update_sources(tm, dtm, pdata)
|
||
end do
|
||
!$omp end parallel do
|
||
|
||
call boundary_fluxes(status)
|
||
|
||
if (status /= 0) go to 100
|
||
|
||
!$omp parallel do default(shared) private(pdata)
|
||
do l = 1, n
|
||
pdata => data_blocks(l)%ptr
|
||
|
||
pdata%uu(:,:,:,:,3) = pdata%uu(:,:,:,:,3) &
|
||
+ dl(i) * pdata%uu(:,:,:,:,2)
|
||
pdata%uu(:,:,:,:,2) = gm(1,i) * pdata%uu(:,:,:,:,2) &
|
||
+ gm(2,i) * pdata%uu(:,:,:,:,3) &
|
||
+ gm(3,i) * pdata%uu(:,:,:,:,1) &
|
||
+ bt(i) * dt * pdata%du(:,:,:,:)
|
||
pdata%uu(:,:,:,:,4) = pdata%uu(:,:,:,:,4) &
|
||
+ bh(i) * dt * pdata%du(:,:,:,:)
|
||
end do
|
||
!$omp end parallel do
|
||
|
||
dtm = c(i+1) * dt
|
||
call update_variables(tm, dtm, status)
|
||
if (status /= 0) go to 100
|
||
|
||
end do ! i = 2, stages
|
||
|
||
!= extra step: decay the magnetic divergence potential of both solutions
|
||
!
|
||
if (ibp > 0) then
|
||
adecay(:) = exp(aglm(:) * cmax * dt)
|
||
|
||
!$omp parallel do default(shared) private(pdata)
|
||
do l = 1, n
|
||
pdata => data_blocks(l)%ptr
|
||
|
||
pdata%uu(ibp,:,:,:,2) = adecay(pdata%meta%level) &
|
||
* pdata%uu(ibp,:,:,:,2)
|
||
pdata%uu(ibp,:,:,:,4) = adecay(pdata%meta%level) &
|
||
* pdata%uu(ibp,:,:,:,4)
|
||
end do
|
||
!$omp end parallel do
|
||
end if
|
||
|
||
!= extra step: FSAL
|
||
!
|
||
if (fsal) then
|
||
|
||
tm = time + dt
|
||
|
||
!$omp parallel do default(shared) private(pdata)
|
||
do l = 1, n
|
||
pdata => data_blocks(l)%ptr
|
||
|
||
call update_increment(pdata)
|
||
call update_sources(tm, 0.0d+00, pdata)
|
||
end do
|
||
!$omp end parallel do
|
||
|
||
call boundary_fluxes(status)
|
||
|
||
if (status /= 0) go to 100
|
||
|
||
!$omp parallel do default(shared) private(pdata)
|
||
do l = 1, n
|
||
pdata => data_blocks(l)%ptr
|
||
|
||
pdata%uu(:,:,:,:,4) = pdata%uu(:,:,:,:,4) &
|
||
+ bh(stages+1) * dt * pdata%du(:,:,:,:)
|
||
end do
|
||
!$omp end parallel do
|
||
|
||
end if
|
||
|
||
!= error estimation
|
||
!
|
||
call update_errors(2, 4)
|
||
|
||
! calculate the tolerance and estimate the next time step due to the error
|
||
!
|
||
errtol = maxval(errors)
|
||
errs(1) = errtol
|
||
fc = product(errs(:)**betas(:))
|
||
fc = 1.0d+00 + chi * atan((fc - 1.0d+00) / chi)
|
||
dte = dt * fc
|
||
cond = errtol <= 1.0d+00 .or. fc > fac .or. nrej >= mrej
|
||
|
||
100 continue
|
||
cond = cond .and. status == 0
|
||
|
||
if (cond) then
|
||
test = .false.
|
||
|
||
errs(3) = errs(2)
|
||
errs(2) = errs(1)
|
||
|
||
if (fsal) fsal_update = .true.
|
||
else
|
||
if (status == 0) then
|
||
dt = max(dte, dtsafe * dth)
|
||
nrej = nrej + 1 ! rejection count in the current step
|
||
else
|
||
dt = 2.5d-01 * dt
|
||
end if
|
||
nrejections = nrejections + 1
|
||
|
||
! since the solution was rejected, we have to revert the primitive variables
|
||
! to the previous state
|
||
!
|
||
!$omp parallel do default(shared) private(pdata)
|
||
do l = 1, n
|
||
pdata => data_blocks(l)%ptr
|
||
|
||
pdata%u => pdata%uu(:,:,:,:,1)
|
||
end do
|
||
!$omp end parallel do
|
||
|
||
call update_variables(tm, dtm, status)
|
||
if (status /= 0) &
|
||
call print_message(loc, "Possible bug: the revert to " // &
|
||
"the previous state found it unphysical.")
|
||
|
||
if (fsal) fsal_update = .false.
|
||
end if
|
||
|
||
niterations = niterations + 1
|
||
|
||
end do
|
||
|
||
!= final step: U(n+1) = U(1)
|
||
!
|
||
!$omp parallel do default(shared) private(pdata)
|
||
do l = 1, n
|
||
pdata => data_blocks(l)%ptr
|
||
|
||
pdata%uu(:,:,:,:,1) = pdata%uu(:,:,:,:,2)
|
||
|
||
pdata%u => pdata%uu(:,:,:,:,1)
|
||
end do
|
||
!$omp end parallel do
|
||
|
||
tm = time + dt
|
||
call update_variables(tm, dt, status)
|
||
if (status /= 0) &
|
||
call print_message(loc, "Possible bug: the new state has been " // &
|
||
"accepted, nevertheless the variable " // &
|
||
"update found it unphysical.")
|
||
|
||
!-------------------------------------------------------------------------------
|
||
!
|
||
end subroutine evolve_3sstarplus
|
||
!
|
||
!===============================================================================
|
||
!
|
||
! subroutine UPDATE_INCREMENT:
|
||
! ---------------------------
|
||
!
|
||
! Subroutine calculates the conservative variable increment from
|
||
! directional fluxes.
|
||
!
|
||
! Arguments:
|
||
!
|
||
! pdata - the point to data block storing the directional fluxes;
|
||
!
|
||
!===============================================================================
|
||
!
|
||
subroutine update_increment(pdata)
|
||
|
||
use blocks , only : block_data
|
||
use coordinates, only : nbl, ne, neu, nn => bcells
|
||
use coordinates, only : adx, ady, adxi, adyi
|
||
#if NDIMS == 3
|
||
use coordinates, only : adz, adzi
|
||
#endif /* NDIMS == 3 */
|
||
use equations , only : nf, ns
|
||
use equations , only : idn, isl, isu
|
||
use helpers , only : print_message
|
||
use schemes , only : update_flux
|
||
use workspace , only : resize_workspace, work, work_in_use
|
||
|
||
implicit none
|
||
|
||
type(block_data), pointer, intent(inout) :: pdata
|
||
|
||
logical, save :: first = .true.
|
||
|
||
integer :: i, j, k, p
|
||
integer :: im1, ip1
|
||
integer :: jm1, jp1
|
||
#if NDIMS == 3
|
||
integer :: km1, kp1
|
||
#endif /* NDIMS == 3 */
|
||
integer :: status
|
||
real(kind=8) :: df
|
||
|
||
real(kind=8), dimension(NDIMS) :: dh, dhi
|
||
|
||
integer, save :: nt
|
||
!$ integer :: omp_get_thread_num
|
||
|
||
real(kind=8), dimension(:,:,:,:,:) , pointer, save :: f
|
||
real(kind=8), dimension(:,:,:,:,:,:), pointer, save :: s
|
||
!$omp threadprivate(first,nt,f,s)
|
||
|
||
character(len=*), parameter :: loc = 'EVOLUTION:update_increment()'
|
||
|
||
!-------------------------------------------------------------------------------
|
||
!
|
||
nt = 0
|
||
!$ nt = omp_get_thread_num()
|
||
if (first) then
|
||
i = NDIMS * nf * nn**NDIMS
|
||
j = 3 * i
|
||
|
||
call resize_workspace(j, status)
|
||
if (status /= 0) then
|
||
call print_message(loc, "Could not resize the workspace!")
|
||
go to 100
|
||
end if
|
||
|
||
#if NDIMS == 3
|
||
f(1:nf,1:nn,1:nn,1:nn,1:3) => work( 1:i,nt)
|
||
s(1:nf,1:nn,1:nn,1:nn,1:2,1:3) => work(i+1:j,nt)
|
||
#else /* NDIMS == 3 */
|
||
f(1:nf,1:nn,1:nn,1: 1,1:2) => work( 1:i,nt)
|
||
s(1:nf,1:nn,1:nn,1: 1,1:2,1:2) => work(i+1:j,nt)
|
||
#endif /* NDIMS == 3 */
|
||
|
||
first = .false.
|
||
end if
|
||
|
||
if (work_in_use(nt)) &
|
||
call print_message(loc, "Workspace is being used right now! " // &
|
||
"Corruptions can occur!")
|
||
|
||
work_in_use(nt) = .true.
|
||
|
||
dh(1) = adx(pdata%meta%level)
|
||
dh(2) = ady(pdata%meta%level)
|
||
#if NDIMS == 3
|
||
dh(3) = adz(pdata%meta%level)
|
||
#endif /* NDIMS == 3 */
|
||
dhi(1) = adxi(pdata%meta%level)
|
||
dhi(2) = adyi(pdata%meta%level)
|
||
#if NDIMS == 3
|
||
dhi(3) = adzi(pdata%meta%level)
|
||
#endif /* NDIMS == 3 */
|
||
|
||
! calculate the interface fluxes
|
||
!
|
||
call update_flux(dh(1:NDIMS), pdata%q(:,:,:,:), &
|
||
s(:,:,:,:,:,:), f(:,:,:,:,:))
|
||
|
||
! store the block interface fluxes
|
||
!
|
||
pdata%fx(:,:,:,1) = f(:,nbl,:,:,1)
|
||
pdata%fx(:,:,:,2) = f(:,ne ,:,:,1)
|
||
pdata%fy(:,:,:,1) = f(:,:,nbl,:,2)
|
||
pdata%fy(:,:,:,2) = f(:,:,ne ,:,2)
|
||
#if NDIMS == 3
|
||
pdata%fz(:,:,:,1) = f(:,:,:,nbl,3)
|
||
pdata%fz(:,:,:,2) = f(:,:,:,ne ,3)
|
||
#endif /* NDIMS == 3 */
|
||
|
||
! calculate the variable update from the directional fluxes
|
||
!
|
||
#if NDIMS == 2
|
||
k = 1
|
||
#endif /* NDIMS == 2 */
|
||
#if NDIMS == 3
|
||
do k = nbl, neu
|
||
km1 = k - 1
|
||
#endif /* NDIMS == 3 */
|
||
do j = nbl, neu
|
||
jm1 = j - 1
|
||
do i = nbl, neu
|
||
im1 = i - 1
|
||
|
||
#if NDIMS == 3
|
||
pdata%du(1:nf,i,j,k) = - dhi(1) * (f(:,i,j,k,1) - f(:,im1,j,k,1)) &
|
||
- dhi(2) * (f(:,i,j,k,2) - f(:,i,jm1,k,2)) &
|
||
- dhi(3) * (f(:,i,j,k,3) - f(:,i,j,km1,3))
|
||
#else /* NDIMS == 3 */
|
||
pdata%du(1:nf,i,j,k) = - dhi(1) * (f(:,i,j,k,1) - f(:,im1,j,k,1)) &
|
||
- dhi(2) * (f(:,i,j,k,2) - f(:,i,jm1,k,2))
|
||
#endif /* NDIMS == 3 */
|
||
end do ! i = nbl, neu
|
||
end do ! j = nbl, neu
|
||
#if NDIMS == 3
|
||
end do ! k = nbl, neu
|
||
#endif /* NDIMS == 3 */
|
||
|
||
! update passive scalars
|
||
!
|
||
if (ns > 0) then
|
||
|
||
pdata%du(isl:isu,:,:,:) = 0.0d+00
|
||
|
||
#if NDIMS == 3
|
||
do k = nbl - 1, neu
|
||
kp1 = k + 1
|
||
#endif /* NDIMS == 3 */
|
||
do j = nbl - 1, neu
|
||
jp1 = j + 1
|
||
do i = nbl - 1, neu
|
||
ip1 = i + 1
|
||
|
||
! X-face
|
||
!
|
||
if (f(idn,i,j,k,1) >= 0.0d+00) then
|
||
do p = isl, isu
|
||
df = dhi(1) * f(idn,i,j,k,1) * pdata%q(p,i ,j,k)
|
||
pdata%du(p,i ,j,k) = pdata%du(p,i ,j,k) - df
|
||
pdata%du(p,ip1,j,k) = pdata%du(p,ip1,j,k) + df
|
||
end do
|
||
else
|
||
do p = isl, isu
|
||
df = dhi(1) * f(idn,i,j,k,1) * pdata%q(p,ip1,j,k)
|
||
pdata%du(p,i ,j,k) = pdata%du(p,i ,j,k) - df
|
||
pdata%du(p,ip1,j,k) = pdata%du(p,ip1,j,k) + df
|
||
end do
|
||
end if
|
||
|
||
! Y-face
|
||
!
|
||
if (f(idn,i,j,k,2) >= 0.0d+00) then
|
||
do p = isl, isu
|
||
df = dhi(2) * f(idn,i,j,k,2) * pdata%q(p,i,j ,k)
|
||
pdata%du(p,i,j ,k) = pdata%du(p,i,j ,k) - df
|
||
pdata%du(p,i,jp1,k) = pdata%du(p,i,jp1,k) + df
|
||
end do
|
||
else
|
||
do p = isl, isu
|
||
df = dhi(2) * f(idn,i,j,k,2) * pdata%q(p,i,jp1,k)
|
||
pdata%du(p,i,j ,k) = pdata%du(p,i,j ,k) - df
|
||
pdata%du(p,i,jp1,k) = pdata%du(p,i,jp1,k) + df
|
||
end do
|
||
end if
|
||
|
||
#if NDIMS == 3
|
||
! Z-face
|
||
!
|
||
if (f(idn,i,j,k,3) >= 0.0d+00) then
|
||
do p = isl, isu
|
||
df = dhi(3) * f(idn,i,j,k,3) * pdata%q(p,i,j,k )
|
||
pdata%du(p,i,j,k ) = pdata%du(p,i,j,k ) - df
|
||
pdata%du(p,i,j,kp1) = pdata%du(p,i,j,kp1) + df
|
||
end do
|
||
else
|
||
do p = isl, isu
|
||
df = dhi(3) * f(idn,i,j,k,3) * pdata%q(p,i,j,kp1)
|
||
pdata%du(p,i,j,k ) = pdata%du(p,i,j,k ) - df
|
||
pdata%du(p,i,j,kp1) = pdata%du(p,i,j,kp1) + df
|
||
end do
|
||
end if
|
||
#endif /* NDIMS == 3 */
|
||
|
||
end do ! i = nbl, neu
|
||
end do ! j = nbl, neu
|
||
#if NDIMS == 3
|
||
end do ! k = nbl, neu
|
||
#endif /* NDIMS == 3 */
|
||
end if
|
||
|
||
work_in_use(nt) = .false.
|
||
|
||
100 continue
|
||
|
||
!-------------------------------------------------------------------------------
|
||
!
|
||
end subroutine update_increment
|
||
!
|
||
!===============================================================================
|
||
!
|
||
! subroutine UPDATE_VARIABLES:
|
||
! ---------------------------
|
||
!
|
||
! Subroutine iterates over all data blocks and converts the conservative
|
||
! variables to their primitive representation.
|
||
!
|
||
! Arguments:
|
||
!
|
||
! tm - time at the moment of update;
|
||
! dtm - time step since the last update;
|
||
! status - status flag indicating if the update was successful;
|
||
!
|
||
!===============================================================================
|
||
!
|
||
subroutine update_variables(tm, dtm, status)
|
||
|
||
use blocks , only : block_meta, block_data, data_blocks, list_meta
|
||
use blocks , only : set_neighbors_update, get_dblocks
|
||
use boundaries, only : boundary_variables
|
||
use equations , only : update_primitive_variables
|
||
use equations , only : fix_unphysical_cells, correct_unphysical_states
|
||
#ifdef MPI
|
||
use mpitools , only : reduce_maximum
|
||
#endif /* MPI */
|
||
use shapes , only : update_shapes
|
||
|
||
implicit none
|
||
|
||
real(kind=8), intent(in) :: tm, dtm
|
||
integer , intent(out) :: status
|
||
|
||
type(block_meta), pointer :: pmeta
|
||
type(block_data), pointer :: pdata
|
||
|
||
integer :: l, n, s
|
||
|
||
!-------------------------------------------------------------------------------
|
||
!
|
||
status = 0
|
||
|
||
n = get_dblocks()
|
||
|
||
!$omp parallel do default(shared) private(pdata,pmeta)
|
||
do l = 1, n
|
||
pdata => data_blocks(l)%ptr
|
||
pmeta => pdata%meta
|
||
|
||
if (pmeta%update) call update_shapes(pdata, tm, dtm)
|
||
end do
|
||
!$omp end parallel do
|
||
|
||
call boundary_variables(tm, dtm, status)
|
||
|
||
#ifdef MPI
|
||
call reduce_maximum(status)
|
||
#endif /* MPI */
|
||
if (status /= 0) go to 100
|
||
|
||
!$omp parallel do default(shared) private(pdata,pmeta)
|
||
do l = 1, n
|
||
pdata => data_blocks(l)%ptr
|
||
pmeta => pdata%meta
|
||
|
||
if (pmeta%boundary) call update_shapes(pdata, tm, dtm)
|
||
end do
|
||
!$omp end parallel do
|
||
|
||
!$omp parallel do default(shared) private(pdata,pmeta,s)
|
||
do l = 1, n
|
||
pdata => data_blocks(l)%ptr
|
||
pmeta => pdata%meta
|
||
|
||
if (pmeta%update .or. pmeta%boundary) then
|
||
call update_primitive_variables(pdata%u, pdata%q, .true., s)
|
||
|
||
pdata%physical = s == 0
|
||
else
|
||
pdata%physical = .true.
|
||
end if
|
||
end do
|
||
!$omp end parallel do
|
||
|
||
if (fix_unphysical_cells) then
|
||
!$omp parallel do default(shared) private(pdata,pmeta,s)
|
||
do l = 1, n
|
||
pdata => data_blocks(l)%ptr
|
||
pmeta => pdata%meta
|
||
|
||
if (.not. pdata%physical) then
|
||
call correct_unphysical_states(step, pdata, s)
|
||
!$omp critical
|
||
if (s /= 0) status = 1
|
||
!$omp end critical
|
||
|
||
call update_shapes(pdata, tm, dtm)
|
||
end if
|
||
|
||
end do
|
||
!$omp end parallel do
|
||
else
|
||
do l = 1, n
|
||
pdata => data_blocks(l)%ptr
|
||
if (.not. pdata%physical) status = 1
|
||
end do
|
||
end if
|
||
|
||
#ifdef MPI
|
||
call reduce_maximum(status)
|
||
#endif /* MPI */
|
||
if (status /= 0) go to 100
|
||
|
||
100 continue
|
||
|
||
pmeta => list_meta
|
||
do while (associated(pmeta))
|
||
pmeta%boundary = .false.
|
||
pmeta => pmeta%next
|
||
end do
|
||
|
||
!-------------------------------------------------------------------------------
|
||
!
|
||
end subroutine update_variables
|
||
!
|
||
!===============================================================================
|
||
!
|
||
! subroutine UPDATE_ERRORS_L1:
|
||
! ---------------------------
|
||
!
|
||
! Description:
|
||
!
|
||
! The subroutine is designed to update errors with respect to absolute and
|
||
! relative tolerances using the L1 norm. The errors are calculated for
|
||
! each variable.
|
||
!
|
||
! Arguments:
|
||
!
|
||
! nh - the index of the higher order solution;
|
||
! nl - the index of the lower order solution;
|
||
!
|
||
!===============================================================================
|
||
!
|
||
subroutine update_errors_l1(nh, nl)
|
||
|
||
use blocks , only : block_data, data_blocks
|
||
use blocks , only : get_nleafs, get_dblocks
|
||
use coordinates, only : nc => ncells, nb, ne
|
||
use equations , only : nf, errors
|
||
use helpers , only : print_message
|
||
#ifdef MPI
|
||
use mpitools , only : reduce_sum
|
||
#endif /* MPI */
|
||
use workspace , only : resize_workspace, work, work_in_use
|
||
|
||
implicit none
|
||
|
||
integer, intent(in) :: nh, nl
|
||
|
||
character(len=*), parameter :: loc = 'EVOLUTION:update_errors_l1()'
|
||
|
||
type(block_data), pointer :: pdata
|
||
|
||
integer :: nblks, n, p
|
||
|
||
logical , save :: first = .true.
|
||
integer , save :: nt = 0
|
||
real(kind=8), save :: fnorm = 1.0d+00
|
||
|
||
real(kind=8), dimension(nf) :: lerrors
|
||
real(kind=8), dimension(:,:,:), pointer, save :: uhi, ulo, div
|
||
|
||
!$omp threadprivate(first,nt,uhi,ulo,div)
|
||
!$ integer :: omp_get_thread_num
|
||
|
||
!-------------------------------------------------------------------------------
|
||
!
|
||
errors(:) = 0.0d+00
|
||
|
||
nblks = get_dblocks()
|
||
|
||
!$omp parallel default(shared) private(pdata,lerrors,n,p)
|
||
if (first) then
|
||
!$ nt = omp_get_thread_num()
|
||
n = nc**NDIMS
|
||
|
||
#if NDIMS == 3
|
||
uhi(1:nc,1:nc,1:nc) => work( 1: n,nt)
|
||
ulo(1:nc,1:nc,1:nc) => work( n+1:2*n,nt)
|
||
div(1:nc,1:nc,1:nc) => work(2*n+1:3*n,nt)
|
||
#else /* NDIMS == 3 */
|
||
uhi(1:nc,1:nc,1: 1) => work( 1: n,nt)
|
||
ulo(1:nc,1:nc,1: 1) => work( n+1:2*n,nt)
|
||
div(1:nc,1:nc,1: 1) => work(2*n+1:3*n,nt)
|
||
#endif /* NDIMS == 3 */
|
||
|
||
!$omp single
|
||
fnorm = 1.0d+00 / n
|
||
!$omp end single
|
||
|
||
first = .false.
|
||
end if
|
||
|
||
if (work_in_use(nt)) &
|
||
call print_message(loc, "Workspace is being used right now! " // &
|
||
"Corruptions can occur!")
|
||
|
||
work_in_use(nt) = .true.
|
||
!$omp barrier
|
||
|
||
!$omp do reduction(+:errors)
|
||
do n = 1, nblks
|
||
pdata => data_blocks(n)%ptr
|
||
|
||
do p = 1, nf
|
||
#if NDIMS == 3
|
||
uhi = pdata%uu(p,nb:ne,nb:ne,nb:ne,nh)
|
||
ulo = pdata%uu(p,nb:ne,nb:ne,nb:ne,nl)
|
||
#else /* NDIMS == 3 */
|
||
uhi = pdata%uu(p,nb:ne,nb:ne, : ,nh)
|
||
ulo = pdata%uu(p,nb:ne,nb:ne, : ,nl)
|
||
#endif /* NDIMS == 3 */
|
||
|
||
div = atol + rtol * max(abs(uhi), abs(ulo))
|
||
|
||
lerrors(p) = fnorm * sum(abs(uhi - ulo) / div)
|
||
end do
|
||
|
||
errors = errors + lerrors
|
||
end do
|
||
!$omp end do nowait
|
||
|
||
work_in_use(nt) = .false.
|
||
!$omp end parallel
|
||
|
||
errors(:) = errors(:) / get_nleafs()
|
||
|
||
#ifdef MPI
|
||
call reduce_sum(errors)
|
||
#endif /* MPI */
|
||
|
||
!-------------------------------------------------------------------------------
|
||
!
|
||
end subroutine update_errors_l1
|
||
!
|
||
!===============================================================================
|
||
!
|
||
! subroutine UPDATE_ERRORS_L2:
|
||
! ---------------------------
|
||
!
|
||
! Description:
|
||
!
|
||
! The subroutine is designed to update errors with respect to absolute and
|
||
! relative tolerances using the L2 norm. The errors are calculated for
|
||
! each variable.
|
||
!
|
||
! Arguments:
|
||
!
|
||
! nh - the index of the higher order solution;
|
||
! nl - the index of the lower order solution;
|
||
!
|
||
!===============================================================================
|
||
!
|
||
subroutine update_errors_l2(nh, nl)
|
||
|
||
use blocks , only : block_data, data_blocks
|
||
use blocks , only : get_nleafs, get_dblocks
|
||
use coordinates, only : nc => ncells, nb, ne
|
||
use equations , only : nf, errors
|
||
use helpers , only : print_message
|
||
#ifdef MPI
|
||
use mpitools , only : reduce_sum
|
||
#endif /* MPI */
|
||
use workspace , only : resize_workspace, work, work_in_use
|
||
|
||
implicit none
|
||
|
||
integer, intent(in) :: nh, nl
|
||
|
||
character(len=*), parameter :: loc = 'EVOLUTION:update_errors_l2()'
|
||
|
||
type(block_data), pointer :: pdata
|
||
|
||
integer :: nblks, n, p
|
||
|
||
logical , save :: first = .true.
|
||
integer , save :: nt = 0
|
||
real(kind=8), save :: fnorm = 1.0d+00
|
||
|
||
real(kind=8), dimension(nf) :: lerrors
|
||
real(kind=8), dimension(:,:,:), pointer, save :: uhi, ulo, div
|
||
|
||
!$omp threadprivate(first,nt,uhi,ulo,div)
|
||
!$ integer :: omp_get_thread_num
|
||
|
||
!-------------------------------------------------------------------------------
|
||
!
|
||
errors(:) = 0.0d+00
|
||
|
||
nblks = get_dblocks()
|
||
|
||
!$omp parallel default(shared) private(pdata,lerrors,n,p)
|
||
if (first) then
|
||
!$ nt = omp_get_thread_num()
|
||
n = nc**NDIMS
|
||
|
||
#if NDIMS == 3
|
||
uhi(1:nc,1:nc,1:nc) => work( 1: n,nt)
|
||
ulo(1:nc,1:nc,1:nc) => work( n+1:2*n,nt)
|
||
div(1:nc,1:nc,1:nc) => work(2*n+1:3*n,nt)
|
||
#else /* NDIMS == 3 */
|
||
uhi(1:nc,1:nc,1: 1) => work( 1: n,nt)
|
||
ulo(1:nc,1:nc,1: 1) => work( n+1:2*n,nt)
|
||
div(1:nc,1:nc,1: 1) => work(2*n+1:3*n,nt)
|
||
#endif /* NDIMS == 3 */
|
||
|
||
!$omp single
|
||
fnorm = 1.0d+00 / n
|
||
!$omp end single
|
||
|
||
first = .false.
|
||
end if
|
||
|
||
if (work_in_use(nt)) &
|
||
call print_message(loc, "Workspace is being used right now! " // &
|
||
"Corruptions can occur!")
|
||
|
||
work_in_use(nt) = .true.
|
||
!$omp barrier
|
||
|
||
!$omp do reduction(+:errors)
|
||
do n = 1, nblks
|
||
pdata => data_blocks(n)%ptr
|
||
|
||
do p = 1, nf
|
||
#if NDIMS == 3
|
||
uhi = pdata%uu(p,nb:ne,nb:ne,nb:ne,nh)
|
||
ulo = pdata%uu(p,nb:ne,nb:ne,nb:ne,nl)
|
||
#else /* NDIMS == 3 */
|
||
uhi = pdata%uu(p,nb:ne,nb:ne, : ,nh)
|
||
ulo = pdata%uu(p,nb:ne,nb:ne, : ,nl)
|
||
#endif /* NDIMS == 3 */
|
||
|
||
div = atol + rtol * max(abs(uhi), abs(ulo))
|
||
|
||
lerrors(p) = fnorm * sum((abs(uhi - ulo) / div)**2)
|
||
end do
|
||
|
||
errors = errors + lerrors
|
||
end do
|
||
!$omp end do nowait
|
||
|
||
work_in_use(nt) = .false.
|
||
!$omp end parallel
|
||
|
||
errors(:) = errors(:) / get_nleafs()
|
||
|
||
#ifdef MPI
|
||
call reduce_sum(errors)
|
||
#endif /* MPI */
|
||
|
||
errors(:) = sqrt(errors(:))
|
||
|
||
!-------------------------------------------------------------------------------
|
||
!
|
||
end subroutine update_errors_l2
|
||
!
|
||
!===============================================================================
|
||
!
|
||
! subroutine UPDATE_ERRORS_LMAX:
|
||
! -----------------------------
|
||
!
|
||
! Description:
|
||
!
|
||
! The subroutine is designed to update errors with respect to absolute and
|
||
! relative tolerances using the Lmax norm. The errors are calculated for
|
||
! each variable.
|
||
!
|
||
! Arguments:
|
||
!
|
||
! nh - the index of the higher order solution;
|
||
! nl - the index of the lower order solution;
|
||
!
|
||
!===============================================================================
|
||
!
|
||
subroutine update_errors_lmax(nh, nl)
|
||
|
||
use blocks , only : block_data, data_blocks, get_dblocks
|
||
use coordinates, only : nc => ncells, nb, ne
|
||
use equations , only : nf, errors
|
||
use helpers , only : print_message
|
||
#ifdef MPI
|
||
use mpitools , only : reduce_maximum
|
||
#endif /* MPI */
|
||
use workspace , only : resize_workspace, work, work_in_use
|
||
|
||
implicit none
|
||
|
||
integer, intent(in) :: nh, nl
|
||
|
||
character(len=*), parameter :: loc = 'EVOLUTION:update_errors_lmax()'
|
||
|
||
type(block_data), pointer :: pdata
|
||
|
||
integer :: nblks, n, p
|
||
|
||
logical , save :: first = .true.
|
||
integer , save :: nt = 0
|
||
|
||
real(kind=8), dimension(nf) :: lerrors
|
||
real(kind=8), dimension(:,:,:), pointer, save :: uhi, ulo, div
|
||
|
||
!$omp threadprivate(first,nt,uhi,ulo,div)
|
||
!$ integer :: omp_get_thread_num
|
||
|
||
!-------------------------------------------------------------------------------
|
||
!
|
||
errors(:) = 0.0d+00
|
||
|
||
nblks = get_dblocks()
|
||
|
||
!$omp parallel default(shared) private(pdata,lerrors,n,p)
|
||
if (first) then
|
||
!$ nt = omp_get_thread_num()
|
||
n = nc**NDIMS
|
||
|
||
#if NDIMS == 3
|
||
uhi(1:nc,1:nc,1:nc) => work( 1: n,nt)
|
||
ulo(1:nc,1:nc,1:nc) => work( n+1:2*n,nt)
|
||
div(1:nc,1:nc,1:nc) => work(2*n+1:3*n,nt)
|
||
#else /* NDIMS == 3 */
|
||
uhi(1:nc,1:nc,1: 1) => work( 1: n,nt)
|
||
ulo(1:nc,1:nc,1: 1) => work( n+1:2*n,nt)
|
||
div(1:nc,1:nc,1: 1) => work(2*n+1:3*n,nt)
|
||
#endif /* NDIMS == 3 */
|
||
|
||
first = .false.
|
||
end if
|
||
|
||
if (work_in_use(nt)) &
|
||
call print_message(loc, "Workspace is being used right now! " // &
|
||
"Corruptions can occur!")
|
||
|
||
work_in_use(nt) = .true.
|
||
!$omp barrier
|
||
|
||
!$omp do reduction(max:errors)
|
||
do n = 1, nblks
|
||
pdata => data_blocks(n)%ptr
|
||
|
||
do p = 1, nf
|
||
#if NDIMS == 3
|
||
uhi = pdata%uu(p,nb:ne,nb:ne,nb:ne,nh)
|
||
ulo = pdata%uu(p,nb:ne,nb:ne,nb:ne,nl)
|
||
#else /* NDIMS == 3 */
|
||
uhi = pdata%uu(p,nb:ne,nb:ne, : ,nh)
|
||
ulo = pdata%uu(p,nb:ne,nb:ne, : ,nl)
|
||
#endif /* NDIMS == 3 */
|
||
|
||
div = atol + rtol * max(abs(uhi), abs(ulo))
|
||
|
||
lerrors(p) = maxval(abs(uhi - ulo) / div)
|
||
end do
|
||
|
||
errors = max(errors, lerrors)
|
||
end do
|
||
!$omp end do nowait
|
||
|
||
work_in_use(nt) = .false.
|
||
!$omp end parallel
|
||
|
||
#ifdef MPI
|
||
call reduce_maximum(errors)
|
||
#endif /* MPI */
|
||
|
||
!-------------------------------------------------------------------------------
|
||
!
|
||
end subroutine update_errors_lmax
|
||
|
||
!===============================================================================
|
||
!
|
||
end module evolution
|