Skip to content

Commit cc57e35

Browse files
committed
add fast mode to all remaining solvers
1 parent b8e951f commit cc57e35

File tree

3 files changed

+207
-8
lines changed

3 files changed

+207
-8
lines changed

src/lib/foodie_integrator_adams_bashforth_moulton.f90

Lines changed: 22 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -105,7 +105,7 @@ module foodie_integrator_adams_bashforth_moulton
105105
trim(class_name_)//'_15', &
106106
trim(class_name_)//'_16'] !< List of supported schemes.
107107

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

110110
type, extends(integrator_object) :: integrator_adams_bashforth_moulton
111111
!< FOODIE integrator: provide an explicit class of Adams-Bashforth-Moulton multi-step schemes, from 1st to 4rd order accurate.
@@ -124,10 +124,11 @@ module foodie_integrator_adams_bashforth_moulton
124124
procedure, pass(self) :: is_supported !< Return .true. if the integrator class support the given scheme.
125125
procedure, pass(self) :: supported_schemes !< Return the list of supported schemes.
126126
! public methods
127-
procedure, pass(self) :: destroy !< Destroy the integrator.
128-
procedure, pass(self) :: initialize !< Initialize (create) the integrator.
129-
procedure, pass(self) :: integrate !< Integrate integrand field.
130-
procedure, pass(self) :: scheme_number !< Return the scheme number in the list of supported schemes.
127+
procedure, pass(self) :: destroy !< Destroy the integrator.
128+
procedure, pass(self) :: initialize !< Initialize (create) the integrator.
129+
procedure, pass(self) :: integrate !< Integrate integrand field.
130+
procedure, pass(self) :: integrate_fast !< Integrate integrand field.
131+
procedure, pass(self) :: scheme_number !< Return the scheme number in the list of supported schemes.
131132
endtype integrator_adams_bashforth_moulton
132133

133134
contains
@@ -254,6 +255,22 @@ subroutine integrate(self, U, previous, Dt, t, iterations)
254255
call self%predictor%update_previous(U=U, previous=previous)
255256
endsubroutine integrate
256257

258+
subroutine integrate_fast(self, U, previous, buffer, Dt, t, iterations)
259+
!< Integrate field with Adams-Bashforth-Moulton class scheme, fast mode.
260+
class(integrator_adams_bashforth_moulton), intent(in) :: self !< Integrator.
261+
class(integrand_object), intent(inout) :: U !< Field to be integrated.
262+
class(integrand_object), intent(inout) :: previous(1:) !< Previous time steps solutions of integrand.
263+
class(integrand_object), intent(inout) :: buffer !< Temporary buffer for doing fast operation.
264+
real(R_P), intent(in) :: Dt !< Time steps.
265+
real(R_P), intent(in) :: t(:) !< Times.
266+
integer(I_P), intent(in), optional :: iterations !< Fixed point iterations of AM scheme.
267+
268+
call self%predictor%integrate_fast(U=U, previous=previous, buffer=buffer, Dt=Dt, t=t, autoupdate=.false.)
269+
call self%corrector%integrate_fast(U=U, previous=previous(2:), buffer=buffer, Dt=Dt, t=t, iterations=iterations, &
270+
autoupdate=.false.)
271+
call self%predictor%update_previous(U=U, previous=previous)
272+
endsubroutine integrate_fast
273+
257274
elemental function scheme_number(self, scheme)
258275
!< Return the scheme number in the list of supported schemes.
259276
class(integrator_adams_bashforth_moulton), intent(in) :: self !< Integrator.

src/lib/foodie_integrator_adams_moulton.f90

Lines changed: 54 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -54,7 +54,7 @@ module foodie_integrator_adams_moulton
5454
trim(class_name_)//'_14', &
5555
trim(class_name_)//'_15'] !< List of supported schemes.
5656

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

5959
type, extends(integrator_object) :: integrator_adams_moulton
6060
!< FOODIE integrator: provide an explicit class of Adams-Moulton multi-step schemes, from 1st to 16th order accurate.
@@ -75,6 +75,7 @@ module foodie_integrator_adams_moulton
7575
procedure, pass(self) :: destroy !< Destroy the integrator.
7676
procedure, pass(self) :: initialize !< Initialize (create) the integrator.
7777
procedure, pass(self) :: integrate !< Integrate integrand field.
78+
procedure, pass(self) :: integrate_fast !< Integrate integrand field, fast mode.
7879
procedure, pass(self) :: update_previous !< Cyclic update previous time steps.
7980
endtype integrator_adams_moulton
8081

