timedisc_rkfehlberg.f90
Go to the documentation of this file.
1 !#############################################################################
2 !# #
3 !# fosite - 3D hydrodynamical simulation program #
4 !# module: timedisc_rkfehlberg .f90 #
5 !# #
6 !# Copyright (C) 2011,2014 #
7 !# Björn Sperling <sperling@astrophysik.uni-kiel.de> #
8 !# Tobias Illenseer <tillense@astrophysik.uni-kiel.de> #
9 !# #
10 !# This program is free software; you can redistribute it and/or modify #
11 !# it under the terms of the GNU General Public License as published by #
12 !# the Free Software Foundation; either version 2 of the License, or (at #
13 !# your option) any later version. #
14 !# #
15 !# This program is distributed in the hope that it will be useful, but #
16 !# WITHOUT ANY WARRANTY; without even the implied warranty of #
17 !# MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, GOOD TITLE or #
18 !# NON INFRINGEMENT. See the GNU General Public License for more #
19 !# details. #
20 !# #
21 !# You should have received a copy of the GNU General Public License #
22 !# along with this program; if not, write to the Free Software #
23 !# Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. #
24 !# #
25 !#############################################################################
26 
27 !----------------------------------------------------------------------------!
41 !----------------------------------------------------------------------------!
44  USE mesh_base_mod
45  USE fluxes_base_mod
49  USE marray_base_mod
52  USE common_dict
53 #ifdef PARALLEL
54 #ifdef HAVE_MPI_MOD
55  USE mpi
56 #endif
57 #endif
58  IMPLICIT NONE
59 #ifdef PARALLEL
60 #ifdef HAVE_MPIF_H
61  include 'mpif.h'
62 #endif
63 #endif
64  !--------------------------------------------------------------------------!
65  PRIVATE
67  CLASS(marray_compound), POINTER :: p
68  END TYPE coeff_type
70  TYPE(coeff_type), DIMENSION(:), ALLOCATABLE :: coeff
71  REAL, DIMENSION(:), POINTER :: b_low,b_high,c
72  REAL, DIMENSION(:,:), POINTER :: a
73  CONTAINS
74  PROCEDURE :: inittimedisc
76  PROCEDURE :: finalize
77  PROCEDURE :: solveode
79  generic :: computecvar => computecvar_rkfehlberg
80  PROCEDURE :: setbutchertableau
81  PROCEDURE :: showbutchertableau
82  END TYPE timedisc_rkfehlberg
83  CHARACTER(LEN=32), PARAMETER :: odesolver_name = "Runge-Kutta Fehlberg"
84 
85  !--------------------------------------------------------------------------!
86  PUBLIC :: &
87  ! types
88  coeff_type, &
90  !--------------------------------------------------------------------------!
91 
92 CONTAINS
93 
94  SUBROUTINE inittimedisc(this,Mesh,Physics,config,IO,ttype,tname)
97  IMPLICIT NONE
98  !------------------------------------------------------------------------!
99  CLASS(timedisc_rkfehlberg), INTENT(INOUT) :: this
100  CLASS(mesh_base), INTENT(INOUT) :: Mesh
101  CLASS(physics_base), INTENT(IN) :: Physics
102  TYPE(Dict_TYP), POINTER :: config,IO
103  INTEGER, INTENT(IN) :: ttype
104  CHARACTER(LEN=32), INTENT(IN) :: tname
105  !------------------------------------------------------------------------!
106  INTEGER :: err,k,ShowBT
107  !------------------------------------------------------------------------!
108  CALL this%timedisc_modeuler%InitTimedisc(mesh,physics,config,io,ttype,tname)
109 
110  ALLOCATE(this%b_high(this%m),this%b_low(this%m),&
111  this%c(this%m),this%a(this%m,this%m), &
112  this%coeff(this%m), &
113  stat = err)
114  IF (err.NE.0) THEN
115  CALL this%Error("timedisc_rkfehlberg::InitTimedisc", "Unable to allocate memory.")
116  END IF
117 
118  ! init Butcher tableau
119  CALL this%SetButcherTableau()
120  CALL getattr(config, "ShowButcherTableau", showbt, 0)
121  IF (showbt.EQ.1) CALL this%ShowButcherTableau()
122 
123  ! init coefficient compounds
124  this%coeff(1)%p => this%rhs
125  DO k=2,this%m
126  CALL physics%new_statevector(this%coeff(k)%p,conservative)
127  this%coeff(k)%p%data1d(:) = 0.0
128  END DO
129 
130  IF ((this%tol_rel.LT.0.0).OR.minval(this%tol_abs(:)).LT.0.0) &
131  CALL this%Error("timedisc_rkfehlberg::InitTimedisc", &
132  "error tolerance levels must be greater than 0")
133 
134  IF (this%tol_rel.GT.1.0) THEN
135  CALL this%Warning("timedisc_rkfehlberg::InitTimedisc", &
136  "adaptive step size control disabled (tol_rel>1)",0)
137  ELSE IF(this%tol_rel.GE.0.01 .AND. this%order .GE. 5) THEN
138  CALL this%Warning("timedisc_rkfehlberg::InitTimedisc", &
139  "You chose a relatively high tol_rel (in comparison to order)",0)
140  END IF
141 
142  END SUBROUTINE
143 
144  SUBROUTINE inittimedisc_rkfehlberg(this,Mesh,Physics,config,IO)
145  IMPLICIT NONE
146  !------------------------------------------------------------------------!
147  CLASS(Timedisc_rkfehlberg), INTENT(INOUT) :: this
148  CLASS(Mesh_base), INTENT(INOUT) :: Mesh
149  CLASS(Physics_base), INTENT(IN) :: Physics
150  TYPE(Dict_TYP), POINTER :: config,IO
151  !------------------------------------------------------------------------!
152  ! set default order
153  CALL getattr(config, "order", this%order, 5)
154 
155  ! set number of coefficients
156  SELECT CASE(this%GetOrder())
157  CASE(3)
158  this%m = 3
159  CASE(5)
160  this%m = 6
161  CASE DEFAULT
162  CALL this%Error("InitTimedisc_rkfehlberg","time order must be 3 or 5")
163  END SELECT
164 
165  CALL this%InitTimedisc(mesh,physics,config,io,rk_fehlberg,odesolver_name)
166  END SUBROUTINE inittimedisc_rkfehlberg
167 
168 
169  SUBROUTINE solveode(this,Mesh,Physics,Sources,Fluxes,time,dt,err)
170  IMPLICIT NONE
171  !------------------------------------------------------------------------!
172  CLASS(Timedisc_rkfehlberg), INTENT(INOUT) :: this
173  CLASS(Mesh_base), INTENT(IN) :: Mesh
174  CLASS(Physics_base), INTENT(INOUT) :: Physics
175  CLASS(Fluxes_base), INTENT(INOUT) :: Fluxes
176  CLASS(sources_base), POINTER :: Sources
177  REAL, INTENT(IN) :: time
178  REAL, INTENT(INOUT) :: dt,err
179  !------------------------------------------------------------------------!
180  INTEGER :: i,j,k,l,m
181  REAL :: t
182  !------------------------------------------------------------------------!
183  t = time
184  ! ATTENTION: rhs and therefore coeff(1)%p should already be up to date.
185  ! In the very first step this is done in FirstStepFosite, any later step
186  ! must update coeff(1)%p at the end of the whole time step update. This is
187  ! done in timedisc_base::AcceptTimestep or timedisc_base::RejectTimestep.
188  ! Don't forget: this%rhs => this%coeff(1)%p.
189 !NEC$ SHORTLOOP
190  DO m=2,this%m
191  ! time step update of cell mean values
192  CALL this%ComputeCVar_rkfehlberg(mesh,physics,fluxes,dt,m,this%coeff,this%cvar,this%ctmp)
193  ! compute right-hand-side
194  ! coeff_m is k_m/dt from Butcher tableau
195  CALL this%ComputeRHS(mesh,physics,sources,fluxes,t+this%c(m)*dt,dt,&
196  this%ptmp,this%ctmp,check_nothing,this%coeff(m)%p)
197  END DO
198 
199  !reset ctmp
200  this%ctmp = this%cvar
201 !NEC$ SHORTLOOP
202  DO m=1,this%m
203  ! compute two solutions with different numerical orders
204  ! y_n+1 = y_n + SUM(b_i*k_i) = y_n + SUM(b_i*dt*coeff_i)
205  this%ctmp%data1d(:) = this%ctmp%data1d(:) &
206  - this%b_low(m)*dt*this%coeff(m)%p%data1d(:)
207  this%cvar%data1d(:) = this%cvar%data1d(:) &
208  - this%b_high(m)*dt*this%coeff(m)%p%data1d(:)
209  END DO
210 
211  ! at the boundary the this%rhs contains the boundary fluxes
212  ! (see subroutine ComputeRHS_modeuler )
213 !NEC$ SHORTLOOP
214  DO m=1,this%m
215 !NEC$ SHORTLOOP
216  DO l=1,physics%VNUM
217  IF(mesh%INUM.GT.1) THEN
218  ! western and eastern
219 !NEC$ IVDEP
220  DO k=mesh%KMIN,mesh%KMAX
221 !NEC$ IVDEP
222  DO j=mesh%JMIN,mesh%JMAX
223  fluxes%bxflux(j,k,1,l) = fluxes%bxflux(j,k,1,l) &
224  - dt*this%b_high(m)*this%coeff(m)%p%data4d(mesh%IMIN-mesh%IP1,j,k,l)
225  fluxes%bxflux(j,k,2,l) = fluxes%bxflux(j,k,2,l) &
226  - dt*this%b_high(m)*this%coeff(m)%p%data4d(mesh%IMAX+mesh%IP1,j,k,l)
227  END DO
228  END DO
229  END IF
230  ! southern and northern
231  IF(mesh%JNUM.GT.1) THEN
232 !NEC$ IVDEP
233  DO k=mesh%KMIN,mesh%KMAX
234 !NEC$ IVDEP
235  DO i=mesh%IMIN,mesh%IMAX
236  fluxes%byflux(k,i,1,l) = fluxes%byflux(k,i,1,l) &
237  - dt*this%b_high(m)*this%coeff(m)%p%data4d(i,mesh%JMIN-mesh%JP1,k,l)
238  fluxes%byflux(k,i,2,l) = fluxes%byflux(k,i,2,l) &
239  - dt*this%b_high(m)*this%coeff(m)%p%data4d(i,mesh%JMAX+mesh%JP1,k,l)
240  END DO
241  END DO
242  END IF
243  ! bottom and top
244  IF(mesh%KNUM.GT.1) THEN
245 !NEC$ IVDEP
246  DO j=mesh%JMIN,mesh%JMAX
247 !NEC$ IVDEP
248  DO i=mesh%IMIN,mesh%IMAX
249  fluxes%bzflux(i,j,1,l) = fluxes%bzflux(i,j,1,l) &
250  - dt*this%b_high(m)*this%coeff(m)%p%data4d(i,j,mesh%KMIN-mesh%KP1,l)
251  fluxes%bzflux(i,j,2,l) = fluxes%bzflux(i,j,2,l) &
252  - dt*this%b_high(m)*this%coeff(m)%p%data4d(i,j,mesh%KMAX+mesh%KP1,l)
253  END DO
254  END DO
255  END IF
256  END DO
257  END DO
258 
259  ! compute an error estimate based on the two independent numerical
260  ! solutions err and dt
261  IF (this%tol_rel.LE.1.0) THEN
262  err = this%ComputeError(mesh,physics,this%cvar,this%ctmp)
263  dt = this%AdjustTimestep(err,dt)
264  END IF
265 
266  END SUBROUTINE solveode
267 
275  SUBROUTINE computecvar_rkfehlberg(this,Mesh,Physics,Fluxes,dt,m,coeff,cvar,cnew)
276  IMPLICIT NONE
277  !------------------------------------------------------------------------!
278  CLASS(Timedisc_rkfehlberg),INTENT(INOUT) :: this
279  CLASS(Mesh_base) ,INTENT(IN) :: Mesh
280  CLASS(Physics_base) ,INTENT(INOUT) :: Physics
281  CLASS(Fluxes_base) ,INTENT(INOUT) :: Fluxes
282  REAL ,INTENT(IN) :: dt
283  INTEGER ,INTENT(IN) :: m
284  TYPE(coeff_type), DIMENSION(m), INTENT(IN) :: coeff
285  CLASS(marray_compound) ,INTENT(INOUT) :: cvar,cnew
286  !------------------------------------------------------------------------!
287  INTEGER :: mm
288  !------------------------------------------------------------------------!
289  ! compute y + SUM(a_mi*k_i) = y + SUM(a_mi*dt*rhs_i) : i in [1,m-1]
290  ! see Runge-Kutta method (Butcher tableau)
291  IF (m.EQ.1) THEN
292  cnew = cvar
293  ELSE
294  cnew%data1d(:) = cvar%data1d(:) - this%a(m,1)*dt*coeff(1)%p%data1d(:)
295 !NEC$ SHORTLOOP
296  DO mm=2,m-1
297  cnew%data1d(:) = cnew%data1d(:) - this%a(m,mm)*dt*coeff(mm)%p%data1d(:)
298  END DO
299  END IF
300  END SUBROUTINE computecvar_rkfehlberg
301 
303  SUBROUTINE setbutchertableau(this)
304  IMPLICIT NONE
305  !------------------------------------------------------------------------!
306  CLASS(timedisc_rkfehlberg) :: this
307  !------------------------------------------------------------------------!
308  SELECT CASE(this%GetOrder())
309  CASE(3) ! RK-Fehlberg rkf23
310  this%b_high = (/ 1.0/6.0, 2.0/3.0, 1.0/6.0 /)
311  this%b_low = (/ 0.0, 1.0, 0.0 /)
312  this%c = (/ 0.0, 0.5, 1.0 /)
313  this%a = transpose(reshape((/ &
314  0.0, 0.0, 0.0, &
315  0.5, 0.0, 0.0, &
316  -1.0, 2.0, 0.0 /),(/this%m,this%m/)))
317  CASE(5) ! RK-Fehlberg rkf45
318  this%b_high = (/ 16.0/135.0, 0.0, 6656.0/12825.0, &
319  28561.0/56430.0, -9.0/50.0, 2.0/55.0 /)
320  this%b_low = (/ 25.0/216.0, 0.0, 1408.0/2565.0, 2197.0/4104.0, -0.2, 0.0 /)
321  this%c = (/ 0.0, 0.25, 3.0/8.0, 12.0/13.0, 1.0, 0.5 /)
322  this%a = transpose(reshape((/ &
323  0.0, 0.0, 0.0, 0.0, 0.0, 0.0, &
324  0.25, 0.0, 0.0, 0.0, 0.0, 0.0, &
325  3.0/32.0, 9.0/32.0, 0.0, 0.0, 0.0, 0.0, &
326  1932.0/2197.0, -7200.0/2197.0, 7296.0/2197.0, 0.0, 0.0, 0.0, &
327  439.0/216.0, -8.0, 3680.0/513.0, -845.0/4104.0, 0.0, 0.0, &
328  -8.0/27.0, 2.0, -3544.0/2565.0, 1859.0/4104.0, -11.0/40.0, 0.0/),&
329  (/this%m,this%m/)))
330  CASE DEFAULT
331  CALL this%Error("timedisc_rkfehlberg::SetButcherTableau","only order 3 or 5 supported")
332  END SELECT
333  END SUBROUTINE setbutchertableau
334 
335 
336  SUBROUTINE showbutchertableau(this)
337  IMPLICIT NONE
338  !------------------------------------------------------------------------!
339  CLASS(Timedisc_rkfehlberg) :: this
340  !------------------------------------------------------------------------!
341  INTEGER :: i
342  CHARACTER(LEN=64) :: sformat
343  CHARACTER(LEN=128) :: buffer
344  !------------------------------------------------------------------------!
345  INTENT(INOUT) :: this
346  !------------------------------------------------------------------------!
347  CALL this%Info(repeat("+",(this%m+1)*12+4))
348  CALL this%Info("Butcher tableau")
349  DO i=1,this%m
350  IF (i == 1) THEN
351  WRITE (sformat,'(A)') '(ES12.3,A)'
352  ELSE
353  WRITE (sformat,'(A,I1,A)') '(ES12.3,A,',i-1,'ES12.3)'
354  END IF
355  WRITE (buffer,fmt=sformat) this%c(i), " | " , this%a(i,1:i-1)
356  CALL this%Info(buffer)
357  END DO
358  CALL this%Info(repeat("-",(this%m+1)*12+4))
359  WRITE (sformat,'(A,I1,A)') '(A,',this%m,'ES12.3)'
360  WRITE (buffer,fmt=sformat) " high order | ", this%b_high(:)
361  CALL this%Info(buffer)
362  WRITE (buffer,fmt=sformat) " low order | ", this%b_low(:)
363  CALL this%Info(buffer)
364  CALL this%Info(repeat("+",(this%m+1)*12+4))
365  WRITE (buffer,fmt=sformat) "c_i-SUM(a_ij)| ", this%c(:)-sum(this%a(:,:),dim=2)
366  CALL this%Info(buffer)
367  END SUBROUTINE showbutchertableau
368 
369 
370  SUBROUTINE finalize(this)
371  IMPLICIT NONE
372  !------------------------------------------------------------------------!
373  CLASS(Timedisc_rkfehlberg) :: this
374  !------------------------------------------------------------------------!
375  INTEGER :: k
376  !------------------------------------------------------------------------!
377  DEALLOCATE(this%b_high,this%b_low,this%c,this%a)
378  DO k=2,this%m
379  CALL this%coeff(k)%p%Destroy()
380  DEALLOCATE(this%coeff(k)%p)
381  END DO
382  DEALLOCATE(this%coeff)
383  CALL this%timedisc_modeuler%Finalize()
384  END SUBROUTINE finalize
385 
386 END MODULE timedisc_rkfehlberg_mod
character(len=32), parameter odesolver_name
generic source terms module providing functionaly common to all source terms
derived class for compound of mesh arrays
base class for mesh arrays
Definition: marray_base.f90:36
subroutine solveode(this, Mesh, Physics, Sources, Fluxes, time, dt, err)
integer, parameter, public check_nothing
physics module for 1D,2D and 3D isothermal Euler equations
subroutine setbutchertableau(this)
set coefficients for RK-Fehlberg schemes
Basic physics module.
Dictionary for generic data types.
Definition: common_dict.f90:61
physics module for 1D,2D and 3D non-isothermal Euler equations
subroutine showbutchertableau(this)
integer, parameter, public rk_fehlberg
subroutines for Runge-Kutta Fehlberg method
subroutines for modified Euler i.e. Runge-Kutta methods
base module for numerical flux functions
Definition: fluxes_base.f90:39
subroutine inittimedisc(this, Mesh, Physics, config, IO, ttype, tname)
subroutine computecvar_rkfehlberg(this, Mesh, Physics, Fluxes, dt, m, coeff, cvar, cnew)
perfroms the time step update using the RHS
subroutine inittimedisc_rkfehlberg(this, Mesh, Physics, config, IO)