Skip to content

Commit a75c016

Browse files
committed
add fast mode to many inegrators
1 parent af6d75a commit a75c016

7 files changed

+769
-104
lines changed

src/lib/foodie_integrator_lmm_ssp_vss.f90

Lines changed: 87 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -53,16 +53,17 @@ module foodie_integrator_lmm_ssp_vss
5353
trim(class_name_)//'_steps_4_order_3', &
5454
trim(class_name_)//'_steps_5_order_3'] !< List of supported schemes.
5555

56-
logical, parameter :: has_fast_mode_=.false. !< Flag to check if integrator provides *fast mode* integrate.
56+
logical, parameter :: has_fast_mode_=.true. !< Flag to check if integrator provides *fast mode* integrate.
5757

5858
type, extends(integrator_object) :: integrator_lmm_ssp_vss
5959
!< FOODIE integrator: provide an explicit class of Linear Multi-step Methods (LLM) with Strong Stability Preserving property and
6060
!< variable stepsize (VSS), from 2nd to 3rd order accurate.
6161
!<
6262
!< @note The integrator must be created or initialized before used.
6363
private
64-
integer(I_P), public :: steps=0 !< Number of time steps.
65-
procedure(integrate_interface), pointer :: integrate_ => integrate_order_2 !< Integrate integrand field.
64+
integer(I_P), public :: steps=0 !< Number of time steps.
65+
procedure(integrate_interface), pointer :: integrate_ => integrate_order_2 !< Integrate integrand field.
66+
procedure(integrate_fast_interface), pointer :: integrate_fast_ => integrate_order_2_fast !< Integrate integrand field, fast.
6667
contains
6768
! deferred methods
6869
procedure, pass(self) :: class_name !< Return the class name of schemes.
@@ -75,10 +76,13 @@ module foodie_integrator_lmm_ssp_vss
7576
procedure, pass(self) :: destroy !< Destroy the integrator.
7677
procedure, pass(self) :: initialize !< Initialize (create) the integrator.
7778
procedure, pass(self) :: integrate !< Integrate integrand field.
79+
procedure, pass(self) :: integrate_fast !< Integrate integrand field, fast mode.
7880
procedure, pass(self) :: update_previous !< Cyclic update previous time steps.
7981
! private methods
80-
procedure, pass(self), private :: integrate_order_2 !< Integrate integrand field by 2nd order formula.
81-
procedure, pass(self), private :: integrate_order_3 !< Integrate integrand field by 3rd order formula.
82+
procedure, pass(self), private :: integrate_order_2 !< Integrate integrand field by 2nd order formula.
83+
procedure, pass(self), private :: integrate_order_3 !< Integrate integrand field by 3rd order formula.
84+
procedure, pass(self), private :: integrate_order_2_fast !< Integrate integrand field by 2nd order formula, fast mode.
85+
procedure, pass(self), private :: integrate_order_3_fast !< Integrate integrand field by 3rd order formula, fast mode.
8286
endtype integrator_lmm_ssp_vss
8387

8488
abstract interface
@@ -93,6 +97,18 @@ subroutine integrate_interface(self, U, previous, Dt, t, autoupdate)
9397
real(R_P), intent(in) :: t(:) !< Times.
9498
logical, optional, intent(in) :: autoupdate !< Perform cyclic autoupdate of previous time steps.
9599
endsubroutine integrate_interface
100+
101+
subroutine integrate_fast_interface(self, U, previous, buffer, Dt, t, autoupdate)
102+
!< Integrate field with LMM-SSP class scheme.
103+
import :: integrand_object, integrator_lmm_ssp_vss, R_P
104+
class(integrator_lmm_ssp_vss), intent(in) :: self !< Integrator.
105+
class(integrand_object), intent(inout) :: U !< Field to be integrated.
106+
class(integrand_object), intent(inout) :: previous(1:) !< Previous time steps solutions of integrand field.
107+
class(integrand_object), intent(inout) :: buffer !< Temporary buffer for doing fast operation.
108+
real(R_P), intent(inout) :: Dt(:) !< Time steps.
109+
real(R_P), intent(in) :: t(:) !< Times.
110+
logical, optional, intent(in) :: autoupdate !< Perform cyclic autoupdate of previous time steps.
111+
endsubroutine integrate_fast_interface
96112
endinterface
97113

