Skip to content

Commit 932e692

Browse files
committed
add fast operation mode; currently only AB solver has it implemented
1 parent 4a45faf commit 932e692

4 files changed

Lines changed: 297 additions & 34 deletions

File tree

src/lib/foodie_integrand_object.f90

Lines changed: 63 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -49,6 +49,16 @@ module foodie_integrand_object
4949
procedure(assignment_integrand), pass(lhs), deferred, public :: assign_integrand !< `=` operator.
5050
procedure(assignment_real), pass(lhs), deferred, public :: assign_real !< `= real` operator.
5151
generic, public :: assignment(=) => assign_integrand, assign_real !< Overloading `=` assignament.
52+
! public methods for fast operational mode, must be overridden
53+
procedure, pass(self), public :: t_fast !< Time derivative, residuals, fast mode.
54+
procedure, pass(opr), public :: integrand_add_integrand_fast !< `+` fast operator.
55+
generic, public :: add_fast => integrand_add_integrand_fast !< Overloading `add` method.
56+
procedure, pass(opr), public :: integrand_multiply_integrand_fast !< `*` fast operator.
57+
procedure, pass(opr), public :: integrand_multiply_real_scalar_fast !< `* real_scalar` fast operator.
58+
generic, public :: multiply_fast => integrand_multiply_integrand_fast, &
59+
integrand_multiply_real_scalar_fast !< Overloading `multiply` method.
60+
procedure, pass(opr), public :: integrand_subtract_integrand_fast !< `-` fast operator.
61+
generic, public :: subtract_fast => integrand_multiply_integrand_fast !< Overloading `subtract` method.
5262
endtype integrand_object
5363

5464
abstract interface
@@ -57,9 +67,9 @@ module foodie_integrand_object
5767
function time_derivative(self, t) result(dState_dt)
5868
!< Time derivative function of integrand class, i.e. the residuals function.
5969
import :: integrand_object, R_P
60-
class(integrand_object), intent(in) :: self !< Integrand field.
61-
real(R_P), optional, intent(in) :: t !< Time.
62-
real(R_P), allocatable :: dState_dt(:) !< Result of the time derivative function of integrand field.
70+
class(integrand_object), intent(in) :: self !< Integrand field.
71+
real(R_P), intent(in), optional :: t !< Time.
72+
real(R_P), allocatable :: dState_dt(:) !< Result of the time derivative function of integrand field.
6373
endfunction time_derivative
6474

6575
! operators
@@ -125,4 +135,54 @@ pure subroutine assignment_real(lhs, rhs)
125135
real(R_P), intent(in) :: rhs(1:) !< Right hand side.
126136
endsubroutine assignment_real
127137
endinterface
138+
139+
contains
140+
! fast operators
141+
! time derivative
142+
subroutine t_fast(self, t)
143+
!< Time derivative function of integrand class, i.e. the residuals function. Fast mode acting directly on self.
144+
!<
145+
!< @note This procedure must be overridden, it does not implement anything.
146+
class(integrand_object), intent(inout) :: self !< Integrand field.
147+
real(R_P), intent(in), optional :: t !< Time.
148+
endsubroutine t_fast
149+
150+
! +
151+
pure subroutine integrand_add_integrand_fast(opr, lhs, rhs)
152+
!< `+` fast operator.
153+
!<
154+
!< @note This procedure must be overridden, it does not implement anything.
155+
class(integrand_object), intent(inout) :: opr !< Operator result.
156+
class(integrand_object), intent(in) :: lhs !< Left hand side.
157+
class(integrand_object), intent(in) :: rhs !< Right hand side.
158+
endsubroutine integrand_add_integrand_fast
159+
160+
! *
161+
pure subroutine integrand_multiply_integrand_fast(opr, lhs, rhs)
162+
!< `*` fast operator.
163+
!<
164+
!< @note This procedure must be overridden, it does not implement anything.
165+
class(integrand_object), intent(inout) :: opr !< Operator result.
166+
class(integrand_object), intent(in) :: lhs !< Left hand side.
167+
class(integrand_object), intent(in) :: rhs !< Right hand side.
168+
endsubroutine integrand_multiply_integrand_fast
169+
170+
pure subroutine integrand_multiply_real_scalar_fast(opr, lhs, rhs)
171+
!< `* real_scalar` fast operator.
172+
!<
173+
!< @note This procedure must be overridden, it does not implement anything.
174+
class(integrand_object), intent(inout) :: opr !< Operator result.
175+
class(integrand_object), intent(in) :: lhs !< Left hand side.
176+
real(R_P), intent(in) :: rhs !< Right hand side.
177+
endsubroutine integrand_multiply_real_scalar_fast
178+
179+
! -
180+
pure subroutine integrand_subtract_integrand_fast(opr, lhs, rhs)
181+
!< `-` fast operator.
182+
!<
183+
!< @note This procedure must be overridden, it does not implement anything.
184+
class(integrand_object), intent(inout) :: opr !< Operator result.
185+
class(integrand_object), intent(in) :: lhs !< Left hand side.
186+
class(integrand_object), intent(in) :: rhs !< Right hand side.
187+
endsubroutine integrand_subtract_integrand_fast
128188
endmodule foodie_integrand_object