@@ -383,6 +384,58 @@ subroutine integrate(self, U, previous, Dt, t, iterations, autoupdate)
383384
endif
384385
endsubroutine integrate
385386

387+
subroutine integrate_fast(self, U, previous, buffer, Dt, t, iterations, autoupdate)
388+
!< Integrate field with Adams-Moulton class scheme, fast mode.
389+
class(integrator_adams_moulton), intent(in) :: self !< Integrator.
390+
class(integrand_object), intent(inout) :: U !< Field to be integrated.
391+
class(integrand_object), intent(inout) :: previous(1:) !< Previous time steps solutions of integrand field.
392+
class(integrand_object), intent(inout) :: buffer !< Temporary buffer for doing fast operation.
393+
real(R_P), intent(in) :: Dt !< Time steps.
394+
real(R_P), intent(in) :: t(:) !< Times.
395+
integer(I_P), intent(in), optional :: iterations !< Fixed point iterations.
396+
logical, intent(in), optional :: autoupdate !< Cyclic autoupdate of previous time steps flag.
397+
logical :: autoupdate_ !< Cyclic autoupdate of previous time steps flag, dummy var.
398+
class(integrand_object), allocatable :: delta !< Delta RHS for fixed point iterations.
399+
integer(I_P) :: s !< Steps counter.
400+
401+
autoupdate_ = .true. ; if (present(autoupdate)) autoupdate_ = autoupdate
402+
if (self%steps>0) then
403+
if (present(iterations)) then ! perform fixed point iterations
404+
allocate(delta, mold=U)
405+
delta = previous(self%steps)
406+
do s=0, self%steps - 1
407+
buffer = previous(s+1)
408+
call buffer%t_fast(t=t(s+1))
409+
call buffer%multiply_fast(lhs=buffer, rhs=Dt * self%b(s))
410+
call delta%add_fast(lhs=delta, rhs=buffer)
411+
enddo
412+
do s=1, iterations
413+
buffer = U
414+
call buffer%t_fast(t=t(self%steps) + Dt)
415+
call buffer%multiply_fast(lhs=buffer, rhs=Dt * self%b(self%steps))
416+
call U%add_fast(lhs=delta, rhs=buffer)
417+
enddo
418+
else
419+
buffer = U
420+
call buffer%t_fast(t=t(self%steps) + Dt)
421+
call buffer%multiply_fast(lhs=buffer, rhs=Dt * self%b(self%steps))
422+
call U%add_fast(lhs=previous(self%steps), rhs=buffer)
423+
do s=0, self%steps - 1
424+
buffer = previous(s+1)
425+
call buffer%t_fast(t=t(s+1))
426+
call buffer%multiply_fast(lhs=buffer, rhs=Dt * self%b(s))
427+
call U%add_fast(lhs=U, rhs=buffer)
428+
enddo
429+
endif
430+
if (autoupdate_) call self%update_previous(U=U, previous=previous)
431+
else
432+
buffer = U
433+
call buffer%t_fast(t=t(1))
434+
call buffer%multiply_fast(lhs=buffer, rhs=Dt * self%b(0))
435+
call U%add_fast(lhs=U, rhs=buffer)
436+
endif
437+
endsubroutine integrate_fast
438+
386439
subroutine update_previous(self, U, previous)
387440
!< Cyclic update previous time steps.
388441
class(integrator_adams_moulton), intent(in) :: self !< Integrator.

src/tests/accuracy/oscillation/oscillation.f90

