amun-code/sources/evolution.F90
2024-07-10 20:54:55 -03:00

4535 lines
140 KiB
Fortran
Raw Permalink Blame History

This file contains ambiguous Unicode characters

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

!!******************************************************************************
!!
!! This file is part of the AMUN source code, a program to perform
!! Newtonian or relativistic magnetohydrodynamical simulations on uniform or
!! adaptive mesh.
!!
!! Copyright (C) 2008-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 3274,
! 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 3274,
! 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 RungeKutta 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 RungeKutta 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 RungeKutta 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