src/lib/foodie_integrator_adams_bashforth.f90

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -71,6 +71,7 @@ module foodie_integrator_adams_bashforth
7171
procedure, pass(self) :: destroy !< Destroy the integrator.
7272
procedure, pass(self) :: initialize !< Initialize (create) the integrator.
7373
procedure, pass(self) :: integrate !< Integrate integrand field.
74+
procedure, pass(self) :: integrate_fast !< Integrate integrand field, fast mode.
7475
procedure, pass(self) :: update_previous !< Cyclic update previous time steps.
7576
endtype integrator_adams_bashforth
7677

@@ -356,6 +357,28 @@ subroutine integrate(self, U, previous, Dt, t, autoupdate)
356357
if (autoupdate_) call self%update_previous(U=U, previous=previous)
357358
endsubroutine integrate
358359

360+
subroutine integrate_fast(self, U, previous, buffer, Dt, t, autoupdate)
361+
!< Integrate field with Adams-Bashforth class scheme.
362+
class(integrator_adams_bashforth), intent(in) :: self !< Integrator.
363+
class(integrand_object), intent(inout) :: U !< Field to be integrated.
364+
class(integrand_object), intent(inout) :: previous(1:) !< Previous time steps solutions of integrand field.
365+
class(integrand_object), intent(inout) :: buffer !< Temporary buffer for doing fast operation.
366+
real(R_P), intent(in) :: Dt !< Time steps.
367+
real(R_P), intent(in) :: t(:) !< Times.
368+
logical, optional, intent(in) :: autoupdate !< Perform cyclic autoupdate of previous time steps.
369+
logical :: autoupdate_ !< Perform cyclic autoupdate of previous time steps, dummy var.
370+
integer(I_P) :: s !< Steps counter.
371+
372+
autoupdate_ = .true. ; if (present(autoupdate)) autoupdate_ = autoupdate
373+
do s=1, self%steps
374+
buffer = previous(s)
375+
call buffer%t_fast(t=t(s))
376+
call buffer%multiply_fast(lhs=buffer, rhs=Dt * self%b(s))
377+
call U%add_fast(lhs=U, rhs=buffer)
378+
enddo
379+
if (autoupdate_) call self%update_previous(U=U, previous=previous)
380+
endsubroutine integrate_fast
381+
359382
subroutine update_previous(self, U, previous)
360383
!< Cyclic update previous time steps.
361384
class(integrator_adams_bashforth), intent(in) :: self !< Integrator.

src/tests/accuracy/oscillation/oscillation.f90

Lines changed: 130 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -51,6 +51,7 @@ module oscillation_test_t
5151
real(R_P), allocatable :: tolerance(:) !< Tolerance(s) exercised on local truncation error.
5252
logical :: errors_analysis=.false. !< Flag for activating errors analysis.
5353
logical :: results=.false. !< Flag for activating results saving.
54+
logical :: is_fast=.false. !< Flag for activating fast schemes.
5455
contains
5556
! public methods
5657
procedure, pass(self) :: execute !< Execute selected test(s).
@@ -119,6 +120,7 @@ subroutine set_cli()
119120
examples = ["oscillation --scheme euler_explicit --save_results ", &
120121
"oscillation --scheme all -r "])
121122
call cli%add(switch='--scheme', switch_ab='-s', help='integrator scheme used', required=.false., def='all', act='store')
123+
call cli%add(switch='--fast', help='activate fast solvers', required=.false., act='store_true', def='.false.')
122124
call cli%add(switch='--iterations', help='number of iterations for implicit schemes', required=.false., act='store', def='5')
123125
call cli%add(switch='--frequency', switch_ab='-f', help='oscillation frequency', required=.false., def='1e-4', act='store')
124126
call cli%add(switch='--time_step', switch_ab='-Dt', nargs='+', help='time step', required=.false., def='100.d0', act='store')
@@ -140,6 +142,7 @@ subroutine parse_cli()
140142