98114
contains
@@ -195,18 +211,23 @@ subroutine initialize(self, scheme, stop_on_fail)
195211
case('lmm_ssp_vss_steps_2_order_2')
196212
self%steps = 2
197213
self%integrate_ => integrate_order_2
214+
self%integrate_fast_ => integrate_order_2_fast
198215
case('lmm_ssp_vss_steps_3_order_2')
199216
self%steps = 3
200217
self%integrate_ => integrate_order_2
218+
self%integrate_fast_ => integrate_order_2_fast
201219
case('lmm_ssp_vss_steps_3_order_3')
202220
self%steps = 3
203221
self%integrate_ => integrate_order_3
222+
self%integrate_fast_ => integrate_order_3_fast
204223
case('lmm_ssp_vss_steps_4_order_3')
205224
self%steps = 4
206225
self%integrate_ => integrate_order_3
226+
self%integrate_fast_ => integrate_order_3_fast
207227
case('lmm_ssp_vss_steps_5_order_3')
208228
self%steps = 5
209229
self%integrate_ => integrate_order_3
230+
self%integrate_fast_ => integrate_order_3_fast
210231
endselect
211232
else
212233
call self%trigger_error(error=ERROR_UNSUPPORTED_SCHEME, &
@@ -227,6 +248,19 @@ subroutine integrate(self, U, previous, Dt, t, autoupdate)
227248
call self%integrate_(U=U, previous=previous, Dt=Dt, t=t, autoupdate=autoupdate)
228249
endsubroutine integrate
229250

251+
subroutine integrate_fast(self, U, previous, buffer, Dt, t, autoupdate)
252+
!< Integrate field with LMM-SSP class scheme.
253+
class(integrator_lmm_ssp_vss), intent(in) :: self !< Integrator.
254+
class(integrand_object), intent(inout) :: U !< Field to be integrated.
255+
class(integrand_object), intent(inout) :: previous(1:) !< Previous time steps solutions of integrand field.
256+
class(integrand_object), intent(inout) :: buffer !< Temporary buffer for doing fast operation.
257+
real(R_P), intent(inout) :: Dt(:) !< Time steps.
258+
real(R_P), intent(in) :: t(:) !< Times.
259+
logical, optional, intent(in) :: autoupdate !< Perform cyclic autoupdate of previous time steps.
260+
261+
call self%integrate_fast_(U=U, previous=previous, buffer=buffer, Dt=Dt, t=t, autoupdate=autoupdate)
262+
endsubroutine integrate_fast
263+
230264
subroutine update_previous(self, U, previous, Dt)
231265
!< Cyclic update previous time steps.
232266
class(integrator_lmm_ssp_vss), intent(in) :: self !< Integrator.
@@ -283,6 +317,54 @@ subroutine integrate_order_3(self, U, previous, Dt, t, autoupdate)
283317
if (autoupdate_) call self%update_previous(U=U, previous=previous, Dt=Dt)
284318
endsubroutine integrate_order_3
285319

320+
subroutine integrate_order_2_fast(self, U, previous, buffer, Dt, t, autoupdate)
321+
!< Integrate field with LMM-SSP-VSS 2nd order class scheme.
322+
class(integrator_lmm_ssp_vss), intent(in) :: self !< Integrator.
323+
class(integrand_object), intent(inout) :: U !< Field to be integrated.
324+
class(integrand_object), intent(inout) :: previous(1:) !< Previous time steps solutions of integrand field.
325+
class(integrand_object), intent(inout) :: buffer !< Temporary buffer for doing fast operation.
326+
real(R_P), intent(inout) :: Dt(:) !< Time steps.
327+
real(R_P), intent(in) :: t(:) !< Times.
328+
logical, optional, intent(in) :: autoupdate !< Perform cyclic autoupdate of previous time steps.
329+
logical :: autoupdate_ !< Perform cyclic autoupdate of previous time steps, dummy var.
330+
real(R_P) :: omega_ !< Omega coefficient.
331+
real(R_P) :: omega_sq !< Square of omega coefficient.
332+
333+
autoupdate_ = .true. ; if (present(autoupdate)) autoupdate_ = autoupdate
334+
omega_ = omega(Dt=Dt, s=self%steps-1)
335+
omega_sq = omega_ * omega_
336+
call U%multiply_fast(lhs=previous(1), rhs=1._R_P / omega_sq)
337+
call buffer%multiply_fast(lhs=previous(self%steps), rhs=(omega_sq - 1._R_P) / omega_sq)
338+
call U%add_fast(lhs=U, rhs=buffer)
339+
buffer = previous(self%steps)
340+
call buffer%t_fast(t=t(self%steps))
341+
call buffer%multiply_fast(lhs=buffer, rhs=Dt(self%steps) * (omega_ + 1._R_P) / omega_)
342+
call U%add_fast(lhs=U, rhs=buffer)
343+
if (autoupdate_) call self%update_previous(U=U, previous=previous, Dt=Dt)
344+
endsubroutine integrate_order_2_fast
345+
346+
subroutine integrate_order_3_fast(self, U, previous, buffer, Dt, t, autoupdate)
347+
!< Integrate field with LMM-SSP-VSS 3rd order class scheme, fast mode.
348+
class(integrator_lmm_ssp_vss), intent(in) :: self !< Integrator.
349+
class(integrand_object), intent(inout) :: U !< Field to be integrated.
350+
class(integrand_object), intent(inout) :: previous(1:) !< Previous time steps solutions of integrand field.
351+
class(integrand_object), intent(inout) :: buffer !< Temporary buffer for doing fast operation.
352+
real(R_P), intent(inout) :: Dt(:) !< Time steps.
353+
real(R_P), intent(in) :: t(:) !< Times.
354+
logical, optional, intent(in) :: autoupdate !< Perform cyclic autoupdate of previous time steps.
355+
logical :: autoupdate_ !< Perform cyclic autoupdate of previous time steps, dummy var.
356+
real(R_P) :: omega_ !< Omega coefficient.
357+
358+
autoupdate_ = .true. ; if (present(autoupdate)) autoupdate_ = autoupdate
359+
omega_= omega(Dt=Dt, s=self%steps-1)
360+
! @TODO to be completed
361+
U = (previous(1) * ((3._R_P * omega_ + 2._R_P) / omega_ ** 3 )) + &
362+
(previous(self%steps) * (((omega_ + 1._R_P) ** 2) * (omega_ - 2._R_P) / omega_ ** 3)) + &
363+
(previous(1)%t(t=t(1)) * (Dt(self%steps) * (omega_ + 1._R_P) / omega_ ** 2)) + &
364+
(previous(self%steps)%t(t=t(self%steps)) * (Dt(self%steps) * (omega_ + 1._R_P) ** 2 / omega_ ** 2))
365+
if (autoupdate_) call self%update_previous(U=U, previous=previous, Dt=Dt)
366+
endsubroutine integrate_order_3_fast
367+
286368
! private non TBP
287369
pure function dt_ratio(Dt, s) result(ratio)
288370
!< Return `Dt(n+s)/Dt(n+Ns)` ratio.

src/lib/foodie_integrator_ms_runge_kutta_ssp.f90

Lines changed: 73 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -49,7 +49,7 @@ module foodie_integrator_ms_runge_kutta_ssp
4949
trim(class_name_)//'_steps_4_stages_5_order_8'] !< List of supported
5050
!< schemes.
5151

52-
logical, parameter :: has_fast_mode_=.false. !< Flag to check if integrator provides *fast mode* integrate.
52+
logical, parameter :: has_fast_mode_=.true. !< Flag to check if integrator provides *fast mode* integrate.
5353

5454
type, extends(integrator_object) :: integrator_ms_runge_kutta_ssp
5555
!< FOODIE integrator: provide an explicit class of Multi-step Runge-Kutta Methods with Strong Stability Preserving property,
@@ -77,6 +77,7 @@ module foodie_integrator_ms_runge_kutta_ssp
7777
procedure, pass(self) :: destroy !< Destroy the integrator.
7878
procedure, pass(self) :: initialize !< Initialize (create) the integrator.
7979
procedure, pass(self) :: integrate !< Integrate integrand field.
80+
procedure, pass(self) :: integrate_fast !< Integrate integrand field, fast mode.
8081
procedure, pass(self) :: update_previous !< Cyclic update previous time steps.
8182
endtype integrator_ms_runge_kutta_ssp
8283

@@ -361,6 +362,77 @@ subroutine integrate(self, U, previous, stage, Dt, t, autoupdate)
361362
if (autoupdate_) call self%update_previous(U=U, previous=previous)
362363
endsubroutine integrate
363364

365+
subroutine integrate_fast(self, U, previous, stage, buffer, Dt, t, autoupdate)
366+
!< Integrate field with LMM-SSP class scheme, fast mode.
367+
class(integrator_ms_runge_kutta_ssp), intent(in) :: self !< Integrator.
368+
class(integrand_object), intent(inout) :: U !< Field to be integrated.
369+
class(integrand_object), intent(inout) :: previous(1:) !< Previous time steps solutions of integrand.
370+
class(integrand_object), intent(inout) :: stage(1:) !< Runge-Kutta stages [1:stages].
371+
class(integrand_object), intent(inout) :: buffer !< Temporary buffer for doing fast operation.
372+
real(R_P), intent(in) :: Dt !< Time steps.
373+
real(R_P), intent(in) :: t(:) !< Times.
374+
logical, intent(in), optional :: autoupdate !< Perform cyclic autoupdate of previous steps.
375+
logical :: autoupdate_ !< Perform cyclic autoupdate of previous steps,
376+
!< local variable.
377+
integer(I_P) :: k, kk !< Stages counters.
378+
integer(I_P) :: s !< Steps counter.
379+
380+
autoupdate_ = .true. ; if (present(autoupdate)) autoupdate_ = autoupdate
381+
! computing stages
382+
stage(1) = U
383+
do k=2, self%stages
384+
call stage(k)%multiply_fast(lhs=U, rhs=0._R_P)
385+
do s=1, self%steps
386+
if (self%D(k, s) /= 0._R_P) then
387+
call buffer%multiply_fast(lhs=previous(s), rhs=self%D(k, s))
388+
call stage(k)%add_fast(lhs=stage(k), rhs=buffer)
389+
endif
390+
enddo
391+
do s=1, self%steps - 1
392+
if (self%Ahat(k, s) /= 0._R_P) then
393+
buffer = previous(s)
394+
call buffer%t_fast(t=t(s))
395+
call buffer%multiply_fast(lhs=buffer, rhs=Dt * self%Ahat(k, s))
396+
call stage(k)%add_fast(lhs=stage(k), rhs=buffer)
397+
endif
398+
enddo
399+
do kk=1, k - 1
400+
if (self%A(k, kk) /= 0._R_P) then
401+
buffer = stage(kk)
402+
call buffer%t_fast(t=t(self%steps))
403+
call buffer%multiply_fast(lhs=buffer, rhs=Dt * self%A(k, kk))
404+
call stage(k)%add_fast(lhs=stage(k), rhs=buffer)
405+
endif
406+
enddo
407+
enddo
408+
! computing new time step
409+
U = U * 0._R_P
410+
do s=1, self%steps
411+
if (self%T(s) /= 0._R_P) then
412+
call buffer%multiply_fast(lhs=previous(s), rhs=self%T(s))
413+
call U%add_fast(lhs=U, rhs=buffer)
414+
endif
415+
enddo
416+
do s=1, self%steps - 1
417+
if (self%Bhat(s) /= 0._R_P) then
418+
buffer = previous(s)
419+
call buffer%t_fast(t=t(s))
420+
call buffer%multiply_fast(lhs=buffer, rhs=Dt * self%Bhat(s))
421+
call U%add_fast(lhs=U, rhs=buffer)
422+
endif
423+
enddo
424+
do k=1, self%stages
425+
if (self%B(k) /= 0._R_P) U = U + (stage(k)%t(t=t(self%steps)) * (Dt * self%B(k)))
426+
if (self%B(k) /= 0._R_P) then
427+
buffer = stage(k)
428+
call buffer%t_fast(t=t(self%steps))
429+
call buffer%multiply_fast(lhs=buffer, rhs=Dt * self%B(k))
430+
call U%add_fast(lhs=U, rhs=buffer)
431+
endif
432+
enddo
433+
if (autoupdate_) call self%update_previous(U=U, previous=previous)
434+
endsubroutine integrate_fast
435+
364436
subroutine update_previous(self, U, previous)
365437
!< Cyclic update previous time steps.
366438
class(integrator_ms_runge_kutta_ssp), intent(in) :: self !< Integrator.

src/lib/foodie_integrator_runge_kutta_embedded.f90

Lines changed: 49 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -281,7 +281,7 @@ module foodie_integrator_runge_kutta_emd
281281
trim(class_name_)//'_stages_9_order_6 ', &
282282
trim(class_name_)//'_stages_17_order_10'] !< List of supported schemes.
283283

284-
logical, parameter :: has_fast_mode_=.false. !< Flag to check if integrator provides *fast mode* integrate.
284+
logical, parameter :: has_fast_mode_=.true. !< Flag to check if integrator provides *fast mode* integrate.
285285

286286
type, extends(integrator_object) :: integrator_runge_kutta_emd
287287
!< FOODIE integrator: provide an explicit class of embedded Runge-Kutta schemes, from 2nd to 10th order accurate.
@@ -303,9 +303,10 @@ module foodie_integrator_runge_kutta_emd
303303
procedure, pass(self) :: is_supported !< Return .true. if the integrator class support the given scheme.
304304
procedure, pass(self) :: supported_schemes !< Return the list of supported schemes.
305305
! public methods
306-
procedure, pass(self) :: destroy !< Destroy the integrator.
307-
procedure, pass(self) :: initialize !< Initialize (create) the integrator.
308-
procedure, pass(self) :: integrate !< Integrate integrand field.
306+
procedure, pass(self) :: destroy !< Destroy the integrator.
307+
procedure, pass(self) :: initialize !< Initialize (create) the integrator.
308+
procedure, pass(self) :: integrate !< Integrate integrand field.
309+
procedure, pass(self) :: integrate_fast !< Integrate integrand field, fast mode.
309310
! private methods
310311
procedure, pass(self), private :: new_Dt !< Compute new estimation of the time step Dt.
311312
endtype integrator_runge_kutta_emd
@@ -677,8 +678,6 @@ subroutine integrate(self, U, stage, Dt, t)
677678
!< Integrate field with explicit embedded Runge-Kutta scheme.
678679
!<
679680
!< The time steps is adaptively resized using the local truncation error estimation by means of the embedded pairs of RK schemes.
680-
!<
681-
!< @note This method can be used **after** the integrator is created (i.e. the RK coefficients are initialized).
682681
class(integrator_runge_kutta_emd), intent(in) :: self !< Integrator.
683682
class(integrand_object), intent(inout) :: U !< Field to be integrated.
684683
class(integrand_object), intent(inout) :: stage(1:) !< Runge-Kutta stages [1:stages].
@@ -715,6 +714,50 @@ subroutine integrate(self, U, stage, Dt, t)
715714
U = U1
716715
endsubroutine integrate
717716

717+
subroutine integrate_fast(self, U, stage, buffer, Dt, t)
718+
!< Integrate field with explicit embedded Runge-Kutta scheme, fast mode.
719+
!<
720+
!< The time steps is adaptively resized using the local truncation error estimation by means of the embedded pairs of RK schemes.
721+
class(integrator_runge_kutta_emd), intent(in) :: self !< Integrator.
722+
class(integrand_object), intent(inout) :: U !< Field to be integrated.
723+
class(integrand_object), intent(inout) :: stage(1:) !< Runge-Kutta stages [1:stages].
724+
class(integrand_object), intent(inout) :: buffer !< Temporary buffer for doing fast operation.
725+
real(R_P), intent(inout) :: Dt !< Time step.
726+
real(R_P), intent(in) :: t !< Time.
727+
class(integrand_object), allocatable :: U1 !< First U evaluation.
728+
class(integrand_object), allocatable :: U2 !< Second U evaluation.
729+
real(R_P) :: error !< Local truncation error estimation.
730+
integer(I_P) :: s !< First stages counter.
731+
integer(I_P) :: ss !< Second stages counter.
732+
733+
allocate(U1, mold=U) ; U1 = U
734+
allocate(U2, mold=U) ; U2 = U
735+
error = 1e6
736+
do while(error>self%tolerance)
737+
! compute stages
738+
do s=1, self%stages
739+
stage(s) = U
740+
do ss=1, s - 1
741+
call buffer%multiply_fast(lhs=stage(ss), rhs=Dt * self%alph(s, ss))
742+
call stage(s)%add_fast(lhs=stage(s), rhs=buffer)
743+
enddo
744+
call stage(s)%t_fast(t=t + self%gamm(s) * Dt)
745+
enddo
746+
! compute new time step
747+
U1 = U
748+
U2 = U
749+
do s=1, self%stages
750+
call buffer%multiply_fast(lhs=stage(s), rhs=Dt * self%beta(s, 1))
751+
call U1%add_fast(lhs=U1, rhs=buffer)
752+
call buffer%multiply_fast(lhs=stage(s), rhs=Dt * self%beta(s, 2))
753+
call U2%add_fast(lhs=U2, rhs=buffer)
754+
enddo
755+
error = U2.lterror.U1
756+
call self%new_Dt(error=error, Dt=Dt)
757+
enddo
758+
U = U1
759+
endsubroutine integrate_fast
760+
718761
! private methods
719762
elemental subroutine new_Dt(self, error, Dt)
720763
!< Compute new estimation of the time step Dt.

0 commit comments

Comments
 (0)