Lines changed: 131 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -284,7 +284,7 @@ subroutine initialize_test
284284
if (index(trim(adjustl(scheme)), trim(int_adams_bashforth_moulton%class_name())) > 0) then
285285
if (self%is_fast) then
286286
call check_scheme_has_fast_mode(scheme=trim(adjustl(scheme)), integr=int_adams_bashforth_moulton)
287-
! integrate => integrate_adams_bashforth_moulton_fast
287+
integrate => integrate_adams_bashforth_moulton_fast
288288
else
289289
integrate => integrate_adams_bashforth_moulton
290290
endif
@@ -298,7 +298,7 @@ subroutine initialize_test
298298
elseif (index(trim(adjustl(scheme)), trim(int_adams_moulton%class_name())) > 0) then
299299
if (self%is_fast) then
300300
call check_scheme_has_fast_mode(scheme=trim(adjustl(scheme)), integr=int_adams_moulton)
301-
! integrate => integrate_adams_moulton_fast
301+
integrate => integrate_adams_moulton_fast
302302
else
303303
integrate => integrate_adams_moulton
304304
endif
@@ -567,6 +567,63 @@ subroutine integrate_adams_bashforth_moulton(scheme, frequency, final_time, solu
567567
error = error_L2(frequency=frequency, solution=solution(:, 0:last_step))
568568
endsubroutine integrate_adams_bashforth_moulton
569569

570+
subroutine integrate_adams_bashforth_moulton_fast(scheme, frequency, final_time, solution, error, last_step, iterations, Dt, &
571+
tolerance, stages)
572+
!< Integrate domain by means of the Adams-Bashforth-Moulton scheme.
573+
character(*), intent(in) :: scheme !< Selected scheme.
574+
real(R_P), intent(in) :: frequency !< Oscillation frequency.
575+
real(R_P), intent(in) :: final_time !< Final integration time.
576+
real(R_P), allocatable, intent(out) :: solution(:,:) !< Solution at each time step, X-Y.
577+
real(R_P), intent(out) :: error(1:) !< Error (norm L2) with respect the exact solution.
578+
integer(I_P), intent(out) :: last_step !< Last time step computed.
579+
integer(I_P), intent(in), optional :: iterations !< Number of fixed point iterations.
580+
real(R_P), intent(in), optional :: Dt !< Time step.
581+
real(R_P), intent(in), optional :: tolerance !< Local error tolerance.
582+
integer(I_P), intent(in), optional :: stages !< Number of stages.
583+
type(integrator_adams_bashforth_moulton) :: integrator !< The integrator.
584+
type(integrator_runge_kutta_ssp) :: integrator_rk !< RK integrator for starting non self-starting integrators.
585+
type(oscillator) :: domain !< Oscillation field.
586+
type(oscillator), allocatable :: rk_stage(:) !< Runge-Kutta stages.
587+
type(oscillator), allocatable :: previous(:) !< Previous time steps solutions.
588+
type(oscillator) :: buffer !< Buffer oscillation field.
589+
integer :: step !< Time steps counter.
590+
591+
call domain%init(initial_state=initial_state, frequency=frequency)
592+
593+
if (allocated(solution)) deallocate(solution) ; allocate(solution(0:space_dimension, 0:int(final_time/Dt)))
594+
solution = 0.0_R_P
595+
solution(1:, 0) = domain%output()
596+
597+
call integrator%initialize(scheme=scheme)
598+
if (allocated(previous)) deallocate(previous) ; allocate(previous(1:integrator%steps))
599+
600+
call integrator_rk%initialize(scheme='runge_kutta_ssp_stages_5_order_4')
601+
if (allocated(rk_stage)) deallocate(rk_stage) ; allocate(rk_stage(1:integrator_rk%stages))
602+
603+
step = 0
604+
do while(solution(0, step) < final_time .and. step < ubound(solution, dim=2))
605+
step = step + 1
606+
607+
if (integrator%steps >= step) then
608+
call integrator_rk%integrate_fast(U=domain, stage=rk_stage, buffer=buffer, Dt=Dt, t=solution(0, step))
609+
previous(step) = domain
610+
else
611+
call integrator%integrate_fast(U=domain, &
612+
previous=previous, &
613+
buffer=buffer, &
614+
Dt=Dt, &
615+
t=solution(0, step-integrator%steps:step-1))
616+
endif
617+
618+
solution(0, step) = step * Dt
619+
620+
solution(1:, step) = domain%output()
621+
enddo
622+
last_step = step
623+
624+
error = error_L2(frequency=frequency, solution=solution(:, 0:last_step))
625+
endsubroutine integrate_adams_bashforth_moulton_fast
626+
570627
subroutine integrate_adams_moulton(scheme, frequency, final_time, solution, error, last_step, iterations, Dt, tolerance, stages)
571628
!< Integrate domain by means of the Adams-Moulton scheme.
572629
character(*), intent(in) :: scheme !< Selected scheme.
@@ -635,6 +692,78 @@ subroutine integrate_adams_moulton(scheme, frequency, final_time, solution, erro
635692
error = error_L2(frequency=frequency, solution=solution(:, 0:last_step))
636693
endsubroutine integrate_adams_moulton
637694

695+
subroutine integrate_adams_moulton_fast(scheme, frequency, final_time, solution, error, last_step, iterations, Dt, &
696+
tolerance, stages)
697+
!< Integrate domain by means of the Adams-Moulton scheme, fast mode.
698+
character(*), intent(in) :: scheme !< Selected scheme.
699+
real(R_P), intent(in) :: frequency !< Oscillation frequency.
700+
real(R_P), intent(in) :: final_time !< Final integration time.
701+
real(R_P), allocatable, intent(out) :: solution(:,:) !< Solution at each time step, X-Y.
702+
real(R_P), intent(out) :: error(1:) !< Error (norm L2) with respect the exact solution.
703+
integer(I_P), intent(out) :: last_step !< Last time step computed.
704+
integer(I_P), intent(in), optional :: iterations !< Number of fixed point iterations.
705+
real(R_P), intent(in), optional :: Dt !< Time step.
706+
real(R_P), intent(in), optional :: tolerance !< Local error tolerance.
707+
integer(I_P), intent(in), optional :: stages !< Number of stages.
708+
type(integrator_adams_moulton) :: integrator !< The integrator.
709+
type(integrator_runge_kutta_ssp) :: integrator_rk !< RK integrator for starting non self-starting integrators.
710+
type(oscillator) :: domain !< Oscillation field.
711+
type(oscillator), allocatable :: rk_stage(:) !< Runge-Kutta stages.
712+
type(oscillator), allocatable :: previous(:) !< Previous time steps solutions.
713+
type(oscillator) :: buffer !< Buffer oscillation field.
714+
integer :: step !< Time steps counter.
715+
integer :: step_offset !< Time steps counter offset for slicing previous data array.
716+
717+
call domain%init(initial_state=initial_state, frequency=frequency)
718+
719+
if (allocated(solution)) deallocate(solution) ; allocate(solution(0:space_dimension, 0:int(final_time/Dt)))
720+
solution = 0.0_R_P
721+
solution(1:, 0) = domain%output()
722+
723+
call integrator%initialize(scheme=scheme)
724+
if (allocated(previous)) deallocate(previous) ; allocate(previous(1:integrator%steps+1))
725+
if (integrator%steps==0) then
726+
step_offset = 1 ! for 0 step-(a convention)-solver offset is 1
727+
else
728+
step_offset = integrator%steps ! for >0 step-solver offset is steps
729+
endif
730+
731+
call integrator_rk%initialize(scheme='runge_kutta_ssp_stages_5_order_4')
732+
if (allocated(rk_stage)) deallocate(rk_stage) ; allocate(rk_stage(1:integrator_rk%stages))
733+
734+
step = 0
735+
do while(solution(0, step) < final_time .and. step < ubound(solution, dim=2))
736+
step = step + 1
737+
738+
if (integrator%steps >= step) then
739+
call integrator_rk%integrate_fast(U=domain, stage=rk_stage, buffer=buffer, Dt=Dt, t=solution(0, step))
740+
previous(step) = domain
741+
else
742+
if (iterations>1) then
743+
call integrator%integrate_fast(U=domain, &
744+
previous=previous, &
745+
buffer=buffer, &
746+
Dt=Dt, &
747+
t=solution(0,step-step_offset:step-1), &
748+
iterations=iterations)
749+
else
750+
call integrator%integrate_fast(U=domain, &
751+
previous=previous, &
752+
buffer=buffer, &
753+
Dt=Dt, &
754+
t=solution(0,step-step_offset:step-1))
755+
endif
756+
endif
757+
758+
solution(0, step) = step * Dt
759+
760+
solution(1:, step) = domain%output()
761+
enddo
762+
last_step = step
763+
764+
error = error_L2(frequency=frequency, solution=solution(:, 0:last_step))
765+
endsubroutine integrate_adams_moulton_fast
766+
638767
subroutine integrate_back_df(scheme, frequency, final_time, solution, error, last_step, iterations, Dt, tolerance, stages)
639768
!< Integrate domain by means of the back differentiation formula scheme.
640769
character(*), intent(in) :: scheme !< Selected scheme.

0 commit comments

Comments
 (0)