141143
call self%cli%parse(error=self%error)
142144
call self%cli%get(switch='-s', val=self%scheme, error=self%error) ; if (self%error/=0) stop
145+
call self%cli%get(switch='--fast', val=self%is_fast, error=self%error) ; if (self%error/=0) stop
143146
call self%cli%get(switch='--iterations', val=self%implicit_iterations, error=self%error) ; if (self%error/=0) stop
144147
call self%cli%get(switch='--stages', val=self%stages, error=self%error) ; if (self%error/=0) stop
145148
call self%cli%get(switch='-f', val=self%frequency, error=self%error) ; if (self%error/=0) stop
@@ -277,39 +280,78 @@ subroutine initialize_test
277280
type(integrator_runge_kutta_lssp) :: int_runge_kutta_lssp !< Linear Runge-Kutta SSP integrator.
278281
type(integrator_runge_kutta_ssp) :: int_runge_kutta_ssp !< Runge Kutta-SSP integrator.
279282

280-
if (index(trim(adjustl(scheme)), trim(int_adams_bashforth_moulton%class_name())) > 0) then
281-
integrate => integrate_adams_bashforth_moulton
282-
elseif (index(trim(adjustl(scheme)), trim(int_adams_bashforth%class_name())) > 0) then
283-
integrate => integrate_adams_bashforth
284-
elseif (index(trim(adjustl(scheme)), trim(int_adams_moulton%class_name())) > 0) then
285-
integrate => integrate_adams_moulton
286-
elseif (index(trim(adjustl(scheme)), trim(int_back_df%class_name())) > 0) then
287-
integrate => integrate_back_df
288-
elseif (index(trim(adjustl(scheme)), trim(int_euler_explicit%class_name())) > 0) then
289-
integrate => integrate_euler_explicit
290-
elseif (index(trim(adjustl(scheme)), trim(int_leapfrog%class_name())) > 0) then
291-
integrate => integrate_leapfrog
292-
elseif (index(trim(adjustl(scheme)), trim(int_lmm_ssp_vss%class_name())) > 0) then
293-
integrate => integrate_lmm_ssp_vss
294-
elseif (index(trim(adjustl(scheme)), trim(int_lmm_ssp%class_name())) > 0) then
295-
integrate => integrate_lmm_ssp
296-
elseif (index(trim(adjustl(scheme)), trim(int_ms_runge_kutta_ssp%class_name())) > 0) then
297-
integrate => integrate_ms_runge_kutta_ssp
298-
elseif (index(trim(adjustl(scheme)), trim(int_runge_kutta_emd%class_name())) > 0) then
299-
integrate => integrate_runge_kutta_emd
300-
elseif (index(trim(adjustl(scheme)), trim(int_runge_kutta_lssp%class_name())) > 0) then
301-
integrate => integrate_runge_kutta_lssp
302-
elseif (index(trim(adjustl(scheme)), trim(int_runge_kutta_ls%class_name())) > 0) then
303-
integrate => integrate_runge_kutta_ls
304-
elseif (index(trim(adjustl(scheme)), trim(int_runge_kutta_ssp%class_name())) > 0) then
305-
integrate => integrate_runge_kutta_ssp
306-
endif
307-
if (index(trim(adjustl(scheme)), trim(int_runge_kutta_emd%class_name())) > 0) then
308-
if (allocated(error)) deallocate(error) ; allocate(error(1:space_dimension, 1:size(self%tolerance)))
309-
if (allocated(Dt_mean)) deallocate(Dt_mean) ; allocate(Dt_mean(1:size(error, dim=2)))
283+
if (self%is_fast) then
284+
if (index(trim(adjustl(scheme)), trim(int_adams_bashforth_moulton%class_name())) > 0) then
285+
integrate => integrate_adams_bashforth_moulton
286+
elseif (index(trim(adjustl(scheme)), trim(int_adams_bashforth%class_name())) > 0) then
287+
integrate => integrate_adams_bashforth_fast
288+
elseif (index(trim(adjustl(scheme)), trim(int_adams_bashforth%class_name())) > 0) then
289+
integrate => integrate_adams_bashforth
290+
elseif (index(trim(adjustl(scheme)), trim(int_adams_moulton%class_name())) > 0) then
291+
integrate => integrate_adams_moulton
292+
elseif (index(trim(adjustl(scheme)), trim(int_back_df%class_name())) > 0) then
293+
integrate => integrate_back_df
294+
elseif (index(trim(adjustl(scheme)), trim(int_euler_explicit%class_name())) > 0) then
295+
integrate => integrate_euler_explicit
296+
elseif (index(trim(adjustl(scheme)), trim(int_leapfrog%class_name())) > 0) then
297+
integrate => integrate_leapfrog
298+
elseif (index(trim(adjustl(scheme)), trim(int_lmm_ssp_vss%class_name())) > 0) then
299+
integrate => integrate_lmm_ssp_vss
300+
elseif (index(trim(adjustl(scheme)), trim(int_lmm_ssp%class_name())) > 0) then
301+
integrate => integrate_lmm_ssp
302+
elseif (index(trim(adjustl(scheme)), trim(int_ms_runge_kutta_ssp%class_name())) > 0) then
303+
integrate => integrate_ms_runge_kutta_ssp
304+
elseif (index(trim(adjustl(scheme)), trim(int_runge_kutta_emd%class_name())) > 0) then
305+
integrate => integrate_runge_kutta_emd
306+
elseif (index(trim(adjustl(scheme)), trim(int_runge_kutta_lssp%class_name())) > 0) then
307+
integrate => integrate_runge_kutta_lssp
308+
elseif (index(trim(adjustl(scheme)), trim(int_runge_kutta_ls%class_name())) > 0) then
309+
integrate => integrate_runge_kutta_ls
310+
elseif (index(trim(adjustl(scheme)), trim(int_runge_kutta_ssp%class_name())) > 0) then
311+
integrate => integrate_runge_kutta_ssp
312+
endif
313+
if (index(trim(adjustl(scheme)), trim(int_runge_kutta_emd%class_name())) > 0) then
314+
if (allocated(error)) deallocate(error) ; allocate(error(1:space_dimension, 1:size(self%tolerance)))
315+
if (allocated(Dt_mean)) deallocate(Dt_mean) ; allocate(Dt_mean(1:size(error, dim=2)))
316+
else
317+
if (allocated(error)) deallocate(error) ; allocate(error(1:space_dimension, 1:size(self%Dt)))
318+
endif
310319
else
311-
if (allocated(error)) deallocate(error) ; allocate(error(1:space_dimension, 1:size(self%Dt)))
320+
if (index(trim(adjustl(scheme)), trim(int_adams_bashforth_moulton%class_name())) > 0) then
321+
integrate => integrate_adams_bashforth_moulton
322+
elseif (index(trim(adjustl(scheme)), trim(int_adams_bashforth%class_name())) > 0) then
323+
integrate => integrate_adams_bashforth
324+
elseif (index(trim(adjustl(scheme)), trim(int_adams_moulton%class_name())) > 0) then
325+
integrate => integrate_adams_moulton
326+
elseif (index(trim(adjustl(scheme)), trim(int_back_df%class_name())) > 0) then
327+
integrate => integrate_back_df
328+
elseif (index(trim(adjustl(scheme)), trim(int_euler_explicit%class_name())) > 0) then
329+
integrate => integrate_euler_explicit
330+
elseif (index(trim(adjustl(scheme)), trim(int_leapfrog%class_name())) > 0) then
331+
integrate => integrate_leapfrog
332+
elseif (index(trim(adjustl(scheme)), trim(int_lmm_ssp_vss%class_name())) > 0) then
333+
integrate => integrate_lmm_ssp_vss
334+
elseif (index(trim(adjustl(scheme)), trim(int_lmm_ssp%class_name())) > 0) then
335+
integrate => integrate_lmm_ssp
336+
elseif (index(trim(adjustl(scheme)), trim(int_ms_runge_kutta_ssp%class_name())) > 0) then
337+
integrate => integrate_ms_runge_kutta_ssp
338+
elseif (index(trim(adjustl(scheme)), trim(int_runge_kutta_emd%class_name())) > 0) then
339+
integrate => integrate_runge_kutta_emd
340+
elseif (index(trim(adjustl(scheme)), trim(int_runge_kutta_lssp%class_name())) > 0) then
341+
integrate => integrate_runge_kutta_lssp
342+
elseif (index(trim(adjustl(scheme)), trim(int_runge_kutta_ls%class_name())) > 0) then
343+
integrate => integrate_runge_kutta_ls
344+
elseif (index(trim(adjustl(scheme)), trim(int_runge_kutta_ssp%class_name())) > 0) then
345+
integrate => integrate_runge_kutta_ssp
346+
endif
347+
if (index(trim(adjustl(scheme)), trim(int_runge_kutta_emd%class_name())) > 0) then
348+
if (allocated(error)) deallocate(error) ; allocate(error(1:space_dimension, 1:size(self%tolerance)))
349+
if (allocated(Dt_mean)) deallocate(Dt_mean) ; allocate(Dt_mean(1:size(error, dim=2)))
350+
else
351+
if (allocated(error)) deallocate(error) ; allocate(error(1:space_dimension, 1:size(self%Dt)))
352+
endif
312353
endif
354+
313355
error = 0.0_R_P
314356
if (self%errors_analysis) then
315357
if (allocated(order)) deallocate(order) ; allocate(order(1:space_dimension, 1:size(error, dim=2)-1))
@@ -373,6 +415,63 @@ subroutine integrate_adams_bashforth(scheme, frequency, final_time, solution, er
373415
error = error_L2(frequency=frequency, solution=solution(:, 0:last_step))
374416
endsubroutine integrate_adams_bashforth
375417

418+
subroutine integrate_adams_bashforth_fast(scheme, frequency, final_time, solution, error, last_step, iterations, Dt, tolerance, &
419+
stages)
420+
!< Integrate domain by means of the Adams-Bashforth scheme.
421+
character(*), intent(in) :: scheme !< Selected scheme.
422+
real(R_P), intent(in) :: frequency !< Oscillation frequency.
423+
real(R_P), intent(in) :: final_time !< Final integration time.
424+
real(R_P), allocatable, intent(out) :: solution(:,:) !< Solution at each time step, X-Y.
425+
real(R_P), intent(out) :: error(1:) !< Error (norm L2) with respect the exact solution.
426+
integer(I_P), intent(out) :: last_step !< Last time step computed.
427+
integer(I_P), intent(in), optional :: iterations !< Number of fixed point iterations.
428+
real(R_P), intent(in), optional :: Dt !< Time step.
429+
real(R_P), intent(in), optional :: tolerance !< Local error tolerance.
430+
integer(I_P), intent(in), optional :: stages !< Number of stages.
431+
type(integrator_adams_bashforth) :: integrator !< The integrator.
432+
type(integrator_runge_kutta_ssp) :: integrator_rk !< RK integrator for starting non self-starting integrators.
433+
type(oscillator) :: domain !< Oscillation field.
434+
type(oscillator), allocatable :: rk_stage(:) !< Runge-Kutta stages.
435+
type(oscillator), allocatable :: previous(:) !< Previous time steps solutions.
436+
type(oscillator) :: buffer !< Buffer oscillation field.
437+
integer :: step !< Time steps counter.
438+
439+
call domain%init(initial_state=initial_state, frequency=frequency)
440+
441+
if (allocated(solution)) deallocate(solution) ; allocate(solution(0:space_dimension, 0:int(final_time/Dt)))
442+
solution = 0.0_R_P
443+
solution(1:, 0) = domain%output()
444+
445+
call integrator%initialize(scheme=scheme)
446+
if (allocated(previous)) deallocate(previous) ; allocate(previous(1:integrator%steps))
447+
448+
call integrator_rk%initialize(scheme='runge_kutta_ssp_stages_5_order_4')
449+
if (allocated(rk_stage)) deallocate(rk_stage) ; allocate(rk_stage(1:integrator_rk%stages))
450+
451+
step = 0
452+
do while(solution(0, step) < final_time .and. step < ubound(solution, dim=2))
453+
step = step + 1
454+
455+
if (integrator%steps >= step) then
456+
call integrator_rk%integrate(U=domain, stage=rk_stage, Dt=Dt, t=solution(0, step))
457+
previous(step) = domain
458+
else
459+
call integrator%integrate_fast(U=domain, &
460+
previous=previous, &
461+
buffer=buffer, &
462+
Dt=Dt, &
463+
t=solution(0, step-integrator%steps:step-1))
464+
endif
465+
466+
solution(0, step) = step * Dt
467+
468+
solution(1:, step) = domain%output()
469+
enddo
470+
last_step = step
471+
472+
error = error_L2(frequency=frequency, solution=solution(:, 0:last_step))
473+
endsubroutine integrate_adams_bashforth_fast
474+
376475
subroutine integrate_adams_bashforth_moulton(scheme, frequency, final_time, solution, error, last_step, iterations, Dt, &
377476
tolerance, stages)
378477
!< Integrate domain by means of the Adams-Bashforth-Moulton scheme.

0 commit comments

Comments
 (0)