From 9a76b798cc3bea3ad44c92e49f93c9a53da88887 Mon Sep 17 00:00:00 2001 From: Stefano Zaghi Date: Sat, 13 May 2017 05:51:46 +0200 Subject: [PATCH 01/25] add linear advection skeleton, to be completed --- src/tests/ladvection/fobos | 127 ++++ .../foodie_test_integrand_ladvection.f90 | 633 +++++++++++++++++ .../ladvection/foodie_test_ladvection.f90 | 660 ++++++++++++++++++ src/tests/lcce/foodie_test_integrand_lcce.f90 | 30 +- .../foodie_test_integrand_oscillation.f90 | 24 +- 5 files changed, 1447 insertions(+), 27 deletions(-) create mode 100644 src/tests/ladvection/fobos create mode 100644 src/tests/ladvection/foodie_test_integrand_ladvection.f90 create mode 100644 src/tests/ladvection/foodie_test_ladvection.f90 diff --git a/src/tests/ladvection/fobos b/src/tests/ladvection/fobos new file mode 100644 index 00000000..811176ff --- /dev/null +++ b/src/tests/ladvection/fobos @@ -0,0 +1,127 @@ +[modes] +modes = gnu gnu-debug gnu-coverage + intel intel-debug + errors-analysis + gnu-pure gnu-debug-pure gnu-coverage-pure + intel-pure intel-debug-pure + +[common-variables] +$CSTATIC_GNU = -cpp -c -frealloc-lhs +$CSTATIC_INT = -cpp -c -assume realloc_lhs +$DEBUG_GNU = -Og -g3 -Warray-bounds -Wcharacter-truncation -Wline-truncation -Wimplicit-interface -Wimplicit-procedure -Wunderflow -Wuninitialized -fcheck=all -fmodule-private -ffree-line-length-132 -fimplicit-none -fbacktrace -fdump-core -finit-real=nan -std=f2008 -fall-intrinsics +$DEBUG_INT = -O0 -debug all -check all -warn all -extend-source 132 -traceback -gen-interfaces -fp-stack-check -fstack-protector-all -ftrapuv -no-ftz -std08 +$OPTIMIZE = -O2 +$EXDIRS = src/tests/parallel/ src/tests/regression/ + PENF/src/tests/ + FACE/src/tests/ FACE/src/third_party/ + FLAP/src/tests/ FLAP/src/third_party/ + WenOOF/src/tests/ WenOOF/src/third_party/ + +# main modes +[gnu] +help = Build test in release mode with GNU gfortran +compiler = gnu +cflags = $CSTATIC_GNU $OPTIMIZE +lflags = $OPTIMIZE +template = template-common + +[gnu-debug] +help = Build test in debug mode with GNU gfortran +compiler = gnu +cflags = $CSTATIC_GNU $DEBUG_GNU +lflags = $DEBUG_GNU +template = template-common + +[gnu-coverage] +help = Build test in release coverage mode with GNU gfortran +compiler = gnu +cflags = $CSTATIC_GNU $DEBUG_GNU +lflags = $DEBUG_GNU +coverage = True +template = template-common + +[intel] +help = Build test in release mode with Intel Fortran +compiler = intel +cflags = $CSTATIC_INT $OPTIMIZE +lflags = $OPTIMIZE +template = template-common + +[intel-debug] +help = Build test in debug mode with Intel Fortran +compiler = intel +cflags = $CSTATIC_INT $DEBUG_INT +lflags = $DEBUG_INT +template = template-common + +[errors-analysis] +help = Build test in release mode (for errors analysis) with GNU gfortran +compiler = gnu +cflags = $CSTATIC_GNU $OPTIMIZE +lflags = $OPTIMIZE +cflags_heritage = True +target = src/tests/ladvection/foodie_test_ladvection.f90 +exclude_dirs = $EXDIRS +mod_dir = mod +obj_dir = obj +src = src/ +colors = True +quiet = False +log = True +jobs = 10 + +# pure modes for testing FOODIE ADT with "pure" procedures +[gnu-pure] +help = Build test in release mode with GNU gfortran +compiler = gnu +cflags = $CSTATIC_GNU $OPTIMIZE +lflags = $OPTIMIZE +preproc = -DPURE +template = template-common + +[gnu-debug-pure] +help = Build test in debug mode with GNU gfortran +compiler = gnu +cflags = $CSTATIC_GNU $DEBUG_GNU +lflags = $DEBUG_GNU +preproc = -DPURE +template = template-common + +[gnu-coverage-pure] +help = Build test in release coverage mode with GNU gfortran +compiler = gnu +cflags = $CSTATIC_GNU $OPTIMIZE +lflags = $OPTIMIZE +preproc = -DPURE +coverage = True +template = template-common + +[intel-pure] +help = Build test in release mode with Intel Fortran +compiler = intel +cflags = $CSTATIC_INT $OPTIMIZE +lflags = $OPTIMIZE +preproc = -DPURE +template = template-common + +[intel-debug-pure] +help = Build test in debug mode with Intel Fortran +compiler = intel +cflags = $CSTATIC_INT $DEBUG_INT +lflags = $DEBUG_INT +preproc = -DPURE +template = template-common + +# templates +[template-common] +cflags_heritage = True +build_dir = build/tests/oscillation/ +mod_dir = mod +obj_dir = obj +src = src/ +target = src/tests/ladvection/foodie_test_ladvection.f90 +exclude_dirs = $EXDIRS +colors = True +quiet = False +log = True +jobs = 10 diff --git a/src/tests/ladvection/foodie_test_integrand_ladvection.f90 b/src/tests/ladvection/foodie_test_integrand_ladvection.f90 new file mode 100644 index 00000000..327b4ea5 --- /dev/null +++ b/src/tests/ladvection/foodie_test_integrand_ladvection.f90 @@ -0,0 +1,633 @@ +!< Define [[integrand_ladvection]], the 1D linear advection PDE test field that is a concrete extension of the +!< abstract integrand type. + +module foodie_test_integrand_ladvection +!< Define [[integrand_ladvection]], the 1D linear advection PDE test field that is a concrete extension of the +!< abstract integrand type. + +use, intrinsic :: iso_fortran_env, only : stderr=>error_unit +use foodie, only : integrand_object +use penf, only : I_P, R_P +use wenoof, only : interpolator_object, wenoof_create + +implicit none +private +public :: integrand_ladvection + +type, extends(integrand_object) :: integrand_ladvection + !< 1D linear advection field. + !< + !< It is a FOODIE integrand class concrete extension. + !< + !<### 1D linear advection field + !< The 1D linear advection equation is a conservation law that reads as + !<$$ + !<\begin{matrix} + ! compute_dt !< Compute the current time step, by means of CFL condition. + procedure, pass(self), public :: exact_solution !< Return exact solution. + procedure, pass(self), public :: initialize !< Initialize integrand. + procedure, pass(self), public :: output !< Extract integrand state field. + ! public deferred methods + procedure, pass(self), public :: integrand_dimension !< Return integrand dimension. + procedure, pass(self), public :: t => dU_dt !< Time derivative, residuals. + ! operators + procedure, pass(lhs), public :: local_error !<`||integrand_ladvection - integrand_ladvection||` operator. + ! + + procedure, pass(lhs), public :: integrand_add_integrand !< `+` operator. + procedure, pass(lhs), public :: integrand_add_real !< `+ real` operator. + procedure, pass(rhs), public :: real_add_integrand !< `real +` operator. + ! * + procedure, pass(lhs), public :: integrand_multiply_integrand !< `*` operator. + procedure, pass(lhs), public :: integrand_multiply_real !< `* real` operator. + procedure, pass(rhs), public :: real_multiply_integrand !< `real *` operator. + procedure, pass(lhs), public :: integrand_multiply_real_scalar !< `* real_scalar` operator. + procedure, pass(rhs), public :: real_scalar_multiply_integrand !< `real_scalar *` operator. + ! - + procedure, pass(lhs), public :: integrand_sub_integrand !< `-` operator. + procedure, pass(lhs), public :: integrand_sub_real !< `- real` operator. + procedure, pass(rhs), public :: real_sub_integrand !< `real -` operator. + ! = + procedure, pass(lhs), public :: assign_integrand !< `=` operator. + procedure, pass(lhs), public :: assign_real !< `= real` operator. + ! override fast operators + procedure, pass(self), public :: t_fast !< Time derivative, residuals, fast mode. + procedure, pass(opr), public :: integrand_add_integrand_fast !< `+` fast operator. + procedure, pass(opr), public :: integrand_multiply_integrand_fast !< `*` fast operator. + procedure, pass(opr), public :: integrand_multiply_real_scalar_fast !< `* real_scalar` fast operator. + procedure, pass(opr), public :: integrand_subtract_integrand_fast !< `-` fast operator. + ! private methods + procedure, pass(self), private :: impose_boundary_conditions !< Impose boundary conditions. + procedure, pass(self), private :: reconstruct_interfaces !< Reconstruct interface states. +endtype integrand_ladvection + +contains + ! auxiliary methods + pure subroutine destroy(self) + !< Destroy field. + class(integrand_ladvection), intent(inout) :: self !< Advection field. + + self%weno_order = 0 + self%Ni = 0 + self%Ng = 0 + self%Dx = 0._R_P + if (allocated(self%u)) deallocate(self%u) + if (allocated(self%BC_L)) deallocate(self%BC_L) + if (allocated(self%BC_R)) deallocate(self%BC_R) + if (allocated(self%interpolator)) deallocate(self%interpolator) + endsubroutine destroy + + pure function compute_dt(self, steps_max, t_max, t, CFL) result(Dt) + !< Compute the current time step by means of CFL condition. + class(integrand_ladvection), intent(in) :: self !< Advection field. + integer(I_P), intent(in) :: steps_max !< Maximun number of time steps. + real(R_P), intent(in) :: t_max !< Maximum integration time. + real(R_P), intent(in) :: t !< Time. + real(R_P), intent(in) :: CFL !< CFL value. + real(R_P) :: Dt !< Time step. + + associate(Ni=>self%Ni, Dx=>self%Dx) + Dt = Dx * CFL / abs(self%a) + if (steps_max <= 0 .and. t_max > 0._R_P) then + if ((t + Dt) > t_max) Dt = t_max - t + endif + endassociate + endfunction compute_dt + + pure function exact_solution(self, u0, t) result(exact) + !< Return exact solution. + class(integrand_ladvection), intent(in) :: self !< Integrand. + real(R_P), intent(in) :: u0(1:) !< Initial state + real(R_P), intent(in) :: t !< Time. + real(R_P), allocatable :: exact(:) !< Exact solution. + + endfunction exact_solution + + subroutine initialize(self, Ni, Dx, BC_L, BC_R, initial_state, w_scheme, a, weno_order) + !< Initialize field. + class(integrand_ladvection), intent(inout) :: self !< Advection field. + integer(I_P), intent(in) :: Ni !< Space dimension. + real(R_P), intent(in) :: Dx !< Space step. + character(*), intent(in) :: BC_L !< Left boundary condition type. + character(*), intent(in) :: BC_R !< Right boundary condition type. + real(R_P), intent(in) :: initial_state(1:) !< Initial state. + character(*), intent(in) :: w_scheme !< WENO scheme. + real(R_P), intent(in), optional :: a !< Advection coefficient. + integer(I_P), intent(in), optional :: weno_order !< WENO reconstruction order. + integer(I_P) :: i !< Space couner. + + call self%destroy + self%a = 1._R_P ; if (present(a)) self%a = a + self%weno_order = 1 ; if (present(weno_order)) self%weno_order = weno_order + self%Ni = Ni + self%Ng = (self%weno_order + 1) / 2 + self%Dx = Dx + if (allocated(self%u)) deallocate(self%u) ; allocate(self%u(1-self%Ng:self%Ni+self%Ng)) + do i=1, Ni + self%u(i) = initial_state(i) + enddo + self%BC_L = BC_L + self%BC_R = BC_R + + if (self%weno_order>1) call wenoof_create(interpolator_type=trim(adjustl(w_scheme)), S=self%Ng, interpolator=self%interpolator, & + eps=self%weno_eps) + endsubroutine initialize + + pure function output(self) result(state) + !< Output the advection field state. + class(integrand_ladvection), intent(in) :: self !< Advection field. + real(R_P), allocatable :: state(:) !< Advection state + + state = self%u(1:self%Ni) + endfunction output + + ! ADT integrand deferred methods + function dU_dt(self, t) result(dState_dt) + !< Time derivative of advection field, the residuals function. + class(integrand_ladvection), intent(in) :: self !< Advection field. + real(R_P), intent(in), optional :: t !< Time. + real(R_P), allocatable :: dState_dt(:) !< Advection field time derivative. + real(R_P) :: u(1-self%Ng:self%Ni+self%Ng) !< Conservative variable. + real(R_P) :: ur(1:2,0:self%Ni+1) !< Reconstructed conservative variable. + real(R_P) :: f(0:self%Ni) !< Flux of conservative variable. + integer(I_P) :: i !< Counter. + + do i=1, self%Ni + U(i) = self%U(i) + enddo + call self%impose_boundary_conditions(u=u) + call self%reconstruct_interfaces(conservative=u, r_conservative=ur) + do i=0, self%Ni + call solve_riemann_problem(state_left=ur(2, i), state_right=ur(1, i+1), flux=f(i)) + enddo + allocate(dState_dt(1:self%Ni)) + do i=1, self%Ni + dState_dt(i) = (f(i - 1) - f(i)) / self%Dx + enddo + contains + subroutine solve_riemann_problem(state_left, state_right, flux) + !< Solver Riemann problem of linear advection by upwinding. + real(R_P), intent(in) :: state_left !< Left state. + real(R_P), intent(in) :: state_right !< right state. + real(R_P), intent(out) :: flux !< Flux of conservative variable. + + if (self%a > 0._R_P) then + flux = self%a * state_left + else + flux = self%a * state_right + endif + endsubroutine solve_riemann_problem + endfunction dU_dt + + pure function integrand_dimension(self) + !< return integrand dimension. + class(integrand_ladvection), intent(in) :: self !< integrand. + integer(I_P) :: integrand_dimension !< integrand dimension. + + integrand_dimension = self%Ni + endfunction integrand_dimension + + function local_error(lhs, rhs) result(error) + !< Estimate local truncation error between 2 advection approximations. + !< + !< The estimation is done by norm L2 of U: + !< + !< $$ error = \sqrt{ \sum_i{\sum_i{ \frac{(lhs\%u_i - rhs\%u_i)^2}{lhs\%u_i^2} }} } $$ + class(integrand_ladvection), intent(in) :: lhs !< Left hand side. + class(integrand), intent(in) :: rhs !< Right hand side. + real(R_P) :: error !< Error estimation. + integer(I_P) :: i !< Space counter. + + select type(rhs) + class is (integrand_ladvection) + error = 0._R_P + do i=1, lhs%Ni + error = error + (lhs%u(i) - rhs%u(i)) ** 2 / lhs%u(i) ** 2 + enddo + error = sqrt(error) + endselect + endfunction advection_local_error + + ! + + pure function integrand_add_integrand(lhs, rhs) result(opr) + !< `+` operator. + class(integrand_ladvection), intent(in) :: lhs !< Left hand side. + class(integrand_object), intent(in) :: rhs !< Right hand side. + real(R_P), allocatable :: opr(:) !< Operator result. + + select type(rhs) + class is(integrand_ladvection) + opr = lhs%u + rhs%u + endselect + endfunction integrand_add_integrand + + pure function integrand_add_real(lhs, rhs) result(opr) + !< `+ real` operator. + class(integrand_ladvection), intent(in) :: lhs !< Left hand side. + real(R_P), intent(in) :: rhs(1:) !< Right hand side. + real(R_P), allocatable :: opr(:) !< Operator result. + + opr = lhs%u + rhs + endfunction integrand_add_real + + pure function real_add_integrand(lhs, rhs) result(opr) + !< `real +` operator. + real(R_P), intent(in) :: lhs(1:) !< Left hand side. + class(integrand_ladvection), intent(in) :: rhs !< Left hand side. + real(R_P), allocatable :: opr(:) !< Operator result. + + opr = lhs + rhs%U + endfunction real_add_integrand + + ! * + pure function integrand_multiply_integrand(lhs, rhs) result(opr) + !< `*` operator. + class(integrand_ladvection), intent(in) :: lhs !< Left hand side. + class(integrand_object), intent(in) :: rhs !< Right hand side. + real(R_P), allocatable :: opr(:) !< Operator result. + + select type(rhs) + class is(integrand_ladvection) + opr = lhs%U * rhs%U + endselect + endfunction integrand_multiply_integrand + + pure function integrand_multiply_real(lhs, rhs) result(opr) + !< `* real_scalar` operator. + class(integrand_ladvection), intent(in) :: lhs !< Left hand side. + real(R_P), intent(in) :: rhs(1:) !< Right hand side. + real(R_P), allocatable :: opr(:) !< Operator result. + + opr = lhs%U * rhs + endfunction integrand_multiply_real + + pure function real_multiply_integrand(lhs, rhs) result(opr) + !< `real_scalar *` operator. + class(integrand_ladvection), intent(in) :: rhs !< Right hand side. + real(R_P), intent(in) :: lhs(1:) !< Left hand side. + real(R_P), allocatable :: opr(:) !< Operator result. + + opr = lhs * rhs%U + endfunction real_multiply_integrand + + pure function integrand_multiply_real_scalar(lhs, rhs) result(opr) + !< `* real_scalar` operator. + class(integrand_ladvection), intent(in) :: lhs !< Left hand side. + real(R_P), intent(in) :: rhs !< Right hand side. + real(R_P), allocatable :: opr(:) !< Operator result. + + opr = lhs%U * rhs + endfunction integrand_multiply_real_scalar + + pure function real_scalar_multiply_integrand(lhs, rhs) result(opr) + !< `real_scalar *` operator. + real(R_P), intent(in) :: lhs !< Left hand side. + class(integrand_ladvection), intent(in) :: rhs !< Right hand side. + real(R_P), allocatable :: opr(:) !< Operator result. + + opr = lhs * rhs%U + endfunction real_scalar_multiply_integrand + + ! - + pure function integrand_sub_integrand(lhs, rhs) result(opr) + !< `-` operator. + class(integrand_ladvection), intent(in) :: lhs !< Left hand side. + class(integrand_object), intent(in) :: rhs !< Right hand side. + real(R_P), allocatable :: opr(:) !< Operator result. + + select type(rhs) + class is(integrand_ladvection) + opr = lhs%U - rhs%U + endselect + endfunction integrand_sub_integrand + + pure function integrand_sub_real(lhs, rhs) result(opr) + !< `- real` operator. + class(integrand_ladvection), intent(in) :: lhs !< Left hand side. + real(R_P), intent(in) :: rhs(1:) !< Right hand side. + real(R_P), allocatable :: opr(:) !< Operator result. + + opr = lhs%U - rhs + endfunction integrand_sub_real + + pure function real_sub_integrand(lhs, rhs) result(opr) + !< `real -` operator. + real(R_P), intent(in) :: lhs(1:) !< Left hand side. + class(integrand_ladvection), intent(in) :: rhs !< Left hand side. + real(R_P), allocatable :: opr(:) !< Operator result. + + opr = lhs - rhs%U + endfunction real_sub_integrand + + pure subroutine assign_integrand(lhs, rhs) + !< `=` operator. + class(integrand_ladvection), intent(inout) :: lhs !< Left hand side. + class(integrand), intent(in) :: rhs !< Right hand side. + integer(I_P) :: i !< Counter. + + select type(rhs) + class is(integrand_ladvection) + lhs%weno_order = rhs%weno_order + lhs%Ni = rhs%Ni + lhs%Ng = rhs%Ng + lhs%Dx = rhs%Dx + lhs%a = rhs%a + if (allocated(rhs%u)) then + if (allocated(lhs%u)) deallocate(lhs%u) ; allocate(lhs%u(1:lhs%Ni)) + select type(rhs) + class is(integrand_ladvection) + if (allocated(rhs%U)) then + do i=1, lhs%Ni + lhs%u(i) = rhs%u(i) + enddo + endif + endselect + endif + if (allocated(rhs%BC_L)) lhs%BC_L = rhs%BC_L + if (allocated(rhs%BC_R)) lhs%BC_R = rhs%BC_R + if (allocated(rhs%interpolator)) then + if (allocated(lhs%interpolator)) deallocate(lhs%interpolator) + allocate(lhs%interpolator, mold=rhs%interpolator) + lhs%interpolator = rhs%interpolator + endif + endselect + endsubroutine assign_advection + + pure subroutine assign_real(lhs, rhs) + !< Assign one real to an advection field. + class(integrand_ladvection), intent(inout) :: lhs !< Left hand side. + real(R_P), intent(in) :: rhs(1:) !< Right hand side. + + lhs%u = rhs + endsubroutine assign_real + + ! private methods + pure subroutine impose_boundary_conditions(self, u) + !< Impose boundary conditions. + class(integrand_ladvection), intent(in) :: self !< Advection field. + real(R_P), intent(inout) :: u(1-self%Ng:) !< Conservative variables. + integer(I_P) :: i !< Space counter. + + select case(trim(adjustl(self%BC_L))) + case('TRA') ! trasmissive (non reflective) BC + do i=1-self%Ng, 0 + u(i) = u(-i+1) + enddo + case('REF') ! reflective BC + do i=1-self%Ng, 0 + u(i) = - u(-i+1) + enddo + case('PER') ! periodic BC + do i=1-self%Ng, 0 + u(i) = u(self%Ni+i) + enddo + endselect + + select case(trim(adjustl(self%BC_R))) + case('TRA') ! trasmissive (non reflective) BC + do i=self%Ni+1, self%Ni+self%Ng + u(i) = u(self%Ni-(i-self%Ni-1)) + enddo + case('REF') ! reflective BC + do i=self%Ni+1, self%Ni+self%Ng + u(i) = - u(self%Ni-(i-self%Ni-1)) + enddo + case('PER') ! periodic BC + do i=self%Ni+1, self%Ni+self%Ng + u(i) = u(i-self%Ni) + enddo + endselect + endsubroutine impose_boundary_conditions + + subroutine reconstruct_interfaces(self, conservative, r_conservative) + !< Reconstruct interfaces states. + class(integrand_ladvection), intent(in) :: self !< Advection field. + real(R_P), intent(in) :: conservative(1-self%Ng:) !< Conservative variables. + real(R_P), intent(inout) :: r_conservative(1:, 0:) !< Reconstructed conservative vars. + real(R_P), allocatable :: U(:) !< Serialized conservative variables. + real(R_P) :: C(1:2, 1-self%Ng:-1+self%Ng) !< Stencils. + real(R_P) :: CR(1:2) !< Reconstrcuted intrafaces. + integer(I_P) :: i !< Counter. + integer(I_P) :: j !< Counter. + integer(I_P) :: f !< Counter. + + select case(self%weno_order) + case(1) ! 1st order piecewise constant reconstruction + do i=0, self%Ni+1 + r_conservative(1, i) = conservative(i) + r_conservative(2, i) = r_conservative(1, i) + enddo + case(3, 5, 7, 9, 11, 13, 15, 17) ! 3rd-17th order WENO reconstruction + do i=0, self%Ni+1 + do j=i+1-self%Ng, i-1+self%Ng + do f=1, 2 + C(f, j-i) = conservative(j) + enddo + enddo + call self%interpolator%interpolate(stencil=C(:, :), interpolation=CR(:)) + do f=1, 2 + r_conservative(f, i) = CR(f) + enddo + enddo + endselect + endsubroutine reconstruct_interfaces +endmodule foodie_test_integrand_ladvection + +program wenoof_test_linear_advection +!< Define [[integrand_ladvection]], the 1D linear advection PDE test field that is a concrete extension of the +!< abstract integrand type. + +use flap, only : command_line_interface +use foodie, only : integrator_runge_kutta_lssp, integrator_runge_kutta_ssp +use foodie_test_integrand_ladvection, only : integrand_ladvection +use penf, only : cton, FR_P, I_P, R_P, str + +implicit none +character(len=99) :: s_scheme !< Space scheme. +character(len=99) :: t_scheme !< Time scheme. +integer(I_P) :: weno_order !< WENO reconstruction order. +real(R_P) :: weno_eps !< WENO epsilon value. +integer(I_P) :: stages !< Number of stages. +type(integrator_runge_kutta_lssp) :: rk_integrator !< Runge-Kutta integrator. +type(integrator_runge_kutta_ssp) :: rk_integrator_s !< Runge-Kutta integrator. +type(integrand_ladvection), allocatable :: rk_stage(:) !< Runge-Kutta stages. +real(R_P) :: dt !< Time step. +real(R_P) :: t !< Time. +integer(I_P) :: step !< Time steps counter. +type(integrand_ladvection) :: domain !< Domain of Advection equations. +real(R_P) :: CFL !< CFL value. +character(3) :: BC_L !< Left boundary condition type. +character(3) :: BC_R !< Right boundary condition type. +integer(I_P) :: Ni !< Number of grid cells. +real(R_P) :: Dx !< Space step discretization. +real(R_P) :: a !< Advection coefficient. +real(R_P), allocatable :: x(:) !< Cell center x-abscissa values. +integer(I_P) :: steps_max !< Maximum number of time steps. +real(R_P) :: t_max !< Maximum integration time. +logical :: results !< Flag for activating results saving. +logical :: time_serie !< Flag for activating time serie-results saving. +logical :: verbose !< Flag for activating more verbose output. +real(R_P), parameter :: pi = 4._R_P * atan(1._R_P) !< Pi greek. + +call parse_command_line_interface +if (verbose) print "(A)", 'Solve 1D linear advection equation " u_t + (a*u)_x =0" with a='//trim(str(a)) +call initialize +call save_time_serie(filename='linear_advection-'// & + trim(adjustl(s_scheme))//'-'//trim(str(weno_order, no_sign=.true.))//'-'// & + trim(adjustl(t_scheme))//'-'//trim(str(stages, no_sign=.true.))//'-'// & + 'Ni_'//trim(str(Ni, no_sign=.true.))//'.dat', t=t) +step = 0 +time_loop: do + step = step + 1 + dt = domain%dt(steps_max=steps_max, t_max=t_max, t=t, CFL=CFL) + if (trim(adjustl(t_scheme))=='runge_kutta_ssp_stages_5_order_4') then + call rk_integrator_s%integrate(U=domain, stage=rk_stage, dt=dt, t=t) + else + call rk_integrator%integrate(U=domain, stage=rk_stage, dt=dt, t=t) + endif + t = t + dt + call save_time_serie(t=t) + if (verbose) print "(A)", 'step = '//str(n=step)//', time step = '//str(n=dt)//', time = '//str(n=t) + if ((t == t_max).or.(step == steps_max)) exit time_loop +enddo time_loop +call save_time_serie(t=t, finish=.true.) + +contains + subroutine initialize() + !< Initialize the test. + real(R_P), allocatable :: initial_state(:) !< Initial state of primitive variables. + integer(I_P) :: i !< Space counter. + + if (trim(adjustl(t_scheme))=='runge_kutta_ssp_stages_5_order_4') then + call rk_integrator_s%initialize(scheme=t_scheme, stop_on_fail=.true.) + if (allocated(rk_stage)) deallocate(rk_stage) ; allocate(rk_stage(1:rk_integrator_s%stages)) + else + call rk_integrator%initialize(scheme=t_scheme, stages=stages) + if (allocated(rk_stage)) deallocate(rk_stage) ; allocate(rk_stage(1:rk_integrator%stages)) + endif + t = 0._R_P + if (allocated(x)) deallocate(x) ; allocate(x(1:Ni)) + if (allocated(initial_state)) deallocate(initial_state) ; allocate(initial_state(1:Ni)) + Dx = 1._R_P / Ni + call square_wave_initial_state(initial_state=initial_state) + call domain%initialize(Ni=Ni, Dx=Dx, & + BC_L=BC_L, BC_R=BC_R, & + initial_state=initial_state, & + s_scheme=s_scheme, & + a=a, & + weno_order=weno_order) + endsubroutine initialize + + subroutine parse_command_line_interface() + !< Parse Command Line Interface (CLI). + type(command_line_interface) :: cli !< Command line interface handler. + integer(I_P) :: error !< Error handler. + character(len=:), allocatable :: buffer !< String buffer. + + call cli%init(description = 'WenOOF test: 1D linear advection equation', & + examples = ["wenoof_test_linear_advection ", & + "wenoof_test_linear_advection --tserie"]) + call cli%add(switch='-a', help='advection coefficient', required=.false., act='store', def='1.0') + call cli%add(switch='--Ni', help='number finite volumes used', required=.false., act='store', def='100') + call cli%add(switch='--steps', help='number time steps performed', required=.false., act='store', def='100') + call cli%add(switch='--t-max', help='maximum integration time', required=.false., act='store', def='0.') + call cli%add(switch='--s-scheme', help='space intergation scheme', required=.false., act='store', def='reconstructor-JS', & + choices='reconstructor-JS,reconstructor-M-JS,reconstructor-M-Z,reconstructor-Z') + call cli%add(switch='--weno-order', help='WENO order', required=.false., act='store', def='1') + call cli%add(switch='--weno-eps', help='WENO epsilon parameter', required=.false., act='store', def='0.000001') + call cli%add(switch='--t-scheme', help='time intergation scheme', required=.false., act='store', & + def='runge_kutta_lssp_stages_s_order_s_1', & + choices='runge_kutta_lssp_stages_s_order_s_1,runge_kutta_lssp_stages_s_order_s,runge_kutta_ssp_stages_5_order_4') + call cli%add(switch='--stages', help='number stages', required=.false., act='store', def='2') + call cli%add(switch='--cfl', help='CFL value', required=.false., act='store', def='0.8') + call cli%add(switch='--tserie', switch_ab='-t', help='Save time-serie-result', required=.false., act='store_true', def='.false.') + call cli%add(switch='--verbose', help='Verbose output', required=.false., act='store_true', def='.false.') + call cli%parse(error=error) + call cli%get(switch='-a', val=a, error=error) ; if (error/=0) stop + call cli%get(switch='--Ni', val=Ni, error=error) ; if (error/=0) stop + call cli%get(switch='--steps', val=steps_max, error=error) ; if (error/=0) stop + call cli%get(switch='--t-max', val=t_max, error=error) ; if (error/=0) stop + call cli%get(switch='--s-scheme', val=s_scheme, error=error) ; if (error/=0) stop + call cli%get(switch='--weno-order', val=weno_order, error=error) ; if (error/=0) stop + call cli%get(switch='--weno-eps', val=weno_eps, error=error) ; if (error/=0) stop + call cli%get(switch='--t-scheme', val=t_scheme, error=error) ; if (error/=0) stop + call cli%get(switch='--stages', val=stages, error=error) ; if (error/=0) stop + call cli%get(switch='--cfl', val=CFL, error=error) ; if (error/=0) stop + call cli%get(switch='--tserie', val=time_serie, error=error) ; if (error/=0) stop + call cli%get(switch='--verbose', val=verbose, error=error) ; if (error/=0) stop + + if (t_max > 0._R_P) steps_max = 0 + endsubroutine parse_command_line_interface + + subroutine square_wave_initial_state(initial_state) + real(R_P), intent(inout) :: initial_state(1:) !< Initial state of primitive variables. + integer(I_P) :: i !< Space counter. + + BC_L = 'PER' + BC_R = 'PER' + do i=1, Ni + x(i) = Dx * i - 0.5_R_P * Dx + if (x(i) < 0.25_R_P) then + initial_state(i) = 0._R_P + elseif (0.25_R_P <= x(i) .and. x(i) < 0.75_R_P) then + initial_state(i) = 1._R_P + else + initial_state(i) = 0._R_P + endif + enddo + endsubroutine square_wave_initial_state + + subroutine save_time_serie(t, filename, finish) + !< Save time-serie results. + real(R_P), intent(in) :: t !< Current integration time. + character(*), intent(in), optional :: filename !< Output filename. + logical, intent(in), optional :: finish !< Flag for triggering the file closing. + integer(I_P), save :: tsfile !< File unit for saving time serie results. + integer(I_P) :: i !< Counter. + + if (time_serie) then + if (present(filename)) then + open(newunit=tsfile, file=filename) + endif + write(tsfile, '(A)')'VARIABLES = "x" "u"' + write(tsfile, '(A)')'ZONE T="'//str(n=t)//'"' + do i=1, Ni + write(tsfile, '(4'//'('//FR_P//',1X))')x(i), domain%u(i) + enddo + if (present(finish)) then + if (finish) close(tsfile) + endif + endif + endsubroutine save_time_serie +endprogram wenoof_test_linear_advection diff --git a/src/tests/ladvection/foodie_test_ladvection.f90 b/src/tests/ladvection/foodie_test_ladvection.f90 new file mode 100644 index 00000000..9bb912ec --- /dev/null +++ b/src/tests/ladvection/foodie_test_ladvection.f90 @@ -0,0 +1,660 @@ +!< Test FOODIE with the integration of 1D linear advection PDE. + +module foodie_test_ladvection_test +!< Oscillation test handler definition. + +use, intrinsic :: iso_fortran_env, only : stderr=>error_unit +use flap, only : command_line_interface +use foodie, only : foodie_integrator_class_names, & + foodie_integrator_factory, & + foodie_integrator_schemes, & + integrator_adams_bashforth, & + integrator_adams_bashforth_moulton, & + integrator_adams_moulton, & + integrator_back_df, & + integrator_euler_explicit, & + integrator_leapfrog, & + integrator_lmm_ssp, & + integrator_lmm_ssp_vss, & + integrator_ms_runge_kutta_ssp, & + integrator_object, & + integrator_runge_kutta_emd, & + integrator_runge_kutta_ls, & + integrator_runge_kutta_lssp, & + integrator_runge_kutta_ssp, & + is_available, is_class_available +use foodie_test_integrand_ladvection, only : integrand_ladvection +use penf, only : I_P, R_P, FR_P, str, strz + +implicit none +private +public :: ladvection_test + +type :: ladvection_test + !< Class to handle 1D linear advection test(s). + !< + !< Test is driven by the Command Line Interface (CLI) options. + !< + !< Test has only 1 public method `execute`: it executes test(s) accordingly to cli options. + private + type(command_line_interface) :: cli !< Command line interface handler. + integer(I_P) :: error=0 !< Error handler. + character(99) :: scheme='' !< Scheme used. + real(R_P) :: CFL !< CFL value. + logical :: is_fast=.false. !< Flag for activating fast schemes. + integer(I_P) :: implicit_iterations=0 !< Number of iterations (implicit solvers). + integer(I_P) :: stages=0 !< Number of stages. + integer(I_P) :: steps_max !< Maximum number of time steps. + real(R_P) :: final_time=0.0_R_P !< Final integration time. + character(99) :: w_scheme='' !< WENO Scheme used. + integer(I_P) :: weno_order=0 !< WENO reconstruction order. + real(R_P) :: weno_eps=0._R_P !< WENO epsilon value. + real(R_P) :: a=0._R_P !< Advection coefficient. + integer(I_P) :: Ni=0 !< Number of grid cells. + character(3) :: BC_L !< Left boundary condition type. + character(3) :: BC_R !< Right boundary condition type. + logical :: results=.false. !< Flag for activating results saving. + character(99) :: output='' !< Output files basename. + logical :: verbose=.false. !< Flag for activating verbose output. + type(integrand_ladvection) :: advection !< Advection handler. + contains + ! public methods + procedure, pass(self) :: execute !< Execute selected test(s). + ! private methods + procedure, pass(self), private :: initialize !< Initialize test: set Command Line Interface, parse it and check its validity. + procedure, pass(self), private :: test !< Perform the test. +endtype ladvection_test + +contains + ! public methods + subroutine execute(self) + !< Execute test(s). + class(ladvection_test), intent(inout) :: self !< Test. + character(99), allocatable :: integrator_schemes(:) !< Name of FOODIE integrator schemes. + integer(I_P) :: s !< Counter. + + call self%initialize + if (trim(adjustl(self%scheme))/='all') then + if (is_class_available(scheme=self%scheme)) then + integrator_schemes = foodie_integrator_schemes(class_name=self%scheme) + elseif (is_available(scheme=self%scheme)) then + integrator_schemes = [trim(adjustl(self%scheme))] + endif + else + integrator_schemes = foodie_integrator_schemes() + endif + do s=1, size(integrator_schemes, dim=1) + self%scheme = trim(integrator_schemes(s)) + call self%test(scheme=self%scheme) + enddo + endsubroutine execute + + ! private methods + subroutine initialize(self) + !< Initialize test: set Command Line Interface, parse it and check its validity. + class(ladvection_test), intent(inout) :: self !< Test. + + call set_cli + call parse_cli + contains + subroutine set_cli() + !< Set Command Line Interface. + + associate(cli => self%cli) + call cli%init(progname = 'foodie_test_ladvection', & + authors = 'Fortran-FOSS-Programmers', & + license = 'GNU GPLv3', & + description = 'Test FOODIE library on 1D linear advection PDE integration', & + examples = ["foodie_test_ladvection --scheme euler_explicit --save_results ", & + "foodie_test_ladvection --scheme all -r "]) + call cli%add(switch='--scheme', switch_ab='-s', help='integrator scheme used', required=.false., def='all', act='store') + call cli%add(switch='--cfl', help='CFL value', required=.false., act='store', def='0.8') + call cli%add(switch='--fast', help='activate fast solvers', required=.false., act='store_true', def='.false.') + call cli%add(switch='--iterations', help='iterations number for implicit schemes', required=.false., act='store', def='5') + call cli%add(switch='--stages', help='stages number', required=.false., def='2', act='store') + call cli%add(switch='--steps', help='number time steps performed', required=.false., act='store', def='100') + call cli%add(switch='--t_final', switch_ab='-tf', help='final integration time', required=.false., def='0', act='store') + call cli%add(switch='--w-scheme', help='WENO scheme', required=.false., act='store', def='reconstructor-JS', & + choices='reconstructor-JS,reconstructor-M-JS,reconstructor-M-Z,reconstructor-Z') + call cli%add(switch='--weno-order', help='WENO order', required=.false., act='store', def='1') + call cli%add(switch='--weno-eps', help='WENO epsilon parameter', required=.false., act='store', def='0.000001') + call cli%add(switch='-a', help='advection coefficient', required=.false., act='store', def='1.0') + call cli%add(switch='--Ni', help='number finite volumes used', required=.false., act='store', def='100') + call cli%add(switch='--save_results', switch_ab='-r',help='save result', required=.false., act='store_true', def='.false.') + call cli%add(switch='--output', help='output file basename', required=.false., act='store', def='foodie_test_ladvection') + call cli%add(switch='--verbose', help='Verbose output', required=.false., act='store_true', def='.false.') + endassociate + endsubroutine set_cli + + subroutine parse_cli() + !< Parse Command Line Interface and check its validity. + character(99), allocatable :: integrator_class_names(:) !< Name of FOODIE integrator classes. + character(99), allocatable :: integrator_schemes(:) !< Name of FOODIE integrator schemes. + real(R_P), allocatable :: initial_state(:) !< Initial integrand state. + integer(I_P) :: i !< Counter. + + call self%cli%parse(error=self%error) + call self%cli%get(switch='-s', val=self%scheme, error=self%error) ; if (self%error/=0) stop + call self%cli%get(switch='--cfl', val=self%CFL, error=error) ; if (error/=0) stop + call self%cli%get(switch='--fast', val=self%is_fast, error=self%error) ; if (self%error/=0) stop + call self%cli%get(switch='--iterations', val=self%implicit_iterations, error=self%error) ; if (self%error/=0) stop + call self%cli%get(switch='--stages', val=self%stages, error=self%error) ; if (self%error/=0) stop + call self%cli%get(switch='--steps', val=self%steps_max, error=error) ; if (error/=0) stop + call self%cli%get(switch='-tf', val=self%final_time, error=self%error) ; if (self%error/=0) stop + call self%cli%get(switch='--w-scheme', val=self%w_scheme, error=error) ; if (error/=0) stop + call self%cli%get(switch='--weno-order', val=self%weno_order, error=error) ; if (error/=0) stop + call self%cli%get(switch='--weno-eps', val=self%weno_eps, error=error) ; if (error/=0) stop + call self%cli%get(switch='-a', val=self%a, error=error) ; if (error/=0) stop + call self%cli%get(switch='--Ni', val=self%Ni, error=error) ; if (error/=0) stop + call self%cli%get(switch='-r', val=self%results, error=self%error) ; if (self%error/=0) stop + call self%cli%get(switch='--output', val=self%output, error=self%error) ; if (self%error/=0) stop + call self%cli%get(switch='--verbose', val=verbose, error=error) ; if (error/=0) stop + + if (self%final_time > 0._R_P) self%steps_max = 0 + + if (trim(adjustl(self%scheme)) /= 'all') then + if (.not.is_available(scheme=self%scheme)) then + integrator_class_names = foodie_integrator_class_names() + integrator_schemes = foodie_integrator_schemes() + print '(A)', 'Error: the scheme "'//trim(adjustl(self%scheme))//'" is unknown!' + print '(A)', 'Supported classes of schemes are:' + do i=1, size(integrator_class_names, dim=1) + print '(A)', ' '//trim(integrator_class_names(i)) + enddo + print '(A)', 'Supported schemes are:' + do i=1, size(integrator_schemes, dim=1) + print '(A)', ' '//trim(integrator_schemes(i)) + enddo + stop + endif + endif + + allocate(initial_state(1:self%Ni)) + call square_wave_initial_state(initial_state=initial_state, BC_L=self%BC_L, BC_R=self%BC_R, Dx=1._R_P / self%Ni) + call self%advection%initialize(Ni=Ni, Dx=1._R_P / self%Ni, & + BC_L=self%BC_L, BC_R=self%BC_R, & + initial_state=initial_state, & + w_scheme=self%w_scheme, & + a=self%a, & + weno_order=self%weno_order) + endsubroutine parse_cli + endsubroutine initialize + + subroutine test(self, scheme) + !< Perform the test. + class(ladvection_test), intent(in) :: self !< Test. + character(*), intent(in) :: scheme !< Selected scheme. + real(R_P), allocatable :: solution(:) !< Solution at each time step. + + print "(A)", trim(adjustl(scheme)) + + call integrate(scheme=scheme, & + CFL=self%CFL, & + advection=self%advection, & + final_step=self%final_step, & + final_time=self%final_time, & + iterations=self%implicit_iterations, & + stages=self%stages, & + is_fast=self%is_fast, & + solution=solution) + if (allocated(solution)) then + call save_results(results=self%results, & + output=self%output, & + scheme=trim(adjustl(scheme)), & + solution=solution) + endif + endsubroutine test + + ! non type bound procedures + subroutine check_scheme_has_fast_mode(scheme, integrator) + !< Check if a scheme support fast mode integrate. + character(*), intent(in) :: scheme !< Scheme name. + class(integrator_object), intent(in) :: integrator !< Integrator instance. + + if (.not.integrator%has_fast_mode()) then + write(stderr, '(A)') 'error: '//trim(adjustl(scheme))//' has not fast integrate mode!' + stop + endif + endsubroutine check_scheme_has_fast_mode + + subroutine integrate(scheme, advection, final_time, iterations, stages, is_fast, solution) + !< Integrate domain by means of the given scheme. + character(*), intent(in) :: scheme !< Selected scheme. + type(integrand_ladvection), intent(in) :: avection !< Advection setup. + real(R_P), intent(in) :: final_time !< Final integration time. + integer(I_P), intent(in) :: iterations !< Number of fixed point iterations. + integer(I_P), intent(in) :: stages !< Number of stages. + logical, intent(in) :: is_fast !< Activate fast mode integration. + real(R_P), allocatable, intent(out) :: solution(:) !< Solution at each time step, X-Y. + class(integrator_object), allocatable :: integrator !< The integrator. + type(integrator_runge_kutta_ssp) :: integrator_start !< The (auto) start integrator. + type(integrand_ladvection) :: domain !< Oscillation field. + type(integrand_ladvection), allocatable :: previous(:) !< Previous time steps solutions. + type(integrand_ladvection), allocatable :: stage(:) !< Runge-Kutta stages. + type(integrand_ladvection), allocatable :: stage_start(:) !< Runge-Kutta (autor) start stages. + type(integrand_ladvection) :: buffer !< Buffer oscillation field. + type(integrand_ladvection) :: filter !< Filter displacement. + real(R_P) :: time !< Time. + integer :: step !< Time steps counter. + integer :: step_offset !< Time steps counter offset for slicing previous data array. + real(R_P), allocatable :: Dts(:) !< Time steps for variable stepsize. + real(R_P) :: Dt !< Time step. + + domain = advection + + if (allocated(solution)) deallocate(solution) ; allocate(solution(1:domain%integrand_dimension())) + solution = 0.0_R_P + + call foodie_integrator_factory(scheme=scheme, integrator=integrator, stages=stages, tolerance=1e2_R_P) + if (is_fast) call check_scheme_has_fast_mode(scheme=trim(adjustl(scheme)), integrator=integrator) + + if (integrator%is_multistep()) then + allocate(previous(1:integrator%steps_number())) + call integrator_start%initialize(scheme='runge_kutta_ssp_stages_5_order_4') + allocate(stage_start(1:integrator_start%stages_number())) + endif + if (integrator%is_multistage()) allocate(stage(1:integrator%stages_number())) + + step = 0 + time = 0._R_P + select type(integrator) + type is(integrator_adams_bashforth) + do + step = step + 1 + Dt = domain%dt(steps_max=final_step, t_max=final_time, t=time, CFL=CFL) + if (integrator%steps_number() >= step) then + call integrator%integrate(U=domain, stage=stage_start, Dt=Dt, t=solution(0, step)) + previous(step) = domain + else + if (is_fast) then + call integrator%integrate_fast(U=domain, & + previous=previous, & + buffer=buffer, & + Dt=Dt, & + t=solution(0, step-integrator%steps_number():step-1)) + else + call integrator%integrate(U=domain, & + previous=previous, & + Dt=Dt, & + t=solution(0, step-integrator%steps_number():step-1)) + endif + endif + solution(0, step) = step * Dt + solution(1:, step) = domain%output() + enddo + last_step = step + + type is(integrator_adams_bashforth_moulton) + step = 0 + do while(solution(0, step) < final_time .and. step < ubound(solution, dim=2)) + step = step + 1 + if (integrator%steps_number() >= step) then + domain = [domain%exact_solution(t=step * Dt)] + previous(step) = domain + else + if (is_fast) then + call integrator%integrate_fast(U=domain, & + previous=previous, & + buffer=buffer, & + Dt=Dt, & + t=solution(0, step-integrator%steps_number():step-1)) + else + call integrator%integrate(U=domain, & + previous=previous, & + Dt=Dt, & + t=solution(0, step-integrator%steps_number():step-1)) + endif + endif + solution(0, step) = step * Dt + solution(1:, step) = domain%output() + enddo + last_step = step + + type is(integrator_adams_moulton) + if (allocated(previous)) deallocate(previous) ; allocate(previous(1:integrator%steps_number()+1)) + if (integrator%steps_number()==0) then + step_offset = 1 ! for 0 step-(a convention)-solver offset is 1 + else + step_offset = integrator%steps_number() ! for >0 step-solver offset is steps + endif + step = 0 + do while(solution(0, step) < final_time .and. step < ubound(solution, dim=2)) + step = step + 1 + if (integrator%steps_number() >= step) then + domain = [domain%exact_solution(t=step * Dt)] + previous(step) = domain + else + if (is_fast) then + if (iterations>1) then + call integrator%integrate_fast(U=domain, & + previous=previous, & + buffer=buffer, & + Dt=Dt, & + t=solution(0,step-step_offset:step-1), & + iterations=iterations) + else + call integrator%integrate_fast(U=domain, & + previous=previous, & + buffer=buffer, & + Dt=Dt, & + t=solution(0,step-step_offset:step-1)) + endif + else + if (iterations>1) then + call integrator%integrate(U=domain, & + previous=previous, & + Dt=Dt, & + t=solution(0,step-step_offset:step-1), & + iterations=iterations) + else + call integrator%integrate(U=domain, & + previous=previous, & + Dt=Dt, & + t=solution(0,step-step_offset:step-1)) + endif + endif + endif + solution(0, step) = step * Dt + solution(1:, step) = domain%output() + enddo + last_step = step + + type is(integrator_back_df) + step = 0 + do while(solution(0, step) < final_time .and. step < ubound(solution, dim=2)) + step = step + 1 + if (integrator%steps_number() >= step) then + domain = [domain%exact_solution(t=step * Dt)] + previous(step) = domain + else + if (is_fast) then + call integrator%integrate_fast(U=domain, & + previous=previous, & + buffer=buffer, & + Dt=Dt, & + t=solution(0, step-integrator%steps_number():step-1)) + else + call integrator%integrate(U=domain, & + previous=previous, & + Dt=Dt, & + t=solution(0, step-integrator%steps_number():step-1)) + endif + endif + solution(0, step) = step * Dt + solution(1:, step) = domain%output() + enddo + last_step = step + + type is(integrator_euler_explicit) + step = 0 + do while(solution(0, step) < final_time .and. step < ubound(solution, dim=2)) + step = step + 1 + if (is_fast) then + call integrator%integrate_fast(U=domain, buffer=buffer, Dt=Dt, t=solution(0, step)) + else + call integrator%integrate(U=domain, Dt=Dt, t=solution(0, step)) + endif + solution(0, step) = step * Dt + solution(1:, step) = domain%output() + enddo + last_step = step + type is(integrator_leapfrog) + step = 0 + do while(solution(0, step) < final_time .and. step < ubound(solution, dim=2)) + step = step + 1 + if (integrator%steps_number() >= step) then + domain = [domain%exact_solution(t=step * Dt)] + previous(step) = domain + else + if (index(scheme, 'raw') > 0 ) then + if (is_fast) then + call integrator%integrate_fast(U=domain, previous=previous, buffer=buffer, Dt=Dt, t=solution(0, step),filter=filter) + else + call integrator%integrate(U=domain, previous=previous, Dt=Dt, t=solution(0, step), filter=filter) + endif + else + if (is_fast) then + call integrator%integrate_fast(U=domain, previous=previous, buffer=buffer, Dt=Dt, t=solution(0, step)) + else + call integrator%integrate(U=domain, previous=previous, Dt=Dt, t=solution(0, step)) + endif + endif + endif + solution(0, step) = step * Dt + solution(1:, step) = domain%output() + enddo + last_step = step + + type is(integrator_lmm_ssp) + step = 0 + do while(solution(0, step) < final_time .and. step < ubound(solution, dim=2)) + step = step + 1 + if (integrator%steps_number() >= step) then + domain = [domain%exact_solution(t=step * Dt)] + previous(step) = domain + else + if (is_fast) then + call integrator%integrate_fast(U=domain, & + previous=previous, & + buffer=buffer, & + Dt=Dt, & + t=solution(0, step-integrator%steps_number():step-1)) + else + call integrator%integrate(U=domain, & + previous=previous, & + Dt=Dt, & + t=solution(0, step-integrator%steps_number():step-1)) + endif + endif + solution(0, step) = step * Dt + solution(1:, step) = domain%output() + enddo + last_step = step + + type is(integrator_lmm_ssp_vss) + if (allocated(Dts)) deallocate(Dts) ; allocate(Dts(1:integrator%steps_number())) ; Dts = Dt + step = 0 + do while(solution(0, step) < final_time .and. step < ubound(solution, dim=2)) + step = step + 1 + if (integrator%steps_number() >= step) then + domain = [domain%exact_solution(t=step * Dt)] + previous(step) = domain + else + if (is_fast) then + call integrator%integrate_fast(U=domain, & + previous=previous, & + buffer=buffer, & + Dt=Dts, & + t=solution(0, step-integrator%steps_number():step-1)) + else + call integrator%integrate(U=domain, & + previous=previous, & + Dt=Dts, & + t=solution(0, step-integrator%steps_number():step-1)) + endif + endif + solution(0, step) = step * Dt + solution(1:, step) = domain%output() + enddo + last_step = step + + type is(integrator_ms_runge_kutta_ssp) + step = 0 + do while(solution(0, step) < final_time .and. step < ubound(solution, dim=2)) + step = step + 1 + if (integrator%steps_number() >= step) then + domain = [domain%exact_solution(t=step * Dt)] + previous(step) = domain + else + if (is_fast) then + call integrator%integrate_fast(U=domain, & + previous=previous, & + stage=stage, & + buffer=buffer, & + Dt=Dt, & + t=solution(0, step-integrator%steps_number():step-1)) + else + call integrator%integrate(U=domain, & + previous=previous, & + stage=stage, & + Dt=Dt, & + t=solution(0, step-integrator%steps_number():step-1)) + endif + endif + solution(0, step) = step * Dt + solution(1:, step) = domain%output() + enddo + last_step = step + + type is(integrator_runge_kutta_emd) + step = 0 + do while(solution(0, step) < final_time .and. step < ubound(solution, dim=2)) + step = step + 1 + Dt_a = Dt + if (is_fast) then + call integrator%integrate_fast(U=domain, stage=stage, buffer=buffer, Dt=Dt_a, t=solution(0, step)) + else + call integrator%integrate(U=domain, stage=stage, Dt=Dt_a, t=solution(0, step)) + endif + solution(0, step) = step * Dt + solution(1:, step) = domain%output() + enddo + last_step = step + + type is(integrator_runge_kutta_ls) + if (allocated(stage)) deallocate(stage) ; allocate(stage(1:integrator%registers_number())) + step = 0 + do while(solution(0, step) < final_time .and. step < ubound(solution, dim=2)) + step = step + 1 + if (is_fast) then + call integrator%integrate_fast(U=domain, stage=stage, buffer=buffer, Dt=Dt, t=solution(0, step)) + else + call integrator%integrate(U=domain, stage=stage, Dt=Dt, t=solution(0, step)) + endif + solution(0, step) = step * Dt + solution(1:, step) = domain%output() + enddo + last_step = step + + type is(integrator_runge_kutta_lssp) + step = 0 + do while(solution(0, step) < final_time .and. step < ubound(solution, dim=2)) + step = step + 1 + if (is_fast) then + call integrator%integrate_fast(U=domain, stage=stage, buffer=buffer, Dt=Dt, t=solution(0, step)) + else + call integrator%integrate(U=domain, stage=stage, Dt=Dt, t=solution(0, step)) + endif + solution(0, step) = step * Dt + solution(1:, step) = domain%output() + enddo + last_step = step + + type is(integrator_runge_kutta_ssp) + step = 0 + do while(solution(0, step) < final_time .and. step < ubound(solution, dim=2)) + step = step + 1 + if (is_fast) then + call integrator%integrate_fast(U=domain, stage=stage, buffer=buffer, Dt=Dt, t=solution(0, step)) + else + call integrator%integrate(U=domain, stage=stage, Dt=Dt, t=solution(0, step)) + endif + solution(0, step) = step * Dt + solution(1:, step) = domain%output() + enddo + last_step = step + endselect + + error = 0._R_P + do step=0, last_step + domain = solution(1:, step) + error = error + (domain%output() - domain%exact_solution(t=solution(0, step))) ** 2 + enddo + error = sqrt(error) + endsubroutine integrate + + subroutine save_results(results, output, scheme, frequency, U0, save_exact_solution, solution) + !< Save results (and plots). + logical, intent(in) :: results !< Flag for activating results saving. + character(*), intent(in) :: output !< Output files basename coming from CLI. + character(*), intent(in) :: scheme !< Selected scheme: must be defined into *solvers*. + real(R_P), intent(in) :: frequency !< Oscillation frequency. + real(R_P), intent(in) :: U0(1:) !< Initial state. + logical, intent(in) :: save_exact_solution !< Flag for saving exact solution. + real(R_P), intent(in) :: solution(0:,0:) !< Solution at each time step. + character(len=:), allocatable :: title !< Output files title. + character(len=:), allocatable :: basename !< Output files basename. + integer(I_P) :: rawfile !< Raw file unit for saving results. + type(integrand_ladvection) :: oscillator !< Oscillation field. + integer(I_P) :: s !< Counter. + + basename = trim(adjustl(output))//'-'//trim(strz(ubound(solution, dim=2), 10))//'-time_steps-'//trim(adjustl(scheme)) + title = 'oscillation equations integration, solver='//trim(adjustl(scheme)) + if (results) then + open(newunit=rawfile, file=basename//'.dat') + write(rawfile, '(A)')'TITLE="'//title//'"' + write(rawfile, '(A)')'VARIABLES="t" "x" "y" "amplitude" "phase"' + write(rawfile, '(A)')'ZONE T="'//trim(adjustl(scheme))//'"' + do s=0, ubound(solution, dim=2) + write(rawfile, '(5('//FR_P//',1X))')solution(:, s), amplitude_phase(solution(1:2, s)) + enddo + close(rawfile) + endif + if (save_exact_solution) then + call oscillator%initialize(U0=U0, frequency=frequency) + basename = trim(adjustl(output))//'-'//trim(strz(ubound(solution, dim=2), 10))//'-time_steps-exact_solution' + title = 'linear constant coefficients equation integration, solver=exact solution' + open(newunit=rawfile, file=basename//'.dat') + write(rawfile, '(A)')'TITLE="'//title//'"' + write(rawfile, '(A)')'VARIABLES="t" "u"' + write(rawfile, '(A)')'ZONE T="exact solution"' + do s=0, ubound(solution, dim=2) + write(rawfile, '(5('//FR_P//',1X))')solution(0, s), oscillator%exact_solution(t=solution(0, s)), & + amplitude_phase(oscillator%exact_solution(t=solution(0, s))) + enddo + close(rawfile) + endif + contains + function amplitude_phase(sol) result(ap) + !< Compute amplitude and phase of the solution provided in X-Y domain. + real(R_P), intent(in) :: sol(1:) !< Solution in X-Y domain. + real(R_P) :: ap(1:2) !< Amplitude and phase solution. + + ap(1) = sqrt(sol(1)**2 + sol(2)**2) + ap(2) = atan(-sol(1) / sol(2)) + endfunction amplitude_phase + endsubroutine save_results + + subroutine square_wave_initial_state(initial_state, BC_L, BC_R, Dx) + real(R_P), intent(inout) :: initial_state(1:) !< Initial state of primitive variables. + character(*), intent(inout) :: BC_L !< Left boundary condition. + character(*), intent(inout) :: BC_R !< Rigth boundary condition. + real(R_P), intent(in) :: Dx !< Space step. + real(R_P) :: x(1:size(initial_state, dim=1)) !< Cell center x-abscissa values. + integer(I_P) :: i !< Space counter. + + BC_L = 'PER' + BC_R = 'PER' + do i=1, size(x, dim=1) + x(i) = Dx * i - 0.5_R_P * Dx + if (x(i) < 0.25_R_P) then + initial_state(i) = 0._R_P + elseif (0.25_R_P <= x(i) .and. x(i) < 0.75_R_P) then + initial_state(i) = 1._R_P + else + initial_state(i) = 0._R_P + endif + enddo + endsubroutine square_wave_initial_state +endmodule foodie_test_ladvection_test + +program foodie_test_ladvection +!< Test FOODIE with the integration of 1D linear advection PDE. + +use foodie_test_ladvection_test, only : ladvection_test + +implicit none +type(ladvection_test) :: test !< Linear advection test. + +call test%execute +endprogram foodie_test_ladvection diff --git a/src/tests/lcce/foodie_test_integrand_lcce.f90 b/src/tests/lcce/foodie_test_integrand_lcce.f90 index 66a0e1b2..ca935f00 100644 --- a/src/tests/lcce/foodie_test_integrand_lcce.f90 +++ b/src/tests/lcce/foodie_test_integrand_lcce.f90 @@ -6,7 +6,7 @@ module foodie_test_integrand_lcce !< abstract integrand type. use foodie, only : integrand_object -use penf, only : R_P, I_P +use penf, only : I_P, R_P implicit none private @@ -47,8 +47,8 @@ module foodie_test_integrand_lcce real(R_P) :: U0=0._R_P !< Integrand initial state. contains ! auxiliary methods - procedure, pass(self), public :: initialize !< Initialize integrand. procedure, pass(self), public :: exact_solution !< Return exact solution. + procedure, pass(self), public :: initialize !< Initialize integrand. procedure, pass(self), public :: output !< Extract integrand state field. ! public deferred methods procedure, pass(self), public :: integrand_dimension !< Return integrand dimension. @@ -82,18 +82,6 @@ module foodie_test_integrand_lcce contains ! auxiliary methods - pure subroutine initialize(self, a, b, U0) - !< Initialize integrand. - class(integrand_lcce), intent(inout) :: self !< Integrand. - real(R_P), intent(in) :: a, b !< Equation coefficients. - real(R_P), intent(in) :: U0 !< Initial state of the integrand. - - self%a = a - self%b = b - self%U = U0 - self%U0 = U0 - endsubroutine initialize - pure function exact_solution(self, t, t0) result(exact) !< Return exact solution. class(integrand_lcce), intent(in) :: self !< Integrand. @@ -106,6 +94,18 @@ pure function exact_solution(self, t, t0) result(exact) exact = (self%U0 + self%b / self%a) * exp(self%a * (t - t0_)) - self%b / self%a endfunction exact_solution + pure subroutine initialize(self, a, b, U0) + !< Initialize integrand. + class(integrand_lcce), intent(inout) :: self !< Integrand. + real(R_P), intent(in) :: a, b !< Equation coefficients. + real(R_P), intent(in) :: U0 !< Initial state of the integrand. + + self%a = a + self%b = b + self%U = U0 + self%U0 = U0 + endsubroutine initialize + pure function output(self) result(state) !< Extract integrand state field. class(integrand_lcce), intent(in) :: self !< Integrand. @@ -118,7 +118,7 @@ pure function output(self) result(state) pure function integrand_dimension(self) !< return integrand dimension. class(integrand_lcce), intent(in) :: self !< integrand. - integer(i_p) :: integrand_dimension !< integrand dimension. + integer(I_P) :: integrand_dimension !< integrand dimension. integrand_dimension = 1 endfunction integrand_dimension diff --git a/src/tests/oscillation/foodie_test_integrand_oscillation.f90 b/src/tests/oscillation/foodie_test_integrand_oscillation.f90 index a7d6820b..8bb2e915 100644 --- a/src/tests/oscillation/foodie_test_integrand_oscillation.f90 +++ b/src/tests/oscillation/foodie_test_integrand_oscillation.f90 @@ -47,8 +47,8 @@ module foodie_test_integrand_oscillation real(R_P) :: U0(1:2)=[0._R_P, 0._R_P] !< Initial state. contains ! auxiliary methods - procedure, pass(self), public :: initialize !< Initialize integrand. procedure, pass(self), public :: exact_solution !< Return exact solution. + procedure, pass(self), public :: initialize !< Initialize integrand. procedure, pass(self), public :: output !< Extract integrand state field. ! public deferred methods procedure, pass(self), public :: integrand_dimension !< Return integrand dimension. @@ -82,6 +82,16 @@ module foodie_test_integrand_oscillation contains ! auxiliary methods + pure function exact_solution(self, t) result(exact) + !< Return exact solution. + class(integrand_oscillation), intent(in) :: self !< Integrand. + real(R_P), intent(in) :: t !< Time. + real(R_P) :: exact(1:2) !< Exact solution. + + exact(1) = self%U0(1) * cos(self%f * t) - self%U0(2) * sin(self%f * t) + exact(2) = self%U0(1) * sin(self%f * t) + self%U0(2) * cos(self%f * t) + endfunction exact_solution + pure subroutine initialize(self, U0, frequency) !< Initialize integrand. class(integrand_oscillation), intent(inout) :: self !< Integrand. @@ -93,16 +103,6 @@ pure subroutine initialize(self, U0, frequency) self%U0 = U0 endsubroutine initialize - pure function exact_solution(self, t) result(exact) - !< Return exact solution. - class(integrand_oscillation), intent(in) :: self !< Integrand. - real(R_P), intent(in) :: t !< Time. - real(R_P) :: exact(1:2) !< Exact solution. - - exact(1) = self%U0(1) * cos(self%f * t) - self%U0(2) * sin(self%f * t) - exact(2) = self%U0(1) * sin(self%f * t) + self%U0(2) * cos(self%f * t) - endfunction exact_solution - pure function output(self) result(state) !< Extract integrand state field. class(integrand_oscillation), intent(in) :: self !< Integrand. @@ -115,7 +115,7 @@ pure function output(self) result(state) pure function integrand_dimension(self) !< return integrand dimension. class(integrand_oscillation), intent(in) :: self !< integrand. - integer(i_p) :: integrand_dimension !< integrand dimension. + integer(I_P) :: integrand_dimension !< integrand dimension. integrand_dimension = size(self%U, dim=1) endfunction integrand_dimension From 4a11af9637c860b12f109bf5c85cda9c8cd97d7c Mon Sep 17 00:00:00 2001 From: Stefano Zaghi Date: Sat, 13 May 2017 07:26:56 +0200 Subject: [PATCH 02/25] improve ladvection --- .../foodie_test_integrand_ladvection.f90 | 74 ++ .../ladvection/foodie_test_ladvection.f90 | 686 ++++++++---------- 2 files changed, 374 insertions(+), 386 deletions(-) diff --git a/src/tests/ladvection/foodie_test_integrand_ladvection.f90 b/src/tests/ladvection/foodie_test_integrand_ladvection.f90 index 327b4ea5..254b3384 100644 --- a/src/tests/ladvection/foodie_test_integrand_ladvection.f90 +++ b/src/tests/ladvection/foodie_test_integrand_ladvection.f90 @@ -464,6 +464,80 @@ subroutine reconstruct_interfaces(self, conservative, r_conservative) endsubroutine reconstruct_interfaces endmodule foodie_test_integrand_ladvection + subroutine save_results(results, output, scheme, frequency, U0, save_exact_solution, solution) + !< Save results (and plots). + logical, intent(in) :: results !< Flag for activating results saving. + character(*), intent(in) :: output !< Output files basename coming from CLI. + character(*), intent(in) :: scheme !< Selected scheme: must be defined into *solvers*. + real(R_P), intent(in) :: frequency !< Oscillation frequency. + real(R_P), intent(in) :: U0(1:) !< Initial state. + logical, intent(in) :: save_exact_solution !< Flag for saving exact solution. + real(R_P), intent(in) :: solution(0:,0:) !< Solution at each time step. + character(len=:), allocatable :: title !< Output files title. + character(len=:), allocatable :: basename !< Output files basename. + integer(I_P) :: rawfile !< Raw file unit for saving results. + type(integrand_ladvection) :: oscillator !< Oscillation field. + integer(I_P) :: s !< Counter. + + basename = trim(adjustl(output))//'-'//trim(strz(ubound(solution, dim=2), 10))//'-time_steps-'//trim(adjustl(scheme)) + title = 'oscillation equations integration, solver='//trim(adjustl(scheme)) + if (results) then + open(newunit=rawfile, file=basename//'.dat') + write(rawfile, '(A)')'TITLE="'//title//'"' + write(rawfile, '(A)')'VARIABLES="t" "x" "y" "amplitude" "phase"' + write(rawfile, '(A)')'ZONE T="'//trim(adjustl(scheme))//'"' + do s=0, ubound(solution, dim=2) + write(rawfile, '(5('//FR_P//',1X))')solution(:, s), amplitude_phase(solution(1:2, s)) + enddo + close(rawfile) + endif + if (save_exact_solution) then + call oscillator%initialize(U0=U0, frequency=frequency) + basename = trim(adjustl(output))//'-'//trim(strz(ubound(solution, dim=2), 10))//'-time_steps-exact_solution' + title = 'linear constant coefficients equation integration, solver=exact solution' + open(newunit=rawfile, file=basename//'.dat') + write(rawfile, '(A)')'TITLE="'//title//'"' + write(rawfile, '(A)')'VARIABLES="t" "u"' + write(rawfile, '(A)')'ZONE T="exact solution"' + do s=0, ubound(solution, dim=2) + write(rawfile, '(5('//FR_P//',1X))')solution(0, s), oscillator%exact_solution(t=solution(0, s)), & + amplitude_phase(oscillator%exact_solution(t=solution(0, s))) + enddo + close(rawfile) + endif + contains + function amplitude_phase(sol) result(ap) + !< Compute amplitude and phase of the solution provided in X-Y domain. + real(R_P), intent(in) :: sol(1:) !< Solution in X-Y domain. + real(R_P) :: ap(1:2) !< Amplitude and phase solution. + + ap(1) = sqrt(sol(1)**2 + sol(2)**2) + ap(2) = atan(-sol(1) / sol(2)) + endfunction amplitude_phase + endsubroutine save_results + + subroutine square_wave_initial_state(initial_state, BC_L, BC_R, Dx) + real(R_P), intent(inout) :: initial_state(1:) !< Initial state of primitive variables. + character(*), intent(inout) :: BC_L !< Left boundary condition. + character(*), intent(inout) :: BC_R !< Rigth boundary condition. + real(R_P), intent(in) :: Dx !< Space step. + real(R_P) :: x(1:size(initial_state, dim=1)) !< Cell center x-abscissa values. + integer(I_P) :: i !< Space counter. + + BC_L = 'PER' + BC_R = 'PER' + do i=1, size(x, dim=1) + x(i) = Dx * i - 0.5_R_P * Dx + if (x(i) < 0.25_R_P) then + initial_state(i) = 0._R_P + elseif (0.25_R_P <= x(i) .and. x(i) < 0.75_R_P) then + initial_state(i) = 1._R_P + else + initial_state(i) = 0._R_P + endif + enddo + endsubroutine square_wave_initial_state + program wenoof_test_linear_advection !< Define [[integrand_ladvection]], the 1D linear advection PDE test field that is a concrete extension of the !< abstract integrand type. diff --git a/src/tests/ladvection/foodie_test_ladvection.f90 b/src/tests/ladvection/foodie_test_ladvection.f90 index 9bb912ec..7a56139b 100644 --- a/src/tests/ladvection/foodie_test_ladvection.f90 +++ b/src/tests/ladvection/foodie_test_ladvection.f90 @@ -53,16 +53,15 @@ module foodie_test_ladvection_test integer(I_P) :: Ni=0 !< Number of grid cells. character(3) :: BC_L !< Left boundary condition type. character(3) :: BC_R !< Right boundary condition type. - logical :: results=.false. !< Flag for activating results saving. + logical :: save_results=.false. !< Flag for activating results saving. character(99) :: output='' !< Output files basename. logical :: verbose=.false. !< Flag for activating verbose output. - type(integrand_ladvection) :: advection !< Advection handler. + type(integrand_ladvection) :: integrand_0 !< Initial conditions. contains ! public methods procedure, pass(self) :: execute !< Execute selected test(s). ! private methods procedure, pass(self), private :: initialize !< Initialize test: set Command Line Interface, parse it and check its validity. - procedure, pass(self), private :: test !< Perform the test. endtype ladvection_test contains @@ -76,16 +75,25 @@ subroutine execute(self) call self%initialize if (trim(adjustl(self%scheme))/='all') then if (is_class_available(scheme=self%scheme)) then - integrator_schemes = foodie_integrator_schemes(class_name=self%scheme) + integrator_schemes = foodie_integrator_schemes(class_name=self%scheme) elseif (is_available(scheme=self%scheme)) then - integrator_schemes = [trim(adjustl(self%scheme))] + integrator_schemes = [trim(adjustl(self%scheme))] endif else - integrator_schemes = foodie_integrator_schemes() + integrator_schemes = foodie_integrator_schemes() endif do s=1, size(integrator_schemes, dim=1) - self%scheme = trim(integrator_schemes(s)) - call self%test(scheme=self%scheme) + call integrate(scheme=trim(integrator_schemes(s)), & + CFL=self%CFL, & + integrand_0=integrand_0, & + final_step=self%final_step, & + final_time=self%final_time, & + iterations=self%implicit_iterations, & + stages=self%stages, & + is_fast=self%is_fast, & + save_results=self%save_results, & + save_frequency=self%save_frequency, & + output_base_name=self%output) enddo endsubroutine execute @@ -180,31 +188,6 @@ subroutine parse_cli() endsubroutine parse_cli endsubroutine initialize - subroutine test(self, scheme) - !< Perform the test. - class(ladvection_test), intent(in) :: self !< Test. - character(*), intent(in) :: scheme !< Selected scheme. - real(R_P), allocatable :: solution(:) !< Solution at each time step. - - print "(A)", trim(adjustl(scheme)) - - call integrate(scheme=scheme, & - CFL=self%CFL, & - advection=self%advection, & - final_step=self%final_step, & - final_time=self%final_time, & - iterations=self%implicit_iterations, & - stages=self%stages, & - is_fast=self%is_fast, & - solution=solution) - if (allocated(solution)) then - call save_results(results=self%results, & - output=self%output, & - scheme=trim(adjustl(scheme)), & - solution=solution) - endif - endsubroutine test - ! non type bound procedures subroutine check_scheme_has_fast_mode(scheme, integrator) !< Check if a scheme support fast mode integrate. @@ -217,33 +200,38 @@ subroutine check_scheme_has_fast_mode(scheme, integrator) endif endsubroutine check_scheme_has_fast_mode - subroutine integrate(scheme, advection, final_time, iterations, stages, is_fast, solution) - !< Integrate domain by means of the given scheme. + subroutine integrate(scheme, integrand_0, CFL, final_step, final_time, iterations, stages, is_fast, & + save_results, save_frequency, output_base_name) + !< Integrate integrand by means of the given scheme. character(*), intent(in) :: scheme !< Selected scheme. - type(integrand_ladvection), intent(in) :: avection !< Advection setup. + type(integrand_ladvection), intent(in) :: integrand_0 !< Initial conditions. + real(R_P), intent(in) :: CFL !< CFL stability coefficient. + integer(I_P), intent(in) :: final_step !< Final integration step. real(R_P), intent(in) :: final_time !< Final integration time. integer(I_P), intent(in) :: iterations !< Number of fixed point iterations. integer(I_P), intent(in) :: stages !< Number of stages. logical, intent(in) :: is_fast !< Activate fast mode integration. - real(R_P), allocatable, intent(out) :: solution(:) !< Solution at each time step, X-Y. + logical, intent(in) :: save_results !< Save results. + integer(I_P), intent(in) :: save_frequency !< Save frequency as steps multiple. + character(*), intent(in) :: output_base_name !< Base name of output results file. class(integrator_object), allocatable :: integrator !< The integrator. type(integrator_runge_kutta_ssp) :: integrator_start !< The (auto) start integrator. - type(integrand_ladvection) :: domain !< Oscillation field. + type(integrand_ladvection) :: integrand !< Integrand. type(integrand_ladvection), allocatable :: previous(:) !< Previous time steps solutions. type(integrand_ladvection), allocatable :: stage(:) !< Runge-Kutta stages. type(integrand_ladvection), allocatable :: stage_start(:) !< Runge-Kutta (autor) start stages. type(integrand_ladvection) :: buffer !< Buffer oscillation field. type(integrand_ladvection) :: filter !< Filter displacement. - real(R_P) :: time !< Time. + real(R_P), allocatable :: time(:) !< Time. + real(R_P), allocatable :: Dt(:) !< Time steps. + real(R_P) :: Dt_a !< Autoadptive time step. integer :: step !< Time steps counter. integer :: step_offset !< Time steps counter offset for slicing previous data array. - real(R_P), allocatable :: Dts(:) !< Time steps for variable stepsize. - real(R_P) :: Dt !< Time step. + character(len=:), allocatable :: output_file_name !< File name of output results file. - domain = advection + integrand = integrand_0 - if (allocated(solution)) deallocate(solution) ; allocate(solution(1:domain%integrand_dimension())) - solution = 0.0_R_P + output_file_name = trim(adjustl(output_base_name))//'-'//trim(adjustl(scheme))//'-'//strz(n=integrand%Ni, zero_pad=10)//'.dat' call foodie_integrator_factory(scheme=scheme, integrator=integrator, stages=stages, tolerance=1e2_R_P) if (is_fast) call check_scheme_has_fast_mode(scheme=trim(adjustl(scheme)), integrator=integrator) @@ -252,400 +240,326 @@ subroutine integrate(scheme, advection, final_time, iterations, stages, is_fast, allocate(previous(1:integrator%steps_number())) call integrator_start%initialize(scheme='runge_kutta_ssp_stages_5_order_4') allocate(stage_start(1:integrator_start%stages_number())) + allocate(time(0:1:integrator%steps_number())) + allocate(Dt(1:1:integrator%steps_number())) endif if (integrator%is_multistage()) allocate(stage(1:integrator%stages_number())) step = 0 time = 0._R_P + Dt = 0._R_P + if (save_results) call integrand%export_tecplot(file_name=output_file_name, t=time(0)) select type(integrator) type is(integrator_adams_bashforth) do - step = step + 1 - Dt = domain%dt(steps_max=final_step, t_max=final_time, t=time, CFL=CFL) - if (integrator%steps_number() >= step) then - call integrator%integrate(U=domain, stage=stage_start, Dt=Dt, t=solution(0, step)) - previous(step) = domain - else - if (is_fast) then - call integrator%integrate_fast(U=domain, & - previous=previous, & - buffer=buffer, & - Dt=Dt, & - t=solution(0, step-integrator%steps_number():step-1)) - else - call integrator%integrate(U=domain, & - previous=previous, & - Dt=Dt, & - t=solution(0, step-integrator%steps_number():step-1)) - endif - endif - solution(0, step) = step * Dt - solution(1:, step) = domain%output() + step = step + 1 + Dt(step) = integrand%dt(final_step=final_step, final_time=final_time, t=time(step), CFL=CFL) + if (integrator%steps_number() >= step) then + call integrator_start%integrate(U=integrand, stage=stage_start, Dt=Dt(step), t=time(step)) + previous(step) = integrand + else + if (is_fast) then + call integrator%integrate_fast(U=integrand, & + previous=previous, & + buffer=buffer, & + Dt=Dt(step), & + t=time(step-integrator%steps_number():step-1)) + else + call integrator%integrate(U=integrand, & + previous=previous, & + Dt=Dt(step), & + t=time(step-integrator%steps_number():step-1)) + endif + endif + time(step) = time(step-1) + Dt(step) + if (save_results.and.mod(step, save_frequency)==0) call integrand%export_tecplot(file_name=output_file_name, t=time(step)) + if ((time(step) == final_time).or.(step == final_step)) exit enddo - last_step = step type is(integrator_adams_bashforth_moulton) - step = 0 - do while(solution(0, step) < final_time .and. step < ubound(solution, dim=2)) - step = step + 1 - if (integrator%steps_number() >= step) then - domain = [domain%exact_solution(t=step * Dt)] - previous(step) = domain - else - if (is_fast) then - call integrator%integrate_fast(U=domain, & - previous=previous, & - buffer=buffer, & - Dt=Dt, & - t=solution(0, step-integrator%steps_number():step-1)) - else - call integrator%integrate(U=domain, & - previous=previous, & - Dt=Dt, & - t=solution(0, step-integrator%steps_number():step-1)) - endif - endif - solution(0, step) = step * Dt - solution(1:, step) = domain%output() + do + step = step + 1 + Dt(step) = integrand%dt(final_step=final_step, final_time=final_time, t=time(step), CFL=CFL) + if (integrator%steps_number() >= step) then + call integrator_start%integrate(U=integrand, stage=stage_start, Dt=Dt(step), t=time(step)) + previous(step) = integrand + else + if (is_fast) then + call integrator%integrate_fast(U=integrand, & + previous=previous, & + buffer=buffer, & + Dt=Dt(step), & + t=time(step-integrator%steps_number():step-1)) + else + call integrator%integrate(U=integrand, & + previous=previous, & + Dt=Dt(step), & + t=time(step-integrator%steps_number():step-1)) + endif + endif + time(step) = time(step-1) + Dt(step) + if (save_results.and.mod(step, save_frequency)==0) call integrand%export_tecplot(file_name=output_file_name, t=time(step)) + if ((time(step) == final_time).or.(step == final_step)) exit enddo - last_step = step type is(integrator_adams_moulton) if (allocated(previous)) deallocate(previous) ; allocate(previous(1:integrator%steps_number()+1)) if (integrator%steps_number()==0) then - step_offset = 1 ! for 0 step-(a convention)-solver offset is 1 + step_offset = 1 ! for 0 step-(a convention)-solver offset is 1 else - step_offset = integrator%steps_number() ! for >0 step-solver offset is steps + step_offset = integrator%steps_number() ! for >0 step-solver offset is steps endif - step = 0 - do while(solution(0, step) < final_time .and. step < ubound(solution, dim=2)) - step = step + 1 - if (integrator%steps_number() >= step) then - domain = [domain%exact_solution(t=step * Dt)] - previous(step) = domain - else - if (is_fast) then - if (iterations>1) then - call integrator%integrate_fast(U=domain, & - previous=previous, & - buffer=buffer, & - Dt=Dt, & - t=solution(0,step-step_offset:step-1), & - iterations=iterations) - else - call integrator%integrate_fast(U=domain, & - previous=previous, & - buffer=buffer, & - Dt=Dt, & - t=solution(0,step-step_offset:step-1)) - endif - else - if (iterations>1) then - call integrator%integrate(U=domain, & - previous=previous, & - Dt=Dt, & - t=solution(0,step-step_offset:step-1), & - iterations=iterations) - else - call integrator%integrate(U=domain, & - previous=previous, & - Dt=Dt, & - t=solution(0,step-step_offset:step-1)) - endif - endif - endif - solution(0, step) = step * Dt - solution(1:, step) = domain%output() + do + step = step + 1 + Dt(step) = integrand%dt(final_step=final_step, final_time=final_time, t=time(step), CFL=CFL) + if (integrator%steps_number() >= step) then + call integrator_start%integrate(U=integrand, stage=stage_start, Dt=Dt(step), t=time(step)) + previous(step) = integrand + else + if (is_fast) then + if (iterations>1) then + call integrator%integrate_fast(U=integrand, & + previous=previous, & + buffer=buffer, & + Dt=Dt(step), & + t=time(step-step_offset:step-1), & + iterations=iterations) + else + call integrator%integrate_fast(U=integrand, & + previous=previous, & + buffer=buffer, & + Dt=Dt(step), & + t=time(step-step_offset:step-1)) + endif + else + if (iterations>1) then + call integrator%integrate(U=integrand, & + previous=previous, & + Dt=Dt(step), & + t=time(step-step_offset:step-1), & + iterations=iterations) + else + call integrator%integrate(U=integrand, & + previous=previous, & + Dt=Dt(step), & + t=time(step-step_offset:step-1)) + endif + endif + endif + time(step) = time(step-1) + Dt(step) + if (save_results.and.mod(step, save_frequency)==0) call integrand%export_tecplot(file_name=output_file_name, t=time(step)) + if ((time(step) == final_time).or.(step == final_step)) exit enddo - last_step = step type is(integrator_back_df) - step = 0 - do while(solution(0, step) < final_time .and. step < ubound(solution, dim=2)) - step = step + 1 - if (integrator%steps_number() >= step) then - domain = [domain%exact_solution(t=step * Dt)] - previous(step) = domain - else - if (is_fast) then - call integrator%integrate_fast(U=domain, & - previous=previous, & - buffer=buffer, & - Dt=Dt, & - t=solution(0, step-integrator%steps_number():step-1)) - else - call integrator%integrate(U=domain, & - previous=previous, & - Dt=Dt, & - t=solution(0, step-integrator%steps_number():step-1)) - endif - endif - solution(0, step) = step * Dt - solution(1:, step) = domain%output() + do + step = step + 1 + Dt(step) = integrand%dt(final_step=final_step, final_time=final_time, t=time(step), CFL=CFL) + if (integrator%steps_number() >= step) then + call integrator_start%integrate(U=integrand, stage=stage_start, Dt=Dt(step), t=time(step)) + previous(step) = integrand + else + if (is_fast) then + call integrator%integrate_fast(U=integrand, & + previous=previous, & + buffer=buffer, & + Dt=Dt(step), & + t=time(step-integrator%steps_number():step-1)) + else + call integrator%integrate(U=integrand, & + previous=previous, & + Dt=Dt(step), & + t=time(step-integrator%steps_number():step-1)) + endif + endif + time(step) = time(step-1) + Dt(step) + if (save_results.and.mod(step, save_frequency)==0) call integrand%export_tecplot(file_name=output_file_name, t=time(step)) + if ((time(step) == final_time).or.(step == final_step)) exit enddo - last_step = step type is(integrator_euler_explicit) - step = 0 - do while(solution(0, step) < final_time .and. step < ubound(solution, dim=2)) - step = step + 1 - if (is_fast) then - call integrator%integrate_fast(U=domain, buffer=buffer, Dt=Dt, t=solution(0, step)) - else - call integrator%integrate(U=domain, Dt=Dt, t=solution(0, step)) - endif - solution(0, step) = step * Dt - solution(1:, step) = domain%output() + do + step = step + 1 + Dt(step) = integrand%dt(final_step=final_step, final_time=final_time, t=time(step), CFL=CFL) + if (is_fast) then + call integrator%integrate_fast(U=integrand, buffer=buffer, Dt=Dt(step), t=time(step)) + else + call integrator%integrate(U=integrand, Dt=Dt(step), t=time(step)) + endif + time(step) = time(step-1) + Dt(step) + if (save_results.and.mod(step, save_frequency)==0) call integrand%export_tecplot(file_name=output_file_name, t=time(step)) + if ((time(step) == final_time).or.(step == final_step)) exit enddo - last_step = step + type is(integrator_leapfrog) - step = 0 - do while(solution(0, step) < final_time .and. step < ubound(solution, dim=2)) - step = step + 1 - if (integrator%steps_number() >= step) then - domain = [domain%exact_solution(t=step * Dt)] - previous(step) = domain - else - if (index(scheme, 'raw') > 0 ) then - if (is_fast) then - call integrator%integrate_fast(U=domain, previous=previous, buffer=buffer, Dt=Dt, t=solution(0, step),filter=filter) - else - call integrator%integrate(U=domain, previous=previous, Dt=Dt, t=solution(0, step), filter=filter) - endif - else - if (is_fast) then - call integrator%integrate_fast(U=domain, previous=previous, buffer=buffer, Dt=Dt, t=solution(0, step)) - else - call integrator%integrate(U=domain, previous=previous, Dt=Dt, t=solution(0, step)) - endif - endif - endif - solution(0, step) = step * Dt - solution(1:, step) = domain%output() + do + step = step + 1 + Dt(step) = integrand%dt(final_step=final_step, final_time=final_time, t=time(step), CFL=CFL) + if (integrator%steps_number() >= step) then + call integrator_start%integrate(U=integrand, stage=stage_start, Dt=Dt(step), t=time(step)) + previous(step) = integrand + else + if (index(scheme, 'raw') > 0 ) then + if (is_fast) then + call integrator%integrate_fast(U=integrand, previous=previous, buffer=buffer, Dt=Dt(step), & + t=time(step), filter=filter) + else + call integrator%integrate(U=integrand, previous=previous, Dt=Dt(step), t=time(step), filter=filter) + endif + else + if (is_fast) then + call integrator%integrate_fast(U=integrand, previous=previous, buffer=buffer, Dt=Dt(step), t=time(step)) + else + call integrator%integrate(U=integrand, previous=previous, Dt=Dt(step), t=time(step)) + endif + endif + endif + time(step) = time(step-1) + Dt(step) + if (save_results.and.mod(step, save_frequency)==0) call integrand%export_tecplot(file_name=output_file_name, t=time(step)) + if ((time(step) == final_time).or.(step == final_step)) exit enddo - last_step = step type is(integrator_lmm_ssp) - step = 0 - do while(solution(0, step) < final_time .and. step < ubound(solution, dim=2)) - step = step + 1 - if (integrator%steps_number() >= step) then - domain = [domain%exact_solution(t=step * Dt)] - previous(step) = domain - else - if (is_fast) then - call integrator%integrate_fast(U=domain, & - previous=previous, & - buffer=buffer, & - Dt=Dt, & - t=solution(0, step-integrator%steps_number():step-1)) - else - call integrator%integrate(U=domain, & - previous=previous, & - Dt=Dt, & - t=solution(0, step-integrator%steps_number():step-1)) - endif - endif - solution(0, step) = step * Dt - solution(1:, step) = domain%output() + do + step = step + 1 + Dt(step) = integrand%dt(final_step=final_step, final_time=final_time, t=time(step), CFL=CFL) + if (integrator%steps_number() >= step) then + call integrator_start%integrate(U=integrand, stage=stage_start, Dt=Dt(step), t=time(step)) + previous(step) = integrand + else + if (is_fast) then + call integrator%integrate_fast(U=integrand, & + previous=previous, & + buffer=buffer, & + Dt=Dt(step), & + t=time(step-integrator%steps_number():step-1)) + else + call integrator%integrate(U=integrand, & + previous=previous, & + Dt=Dt(step), & + t=time(step-integrator%steps_number():step-1)) + endif + endif + time(step) = time(step-1) + Dt(step) + if (save_results.and.mod(step, save_frequency)==0) call integrand%export_tecplot(file_name=output_file_name, t=time(step)) + if ((time(step) == final_time).or.(step == final_step)) exit enddo - last_step = step type is(integrator_lmm_ssp_vss) - if (allocated(Dts)) deallocate(Dts) ; allocate(Dts(1:integrator%steps_number())) ; Dts = Dt - step = 0 - do while(solution(0, step) < final_time .and. step < ubound(solution, dim=2)) - step = step + 1 - if (integrator%steps_number() >= step) then - domain = [domain%exact_solution(t=step * Dt)] - previous(step) = domain - else - if (is_fast) then - call integrator%integrate_fast(U=domain, & - previous=previous, & - buffer=buffer, & - Dt=Dts, & - t=solution(0, step-integrator%steps_number():step-1)) - else - call integrator%integrate(U=domain, & - previous=previous, & - Dt=Dts, & - t=solution(0, step-integrator%steps_number():step-1)) - endif - endif - solution(0, step) = step * Dt - solution(1:, step) = domain%output() + do + step = step + 1 + Dt(step) = integrand%dt(final_step=final_step, final_time=final_time, t=time(step), CFL=CFL) + if (integrator%steps_number() >= step) then + call integrator_start%integrate(U=integrand, stage=stage_start, Dt=Dt(step), t=time(step)) + previous(step) = integrand + else + if (is_fast) then + call integrator%integrate_fast(U=integrand, & + previous=previous, & + buffer=buffer, & + Dt=Dt(step-integrator%steps_number():step-1), & + t=time(step-integrator%steps_number():step-1)) + else + call integrator%integrate(U=integrand, & + previous=previous, & + Dt=Dt(step-integrator%steps_number():step-1), & + t=time(step-integrator%steps_number():step-1)) + endif + endif + time(step) = time(step-1) + Dt(step) + if (save_results.and.mod(step, save_frequency)==0) call integrand%export_tecplot(file_name=output_file_name, t=time(step)) + if ((time(step) == final_time).or.(step == final_step)) exit enddo - last_step = step type is(integrator_ms_runge_kutta_ssp) - step = 0 - do while(solution(0, step) < final_time .and. step < ubound(solution, dim=2)) - step = step + 1 - if (integrator%steps_number() >= step) then - domain = [domain%exact_solution(t=step * Dt)] - previous(step) = domain - else - if (is_fast) then - call integrator%integrate_fast(U=domain, & - previous=previous, & - stage=stage, & - buffer=buffer, & - Dt=Dt, & - t=solution(0, step-integrator%steps_number():step-1)) - else - call integrator%integrate(U=domain, & - previous=previous, & - stage=stage, & - Dt=Dt, & - t=solution(0, step-integrator%steps_number():step-1)) - endif - endif - solution(0, step) = step * Dt - solution(1:, step) = domain%output() + do + step = step + 1 + Dt(step) = integrand%dt(final_step=final_step, final_time=final_time, t=time(step), CFL=CFL) + if (integrator%steps_number() >= step) then + call integrator_start%integrate(U=integrand, stage=stage_start, Dt=Dt(step), t=time(step)) + previous(step) = integrand + else + if (is_fast) then + call integrator%integrate_fast(U=integrand, & + previous=previous, & + stage=stage, & + buffer=buffer, & + Dt=Dt(step), & + t=time(step-integrator%steps_number():step-1)) + else + call integrator%integrate(U=integrand, & + previous=previous, & + stage=stage, & + Dt=Dt(step), & + t=time(step-integrator%steps_number():step-1)) + endif + endif + time(step) = time(step-1) + Dt(step) + if (save_results.and.mod(step, save_frequency)==0) call integrand%export_tecplot(file_name=output_file_name, t=time(step)) + if ((time(step) == final_time).or.(step == final_step)) exit enddo - last_step = step type is(integrator_runge_kutta_emd) - step = 0 - do while(solution(0, step) < final_time .and. step < ubound(solution, dim=2)) - step = step + 1 - Dt_a = Dt - if (is_fast) then - call integrator%integrate_fast(U=domain, stage=stage, buffer=buffer, Dt=Dt_a, t=solution(0, step)) - else - call integrator%integrate(U=domain, stage=stage, Dt=Dt_a, t=solution(0, step)) - endif - solution(0, step) = step * Dt - solution(1:, step) = domain%output() + do + step = step + 1 + Dt(step) = integrand%dt(final_step=final_step, final_time=final_time, t=time(step), CFL=CFL) + Dt_a = Dt(step) + if (is_fast) then + call integrator%integrate_fast(U=integrand, stage=stage, buffer=buffer, Dt=Dt_, t=time(step)) + else + call integrator%integrate(U=integrand, stage=stage, Dt=Dt_a, t=time(step)) + endif + time(step) = time(step-1) + Dt(step) + if (save_results.and.mod(step, save_frequency)==0) call integrand%export_tecplot(file_name=output_file_name, t=time(step)) + if ((time(step) == final_time).or.(step == final_step)) exit enddo - last_step = step type is(integrator_runge_kutta_ls) if (allocated(stage)) deallocate(stage) ; allocate(stage(1:integrator%registers_number())) - step = 0 - do while(solution(0, step) < final_time .and. step < ubound(solution, dim=2)) - step = step + 1 - if (is_fast) then - call integrator%integrate_fast(U=domain, stage=stage, buffer=buffer, Dt=Dt, t=solution(0, step)) - else - call integrator%integrate(U=domain, stage=stage, Dt=Dt, t=solution(0, step)) - endif - solution(0, step) = step * Dt - solution(1:, step) = domain%output() + do + step = step + 1 + Dt(step) = integrand%dt(final_step=final_step, final_time=final_time, t=time(step), CFL=CFL) + if (is_fast) then + call integrator%integrate_fast(U=integrand, stage=stage, buffer=buffer, Dt=Dt(step), t=time(step)) + else + call integrator%integrate(U=integrand, stage=stage, Dt=Dt(step), t=time(step)) + endif + time(step) = time(step-1) + Dt(step) + if (save_results.and.mod(step, save_frequency)==0) call integrand%export_tecplot(file_name=output_file_name, t=time(step)) + if ((time(step) == final_time).or.(step == final_step)) exit enddo - last_step = step type is(integrator_runge_kutta_lssp) - step = 0 - do while(solution(0, step) < final_time .and. step < ubound(solution, dim=2)) - step = step + 1 - if (is_fast) then - call integrator%integrate_fast(U=domain, stage=stage, buffer=buffer, Dt=Dt, t=solution(0, step)) - else - call integrator%integrate(U=domain, stage=stage, Dt=Dt, t=solution(0, step)) - endif - solution(0, step) = step * Dt - solution(1:, step) = domain%output() + do + step = step + 1 + Dt(step) = integrand%dt(final_step=final_step, final_time=final_time, t=time(step), CFL=CFL) + if (is_fast) then + call integrator%integrate_fast(U=integrand, stage=stage, buffer=buffer, Dt=Dt(step), t=time(step)) + else + call integrator%integrate(U=integrand, stage=stage, Dt=Dt(step), t=time(step)) + endif + time(step) = time(step-1) + Dt(step) + if (save_results.and.mod(step, save_frequency)==0) call integrand%export_tecplot(file_name=output_file_name, t=time(step)) + if ((time(step) == final_time).or.(step == final_step)) exit enddo - last_step = step type is(integrator_runge_kutta_ssp) - step = 0 - do while(solution(0, step) < final_time .and. step < ubound(solution, dim=2)) - step = step + 1 - if (is_fast) then - call integrator%integrate_fast(U=domain, stage=stage, buffer=buffer, Dt=Dt, t=solution(0, step)) - else - call integrator%integrate(U=domain, stage=stage, Dt=Dt, t=solution(0, step)) - endif - solution(0, step) = step * Dt - solution(1:, step) = domain%output() + do + step = step + 1 + Dt(step) = integrand%dt(final_step=final_step, final_time=final_time, t=time(step), CFL=CFL) + if (is_fast) then + call integrator%integrate_fast(U=integrand, stage=stage, buffer=buffer, Dt=Dt(step), t=time(step)) + else + call integrator%integrate(U=integrand, stage=stage, Dt=Dt(step), t=time(step)) + endif + time(step) = time(step-1) + Dt(step) + if (save_results.and.mod(step, save_frequency)==0) call integrand%export_tecplot(file_name=output_file_name, t=time(step)) + if ((time(step) == final_time).or.(step == final_step)) exit enddo - last_step = step endselect - error = 0._R_P - do step=0, last_step - domain = solution(1:, step) - error = error + (domain%output() - domain%exact_solution(t=solution(0, step))) ** 2 - enddo - error = sqrt(error) + if (save_results) call integrand%export_tecplot(close_file=.true.) endsubroutine integrate - - subroutine save_results(results, output, scheme, frequency, U0, save_exact_solution, solution) - !< Save results (and plots). - logical, intent(in) :: results !< Flag for activating results saving. - character(*), intent(in) :: output !< Output files basename coming from CLI. - character(*), intent(in) :: scheme !< Selected scheme: must be defined into *solvers*. - real(R_P), intent(in) :: frequency !< Oscillation frequency. - real(R_P), intent(in) :: U0(1:) !< Initial state. - logical, intent(in) :: save_exact_solution !< Flag for saving exact solution. - real(R_P), intent(in) :: solution(0:,0:) !< Solution at each time step. - character(len=:), allocatable :: title !< Output files title. - character(len=:), allocatable :: basename !< Output files basename. - integer(I_P) :: rawfile !< Raw file unit for saving results. - type(integrand_ladvection) :: oscillator !< Oscillation field. - integer(I_P) :: s !< Counter. - - basename = trim(adjustl(output))//'-'//trim(strz(ubound(solution, dim=2), 10))//'-time_steps-'//trim(adjustl(scheme)) - title = 'oscillation equations integration, solver='//trim(adjustl(scheme)) - if (results) then - open(newunit=rawfile, file=basename//'.dat') - write(rawfile, '(A)')'TITLE="'//title//'"' - write(rawfile, '(A)')'VARIABLES="t" "x" "y" "amplitude" "phase"' - write(rawfile, '(A)')'ZONE T="'//trim(adjustl(scheme))//'"' - do s=0, ubound(solution, dim=2) - write(rawfile, '(5('//FR_P//',1X))')solution(:, s), amplitude_phase(solution(1:2, s)) - enddo - close(rawfile) - endif - if (save_exact_solution) then - call oscillator%initialize(U0=U0, frequency=frequency) - basename = trim(adjustl(output))//'-'//trim(strz(ubound(solution, dim=2), 10))//'-time_steps-exact_solution' - title = 'linear constant coefficients equation integration, solver=exact solution' - open(newunit=rawfile, file=basename//'.dat') - write(rawfile, '(A)')'TITLE="'//title//'"' - write(rawfile, '(A)')'VARIABLES="t" "u"' - write(rawfile, '(A)')'ZONE T="exact solution"' - do s=0, ubound(solution, dim=2) - write(rawfile, '(5('//FR_P//',1X))')solution(0, s), oscillator%exact_solution(t=solution(0, s)), & - amplitude_phase(oscillator%exact_solution(t=solution(0, s))) - enddo - close(rawfile) - endif - contains - function amplitude_phase(sol) result(ap) - !< Compute amplitude and phase of the solution provided in X-Y domain. - real(R_P), intent(in) :: sol(1:) !< Solution in X-Y domain. - real(R_P) :: ap(1:2) !< Amplitude and phase solution. - - ap(1) = sqrt(sol(1)**2 + sol(2)**2) - ap(2) = atan(-sol(1) / sol(2)) - endfunction amplitude_phase - endsubroutine save_results - - subroutine square_wave_initial_state(initial_state, BC_L, BC_R, Dx) - real(R_P), intent(inout) :: initial_state(1:) !< Initial state of primitive variables. - character(*), intent(inout) :: BC_L !< Left boundary condition. - character(*), intent(inout) :: BC_R !< Rigth boundary condition. - real(R_P), intent(in) :: Dx !< Space step. - real(R_P) :: x(1:size(initial_state, dim=1)) !< Cell center x-abscissa values. - integer(I_P) :: i !< Space counter. - - BC_L = 'PER' - BC_R = 'PER' - do i=1, size(x, dim=1) - x(i) = Dx * i - 0.5_R_P * Dx - if (x(i) < 0.25_R_P) then - initial_state(i) = 0._R_P - elseif (0.25_R_P <= x(i) .and. x(i) < 0.75_R_P) then - initial_state(i) = 1._R_P - else - initial_state(i) = 0._R_P - endif - enddo - endsubroutine square_wave_initial_state endmodule foodie_test_ladvection_test program foodie_test_ladvection From 6a8e1ed875ee01fcab6b0ccc717b991927f48825 Mon Sep 17 00:00:00 2001 From: Stefano Zaghi Date: Sun, 14 May 2017 21:51:33 +0200 Subject: [PATCH 03/25] fix euler, rk_ssp --- src/tests/ladvection/fobos | 4 +- .../foodie_test_integrand_ladvection.f90 | 480 ++++++------------ .../ladvection/foodie_test_ladvection.f90 | 190 ++++--- src/third_party/WenOOF | 2 +- 4 files changed, 245 insertions(+), 431 deletions(-) diff --git a/src/tests/ladvection/fobos b/src/tests/ladvection/fobos index 811176ff..07064a26 100644 --- a/src/tests/ladvection/fobos +++ b/src/tests/ladvection/fobos @@ -11,7 +11,7 @@ $CSTATIC_INT = -cpp -c -assume realloc_lhs $DEBUG_GNU = -Og -g3 -Warray-bounds -Wcharacter-truncation -Wline-truncation -Wimplicit-interface -Wimplicit-procedure -Wunderflow -Wuninitialized -fcheck=all -fmodule-private -ffree-line-length-132 -fimplicit-none -fbacktrace -fdump-core -finit-real=nan -std=f2008 -fall-intrinsics $DEBUG_INT = -O0 -debug all -check all -warn all -extend-source 132 -traceback -gen-interfaces -fp-stack-check -fstack-protector-all -ftrapuv -no-ftz -std08 $OPTIMIZE = -O2 -$EXDIRS = src/tests/parallel/ src/tests/regression/ +$EXDIRS = src/tests/parallel/ src/tests/quarantena/ src/tests/regression/ PENF/src/tests/ FACE/src/tests/ FACE/src/third_party/ FLAP/src/tests/ FLAP/src/third_party/ @@ -115,7 +115,7 @@ template = template-common # templates [template-common] cflags_heritage = True -build_dir = build/tests/oscillation/ +build_dir = build/tests/ladvection/ mod_dir = mod obj_dir = obj src = src/ diff --git a/src/tests/ladvection/foodie_test_integrand_ladvection.f90 b/src/tests/ladvection/foodie_test_integrand_ladvection.f90 index 254b3384..12bd0023 100644 --- a/src/tests/ladvection/foodie_test_integrand_ladvection.f90 +++ b/src/tests/ladvection/foodie_test_integrand_ladvection.f90 @@ -6,8 +6,9 @@ module foodie_test_integrand_ladvection !< abstract integrand type. use, intrinsic :: iso_fortran_env, only : stderr=>error_unit +use flap, only : command_line_interface use foodie, only : integrand_object -use penf, only : I_P, R_P +use penf, only : FR_P, I_P, R_P, str use wenoof, only : interpolator_object, wenoof_create implicit none @@ -42,23 +43,29 @@ module foodie_test_integrand_ladvection !<``` !< Where *Ni* are the finite volumes (cells) used for discretizing the domain and *Ng* are the ghost cells used for imposing the !< left and right boundary conditions (for a total of *2Ng* cells). - integer(I_P) :: weno_order=0 !< WENO reconstruction order. - real(R_P) :: weno_eps=10._R_P**(-6) !< WENO epsilon to avoid division by zero, default value. - integer(I_P) :: Ni=0 !< Space dimension. - integer(I_P) :: Ng=0 !< Ghost cells number. - real(R_P) :: Dx=0._R_P !< Space step. - real(R_P) :: a=0._R_P !< Advection coefficient. - real(R_P), allocatable :: u(:) !< Integrand (state) variable. - character(:), allocatable :: BC_L !< Left boundary condition type. - character(:), allocatable :: BC_R !< Right boundary condition type. - class(interpolator_object), allocatable :: interpolator !< WENO interpolator. + character(99) :: w_scheme='' !< WENO Scheme used. + integer(I_P) :: weno_order=0 !< WENO reconstruction order. + real(R_P) :: weno_eps=0._R_P !< WENO epsilon to avoid division by zero, default value. + real(R_P) :: CFL=0._R_P !< CFL value. + integer(I_P) :: Ni=0 !< Space dimension. + integer(I_P) :: Ng=0 !< Ghost cells number. + real(R_P) :: length=0._R_P !< Domain length. + real(R_P) :: Dx=0._R_P !< Space step. + real(R_P) :: a=0._R_P !< Advection coefficient. + character(3) :: BC_L='' !< Left boundary condition type. + character(3) :: BC_R='' !< Right boundary condition type. + real(R_P), allocatable :: u(:) !< Integrand (state) variable. + class(interpolator_object), allocatable :: interpolator !< WENO interpolator. contains ! auxiliary methods - procedure, pass(self), public :: destroy !< Destroy field. - procedure, pass(self), public :: dt => compute_dt !< Compute the current time step, by means of CFL condition. - procedure, pass(self), public :: exact_solution !< Return exact solution. - procedure, pass(self), public :: initialize !< Initialize integrand. - procedure, pass(self), public :: output !< Extract integrand state field. + procedure, pass(self), public :: destroy !< Destroy field. + procedure, pass(self), public :: dt => compute_dt !< Compute the current time step, by means of CFL condition. + procedure, pass(self), public :: exact_solution !< Return exact solution. + procedure, pass(self), public :: export_tecplot !< Export integrand to Tecplot file. + procedure, pass(self), public :: output !< Extract integrand state field. + procedure, pass(self), public :: parse_cli !< Initialize from command line interface. + procedure, nopass, public :: set_cli !< Set command line interface. + procedure, pass(self), public :: set_square_wave_initial_state !< Set initial state as a square wave. ! public deferred methods procedure, pass(self), public :: integrand_dimension !< Return integrand dimension. procedure, pass(self), public :: t => dU_dt !< Time derivative, residuals. @@ -82,11 +89,11 @@ module foodie_test_integrand_ladvection procedure, pass(lhs), public :: assign_integrand !< `=` operator. procedure, pass(lhs), public :: assign_real !< `= real` operator. ! override fast operators - procedure, pass(self), public :: t_fast !< Time derivative, residuals, fast mode. - procedure, pass(opr), public :: integrand_add_integrand_fast !< `+` fast operator. - procedure, pass(opr), public :: integrand_multiply_integrand_fast !< `*` fast operator. - procedure, pass(opr), public :: integrand_multiply_real_scalar_fast !< `* real_scalar` fast operator. - procedure, pass(opr), public :: integrand_subtract_integrand_fast !< `-` fast operator. + ! procedure, pass(self), public :: t_fast !< Time derivative, residuals, fast mode. + ! procedure, pass(opr), public :: integrand_add_integrand_fast !< `+` fast operator. + ! procedure, pass(opr), public :: integrand_multiply_integrand_fast !< `*` fast operator. + ! procedure, pass(opr), public :: integrand_multiply_real_scalar_fast !< `* real_scalar` fast operator. + ! procedure, pass(opr), public :: integrand_subtract_integrand_fast !< `-` fast operator. ! private methods procedure, pass(self), private :: impose_boundary_conditions !< Impose boundary conditions. procedure, pass(self), private :: reconstruct_interfaces !< Reconstruct interface states. @@ -96,31 +103,24 @@ module foodie_test_integrand_ladvection ! auxiliary methods pure subroutine destroy(self) !< Destroy field. - class(integrand_ladvection), intent(inout) :: self !< Advection field. - - self%weno_order = 0 - self%Ni = 0 - self%Ng = 0 - self%Dx = 0._R_P - if (allocated(self%u)) deallocate(self%u) - if (allocated(self%BC_L)) deallocate(self%BC_L) - if (allocated(self%BC_R)) deallocate(self%BC_R) - if (allocated(self%interpolator)) deallocate(self%interpolator) + class(integrand_ladvection), intent(inout) :: self !< Advection field. + type(integrand_ladvection) :: fresh !< Fresh field to reset self. + + self = fresh endsubroutine destroy - pure function compute_dt(self, steps_max, t_max, t, CFL) result(Dt) + pure function compute_dt(self, final_step, final_time, t) result(Dt) !< Compute the current time step by means of CFL condition. - class(integrand_ladvection), intent(in) :: self !< Advection field. - integer(I_P), intent(in) :: steps_max !< Maximun number of time steps. - real(R_P), intent(in) :: t_max !< Maximum integration time. - real(R_P), intent(in) :: t !< Time. - real(R_P), intent(in) :: CFL !< CFL value. - real(R_P) :: Dt !< Time step. - - associate(Ni=>self%Ni, Dx=>self%Dx) - Dt = Dx * CFL / abs(self%a) - if (steps_max <= 0 .and. t_max > 0._R_P) then - if ((t + Dt) > t_max) Dt = t_max - t + class(integrand_ladvection), intent(in) :: self !< Advection field. + integer(I_P), intent(in) :: final_step !< Maximun number of time steps. + real(R_P), intent(in) :: final_time !< Maximum integration time. + real(R_P), intent(in) :: t !< Time. + real(R_P) :: Dt !< Time step. + + associate(a=>self%a, Ni=>self%Ni, Dx=>self%Dx, CFL=>self%CFL) + Dt = Dx * CFL / abs(a) + if (final_step <= 0 .and. final_time > 0._R_P) then + if ((t + Dt) > final_time) Dt = final_time - t endif endassociate endfunction compute_dt @@ -134,35 +134,36 @@ pure function exact_solution(self, u0, t) result(exact) endfunction exact_solution - subroutine initialize(self, Ni, Dx, BC_L, BC_R, initial_state, w_scheme, a, weno_order) - !< Initialize field. - class(integrand_ladvection), intent(inout) :: self !< Advection field. - integer(I_P), intent(in) :: Ni !< Space dimension. - real(R_P), intent(in) :: Dx !< Space step. - character(*), intent(in) :: BC_L !< Left boundary condition type. - character(*), intent(in) :: BC_R !< Right boundary condition type. - real(R_P), intent(in) :: initial_state(1:) !< Initial state. - character(*), intent(in) :: w_scheme !< WENO scheme. - real(R_P), intent(in), optional :: a !< Advection coefficient. - integer(I_P), intent(in), optional :: weno_order !< WENO reconstruction order. - integer(I_P) :: i !< Space couner. - - call self%destroy - self%a = 1._R_P ; if (present(a)) self%a = a - self%weno_order = 1 ; if (present(weno_order)) self%weno_order = weno_order - self%Ni = Ni - self%Ng = (self%weno_order + 1) / 2 - self%Dx = Dx - if (allocated(self%u)) deallocate(self%u) ; allocate(self%u(1-self%Ng:self%Ni+self%Ng)) - do i=1, Ni - self%u(i) = initial_state(i) - enddo - self%BC_L = BC_L - self%BC_R = BC_R - - if (self%weno_order>1) call wenoof_create(interpolator_type=trim(adjustl(w_scheme)), S=self%Ng, interpolator=self%interpolator, & - eps=self%weno_eps) - endsubroutine initialize + subroutine export_tecplot(self, file_name, t, close_file) + !< Export integrand to Tecplot file. + class(integrand_ladvection), intent(in) :: self !< Advection field. + character(*), intent(in), optional :: file_name !< File name. + real(R_P), intent(in), optional :: t !< Time. + logical, intent(in), optional :: close_file !< Flag for closing file. + logical, save :: is_open=.false. !< Flag for checking if file is open. + integer(I_P), save :: file_unit !< File unit. + integer(I_P) :: i !< Counter. + + if (present(close_file)) then + if (close_file .and. is_open) then + close(unit=file_unit) + is_open = .false. + endif + else + if (present(file_name)) then + if (is_open) close(unit=file_unit) + open(newunit=file_unit, file=trim(adjustl(file_name))) + is_open = .true. + write(unit=file_unit, fmt='(A)') 'VARIABLES="x" "u"' + endif + if (present(t) .and. is_open) then + write(unit=file_unit, fmt='(A)') 'ZONE T="'//str(t)//'"' + do i=1, self%Ni + write(unit=file_unit, fmt='(2('//FR_P//',1X))') self%Dx * i - 0.5_R_P * self%Dx, self%u(i) + enddo + endif + endif + endsubroutine export_tecplot pure function output(self) result(state) !< Output the advection field state. @@ -172,6 +173,53 @@ pure function output(self) result(state) state = self%u(1:self%Ni) endfunction output + subroutine parse_cli(self, cli) + !< Initialize from command line interface. + class(integrand_ladvection), intent(inout) :: self !< Advection field. + type(command_line_interface), intent(inout) :: cli !< Command line interface handler. + character(99) :: initial_state !< Initial state. + + call self%destroy + + call cli%get(switch='--cfl', val=self%CFL, error=cli%error) ; if (cli%error/=0) stop + call cli%get(switch='--w-scheme', val=self%w_scheme, error=cli%error) ; if (cli%error/=0) stop + call cli%get(switch='--weno-order', val=self%weno_order, error=cli%error) ; if (cli%error/=0) stop + call cli%get(switch='--weno-eps', val=self%weno_eps, error=cli%error) ; if (cli%error/=0) stop + call cli%get(switch='-a', val=self%a, error=cli%error) ; if (cli%error/=0) stop + call cli%get(switch='--length', val=self%length, error=cli%error) ; if (cli%error/=0) stop + call cli%get(switch='--Ni', val=self%Ni, error=cli%error) ; if (cli%error/=0) stop + call cli%get(switch='-is', val=initial_state, error=cli%error) ; if (cli%error/=0) stop + + self%Ng = (self%weno_order + 1) / 2 + self%Dx = self%length / self%Ni + + select case(trim(adjustl(initial_state))) + case('square_wave') + call self%set_square_wave_initial_state + endselect + + if (self%weno_order>1) call wenoof_create(interpolator_type=trim(adjustl(self%w_scheme)), & + S=self%Ng, & + interpolator=self%interpolator, & + eps=self%weno_eps) + endsubroutine parse_cli + + subroutine set_cli(cli) + !< Set command line interface. + type(command_line_interface), intent(inout) :: cli !< Command line interface handler. + + call cli%add(switch='--w-scheme', help='WENO scheme', required=.false., act='store', def='reconstructor-JS', & + choices='reconstructor-JS,reconstructor-M-JS,reconstructor-M-Z,reconstructor-Z') + call cli%add(switch='--weno-order', help='WENO order', required=.false., act='store', def='1') + call cli%add(switch='--weno-eps', help='WENO epsilon parameter', required=.false., act='store', def='0.000001') + call cli%add(switch='--cfl', help='CFL value', required=.false., act='store', def='0.8') + call cli%add(switch='-a', help='advection coefficient', required=.false., act='store', def='1.0') + call cli%add(switch='--length', help='domain lenth', required=.false., act='store', def='1.0') + call cli%add(switch='--Ni', help='number finite volumes used', required=.false., act='store', def='100') + call cli%add(switch='--initial_state', switch_ab='-is', help='initial state', required=.false., act='store', & + def='square_wave', choices='square_wave') + endsubroutine set_cli + ! ADT integrand deferred methods function dU_dt(self, t) result(dState_dt) !< Time derivative of advection field, the residuals function. @@ -191,7 +239,7 @@ function dU_dt(self, t) result(dState_dt) do i=0, self%Ni call solve_riemann_problem(state_left=ur(2, i), state_right=ur(1, i+1), flux=f(i)) enddo - allocate(dState_dt(1:self%Ni)) + allocate(dState_dt(1-self%Ng:self%Ni+self%Ng)) do i=1, self%Ni dState_dt(i) = (f(i - 1) - f(i)) / self%Dx enddo @@ -225,9 +273,9 @@ function local_error(lhs, rhs) result(error) !< !< $$ error = \sqrt{ \sum_i{\sum_i{ \frac{(lhs\%u_i - rhs\%u_i)^2}{lhs\%u_i^2} }} } $$ class(integrand_ladvection), intent(in) :: lhs !< Left hand side. - class(integrand), intent(in) :: rhs !< Right hand side. - real(R_P) :: error !< Error estimation. - integer(I_P) :: i !< Space counter. + class(integrand_object), intent(in) :: rhs !< Right hand side. + real(R_P) :: error !< Error estimation. + integer(I_P) :: i !< Space counter. select type(rhs) class is (integrand_ladvection) @@ -237,7 +285,7 @@ function local_error(lhs, rhs) result(error) enddo error = sqrt(error) endselect - endfunction advection_local_error + endfunction local_error ! + pure function integrand_add_integrand(lhs, rhs) result(opr) @@ -350,39 +398,38 @@ pure function real_sub_integrand(lhs, rhs) result(opr) opr = lhs - rhs%U endfunction real_sub_integrand + ! = pure subroutine assign_integrand(lhs, rhs) !< `=` operator. class(integrand_ladvection), intent(inout) :: lhs !< Left hand side. - class(integrand), intent(in) :: rhs !< Right hand side. - integer(I_P) :: i !< Counter. + class(integrand_object), intent(in) :: rhs !< Right hand side. select type(rhs) class is(integrand_ladvection) + lhs%w_scheme = rhs%w_scheme lhs%weno_order = rhs%weno_order + lhs%weno_eps = rhs%weno_eps + lhs%CFL = rhs%CFL lhs%Ni = rhs%Ni lhs%Ng = rhs%Ng lhs%Dx = rhs%Dx lhs%a = rhs%a + lhs%BC_L = rhs%BC_L + lhs%BC_R = rhs%BC_R if (allocated(rhs%u)) then - if (allocated(lhs%u)) deallocate(lhs%u) ; allocate(lhs%u(1:lhs%Ni)) - select type(rhs) - class is(integrand_ladvection) - if (allocated(rhs%U)) then - do i=1, lhs%Ni - lhs%u(i) = rhs%u(i) - enddo - endif - endselect + lhs%u = rhs%u + else + if (allocated(lhs%u)) deallocate(lhs%u) endif - if (allocated(rhs%BC_L)) lhs%BC_L = rhs%BC_L - if (allocated(rhs%BC_R)) lhs%BC_R = rhs%BC_R if (allocated(rhs%interpolator)) then if (allocated(lhs%interpolator)) deallocate(lhs%interpolator) allocate(lhs%interpolator, mold=rhs%interpolator) lhs%interpolator = rhs%interpolator + else + if (allocated(lhs%interpolator)) deallocate(lhs%interpolator) endif endselect - endsubroutine assign_advection + endsubroutine assign_integrand pure subroutine assign_real(lhs, rhs) !< Assign one real to an advection field. @@ -462,246 +509,25 @@ subroutine reconstruct_interfaces(self, conservative, r_conservative) enddo endselect endsubroutine reconstruct_interfaces -endmodule foodie_test_integrand_ladvection - - subroutine save_results(results, output, scheme, frequency, U0, save_exact_solution, solution) - !< Save results (and plots). - logical, intent(in) :: results !< Flag for activating results saving. - character(*), intent(in) :: output !< Output files basename coming from CLI. - character(*), intent(in) :: scheme !< Selected scheme: must be defined into *solvers*. - real(R_P), intent(in) :: frequency !< Oscillation frequency. - real(R_P), intent(in) :: U0(1:) !< Initial state. - logical, intent(in) :: save_exact_solution !< Flag for saving exact solution. - real(R_P), intent(in) :: solution(0:,0:) !< Solution at each time step. - character(len=:), allocatable :: title !< Output files title. - character(len=:), allocatable :: basename !< Output files basename. - integer(I_P) :: rawfile !< Raw file unit for saving results. - type(integrand_ladvection) :: oscillator !< Oscillation field. - integer(I_P) :: s !< Counter. - - basename = trim(adjustl(output))//'-'//trim(strz(ubound(solution, dim=2), 10))//'-time_steps-'//trim(adjustl(scheme)) - title = 'oscillation equations integration, solver='//trim(adjustl(scheme)) - if (results) then - open(newunit=rawfile, file=basename//'.dat') - write(rawfile, '(A)')'TITLE="'//title//'"' - write(rawfile, '(A)')'VARIABLES="t" "x" "y" "amplitude" "phase"' - write(rawfile, '(A)')'ZONE T="'//trim(adjustl(scheme))//'"' - do s=0, ubound(solution, dim=2) - write(rawfile, '(5('//FR_P//',1X))')solution(:, s), amplitude_phase(solution(1:2, s)) - enddo - close(rawfile) - endif - if (save_exact_solution) then - call oscillator%initialize(U0=U0, frequency=frequency) - basename = trim(adjustl(output))//'-'//trim(strz(ubound(solution, dim=2), 10))//'-time_steps-exact_solution' - title = 'linear constant coefficients equation integration, solver=exact solution' - open(newunit=rawfile, file=basename//'.dat') - write(rawfile, '(A)')'TITLE="'//title//'"' - write(rawfile, '(A)')'VARIABLES="t" "u"' - write(rawfile, '(A)')'ZONE T="exact solution"' - do s=0, ubound(solution, dim=2) - write(rawfile, '(5('//FR_P//',1X))')solution(0, s), oscillator%exact_solution(t=solution(0, s)), & - amplitude_phase(oscillator%exact_solution(t=solution(0, s))) - enddo - close(rawfile) - endif - contains - function amplitude_phase(sol) result(ap) - !< Compute amplitude and phase of the solution provided in X-Y domain. - real(R_P), intent(in) :: sol(1:) !< Solution in X-Y domain. - real(R_P) :: ap(1:2) !< Amplitude and phase solution. - - ap(1) = sqrt(sol(1)**2 + sol(2)**2) - ap(2) = atan(-sol(1) / sol(2)) - endfunction amplitude_phase - endsubroutine save_results - - subroutine square_wave_initial_state(initial_state, BC_L, BC_R, Dx) - real(R_P), intent(inout) :: initial_state(1:) !< Initial state of primitive variables. - character(*), intent(inout) :: BC_L !< Left boundary condition. - character(*), intent(inout) :: BC_R !< Rigth boundary condition. - real(R_P), intent(in) :: Dx !< Space step. - real(R_P) :: x(1:size(initial_state, dim=1)) !< Cell center x-abscissa values. - integer(I_P) :: i !< Space counter. - - BC_L = 'PER' - BC_R = 'PER' - do i=1, size(x, dim=1) - x(i) = Dx * i - 0.5_R_P * Dx - if (x(i) < 0.25_R_P) then - initial_state(i) = 0._R_P - elseif (0.25_R_P <= x(i) .and. x(i) < 0.75_R_P) then - initial_state(i) = 1._R_P - else - initial_state(i) = 0._R_P - endif - enddo - endsubroutine square_wave_initial_state -program wenoof_test_linear_advection -!< Define [[integrand_ladvection]], the 1D linear advection PDE test field that is a concrete extension of the -!< abstract integrand type. + subroutine set_square_wave_initial_state(self) + !< Set initial state as a square wave. + class(integrand_ladvection), intent(inout) :: self !< Advection field. + real(R_P) :: x(1:self%ni) !< Cell center x-abscissa values. + integer(I_P) :: i !< Space counter. -use flap, only : command_line_interface -use foodie, only : integrator_runge_kutta_lssp, integrator_runge_kutta_ssp -use foodie_test_integrand_ladvection, only : integrand_ladvection -use penf, only : cton, FR_P, I_P, R_P, str - -implicit none -character(len=99) :: s_scheme !< Space scheme. -character(len=99) :: t_scheme !< Time scheme. -integer(I_P) :: weno_order !< WENO reconstruction order. -real(R_P) :: weno_eps !< WENO epsilon value. -integer(I_P) :: stages !< Number of stages. -type(integrator_runge_kutta_lssp) :: rk_integrator !< Runge-Kutta integrator. -type(integrator_runge_kutta_ssp) :: rk_integrator_s !< Runge-Kutta integrator. -type(integrand_ladvection), allocatable :: rk_stage(:) !< Runge-Kutta stages. -real(R_P) :: dt !< Time step. -real(R_P) :: t !< Time. -integer(I_P) :: step !< Time steps counter. -type(integrand_ladvection) :: domain !< Domain of Advection equations. -real(R_P) :: CFL !< CFL value. -character(3) :: BC_L !< Left boundary condition type. -character(3) :: BC_R !< Right boundary condition type. -integer(I_P) :: Ni !< Number of grid cells. -real(R_P) :: Dx !< Space step discretization. -real(R_P) :: a !< Advection coefficient. -real(R_P), allocatable :: x(:) !< Cell center x-abscissa values. -integer(I_P) :: steps_max !< Maximum number of time steps. -real(R_P) :: t_max !< Maximum integration time. -logical :: results !< Flag for activating results saving. -logical :: time_serie !< Flag for activating time serie-results saving. -logical :: verbose !< Flag for activating more verbose output. -real(R_P), parameter :: pi = 4._R_P * atan(1._R_P) !< Pi greek. - -call parse_command_line_interface -if (verbose) print "(A)", 'Solve 1D linear advection equation " u_t + (a*u)_x =0" with a='//trim(str(a)) -call initialize -call save_time_serie(filename='linear_advection-'// & - trim(adjustl(s_scheme))//'-'//trim(str(weno_order, no_sign=.true.))//'-'// & - trim(adjustl(t_scheme))//'-'//trim(str(stages, no_sign=.true.))//'-'// & - 'Ni_'//trim(str(Ni, no_sign=.true.))//'.dat', t=t) -step = 0 -time_loop: do - step = step + 1 - dt = domain%dt(steps_max=steps_max, t_max=t_max, t=t, CFL=CFL) - if (trim(adjustl(t_scheme))=='runge_kutta_ssp_stages_5_order_4') then - call rk_integrator_s%integrate(U=domain, stage=rk_stage, dt=dt, t=t) - else - call rk_integrator%integrate(U=domain, stage=rk_stage, dt=dt, t=t) - endif - t = t + dt - call save_time_serie(t=t) - if (verbose) print "(A)", 'step = '//str(n=step)//', time step = '//str(n=dt)//', time = '//str(n=t) - if ((t == t_max).or.(step == steps_max)) exit time_loop -enddo time_loop -call save_time_serie(t=t, finish=.true.) - -contains - subroutine initialize() - !< Initialize the test. - real(R_P), allocatable :: initial_state(:) !< Initial state of primitive variables. - integer(I_P) :: i !< Space counter. - - if (trim(adjustl(t_scheme))=='runge_kutta_ssp_stages_5_order_4') then - call rk_integrator_s%initialize(scheme=t_scheme, stop_on_fail=.true.) - if (allocated(rk_stage)) deallocate(rk_stage) ; allocate(rk_stage(1:rk_integrator_s%stages)) - else - call rk_integrator%initialize(scheme=t_scheme, stages=stages) - if (allocated(rk_stage)) deallocate(rk_stage) ; allocate(rk_stage(1:rk_integrator%stages)) - endif - t = 0._R_P - if (allocated(x)) deallocate(x) ; allocate(x(1:Ni)) - if (allocated(initial_state)) deallocate(initial_state) ; allocate(initial_state(1:Ni)) - Dx = 1._R_P / Ni - call square_wave_initial_state(initial_state=initial_state) - call domain%initialize(Ni=Ni, Dx=Dx, & - BC_L=BC_L, BC_R=BC_R, & - initial_state=initial_state, & - s_scheme=s_scheme, & - a=a, & - weno_order=weno_order) - endsubroutine initialize - - subroutine parse_command_line_interface() - !< Parse Command Line Interface (CLI). - type(command_line_interface) :: cli !< Command line interface handler. - integer(I_P) :: error !< Error handler. - character(len=:), allocatable :: buffer !< String buffer. - - call cli%init(description = 'WenOOF test: 1D linear advection equation', & - examples = ["wenoof_test_linear_advection ", & - "wenoof_test_linear_advection --tserie"]) - call cli%add(switch='-a', help='advection coefficient', required=.false., act='store', def='1.0') - call cli%add(switch='--Ni', help='number finite volumes used', required=.false., act='store', def='100') - call cli%add(switch='--steps', help='number time steps performed', required=.false., act='store', def='100') - call cli%add(switch='--t-max', help='maximum integration time', required=.false., act='store', def='0.') - call cli%add(switch='--s-scheme', help='space intergation scheme', required=.false., act='store', def='reconstructor-JS', & - choices='reconstructor-JS,reconstructor-M-JS,reconstructor-M-Z,reconstructor-Z') - call cli%add(switch='--weno-order', help='WENO order', required=.false., act='store', def='1') - call cli%add(switch='--weno-eps', help='WENO epsilon parameter', required=.false., act='store', def='0.000001') - call cli%add(switch='--t-scheme', help='time intergation scheme', required=.false., act='store', & - def='runge_kutta_lssp_stages_s_order_s_1', & - choices='runge_kutta_lssp_stages_s_order_s_1,runge_kutta_lssp_stages_s_order_s,runge_kutta_ssp_stages_5_order_4') - call cli%add(switch='--stages', help='number stages', required=.false., act='store', def='2') - call cli%add(switch='--cfl', help='CFL value', required=.false., act='store', def='0.8') - call cli%add(switch='--tserie', switch_ab='-t', help='Save time-serie-result', required=.false., act='store_true', def='.false.') - call cli%add(switch='--verbose', help='Verbose output', required=.false., act='store_true', def='.false.') - call cli%parse(error=error) - call cli%get(switch='-a', val=a, error=error) ; if (error/=0) stop - call cli%get(switch='--Ni', val=Ni, error=error) ; if (error/=0) stop - call cli%get(switch='--steps', val=steps_max, error=error) ; if (error/=0) stop - call cli%get(switch='--t-max', val=t_max, error=error) ; if (error/=0) stop - call cli%get(switch='--s-scheme', val=s_scheme, error=error) ; if (error/=0) stop - call cli%get(switch='--weno-order', val=weno_order, error=error) ; if (error/=0) stop - call cli%get(switch='--weno-eps', val=weno_eps, error=error) ; if (error/=0) stop - call cli%get(switch='--t-scheme', val=t_scheme, error=error) ; if (error/=0) stop - call cli%get(switch='--stages', val=stages, error=error) ; if (error/=0) stop - call cli%get(switch='--cfl', val=CFL, error=error) ; if (error/=0) stop - call cli%get(switch='--tserie', val=time_serie, error=error) ; if (error/=0) stop - call cli%get(switch='--verbose', val=verbose, error=error) ; if (error/=0) stop - - if (t_max > 0._R_P) steps_max = 0 - endsubroutine parse_command_line_interface - - subroutine square_wave_initial_state(initial_state) - real(R_P), intent(inout) :: initial_state(1:) !< Initial state of primitive variables. - integer(I_P) :: i !< Space counter. - - BC_L = 'PER' - BC_R = 'PER' - do i=1, Ni - x(i) = Dx * i - 0.5_R_P * Dx + self%BC_L = 'PER' + self%BC_R = 'PER' + if (allocated(self%u)) deallocate(self%u) ; allocate(self%u(1-self%Ng:self%Ni+self%Ng)) + do i=1, self%Ni + x(i) = self%Dx * i - 0.5_R_P * self%Dx if (x(i) < 0.25_R_P) then - initial_state(i) = 0._R_P + self%u(i) = 0._R_P elseif (0.25_R_P <= x(i) .and. x(i) < 0.75_R_P) then - initial_state(i) = 1._R_P + self%u(i) = 1._R_P else - initial_state(i) = 0._R_P + self%u(i) = 0._R_P endif enddo - endsubroutine square_wave_initial_state - - subroutine save_time_serie(t, filename, finish) - !< Save time-serie results. - real(R_P), intent(in) :: t !< Current integration time. - character(*), intent(in), optional :: filename !< Output filename. - logical, intent(in), optional :: finish !< Flag for triggering the file closing. - integer(I_P), save :: tsfile !< File unit for saving time serie results. - integer(I_P) :: i !< Counter. - - if (time_serie) then - if (present(filename)) then - open(newunit=tsfile, file=filename) - endif - write(tsfile, '(A)')'VARIABLES = "x" "u"' - write(tsfile, '(A)')'ZONE T="'//str(n=t)//'"' - do i=1, Ni - write(tsfile, '(4'//'('//FR_P//',1X))')x(i), domain%u(i) - enddo - if (present(finish)) then - if (finish) close(tsfile) - endif - endif - endsubroutine save_time_serie -endprogram wenoof_test_linear_advection + endsubroutine set_square_wave_initial_state +endmodule foodie_test_integrand_ladvection diff --git a/src/tests/ladvection/foodie_test_ladvection.f90 b/src/tests/ladvection/foodie_test_ladvection.f90 index 7a56139b..e3a59df1 100644 --- a/src/tests/ladvection/foodie_test_ladvection.f90 +++ b/src/tests/ladvection/foodie_test_ladvection.f90 @@ -40,20 +40,13 @@ module foodie_test_ladvection_test type(command_line_interface) :: cli !< Command line interface handler. integer(I_P) :: error=0 !< Error handler. character(99) :: scheme='' !< Scheme used. - real(R_P) :: CFL !< CFL value. logical :: is_fast=.false. !< Flag for activating fast schemes. integer(I_P) :: implicit_iterations=0 !< Number of iterations (implicit solvers). integer(I_P) :: stages=0 !< Number of stages. - integer(I_P) :: steps_max !< Maximum number of time steps. - real(R_P) :: final_time=0.0_R_P !< Final integration time. - character(99) :: w_scheme='' !< WENO Scheme used. - integer(I_P) :: weno_order=0 !< WENO reconstruction order. - real(R_P) :: weno_eps=0._R_P !< WENO epsilon value. - real(R_P) :: a=0._R_P !< Advection coefficient. - integer(I_P) :: Ni=0 !< Number of grid cells. - character(3) :: BC_L !< Left boundary condition type. - character(3) :: BC_R !< Right boundary condition type. + integer(I_P) :: final_step=0 !< Maximum number of time steps. + real(R_P) :: final_time=0._R_P !< Final integration time. logical :: save_results=.false. !< Flag for activating results saving. + integer(I_P) :: save_frequency=0 !< Output save frequency. character(99) :: output='' !< Output files basename. logical :: verbose=.false. !< Flag for activating verbose output. type(integrand_ladvection) :: integrand_0 !< Initial conditions. @@ -84,8 +77,7 @@ subroutine execute(self) endif do s=1, size(integrator_schemes, dim=1) call integrate(scheme=trim(integrator_schemes(s)), & - CFL=self%CFL, & - integrand_0=integrand_0, & + integrand_0=self%integrand_0, & final_step=self%final_step, & final_time=self%final_time, & iterations=self%implicit_iterations, & @@ -116,22 +108,17 @@ subroutine set_cli() examples = ["foodie_test_ladvection --scheme euler_explicit --save_results ", & "foodie_test_ladvection --scheme all -r "]) call cli%add(switch='--scheme', switch_ab='-s', help='integrator scheme used', required=.false., def='all', act='store') - call cli%add(switch='--cfl', help='CFL value', required=.false., act='store', def='0.8') call cli%add(switch='--fast', help='activate fast solvers', required=.false., act='store_true', def='.false.') call cli%add(switch='--iterations', help='iterations number for implicit schemes', required=.false., act='store', def='5') call cli%add(switch='--stages', help='stages number', required=.false., def='2', act='store') - call cli%add(switch='--steps', help='number time steps performed', required=.false., act='store', def='100') - call cli%add(switch='--t_final', switch_ab='-tf', help='final integration time', required=.false., def='0', act='store') - call cli%add(switch='--w-scheme', help='WENO scheme', required=.false., act='store', def='reconstructor-JS', & - choices='reconstructor-JS,reconstructor-M-JS,reconstructor-M-Z,reconstructor-Z') - call cli%add(switch='--weno-order', help='WENO order', required=.false., act='store', def='1') - call cli%add(switch='--weno-eps', help='WENO epsilon parameter', required=.false., act='store', def='0.000001') - call cli%add(switch='-a', help='advection coefficient', required=.false., act='store', def='1.0') - call cli%add(switch='--Ni', help='number finite volumes used', required=.false., act='store', def='100') + call cli%add(switch='--final_step', switch_ab='-fs', help='integration steps', required=.false., act='store', def='100') + call cli%add(switch='--final_time', switch_ab='-ft', help='integration time', required=.false., def='0', act='store') call cli%add(switch='--save_results', switch_ab='-r',help='save result', required=.false., act='store_true', def='.false.') + call cli%add(switch='--save_frequency', help='output save frequency', required=.false., act='store', def='1') call cli%add(switch='--output', help='output file basename', required=.false., act='store', def='foodie_test_ladvection') call cli%add(switch='--verbose', help='Verbose output', required=.false., act='store_true', def='.false.') endassociate + call self%integrand_0%set_cli(cli=self%cli) endsubroutine set_cli subroutine parse_cli() @@ -143,22 +130,18 @@ subroutine parse_cli() call self%cli%parse(error=self%error) call self%cli%get(switch='-s', val=self%scheme, error=self%error) ; if (self%error/=0) stop - call self%cli%get(switch='--cfl', val=self%CFL, error=error) ; if (error/=0) stop call self%cli%get(switch='--fast', val=self%is_fast, error=self%error) ; if (self%error/=0) stop call self%cli%get(switch='--iterations', val=self%implicit_iterations, error=self%error) ; if (self%error/=0) stop call self%cli%get(switch='--stages', val=self%stages, error=self%error) ; if (self%error/=0) stop - call self%cli%get(switch='--steps', val=self%steps_max, error=error) ; if (error/=0) stop - call self%cli%get(switch='-tf', val=self%final_time, error=self%error) ; if (self%error/=0) stop - call self%cli%get(switch='--w-scheme', val=self%w_scheme, error=error) ; if (error/=0) stop - call self%cli%get(switch='--weno-order', val=self%weno_order, error=error) ; if (error/=0) stop - call self%cli%get(switch='--weno-eps', val=self%weno_eps, error=error) ; if (error/=0) stop - call self%cli%get(switch='-a', val=self%a, error=error) ; if (error/=0) stop - call self%cli%get(switch='--Ni', val=self%Ni, error=error) ; if (error/=0) stop - call self%cli%get(switch='-r', val=self%results, error=self%error) ; if (self%error/=0) stop + call self%cli%get(switch='-fs', val=self%final_step, error=self%error) ; if (self%error/=0) stop + call self%cli%get(switch='-ft', val=self%final_time, error=self%error) ; if (self%error/=0) stop + call self%cli%get(switch='-r', val=self%save_results, error=self%error) ; if (self%error/=0) stop + call self%cli%get(switch='--save_frequency', val=self%save_frequency, error=self%error) ; if (self%error/=0) stop call self%cli%get(switch='--output', val=self%output, error=self%error) ; if (self%error/=0) stop - call self%cli%get(switch='--verbose', val=verbose, error=error) ; if (error/=0) stop + call self%cli%get(switch='--verbose', val=self%verbose, error=self%error) ; if (self%error/=0) stop + call self%integrand_0%parse_cli(cli=self%cli) - if (self%final_time > 0._R_P) self%steps_max = 0 + if (self%final_time > 0._R_P) self%final_step = 0 if (trim(adjustl(self%scheme)) /= 'all') then if (.not.is_available(scheme=self%scheme)) then @@ -176,15 +159,6 @@ subroutine parse_cli() stop endif endif - - allocate(initial_state(1:self%Ni)) - call square_wave_initial_state(initial_state=initial_state, BC_L=self%BC_L, BC_R=self%BC_R, Dx=1._R_P / self%Ni) - call self%advection%initialize(Ni=Ni, Dx=1._R_P / self%Ni, & - BC_L=self%BC_L, BC_R=self%BC_R, & - initial_state=initial_state, & - w_scheme=self%w_scheme, & - a=self%a, & - weno_order=self%weno_order) endsubroutine parse_cli endsubroutine initialize @@ -200,12 +174,11 @@ subroutine check_scheme_has_fast_mode(scheme, integrator) endif endsubroutine check_scheme_has_fast_mode - subroutine integrate(scheme, integrand_0, CFL, final_step, final_time, iterations, stages, is_fast, & + subroutine integrate(scheme, integrand_0, final_step, final_time, iterations, stages, is_fast, & save_results, save_frequency, output_base_name) !< Integrate integrand by means of the given scheme. character(*), intent(in) :: scheme !< Selected scheme. type(integrand_ladvection), intent(in) :: integrand_0 !< Initial conditions. - real(R_P), intent(in) :: CFL !< CFL stability coefficient. integer(I_P), intent(in) :: final_step !< Final integration step. real(R_P), intent(in) :: final_time !< Final integration time. integer(I_P), intent(in) :: iterations !< Number of fixed point iterations. @@ -231,7 +204,7 @@ subroutine integrate(scheme, integrand_0, CFL, final_step, final_time, iteration integrand = integrand_0 - output_file_name = trim(adjustl(output_base_name))//'-'//trim(adjustl(scheme))//'-'//strz(n=integrand%Ni, zero_pad=10)//'.dat' + output_file_name = trim(adjustl(output_base_name))//'-'//trim(adjustl(scheme))//'-'//trim(strz(integrand%Ni, 10))//'.dat' call foodie_integrator_factory(scheme=scheme, integrator=integrator, stages=stages, tolerance=1e2_R_P) if (is_fast) call check_scheme_has_fast_mode(scheme=trim(adjustl(scheme)), integrator=integrator) @@ -240,10 +213,17 @@ subroutine integrate(scheme, integrand_0, CFL, final_step, final_time, iteration allocate(previous(1:integrator%steps_number())) call integrator_start%initialize(scheme='runge_kutta_ssp_stages_5_order_4') allocate(stage_start(1:integrator_start%stages_number())) - allocate(time(0:1:integrator%steps_number())) - allocate(Dt(1:1:integrator%steps_number())) + if (integrator%steps_number()==0) then + step_offset = 1 ! for 0 step-(a convention)-solver offset is 1 + else + step_offset = integrator%steps_number() ! for >0 step-solver offset is steps + endif + else + step_offset = 1 ! for 0 step-(a convention)-solver offset is 1 endif if (integrator%is_multistage()) allocate(stage(1:integrator%stages_number())) + allocate(time(0:step_offset)) + allocate(Dt(1:step_offset)) step = 0 time = 0._R_P @@ -253,33 +233,30 @@ subroutine integrate(scheme, integrand_0, CFL, final_step, final_time, iteration type is(integrator_adams_bashforth) do step = step + 1 - Dt(step) = integrand%dt(final_step=final_step, final_time=final_time, t=time(step), CFL=CFL) if (integrator%steps_number() >= step) then + Dt(step) = integrand%dt(final_step=final_step, final_time=final_time, t=time(step)) call integrator_start%integrate(U=integrand, stage=stage_start, Dt=Dt(step), t=time(step)) previous(step) = integrand + time(step) = time(step-1) + Dt(step) + if (save_results.and.mod(step, save_frequency)==0) call integrand%export_tecplot(t=time(step)) + if ((time(step) == final_time).or.(step == final_step)) exit else + Dt(step_offset) = integrand%dt(final_step=final_step, final_time=final_time, t=time(step_offset)) if (is_fast) then - call integrator%integrate_fast(U=integrand, & - previous=previous, & - buffer=buffer, & - Dt=Dt(step), & - t=time(step-integrator%steps_number():step-1)) + call integrator%integrate_fast(U=integrand, previous=previous, buffer=buffer, Dt=Dt(step_offset), t=time) else - call integrator%integrate(U=integrand, & - previous=previous, & - Dt=Dt(step), & - t=time(step-integrator%steps_number():step-1)) + call integrator%integrate(U=integrand, previous=previous, Dt=Dt(step_offset), t=time) endif + call update_previous_times + if (save_results.and.mod(step, save_frequency)==0) call integrand%export_tecplot(t=time(step_offset)) + if ((time(step_offset) == final_time).or.(step == final_step)) exit endif - time(step) = time(step-1) + Dt(step) - if (save_results.and.mod(step, save_frequency)==0) call integrand%export_tecplot(file_name=output_file_name, t=time(step)) - if ((time(step) == final_time).or.(step == final_step)) exit enddo type is(integrator_adams_bashforth_moulton) do step = step + 1 - Dt(step) = integrand%dt(final_step=final_step, final_time=final_time, t=time(step), CFL=CFL) + Dt(step) = integrand%dt(final_step=final_step, final_time=final_time, t=time(step)) if (integrator%steps_number() >= step) then call integrator_start%integrate(U=integrand, stage=stage_start, Dt=Dt(step), t=time(step)) previous(step) = integrand @@ -298,20 +275,15 @@ subroutine integrate(scheme, integrand_0, CFL, final_step, final_time, iteration endif endif time(step) = time(step-1) + Dt(step) - if (save_results.and.mod(step, save_frequency)==0) call integrand%export_tecplot(file_name=output_file_name, t=time(step)) + if (save_results.and.mod(step, save_frequency)==0) call integrand%export_tecplot(t=time(step)) if ((time(step) == final_time).or.(step == final_step)) exit enddo type is(integrator_adams_moulton) if (allocated(previous)) deallocate(previous) ; allocate(previous(1:integrator%steps_number()+1)) - if (integrator%steps_number()==0) then - step_offset = 1 ! for 0 step-(a convention)-solver offset is 1 - else - step_offset = integrator%steps_number() ! for >0 step-solver offset is steps - endif do step = step + 1 - Dt(step) = integrand%dt(final_step=final_step, final_time=final_time, t=time(step), CFL=CFL) + Dt(step) = integrand%dt(final_step=final_step, final_time=final_time, t=time(step)) if (integrator%steps_number() >= step) then call integrator_start%integrate(U=integrand, stage=stage_start, Dt=Dt(step), t=time(step)) previous(step) = integrand @@ -347,14 +319,14 @@ subroutine integrate(scheme, integrand_0, CFL, final_step, final_time, iteration endif endif time(step) = time(step-1) + Dt(step) - if (save_results.and.mod(step, save_frequency)==0) call integrand%export_tecplot(file_name=output_file_name, t=time(step)) + if (save_results.and.mod(step, save_frequency)==0) call integrand%export_tecplot(t=time(step)) if ((time(step) == final_time).or.(step == final_step)) exit enddo type is(integrator_back_df) do step = step + 1 - Dt(step) = integrand%dt(final_step=final_step, final_time=final_time, t=time(step), CFL=CFL) + Dt(step) = integrand%dt(final_step=final_step, final_time=final_time, t=time(step)) if (integrator%steps_number() >= step) then call integrator_start%integrate(U=integrand, stage=stage_start, Dt=Dt(step), t=time(step)) previous(step) = integrand @@ -373,28 +345,28 @@ subroutine integrate(scheme, integrand_0, CFL, final_step, final_time, iteration endif endif time(step) = time(step-1) + Dt(step) - if (save_results.and.mod(step, save_frequency)==0) call integrand%export_tecplot(file_name=output_file_name, t=time(step)) + if (save_results.and.mod(step, save_frequency)==0) call integrand%export_tecplot(t=time(step)) if ((time(step) == final_time).or.(step == final_step)) exit enddo type is(integrator_euler_explicit) do step = step + 1 - Dt(step) = integrand%dt(final_step=final_step, final_time=final_time, t=time(step), CFL=CFL) + Dt(step_offset) = integrand%dt(final_step=final_step, final_time=final_time, t=time(step_offset)) if (is_fast) then - call integrator%integrate_fast(U=integrand, buffer=buffer, Dt=Dt(step), t=time(step)) + call integrator%integrate_fast(U=integrand, buffer=buffer, Dt=Dt(step_offset), t=time(step_offset)) else - call integrator%integrate(U=integrand, Dt=Dt(step), t=time(step)) + call integrator%integrate(U=integrand, Dt=Dt(step_offset), t=time(step_offset)) endif - time(step) = time(step-1) + Dt(step) - if (save_results.and.mod(step, save_frequency)==0) call integrand%export_tecplot(file_name=output_file_name, t=time(step)) - if ((time(step) == final_time).or.(step == final_step)) exit + call update_previous_times + if (save_results.and.mod(step, save_frequency)==0) call integrand%export_tecplot(t=time(step_offset)) + if ((time(step_offset) == final_time).or.(step == final_step)) exit enddo type is(integrator_leapfrog) do step = step + 1 - Dt(step) = integrand%dt(final_step=final_step, final_time=final_time, t=time(step), CFL=CFL) + Dt(step) = integrand%dt(final_step=final_step, final_time=final_time, t=time(step)) if (integrator%steps_number() >= step) then call integrator_start%integrate(U=integrand, stage=stage_start, Dt=Dt(step), t=time(step)) previous(step) = integrand @@ -415,14 +387,14 @@ subroutine integrate(scheme, integrand_0, CFL, final_step, final_time, iteration endif endif time(step) = time(step-1) + Dt(step) - if (save_results.and.mod(step, save_frequency)==0) call integrand%export_tecplot(file_name=output_file_name, t=time(step)) + if (save_results.and.mod(step, save_frequency)==0) call integrand%export_tecplot(t=time(step)) if ((time(step) == final_time).or.(step == final_step)) exit enddo type is(integrator_lmm_ssp) do step = step + 1 - Dt(step) = integrand%dt(final_step=final_step, final_time=final_time, t=time(step), CFL=CFL) + Dt(step) = integrand%dt(final_step=final_step, final_time=final_time, t=time(step)) if (integrator%steps_number() >= step) then call integrator_start%integrate(U=integrand, stage=stage_start, Dt=Dt(step), t=time(step)) previous(step) = integrand @@ -441,14 +413,14 @@ subroutine integrate(scheme, integrand_0, CFL, final_step, final_time, iteration endif endif time(step) = time(step-1) + Dt(step) - if (save_results.and.mod(step, save_frequency)==0) call integrand%export_tecplot(file_name=output_file_name, t=time(step)) + if (save_results.and.mod(step, save_frequency)==0) call integrand%export_tecplot(t=time(step)) if ((time(step) == final_time).or.(step == final_step)) exit enddo type is(integrator_lmm_ssp_vss) do step = step + 1 - Dt(step) = integrand%dt(final_step=final_step, final_time=final_time, t=time(step), CFL=CFL) + Dt(step) = integrand%dt(final_step=final_step, final_time=final_time, t=time(step)) if (integrator%steps_number() >= step) then call integrator_start%integrate(U=integrand, stage=stage_start, Dt=Dt(step), t=time(step)) previous(step) = integrand @@ -467,14 +439,14 @@ subroutine integrate(scheme, integrand_0, CFL, final_step, final_time, iteration endif endif time(step) = time(step-1) + Dt(step) - if (save_results.and.mod(step, save_frequency)==0) call integrand%export_tecplot(file_name=output_file_name, t=time(step)) + if (save_results.and.mod(step, save_frequency)==0) call integrand%export_tecplot(t=time(step)) if ((time(step) == final_time).or.(step == final_step)) exit enddo type is(integrator_ms_runge_kutta_ssp) do step = step + 1 - Dt(step) = integrand%dt(final_step=final_step, final_time=final_time, t=time(step), CFL=CFL) + Dt(step) = integrand%dt(final_step=final_step, final_time=final_time, t=time(step)) if (integrator%steps_number() >= step) then call integrator_start%integrate(U=integrand, stage=stage_start, Dt=Dt(step), t=time(step)) previous(step) = integrand @@ -495,22 +467,22 @@ subroutine integrate(scheme, integrand_0, CFL, final_step, final_time, iteration endif endif time(step) = time(step-1) + Dt(step) - if (save_results.and.mod(step, save_frequency)==0) call integrand%export_tecplot(file_name=output_file_name, t=time(step)) + if (save_results.and.mod(step, save_frequency)==0) call integrand%export_tecplot(t=time(step)) if ((time(step) == final_time).or.(step == final_step)) exit enddo type is(integrator_runge_kutta_emd) do step = step + 1 - Dt(step) = integrand%dt(final_step=final_step, final_time=final_time, t=time(step), CFL=CFL) + Dt(step) = integrand%dt(final_step=final_step, final_time=final_time, t=time(step)) Dt_a = Dt(step) if (is_fast) then - call integrator%integrate_fast(U=integrand, stage=stage, buffer=buffer, Dt=Dt_, t=time(step)) + call integrator%integrate_fast(U=integrand, stage=stage, buffer=buffer, Dt=Dt_a, t=time(step)) else call integrator%integrate(U=integrand, stage=stage, Dt=Dt_a, t=time(step)) endif time(step) = time(step-1) + Dt(step) - if (save_results.and.mod(step, save_frequency)==0) call integrand%export_tecplot(file_name=output_file_name, t=time(step)) + if (save_results.and.mod(step, save_frequency)==0) call integrand%export_tecplot(t=time(step)) if ((time(step) == final_time).or.(step == final_step)) exit enddo @@ -518,47 +490,63 @@ subroutine integrate(scheme, integrand_0, CFL, final_step, final_time, iteration if (allocated(stage)) deallocate(stage) ; allocate(stage(1:integrator%registers_number())) do step = step + 1 - Dt(step) = integrand%dt(final_step=final_step, final_time=final_time, t=time(step), CFL=CFL) + Dt(step) = integrand%dt(final_step=final_step, final_time=final_time, t=time(step)) if (is_fast) then call integrator%integrate_fast(U=integrand, stage=stage, buffer=buffer, Dt=Dt(step), t=time(step)) else call integrator%integrate(U=integrand, stage=stage, Dt=Dt(step), t=time(step)) endif time(step) = time(step-1) + Dt(step) - if (save_results.and.mod(step, save_frequency)==0) call integrand%export_tecplot(file_name=output_file_name, t=time(step)) + if (save_results.and.mod(step, save_frequency)==0) call integrand%export_tecplot(t=time(step)) if ((time(step) == final_time).or.(step == final_step)) exit enddo type is(integrator_runge_kutta_lssp) do step = step + 1 - Dt(step) = integrand%dt(final_step=final_step, final_time=final_time, t=time(step), CFL=CFL) + Dt(step_offset) = integrand%dt(final_step=final_step, final_time=final_time, t=time(step_offset)) if (is_fast) then - call integrator%integrate_fast(U=integrand, stage=stage, buffer=buffer, Dt=Dt(step), t=time(step)) + call integrator%integrate_fast(U=integrand, stage=stage, buffer=buffer, Dt=Dt(step_offset), t=time(step_offset)) else - call integrator%integrate(U=integrand, stage=stage, Dt=Dt(step), t=time(step)) + call integrator%integrate(U=integrand, stage=stage, Dt=Dt(step_offset), t=time(step_offset)) endif - time(step) = time(step-1) + Dt(step) - if (save_results.and.mod(step, save_frequency)==0) call integrand%export_tecplot(file_name=output_file_name, t=time(step)) - if ((time(step) == final_time).or.(step == final_step)) exit + call update_previous_times + if (save_results.and.mod(step, save_frequency)==0) call integrand%export_tecplot(t=time(step_offset)) + if ((time(step_offset) == final_time).or.(step == final_step)) exit enddo type is(integrator_runge_kutta_ssp) do step = step + 1 - Dt(step) = integrand%dt(final_step=final_step, final_time=final_time, t=time(step), CFL=CFL) + Dt(step_offset) = integrand%dt(final_step=final_step, final_time=final_time, t=time(step_offset)) if (is_fast) then - call integrator%integrate_fast(U=integrand, stage=stage, buffer=buffer, Dt=Dt(step), t=time(step)) + call integrator%integrate_fast(U=integrand, stage=stage, buffer=buffer, Dt=Dt(step_offset), t=time(step_offset)) else - call integrator%integrate(U=integrand, stage=stage, Dt=Dt(step), t=time(step)) + call integrator%integrate(U=integrand, stage=stage, Dt=Dt(step_offset), t=time(step_offset)) endif - time(step) = time(step-1) + Dt(step) - if (save_results.and.mod(step, save_frequency)==0) call integrand%export_tecplot(file_name=output_file_name, t=time(step)) - if ((time(step) == final_time).or.(step == final_step)) exit + call update_previous_times + if (save_results.and.mod(step, save_frequency)==0) call integrand%export_tecplot(t=time(step_offset)) + if ((time(step_offset) == final_time).or.(step == final_step)) exit enddo endselect if (save_results) call integrand%export_tecplot(close_file=.true.) + contains + subroutine update_previous_times + !< Update previous times. + real(R_P) :: temporary !< Temporary buffer. + integer(I_P) :: p !< Counter. + + do p=1, step_offset - 1 + Dt(p) = Dt(p + 1) + enddo + temporary = time(step_offset) + time(step_offset) = time(step_offset) + Dt(step_offset) + do p=0, step_offset - 2 + time(p) = time(p + 1) + enddo + time(step_offset-1) = temporary + endsubroutine update_previous_times endsubroutine integrate endmodule foodie_test_ladvection_test diff --git a/src/third_party/WenOOF b/src/third_party/WenOOF index f4f5a40e..664cb5b1 160000 --- a/src/third_party/WenOOF +++ b/src/third_party/WenOOF @@ -1 +1 @@ -Subproject commit f4f5a40e4f4839a03559c1142e92701308331395 +Subproject commit 664cb5b131609a915253f64d041c0863f33ee8ee From 9f065e75af14f0e0908f8f23283cfc2b71619642 Mon Sep 17 00:00:00 2001 From: Stefano Zaghi Date: Mon, 15 May 2017 18:10:53 +0200 Subject: [PATCH 04/25] minor improvements to advection test --- .../ladvection/foodie_test_ladvection.f90 | 72 ++++++++++--------- 1 file changed, 37 insertions(+), 35 deletions(-) diff --git a/src/tests/ladvection/foodie_test_ladvection.f90 b/src/tests/ladvection/foodie_test_ladvection.f90 index e3a59df1..044492d2 100644 --- a/src/tests/ladvection/foodie_test_ladvection.f90 +++ b/src/tests/ladvection/foodie_test_ladvection.f90 @@ -37,19 +37,19 @@ module foodie_test_ladvection_test !< !< Test has only 1 public method `execute`: it executes test(s) accordingly to cli options. private - type(command_line_interface) :: cli !< Command line interface handler. - integer(I_P) :: error=0 !< Error handler. - character(99) :: scheme='' !< Scheme used. - logical :: is_fast=.false. !< Flag for activating fast schemes. - integer(I_P) :: implicit_iterations=0 !< Number of iterations (implicit solvers). - integer(I_P) :: stages=0 !< Number of stages. - integer(I_P) :: final_step=0 !< Maximum number of time steps. - real(R_P) :: final_time=0._R_P !< Final integration time. - logical :: save_results=.false. !< Flag for activating results saving. - integer(I_P) :: save_frequency=0 !< Output save frequency. - character(99) :: output='' !< Output files basename. - logical :: verbose=.false. !< Flag for activating verbose output. - type(integrand_ladvection) :: integrand_0 !< Initial conditions. + type(command_line_interface) :: cli !< Command line interface handler. + integer(I_P) :: error=0 !< Error handler. + character(99) :: scheme='' !< Scheme used. + logical :: is_fast=.false. !< Flag for activating fast schemes. + integer(I_P) :: implicit_iterations=0 !< Number of iterations (implicit solvers). + integer(I_P) :: stages=0 !< Number of stages. + integer(I_P) :: final_step=0 !< Maximum number of time steps. + real(R_P) :: final_time=0._R_P !< Final integration time. + logical :: save_results=.false. !< Flag for activating results saving. + integer(I_P) :: save_frequency=0 !< Output save frequency. + character(99) :: output='' !< Output files basename. + logical :: verbose=.false. !< Flag for activating verbose output. + type(integrand_ladvection) :: integrand_0 !< Initial conditions. contains ! public methods procedure, pass(self) :: execute !< Execute selected test(s). @@ -256,27 +256,24 @@ subroutine integrate(scheme, integrand_0, final_step, final_time, iterations, st type is(integrator_adams_bashforth_moulton) do step = step + 1 - Dt(step) = integrand%dt(final_step=final_step, final_time=final_time, t=time(step)) if (integrator%steps_number() >= step) then + Dt(step) = integrand%dt(final_step=final_step, final_time=final_time, t=time(step)) call integrator_start%integrate(U=integrand, stage=stage_start, Dt=Dt(step), t=time(step)) previous(step) = integrand + time(step) = time(step-1) + Dt(step) + if (save_results.and.mod(step, save_frequency)==0) call integrand%export_tecplot(t=time(step)) + if ((time(step) == final_time).or.(step == final_step)) exit else + Dt(step_offset) = integrand%dt(final_step=final_step, final_time=final_time, t=time(step_offset)) if (is_fast) then - call integrator%integrate_fast(U=integrand, & - previous=previous, & - buffer=buffer, & - Dt=Dt(step), & - t=time(step-integrator%steps_number():step-1)) + call integrator%integrate_fast(U=integrand, previous=previous, buffer=buffer, Dt=Dt(step_offset), t=time) else - call integrator%integrate(U=integrand, & - previous=previous, & - Dt=Dt(step), & - t=time(step-integrator%steps_number():step-1)) + call integrator%integrate(U=integrand, previous=previous, Dt=Dt(step_offset), t=time) endif + call update_previous_times + if (save_results.and.mod(step, save_frequency)==0) call integrand%export_tecplot(t=time(step_offset)) + if ((time(step_offset) == final_time).or.(step == final_step)) exit endif - time(step) = time(step-1) + Dt(step) - if (save_results.and.mod(step, save_frequency)==0) call integrand%export_tecplot(t=time(step)) - if ((time(step) == final_time).or.(step == final_step)) exit enddo type is(integrator_adams_moulton) @@ -366,29 +363,34 @@ subroutine integrate(scheme, integrand_0, final_step, final_time, iterations, st type is(integrator_leapfrog) do step = step + 1 - Dt(step) = integrand%dt(final_step=final_step, final_time=final_time, t=time(step)) if (integrator%steps_number() >= step) then + Dt(step) = integrand%dt(final_step=final_step, final_time=final_time, t=time(step)) call integrator_start%integrate(U=integrand, stage=stage_start, Dt=Dt(step), t=time(step)) previous(step) = integrand + time(step) = time(step-1) + Dt(step) + if (save_results.and.mod(step, save_frequency)==0) call integrand%export_tecplot(t=time(step)) + if ((time(step) == final_time).or.(step == final_step)) exit else + Dt(step_offset) = integrand%dt(final_step=final_step, final_time=final_time, t=time(step_offset)) if (index(scheme, 'raw') > 0 ) then if (is_fast) then - call integrator%integrate_fast(U=integrand, previous=previous, buffer=buffer, Dt=Dt(step), & - t=time(step), filter=filter) + call integrator%integrate_fast(U=integrand, previous=previous, buffer=buffer, Dt=Dt(step_offset), & + t=time(step_offset), filter=filter) else - call integrator%integrate(U=integrand, previous=previous, Dt=Dt(step), t=time(step), filter=filter) + call integrator%integrate(U=integrand, previous=previous, Dt=Dt(step_offset), t=time(step_offset), filter=filter) endif else if (is_fast) then - call integrator%integrate_fast(U=integrand, previous=previous, buffer=buffer, Dt=Dt(step), t=time(step)) + call integrator%integrate_fast(U=integrand, previous=previous, buffer=buffer, Dt=Dt(step_offset), & + t=time(step_offset)) else - call integrator%integrate(U=integrand, previous=previous, Dt=Dt(step), t=time(step)) + call integrator%integrate(U=integrand, previous=previous, Dt=Dt(step_offset), t=time(step_offset)) endif endif + call update_previous_times + if (save_results.and.mod(step, save_frequency)==0) call integrand%export_tecplot(t=time(step_offset)) + if ((time(step_offset) == final_time).or.(step == final_step)) exit endif - time(step) = time(step-1) + Dt(step) - if (save_results.and.mod(step, save_frequency)==0) call integrand%export_tecplot(t=time(step)) - if ((time(step) == final_time).or.(step == final_step)) exit enddo type is(integrator_lmm_ssp) From 7a1e15df6bbb9502ea0b0db84b3bb04e7f455d34 Mon Sep 17 00:00:00 2001 From: Stefano Zaghi Date: Mon, 15 May 2017 18:27:04 +0200 Subject: [PATCH 05/25] make integrate subroutine integrand-agnostic --- .../ladvection/foodie_test_ladvection.f90 | 150 ++++++++++-------- 1 file changed, 86 insertions(+), 64 deletions(-) diff --git a/src/tests/ladvection/foodie_test_ladvection.f90 b/src/tests/ladvection/foodie_test_ladvection.f90 index 044492d2..8d2a6f5a 100644 --- a/src/tests/ladvection/foodie_test_ladvection.f90 +++ b/src/tests/ladvection/foodie_test_ladvection.f90 @@ -8,6 +8,7 @@ module foodie_test_ladvection_test use foodie, only : foodie_integrator_class_names, & foodie_integrator_factory, & foodie_integrator_schemes, & + integrand_object, & integrator_adams_bashforth, & integrator_adams_bashforth_moulton, & integrator_adams_moulton, & @@ -177,42 +178,49 @@ subroutine check_scheme_has_fast_mode(scheme, integrator) subroutine integrate(scheme, integrand_0, final_step, final_time, iterations, stages, is_fast, & save_results, save_frequency, output_base_name) !< Integrate integrand by means of the given scheme. - character(*), intent(in) :: scheme !< Selected scheme. - type(integrand_ladvection), intent(in) :: integrand_0 !< Initial conditions. - integer(I_P), intent(in) :: final_step !< Final integration step. - real(R_P), intent(in) :: final_time !< Final integration time. - integer(I_P), intent(in) :: iterations !< Number of fixed point iterations. - integer(I_P), intent(in) :: stages !< Number of stages. - logical, intent(in) :: is_fast !< Activate fast mode integration. - logical, intent(in) :: save_results !< Save results. - integer(I_P), intent(in) :: save_frequency !< Save frequency as steps multiple. - character(*), intent(in) :: output_base_name !< Base name of output results file. - class(integrator_object), allocatable :: integrator !< The integrator. - type(integrator_runge_kutta_ssp) :: integrator_start !< The (auto) start integrator. - type(integrand_ladvection) :: integrand !< Integrand. - type(integrand_ladvection), allocatable :: previous(:) !< Previous time steps solutions. - type(integrand_ladvection), allocatable :: stage(:) !< Runge-Kutta stages. - type(integrand_ladvection), allocatable :: stage_start(:) !< Runge-Kutta (autor) start stages. - type(integrand_ladvection) :: buffer !< Buffer oscillation field. - type(integrand_ladvection) :: filter !< Filter displacement. - real(R_P), allocatable :: time(:) !< Time. - real(R_P), allocatable :: Dt(:) !< Time steps. - real(R_P) :: Dt_a !< Autoadptive time step. - integer :: step !< Time steps counter. - integer :: step_offset !< Time steps counter offset for slicing previous data array. - character(len=:), allocatable :: output_file_name !< File name of output results file. + character(*), intent(in) :: scheme !< Selected scheme. + class(integrand_object), intent(in) :: integrand_0 !< Initial conditions. + integer(I_P), intent(in) :: final_step !< Final integration step. + real(R_P), intent(in) :: final_time !< Final integration time. + integer(I_P), intent(in) :: iterations !< Number of fixed point iterations. + integer(I_P), intent(in) :: stages !< Number of stages. + logical, intent(in) :: is_fast !< Activate fast mode integration. + logical, intent(in) :: save_results !< Save results. + integer(I_P), intent(in) :: save_frequency !< Save frequency as steps multiple. + character(*), intent(in) :: output_base_name !< Base name of output results file. + class(integrator_object), allocatable :: integrator !< The integrator. + type(integrator_runge_kutta_ssp) :: integrator_start !< The (auto) start integrator. + class(integrand_object), allocatable :: integrand !< Integrand. + class(integrand_object), allocatable :: previous(:) !< Previous time steps solutions. + class(integrand_object), allocatable :: stage(:) !< Runge-Kutta stages. + class(integrand_object), allocatable :: stage_start(:) !< Runge-Kutta (autor) start stages. + class(integrand_object), allocatable :: buffer !< Buffer oscillation field. + class(integrand_object), allocatable :: filter !< Filter displacement. + real(R_P), allocatable :: time(:) !< Time. + real(R_P), allocatable :: Dt(:) !< Time steps. + real(R_P) :: Dt_a !< Autoadptive time step. + integer :: step !< Time steps counter. + integer :: step_offset !< Time steps counter offset for slicing previous data array. + character(len=:), allocatable :: output_file_name !< File name of output results file. + + allocate(integrand, mold=integrand_0) + allocate(buffer, mold=integrand_0) + allocate(filter, mold=integrand_0) integrand = integrand_0 - output_file_name = trim(adjustl(output_base_name))//'-'//trim(adjustl(scheme))//'-'//trim(strz(integrand%Ni, 10))//'.dat' + select type(integrand) + type is(integrand_ladvection) + output_file_name = trim(adjustl(output_base_name))//'-'//trim(adjustl(scheme))//'-'//trim(strz(integrand%Ni, 10))//'.dat' + endselect call foodie_integrator_factory(scheme=scheme, integrator=integrator, stages=stages, tolerance=1e2_R_P) if (is_fast) call check_scheme_has_fast_mode(scheme=trim(adjustl(scheme)), integrator=integrator) if (integrator%is_multistep()) then - allocate(previous(1:integrator%steps_number())) + allocate(previous(1:integrator%steps_number()), mold=integrand_0) call integrator_start%initialize(scheme='runge_kutta_ssp_stages_5_order_4') - allocate(stage_start(1:integrator_start%stages_number())) + allocate(stage_start(1:integrator_start%stages_number()), mold=integrand_0) if (integrator%steps_number()==0) then step_offset = 1 ! for 0 step-(a convention)-solver offset is 1 else @@ -221,34 +229,37 @@ subroutine integrate(scheme, integrand_0, final_step, final_time, iterations, st else step_offset = 1 ! for 0 step-(a convention)-solver offset is 1 endif - if (integrator%is_multistage()) allocate(stage(1:integrator%stages_number())) + if (integrator%is_multistage()) allocate(stage(1:integrator%stages_number()), mold=integrand_0) allocate(time(0:step_offset)) allocate(Dt(1:step_offset)) step = 0 time = 0._R_P Dt = 0._R_P - if (save_results) call integrand%export_tecplot(file_name=output_file_name, t=time(0)) + select type(integrand) + type is(integrand_ladvection) + if (save_results) call integrand%export_tecplot(file_name=output_file_name, t=time(0)) + endselect select type(integrator) type is(integrator_adams_bashforth) do step = step + 1 if (integrator%steps_number() >= step) then - Dt(step) = integrand%dt(final_step=final_step, final_time=final_time, t=time(step)) + ! Dt(step) = integrand%dt(final_step=final_step, final_time=final_time, t=time(step)) call integrator_start%integrate(U=integrand, stage=stage_start, Dt=Dt(step), t=time(step)) previous(step) = integrand time(step) = time(step-1) + Dt(step) - if (save_results.and.mod(step, save_frequency)==0) call integrand%export_tecplot(t=time(step)) + ! if (save_results.and.mod(step, save_frequency)==0) call integrand%export_tecplot(t=time(step)) if ((time(step) == final_time).or.(step == final_step)) exit else - Dt(step_offset) = integrand%dt(final_step=final_step, final_time=final_time, t=time(step_offset)) + ! Dt(step_offset) = integrand%dt(final_step=final_step, final_time=final_time, t=time(step_offset)) if (is_fast) then call integrator%integrate_fast(U=integrand, previous=previous, buffer=buffer, Dt=Dt(step_offset), t=time) else call integrator%integrate(U=integrand, previous=previous, Dt=Dt(step_offset), t=time) endif call update_previous_times - if (save_results.and.mod(step, save_frequency)==0) call integrand%export_tecplot(t=time(step_offset)) + ! if (save_results.and.mod(step, save_frequency)==0) call integrand%export_tecplot(t=time(step_offset)) if ((time(step_offset) == final_time).or.(step == final_step)) exit endif enddo @@ -257,30 +268,30 @@ subroutine integrate(scheme, integrand_0, final_step, final_time, iterations, st do step = step + 1 if (integrator%steps_number() >= step) then - Dt(step) = integrand%dt(final_step=final_step, final_time=final_time, t=time(step)) + ! Dt(step) = integrand%dt(final_step=final_step, final_time=final_time, t=time(step)) call integrator_start%integrate(U=integrand, stage=stage_start, Dt=Dt(step), t=time(step)) previous(step) = integrand time(step) = time(step-1) + Dt(step) - if (save_results.and.mod(step, save_frequency)==0) call integrand%export_tecplot(t=time(step)) + ! if (save_results.and.mod(step, save_frequency)==0) call integrand%export_tecplot(t=time(step)) if ((time(step) == final_time).or.(step == final_step)) exit else - Dt(step_offset) = integrand%dt(final_step=final_step, final_time=final_time, t=time(step_offset)) + ! Dt(step_offset) = integrand%dt(final_step=final_step, final_time=final_time, t=time(step_offset)) if (is_fast) then call integrator%integrate_fast(U=integrand, previous=previous, buffer=buffer, Dt=Dt(step_offset), t=time) else call integrator%integrate(U=integrand, previous=previous, Dt=Dt(step_offset), t=time) endif call update_previous_times - if (save_results.and.mod(step, save_frequency)==0) call integrand%export_tecplot(t=time(step_offset)) + ! if (save_results.and.mod(step, save_frequency)==0) call integrand%export_tecplot(t=time(step_offset)) if ((time(step_offset) == final_time).or.(step == final_step)) exit endif enddo type is(integrator_adams_moulton) - if (allocated(previous)) deallocate(previous) ; allocate(previous(1:integrator%steps_number()+1)) + if (allocated(previous)) deallocate(previous) ; allocate(previous(1:integrator%steps_number()+1), mold=integrand_0) do step = step + 1 - Dt(step) = integrand%dt(final_step=final_step, final_time=final_time, t=time(step)) + ! Dt(step) = integrand%dt(final_step=final_step, final_time=final_time, t=time(step)) if (integrator%steps_number() >= step) then call integrator_start%integrate(U=integrand, stage=stage_start, Dt=Dt(step), t=time(step)) previous(step) = integrand @@ -316,14 +327,14 @@ subroutine integrate(scheme, integrand_0, final_step, final_time, iterations, st endif endif time(step) = time(step-1) + Dt(step) - if (save_results.and.mod(step, save_frequency)==0) call integrand%export_tecplot(t=time(step)) + ! if (save_results.and.mod(step, save_frequency)==0) call integrand%export_tecplot(t=time(step)) if ((time(step) == final_time).or.(step == final_step)) exit enddo type is(integrator_back_df) do step = step + 1 - Dt(step) = integrand%dt(final_step=final_step, final_time=final_time, t=time(step)) + ! Dt(step) = integrand%dt(final_step=final_step, final_time=final_time, t=time(step)) if (integrator%steps_number() >= step) then call integrator_start%integrate(U=integrand, stage=stage_start, Dt=Dt(step), t=time(step)) previous(step) = integrand @@ -342,21 +353,21 @@ subroutine integrate(scheme, integrand_0, final_step, final_time, iterations, st endif endif time(step) = time(step-1) + Dt(step) - if (save_results.and.mod(step, save_frequency)==0) call integrand%export_tecplot(t=time(step)) + ! if (save_results.and.mod(step, save_frequency)==0) call integrand%export_tecplot(t=time(step)) if ((time(step) == final_time).or.(step == final_step)) exit enddo type is(integrator_euler_explicit) do step = step + 1 - Dt(step_offset) = integrand%dt(final_step=final_step, final_time=final_time, t=time(step_offset)) + ! Dt(step_offset) = integrand%dt(final_step=final_step, final_time=final_time, t=time(step_offset)) if (is_fast) then call integrator%integrate_fast(U=integrand, buffer=buffer, Dt=Dt(step_offset), t=time(step_offset)) else call integrator%integrate(U=integrand, Dt=Dt(step_offset), t=time(step_offset)) endif call update_previous_times - if (save_results.and.mod(step, save_frequency)==0) call integrand%export_tecplot(t=time(step_offset)) + ! if (save_results.and.mod(step, save_frequency)==0) call integrand%export_tecplot(t=time(step_offset)) if ((time(step_offset) == final_time).or.(step == final_step)) exit enddo @@ -364,14 +375,14 @@ subroutine integrate(scheme, integrand_0, final_step, final_time, iterations, st do step = step + 1 if (integrator%steps_number() >= step) then - Dt(step) = integrand%dt(final_step=final_step, final_time=final_time, t=time(step)) + ! Dt(step) = integrand%dt(final_step=final_step, final_time=final_time, t=time(step)) call integrator_start%integrate(U=integrand, stage=stage_start, Dt=Dt(step), t=time(step)) previous(step) = integrand time(step) = time(step-1) + Dt(step) - if (save_results.and.mod(step, save_frequency)==0) call integrand%export_tecplot(t=time(step)) + ! if (save_results.and.mod(step, save_frequency)==0) call integrand%export_tecplot(t=time(step)) if ((time(step) == final_time).or.(step == final_step)) exit else - Dt(step_offset) = integrand%dt(final_step=final_step, final_time=final_time, t=time(step_offset)) + ! Dt(step_offset) = integrand%dt(final_step=final_step, final_time=final_time, t=time(step_offset)) if (index(scheme, 'raw') > 0 ) then if (is_fast) then call integrator%integrate_fast(U=integrand, previous=previous, buffer=buffer, Dt=Dt(step_offset), & @@ -388,7 +399,7 @@ subroutine integrate(scheme, integrand_0, final_step, final_time, iterations, st endif endif call update_previous_times - if (save_results.and.mod(step, save_frequency)==0) call integrand%export_tecplot(t=time(step_offset)) + ! if (save_results.and.mod(step, save_frequency)==0) call integrand%export_tecplot(t=time(step_offset)) if ((time(step_offset) == final_time).or.(step == final_step)) exit endif enddo @@ -396,7 +407,7 @@ subroutine integrate(scheme, integrand_0, final_step, final_time, iterations, st type is(integrator_lmm_ssp) do step = step + 1 - Dt(step) = integrand%dt(final_step=final_step, final_time=final_time, t=time(step)) + ! Dt(step) = integrand%dt(final_step=final_step, final_time=final_time, t=time(step)) if (integrator%steps_number() >= step) then call integrator_start%integrate(U=integrand, stage=stage_start, Dt=Dt(step), t=time(step)) previous(step) = integrand @@ -415,14 +426,14 @@ subroutine integrate(scheme, integrand_0, final_step, final_time, iterations, st endif endif time(step) = time(step-1) + Dt(step) - if (save_results.and.mod(step, save_frequency)==0) call integrand%export_tecplot(t=time(step)) + ! if (save_results.and.mod(step, save_frequency)==0) call integrand%export_tecplot(t=time(step)) if ((time(step) == final_time).or.(step == final_step)) exit enddo type is(integrator_lmm_ssp_vss) do step = step + 1 - Dt(step) = integrand%dt(final_step=final_step, final_time=final_time, t=time(step)) + ! Dt(step) = integrand%dt(final_step=final_step, final_time=final_time, t=time(step)) if (integrator%steps_number() >= step) then call integrator_start%integrate(U=integrand, stage=stage_start, Dt=Dt(step), t=time(step)) previous(step) = integrand @@ -441,14 +452,14 @@ subroutine integrate(scheme, integrand_0, final_step, final_time, iterations, st endif endif time(step) = time(step-1) + Dt(step) - if (save_results.and.mod(step, save_frequency)==0) call integrand%export_tecplot(t=time(step)) + ! if (save_results.and.mod(step, save_frequency)==0) call integrand%export_tecplot(t=time(step)) if ((time(step) == final_time).or.(step == final_step)) exit enddo type is(integrator_ms_runge_kutta_ssp) do step = step + 1 - Dt(step) = integrand%dt(final_step=final_step, final_time=final_time, t=time(step)) + ! Dt(step) = integrand%dt(final_step=final_step, final_time=final_time, t=time(step)) if (integrator%steps_number() >= step) then call integrator_start%integrate(U=integrand, stage=stage_start, Dt=Dt(step), t=time(step)) previous(step) = integrand @@ -469,14 +480,14 @@ subroutine integrate(scheme, integrand_0, final_step, final_time, iterations, st endif endif time(step) = time(step-1) + Dt(step) - if (save_results.and.mod(step, save_frequency)==0) call integrand%export_tecplot(t=time(step)) + ! if (save_results.and.mod(step, save_frequency)==0) call integrand%export_tecplot(t=time(step)) if ((time(step) == final_time).or.(step == final_step)) exit enddo type is(integrator_runge_kutta_emd) do step = step + 1 - Dt(step) = integrand%dt(final_step=final_step, final_time=final_time, t=time(step)) + ! Dt(step) = integrand%dt(final_step=final_step, final_time=final_time, t=time(step)) Dt_a = Dt(step) if (is_fast) then call integrator%integrate_fast(U=integrand, stage=stage, buffer=buffer, Dt=Dt_a, t=time(step)) @@ -484,55 +495,66 @@ subroutine integrate(scheme, integrand_0, final_step, final_time, iterations, st call integrator%integrate(U=integrand, stage=stage, Dt=Dt_a, t=time(step)) endif time(step) = time(step-1) + Dt(step) - if (save_results.and.mod(step, save_frequency)==0) call integrand%export_tecplot(t=time(step)) + ! if (save_results.and.mod(step, save_frequency)==0) call integrand%export_tecplot(t=time(step)) if ((time(step) == final_time).or.(step == final_step)) exit enddo type is(integrator_runge_kutta_ls) - if (allocated(stage)) deallocate(stage) ; allocate(stage(1:integrator%registers_number())) + if (allocated(stage)) deallocate(stage) ; allocate(stage(1:integrator%registers_number()), mold=integrand_0) do step = step + 1 - Dt(step) = integrand%dt(final_step=final_step, final_time=final_time, t=time(step)) + ! Dt(step) = integrand%dt(final_step=final_step, final_time=final_time, t=time(step)) if (is_fast) then call integrator%integrate_fast(U=integrand, stage=stage, buffer=buffer, Dt=Dt(step), t=time(step)) else call integrator%integrate(U=integrand, stage=stage, Dt=Dt(step), t=time(step)) endif time(step) = time(step-1) + Dt(step) - if (save_results.and.mod(step, save_frequency)==0) call integrand%export_tecplot(t=time(step)) + ! if (save_results.and.mod(step, save_frequency)==0) call integrand%export_tecplot(t=time(step)) if ((time(step) == final_time).or.(step == final_step)) exit enddo type is(integrator_runge_kutta_lssp) do step = step + 1 - Dt(step_offset) = integrand%dt(final_step=final_step, final_time=final_time, t=time(step_offset)) + ! Dt(step_offset) = integrand%dt(final_step=final_step, final_time=final_time, t=time(step_offset)) if (is_fast) then call integrator%integrate_fast(U=integrand, stage=stage, buffer=buffer, Dt=Dt(step_offset), t=time(step_offset)) else call integrator%integrate(U=integrand, stage=stage, Dt=Dt(step_offset), t=time(step_offset)) endif call update_previous_times - if (save_results.and.mod(step, save_frequency)==0) call integrand%export_tecplot(t=time(step_offset)) + ! if (save_results.and.mod(step, save_frequency)==0) call integrand%export_tecplot(t=time(step_offset)) if ((time(step_offset) == final_time).or.(step == final_step)) exit enddo type is(integrator_runge_kutta_ssp) do step = step + 1 - Dt(step_offset) = integrand%dt(final_step=final_step, final_time=final_time, t=time(step_offset)) + ! Dt(step_offset) = integrand%dt(final_step=final_step, final_time=final_time, t=time(step_offset)) + select type(integrand) + type is(integrand_ladvection) + Dt(step_offset) = integrand%dt(final_step=final_step, final_time=final_time, t=time(step_offset)) + endselect if (is_fast) then call integrator%integrate_fast(U=integrand, stage=stage, buffer=buffer, Dt=Dt(step_offset), t=time(step_offset)) else call integrator%integrate(U=integrand, stage=stage, Dt=Dt(step_offset), t=time(step_offset)) endif call update_previous_times - if (save_results.and.mod(step, save_frequency)==0) call integrand%export_tecplot(t=time(step_offset)) + ! if (save_results.and.mod(step, save_frequency)==0) call integrand%export_tecplot(t=time(step_offset)) + select type(integrand) + type is(integrand_ladvection) + if (save_results.and.mod(step, save_frequency)==0) call integrand%export_tecplot(t=time(step_offset)) + endselect if ((time(step_offset) == final_time).or.(step == final_step)) exit enddo endselect - if (save_results) call integrand%export_tecplot(close_file=.true.) + select type(integrand) + type is(integrand_ladvection) + if (save_results) call integrand%export_tecplot(close_file=.true.) + endselect contains subroutine update_previous_times !< Update previous times. From ef7439ca2fcdd6f4f60c0f6b72db5094e91b2368 Mon Sep 17 00:00:00 2001 From: Stefano Zaghi Date: Mon, 15 May 2017 23:11:21 +0200 Subject: [PATCH 06/25] add intermediate rk integrator --- src/lib/foodie_integrator_object.f90 | 4 +- ...die_integrator_runge_kutta_low_storage.f90 | 23 +----- .../foodie_integrator_runge_kutta_lssp.f90 | 23 +----- .../foodie_integrator_runge_kutta_object.f90 | 70 +++++++++++++++++++ src/lib/foodie_integrator_runge_kutta_ssp.f90 | 23 +----- 5 files changed, 78 insertions(+), 65 deletions(-) create mode 100644 src/lib/foodie_integrator_runge_kutta_object.f90 diff --git a/src/lib/foodie_integrator_object.f90 b/src/lib/foodie_integrator_object.f90 index e34d44f9..19559243 100644 --- a/src/lib/foodie_integrator_object.f90 +++ b/src/lib/foodie_integrator_object.f90 @@ -1,7 +1,7 @@ -!< Define the abstract type *integrator* of FOODIE ODE integrators. +!< Define the abstract type [[integrator_object]] of FOODIE ODE integrators. module foodie_integrator_object -!< Define the abstract type *integrator* of FOODIE ODE integrators. +!< Define the abstract type [[integrator_object]] of FOODIE ODE integrators. use, intrinsic :: iso_fortran_env, only : stderr=>error_unit use penf, only : I_P diff --git a/src/lib/foodie_integrator_runge_kutta_low_storage.f90 b/src/lib/foodie_integrator_runge_kutta_low_storage.f90 index a48580e0..e99c7481 100644 --- a/src/lib/foodie_integrator_runge_kutta_low_storage.f90 +++ b/src/lib/foodie_integrator_runge_kutta_low_storage.f90 @@ -150,6 +150,7 @@ module foodie_integrator_runge_kutta_low_storage use foodie_error_codes, only : ERROR_UNSUPPORTED_SCHEME use foodie_integrand_object, only : integrand_object use foodie_integrator_object, only : integrator_object +use foodie_integrator_runge_kutta_object, only : integrator_runge_kutta_object use penf, only : I_P, I8P, R_P implicit none @@ -168,10 +169,8 @@ module foodie_integrator_runge_kutta_low_storage integer(I_P), parameter :: registers=2 !< Registers used (2N schemes). logical, parameter :: has_fast_mode_=.true. !< Flag to check if integrator provides *fast mode* integrate. -logical, parameter :: is_multistage_=.true. !< Flag to check if integrator is multistage. -logical, parameter :: is_multistep_=.false. !< Flag to check if integrator is multistep. -type, extends(integrator_object) :: integrator_runge_kutta_ls +type, extends(integrator_runge_kutta_object) :: integrator_runge_kutta_ls !< FOODIE integrator: provide an explicit class of low storage Runge-Kutta schemes, from 1st to 4th order accurate. !< !< @note The integrator must be created or initialized (initialize the RK coefficients) before used. @@ -186,8 +185,6 @@ module foodie_integrator_runge_kutta_low_storage procedure, pass(self) :: description !< Return pretty-printed object description. procedure, pass(self) :: has_fast_mode !< Return .true. if the integrator class has *fast mode* integrate. procedure, pass(lhs) :: integr_assign_integr !< Operator `=`. - procedure, pass(self) :: is_multistage !< Return .true. for multistage integrator. - procedure, pass(self) :: is_multistep !< Return .true. for multistep integrator. procedure, pass(self) :: is_supported !< Return .true. if the integrator class support the given scheme. procedure, pass(self) :: stages_number !< Return number of stages used. procedure, pass(self) :: steps_number !< Return number of steps used. @@ -252,22 +249,6 @@ pure subroutine integr_assign_integr(lhs, rhs) endselect endsubroutine integr_assign_integr - elemental function is_multistage(self) - !< Return .true. for multistage integrator. - class(integrator_runge_kutta_ls), intent(in) :: self !< Integrator. - logical :: is_multistage !< Inquire result. - - is_multistage = is_multistage_ - endfunction is_multistage - - elemental function is_multistep(self) - !< Return .true. for multistage integrator. - class(integrator_runge_kutta_ls), intent(in) :: self !< Integrator. - logical :: is_multistep !< Inquire result. - - is_multistep = is_multistep_ - endfunction is_multistep - elemental function is_supported(self, scheme) !< Return .true. if the integrator class support the given scheme. class(integrator_runge_kutta_ls), intent(in) :: self !< Integrator. diff --git a/src/lib/foodie_integrator_runge_kutta_lssp.f90 b/src/lib/foodie_integrator_runge_kutta_lssp.f90 index e58012bc..55334383 100644 --- a/src/lib/foodie_integrator_runge_kutta_lssp.f90 +++ b/src/lib/foodie_integrator_runge_kutta_lssp.f90 @@ -65,6 +65,7 @@ module foodie_integrator_runge_kutta_lssp use foodie_error_codes, only : ERROR_UNSUPPORTED_SCHEME use foodie_integrand_object, only : integrand_object use foodie_integrator_object, only : integrator_object +use foodie_integrator_runge_kutta_object, only : integrator_runge_kutta_object use penf, only : I_P, R_P implicit none @@ -76,10 +77,8 @@ module foodie_integrator_runge_kutta_lssp trim(class_name_)//'_stages_s_order_s '] !< List of supported schemes. logical, parameter :: has_fast_mode_=.true. !< Flag to check if integrator provides *fast mode* integrate. -logical, parameter :: is_multistage_=.true. !< Flag to check if integrator is multistage. -logical, parameter :: is_multistep_=.false. !< Flag to check if integrator is multistep. -type, extends(integrator_object) :: integrator_runge_kutta_lssp +type, extends(integrator_runge_kutta_object) :: integrator_runge_kutta_lssp !< FOODIE integrator: provide an explicit class of Linear SSP Runge-Kutta schemes, from 1st to s-th order accurate. !< !< @note The integrator must be created or initialized (initialize the RK coefficients) before used. @@ -94,8 +93,6 @@ module foodie_integrator_runge_kutta_lssp procedure, pass(self) :: description !< Return pretty-printed object description. procedure, pass(self) :: has_fast_mode !< Return .true. if the integrator class has *fast mode* integrate. procedure, pass(lhs) :: integr_assign_integr !< Operator `=`. - procedure, pass(self) :: is_multistage !< Return .true. for multistage integrator. - procedure, pass(self) :: is_multistep !< Return .true. for multistep integrator. procedure, pass(self) :: is_supported !< Return .true. if the integrator class support the given scheme. procedure, pass(self) :: stages_number !< Return number of stages used. procedure, pass(self) :: steps_number !< Return number of steps used. @@ -186,22 +183,6 @@ pure subroutine integr_assign_integr(lhs, rhs) endselect endsubroutine integr_assign_integr - elemental function is_multistage(self) - !< Return .true. for multistage integrator. - class(integrator_runge_kutta_lssp), intent(in) :: self !< Integrator. - logical :: is_multistage !< Inquire result. - - is_multistage = is_multistage_ - endfunction is_multistage - - elemental function is_multistep(self) - !< Return .true. for multistage integrator. - class(integrator_runge_kutta_lssp), intent(in) :: self !< Integrator. - logical :: is_multistep !< Inquire result. - - is_multistep = is_multistep_ - endfunction is_multistep - elemental function is_supported(self, scheme) !< Return .true. if the integrator class support the given scheme. class(integrator_runge_kutta_lssp), intent(in) :: self !< Integrator. diff --git a/src/lib/foodie_integrator_runge_kutta_object.f90 b/src/lib/foodie_integrator_runge_kutta_object.f90 new file mode 100644 index 00000000..d5cdcf21 --- /dev/null +++ b/src/lib/foodie_integrator_runge_kutta_object.f90 @@ -0,0 +1,70 @@ +!< Define the abstract type [[integrator_runge_kutta_object]] of FOODIE ODE integrators. + +module foodie_integrator_runge_kutta_object +!< Define the abstract type [[integrator_runge_kutta_object]] of FOODIE ODE integrators. + +use, intrinsic :: iso_fortran_env, only : stderr=>error_unit +use foodie_integrand_object, only : integrand_object +use foodie_integrator_object, only : integrator_object +use penf, only : I_P, R_P + +implicit none +private +public :: integrator_runge_kutta_object + +logical, parameter :: is_multistage_=.true. !< Flag to check if integrator is multistage. +logical, parameter :: is_multistep_=.false. !< Flag to check if integrator is multistep. + +type, extends(integrator_object), abstract :: integrator_runge_kutta_object + !< Abstract type of FOODIE ODE integrators of the family Runge-Kutta. + contains + ! deferred methods + procedure(integrate_interface), pass(self), deferred :: integrate !< Integrate integrand field. + procedure(integrate_fast_interface), pass(self), deferred :: integrate_fast !< Integrate integrand field, fast mode. + ! deferred methods of parent + procedure, pass(self) :: is_multistage !< Return .true. for multistage integrator. + procedure, pass(self) :: is_multistep !< Return .true. for multistep integrator. +endtype integrator_runge_kutta_object + +abstract interface + !< Abstract interfaces of deferred methods of [[integrator_object]]. + subroutine integrate_interface(self, U, stage, Dt, t) + !< Integrate integrand field. + import :: integrand_object, integrator_runge_kutta_object, R_P + class(integrator_runge_kutta_object), intent(in) :: self !< Integrator. + class(integrand_object), intent(inout) :: U !< Integrand. + class(integrand_object), intent(inout) :: stage(1:) !< Runge-Kutta stages. + real(R_P), intent(in) :: Dt !< Time step. + real(R_P), intent(in) :: t !< Time. + endsubroutine integrate_interface + + subroutine integrate_fast_interface(self, U, stage, buffer, Dt, t) + !< Integrate integrand field, fast mode. + import :: integrand_object, integrator_runge_kutta_object, R_P + class(integrator_runge_kutta_object), intent(in) :: self !< Integrator. + class(integrand_object), intent(inout) :: U !< Field to be integrated. + class(integrand_object), intent(inout) :: stage(1:) !< Runge-Kutta stages. + class(integrand_object), intent(inout) :: buffer !< Temporary buffer for doing fast operation. + real(R_P), intent(in) :: Dt !< Time step. + real(R_P), intent(in) :: t !< Time. + endsubroutine integrate_fast_interface +endinterface + +contains + ! public methods + elemental function is_multistage(self) + !< Return .true. for multistage integrator. + class(integrator_runge_kutta_object), intent(in) :: self !< Integrator. + logical :: is_multistage !< Inquire result. + + is_multistage = is_multistage_ + endfunction is_multistage + + elemental function is_multistep(self) + !< Return .true. for multistage integrator. + class(integrator_runge_kutta_object), intent(in) :: self !< Integrator. + logical :: is_multistep !< Inquire result. + + is_multistep = is_multistep_ + endfunction is_multistep +endmodule foodie_integrator_runge_kutta_object diff --git a/src/lib/foodie_integrator_runge_kutta_ssp.f90 b/src/lib/foodie_integrator_runge_kutta_ssp.f90 index e9bdc048..6e7319ae 100644 --- a/src/lib/foodie_integrator_runge_kutta_ssp.f90 +++ b/src/lib/foodie_integrator_runge_kutta_ssp.f90 @@ -103,6 +103,7 @@ module foodie_integrator_runge_kutta_ssp use foodie_error_codes, only : ERROR_UNSUPPORTED_SCHEME use foodie_integrand_object, only : integrand_object use foodie_integrator_object, only : integrator_object +use foodie_integrator_runge_kutta_object, only : integrator_runge_kutta_object use penf, only : I_P, R_P implicit none @@ -116,10 +117,8 @@ module foodie_integrator_runge_kutta_ssp trim(class_name_)//'_stages_5_order_4'] !< List of supported schemes. logical, parameter :: has_fast_mode_=.true. !< Flag to check if integrator provides *fast mode* integrate. -logical, parameter :: is_multistage_=.true. !< Flag to check if integrator is multistage. -logical, parameter :: is_multistep_=.false. !< Flag to check if integrator is multistep. -type, extends(integrator_object) :: integrator_runge_kutta_ssp +type, extends(integrator_runge_kutta_object) :: integrator_runge_kutta_ssp !< FOODIE integrator: provide an explicit class of SSP Runge-Kutta schemes, from 1st to 4th order accurate. !< !< @note The integrator must be created or initialized (initialize the RK coefficients) before used. @@ -134,8 +133,6 @@ module foodie_integrator_runge_kutta_ssp procedure, pass(self) :: description !< Return pretty-printed object description. procedure, pass(self) :: has_fast_mode !< Return .true. if the integrator class has *fast mode* integrate. procedure, pass(lhs) :: integr_assign_integr !< Operator `=`. - procedure, pass(self) :: is_multistage !< Return .true. for multistage integrator. - procedure, pass(self) :: is_multistep !< Return .true. for multistep integrator. procedure, pass(self) :: is_supported !< Return .true. if the integrator class support the given scheme. procedure, pass(self) :: stages_number !< Return number of stages used. procedure, pass(self) :: steps_number !< Return number of steps used. @@ -199,22 +196,6 @@ pure subroutine integr_assign_integr(lhs, rhs) endselect endsubroutine integr_assign_integr - elemental function is_multistage(self) - !< Return .true. for multistage integrator. - class(integrator_runge_kutta_ssp), intent(in) :: self !< Integrator. - logical :: is_multistage !< Inquire result. - - is_multistage = is_multistage_ - endfunction is_multistage - - elemental function is_multistep(self) - !< Return .true. for multistage integrator. - class(integrator_runge_kutta_ssp), intent(in) :: self !< Integrator. - logical :: is_multistep !< Inquire result. - - is_multistep = is_multistep_ - endfunction is_multistep - elemental function is_supported(self, scheme) !< Return .true. if the integrator class support the given scheme. class(integrator_runge_kutta_ssp), intent(in) :: self !< Integrator. From 67947e6db072ff90a19fea3278a0fb7e40b5f6e0 Mon Sep 17 00:00:00 2001 From: Stefano Zaghi Date: Mon, 15 May 2017 23:19:53 +0200 Subject: [PATCH 07/25] improve genericity of integrate subroutine --- src/lib/foodie.f90 | 2 + .../ladvection/foodie_test_ladvection.f90 | 71 ++++++------------- 2 files changed, 23 insertions(+), 50 deletions(-) diff --git a/src/lib/foodie.f90 b/src/lib/foodie.f90 index b147e226..b2acad42 100644 --- a/src/lib/foodie.f90 +++ b/src/lib/foodie.f90 @@ -77,6 +77,7 @@ module foodie use foodie_integrator_runge_kutta_emd, only : integrator_runge_kutta_emd use foodie_integrator_runge_kutta_low_storage, only : integrator_runge_kutta_ls use foodie_integrator_runge_kutta_lssp, only : integrator_runge_kutta_lssp +use foodie_integrator_runge_kutta_object, only : integrator_runge_kutta_object use foodie_integrator_runge_kutta_ssp, only : integrator_runge_kutta_ssp use penf, only : I_P, R_P @@ -99,6 +100,7 @@ module foodie public :: integrator_runge_kutta_emd public :: integrator_runge_kutta_ls public :: integrator_runge_kutta_lssp +public :: integrator_runge_kutta_object public :: integrator_runge_kutta_ssp public :: is_available public :: is_class_available diff --git a/src/tests/ladvection/foodie_test_ladvection.f90 b/src/tests/ladvection/foodie_test_ladvection.f90 index 8d2a6f5a..d353eff5 100644 --- a/src/tests/ladvection/foodie_test_ladvection.f90 +++ b/src/tests/ladvection/foodie_test_ladvection.f90 @@ -22,6 +22,7 @@ module foodie_test_ladvection_test integrator_runge_kutta_emd, & integrator_runge_kutta_ls, & integrator_runge_kutta_lssp, & + integrator_runge_kutta_object, & integrator_runge_kutta_ssp, & is_available, is_class_available use foodie_test_integrand_ladvection, only : integrand_ladvection @@ -241,6 +242,26 @@ subroutine integrate(scheme, integrand_0, final_step, final_time, iterations, st if (save_results) call integrand%export_tecplot(file_name=output_file_name, t=time(0)) endselect select type(integrator) + class is(integrator_runge_kutta_object) + do + step = step + 1 + select type(integrand) + type is(integrand_ladvection) + Dt(step_offset) = integrand%dt(final_step=final_step, final_time=final_time, t=time(step_offset)) + endselect + if (is_fast) then + call integrator%integrate_fast(U=integrand, stage=stage, buffer=buffer, Dt=Dt(step_offset), t=time(step_offset)) + else + call integrator%integrate(U=integrand, stage=stage, Dt=Dt(step_offset), t=time(step_offset)) + endif + call update_previous_times + select type(integrand) + type is(integrand_ladvection) + if (save_results.and.mod(step, save_frequency)==0) call integrand%export_tecplot(t=time(step_offset)) + endselect + if ((time(step_offset) == final_time).or.(step == final_step)) exit + enddo + type is(integrator_adams_bashforth) do step = step + 1 @@ -499,56 +520,6 @@ subroutine integrate(scheme, integrand_0, final_step, final_time, iterations, st if ((time(step) == final_time).or.(step == final_step)) exit enddo - type is(integrator_runge_kutta_ls) - if (allocated(stage)) deallocate(stage) ; allocate(stage(1:integrator%registers_number()), mold=integrand_0) - do - step = step + 1 - ! Dt(step) = integrand%dt(final_step=final_step, final_time=final_time, t=time(step)) - if (is_fast) then - call integrator%integrate_fast(U=integrand, stage=stage, buffer=buffer, Dt=Dt(step), t=time(step)) - else - call integrator%integrate(U=integrand, stage=stage, Dt=Dt(step), t=time(step)) - endif - time(step) = time(step-1) + Dt(step) - ! if (save_results.and.mod(step, save_frequency)==0) call integrand%export_tecplot(t=time(step)) - if ((time(step) == final_time).or.(step == final_step)) exit - enddo - - type is(integrator_runge_kutta_lssp) - do - step = step + 1 - ! Dt(step_offset) = integrand%dt(final_step=final_step, final_time=final_time, t=time(step_offset)) - if (is_fast) then - call integrator%integrate_fast(U=integrand, stage=stage, buffer=buffer, Dt=Dt(step_offset), t=time(step_offset)) - else - call integrator%integrate(U=integrand, stage=stage, Dt=Dt(step_offset), t=time(step_offset)) - endif - call update_previous_times - ! if (save_results.and.mod(step, save_frequency)==0) call integrand%export_tecplot(t=time(step_offset)) - if ((time(step_offset) == final_time).or.(step == final_step)) exit - enddo - - type is(integrator_runge_kutta_ssp) - do - step = step + 1 - ! Dt(step_offset) = integrand%dt(final_step=final_step, final_time=final_time, t=time(step_offset)) - select type(integrand) - type is(integrand_ladvection) - Dt(step_offset) = integrand%dt(final_step=final_step, final_time=final_time, t=time(step_offset)) - endselect - if (is_fast) then - call integrator%integrate_fast(U=integrand, stage=stage, buffer=buffer, Dt=Dt(step_offset), t=time(step_offset)) - else - call integrator%integrate(U=integrand, stage=stage, Dt=Dt(step_offset), t=time(step_offset)) - endif - call update_previous_times - ! if (save_results.and.mod(step, save_frequency)==0) call integrand%export_tecplot(t=time(step_offset)) - select type(integrand) - type is(integrand_ladvection) - if (save_results.and.mod(step, save_frequency)==0) call integrand%export_tecplot(t=time(step_offset)) - endselect - if ((time(step_offset) == final_time).or.(step == final_step)) exit - enddo endselect select type(integrand) From 7641c3751ad5a4b6c28471b2c402e401aa8c26ca Mon Sep 17 00:00:00 2001 From: Stefano Zaghi Date: Tue, 16 May 2017 17:09:47 +0200 Subject: [PATCH 08/25] finish with intermediates --- src/lib/foodie.f90 | 17 +- src/lib/foodie_integrator_adams_bashforth.f90 | 715 ++++++++---------- ...die_integrator_adams_bashforth_moulton.f90 | 116 ++- src/lib/foodie_integrator_adams_moulton.f90 | 239 +++--- ...rator_backward_differentiation_formula.f90 | 177 ++--- src/lib/foodie_integrator_lmm_ssp.f90 | 161 ++-- ..._integrator_multistage_explicit_object.f90 | 99 +++ ...e_integrator_multistep_explicit_object.f90 | 113 +++ ...e_integrator_multistep_implicit_object.f90 | 127 ++++ ...foodie_integrator_runge_kutta_embedded.f90 | 219 +++--- ...die_integrator_runge_kutta_low_storage.f90 | 128 ++-- .../foodie_integrator_runge_kutta_lssp.f90 | 84 +- .../foodie_integrator_runge_kutta_object.f90 | 70 -- src/lib/foodie_integrator_runge_kutta_ssp.f90 | 138 ++-- .../foodie_test_integrand_ladvection.f90 | 2 +- .../ladvection/foodie_test_ladvection.f90 | 269 ++----- 16 files changed, 1250 insertions(+), 1424 deletions(-) create mode 100644 src/lib/foodie_integrator_multistage_explicit_object.f90 create mode 100644 src/lib/foodie_integrator_multistep_explicit_object.f90 create mode 100644 src/lib/foodie_integrator_multistep_implicit_object.f90 delete mode 100644 src/lib/foodie_integrator_runge_kutta_object.f90 diff --git a/src/lib/foodie.f90 b/src/lib/foodie.f90 index b2acad42..97b35c2b 100644 --- a/src/lib/foodie.f90 +++ b/src/lib/foodie.f90 @@ -74,20 +74,31 @@ module foodie use foodie_integrator_lmm_ssp, only : integrator_lmm_ssp use foodie_integrator_lmm_ssp_vss, only : integrator_lmm_ssp_vss use foodie_integrator_ms_runge_kutta_ssp, only : integrator_ms_runge_kutta_ssp +use foodie_integrator_multistage_explicit_object, only : integrator_multistage_explicit_object +use foodie_integrator_multistep_explicit_object, only : integrator_multistep_explicit_object +use foodie_integrator_multistep_implicit_object, only : integrator_multistep_implicit_object use foodie_integrator_runge_kutta_emd, only : integrator_runge_kutta_emd use foodie_integrator_runge_kutta_low_storage, only : integrator_runge_kutta_ls use foodie_integrator_runge_kutta_lssp, only : integrator_runge_kutta_lssp -use foodie_integrator_runge_kutta_object, only : integrator_runge_kutta_object use foodie_integrator_runge_kutta_ssp, only : integrator_runge_kutta_ssp use penf, only : I_P, R_P implicit none private +! helper procedures public :: foodie_integrator_class_names public :: foodie_integrator_factory public :: foodie_integrator_schemes +public :: is_available +public :: is_class_available +public :: is_scheme_available +! abstract objects public :: integrand_object public :: integrator_object +public :: integrator_multistage_explicit_object +public :: integrator_multistep_explicit_object +public :: integrator_multistep_implicit_object +! concrete objects public :: integrator_adams_bashforth public :: integrator_adams_bashforth_moulton public :: integrator_adams_moulton @@ -100,11 +111,7 @@ module foodie public :: integrator_runge_kutta_emd public :: integrator_runge_kutta_ls public :: integrator_runge_kutta_lssp -public :: integrator_runge_kutta_object public :: integrator_runge_kutta_ssp -public :: is_available -public :: is_class_available -public :: is_scheme_available contains pure function foodie_integrator_class_names() result(names) diff --git a/src/lib/foodie_integrator_adams_bashforth.f90 b/src/lib/foodie_integrator_adams_bashforth.f90 index bcad1eba..4f84b140 100644 --- a/src/lib/foodie_integrator_adams_bashforth.f90 +++ b/src/lib/foodie_integrator_adams_bashforth.f90 @@ -28,6 +28,7 @@ module foodie_integrator_adams_bashforth use foodie_error_codes, only : ERROR_UNSUPPORTED_SCHEME use foodie_integrand_object, only : integrand_object +use foodie_integrator_multistep_explicit_object, only : integrator_multistep_explicit_object use foodie_integrator_object, only : integrator_object use penf, only : I_P, R_P @@ -53,391 +54,337 @@ module foodie_integrator_adams_bashforth trim(class_name_)//'_15', & trim(class_name_)//'_16'] !< List of supported schemes. -logical, parameter :: has_fast_mode_=.true. !< Flag to check if integrator provides *fast mode* integrate. -logical, parameter :: is_multistage_=.false. !< Flag to check if integrator is multistage. -logical, parameter :: is_multistep_=.true. !< Flag to check if integrator is multistep. - -type, extends(integrator_object) :: integrator_adams_bashforth - !< FOODIE integrator: provide an explicit class of Adams-Bashforth multi-step schemes, from 1st to 16th order accurate. - !< - !< @note The integrator must be created or initialized (initialize the *b* coefficients) before used. - private - integer(I_P) :: steps=0 !< Number of time steps. - real(R_P), allocatable :: b(:) !< *b* coefficients. - contains - ! deferred methods - procedure, pass(self) :: class_name !< Return the class name of schemes. - procedure, pass(self) :: description !< Return pretty-printed object description. - procedure, pass(self) :: has_fast_mode !< Return .true. if the integrator class has *fast mode* integrate. - procedure, pass(lhs) :: integr_assign_integr !< Operator `=`. - procedure, pass(self) :: is_multistage !< Return .true. for multistage integrator. - procedure, pass(self) :: is_multistep !< Return .true. for multistep integrator. - procedure, pass(self) :: is_supported !< Return .true. if the integrator class support the given scheme. - procedure, pass(self) :: stages_number !< Return number of stages used. - procedure, pass(self) :: steps_number !< Return number of steps used. - procedure, pass(self) :: supported_schemes !< Return the list of supported schemes. - ! public methods - procedure, pass(self) :: destroy !< Destroy the integrator. - procedure, pass(self) :: initialize !< Initialize (create) the integrator. - procedure, pass(self) :: integrate !< Integrate integrand field. - procedure, pass(self) :: integrate_fast !< Integrate integrand field, fast mode. - procedure, pass(self) :: update_previous !< Cyclic update previous time steps. +logical, parameter :: has_fast_mode_=.true. !< Flag to check if integrator provides *fast mode* integrate. + +type, extends(integrator_multistep_explicit_object) :: integrator_adams_bashforth + !< FOODIE integrator: provide an explicit class of Adams-Bashforth multi-step schemes, from 1st to 16th order accurate. + !< + !< @note The integrator must be created or initialized (initialize the *b* coefficients) before used. + private + real(R_P), allocatable :: b(:) !< *b* coefficients. + contains + ! deferred methods + procedure, pass(self) :: class_name !< Return the class name of schemes. + procedure, pass(self) :: description !< Return pretty-printed object description. + procedure, pass(self) :: has_fast_mode !< Return .true. if the integrator class has *fast mode* integrate. + procedure, pass(lhs) :: integr_assign_integr !< Operator `=`. + procedure, pass(self) :: integrate !< Integrate integrand field. + procedure, pass(self) :: integrate_fast !< Integrate integrand field, fast mode. + procedure, pass(self) :: is_supported !< Return .true. if the integrator class support the given scheme. + procedure, pass(self) :: supported_schemes !< Return the list of supported schemes. + ! public methods + procedure, pass(self) :: destroy !< Destroy the integrator. + procedure, pass(self) :: initialize !< Initialize (create) the integrator. endtype integrator_adams_bashforth contains - ! deferred methods - pure function class_name(self) - !< Return the class name of schemes. - class(integrator_adams_bashforth), intent(in) :: self !< Integrator. - character(len=99) :: class_name !< Class name. - - class_name = trim(adjustl(class_name_)) - endfunction class_name - - pure function description(self, prefix) result(desc) - !< Return a pretty-formatted object description. - class(integrator_adams_bashforth), intent(in) :: self !< Integrator. - character(*), intent(in), optional :: prefix !< Prefixing string. - character(len=:), allocatable :: desc !< Description. - character(len=:), allocatable :: prefix_ !< Prefixing string, local variable. - character(len=1), parameter :: NL=new_line('a') !< New line character. - integer(I_P) :: s !< Counter. - - prefix_ = '' ; if (present(prefix)) prefix_ = prefix - desc = '' - desc = desc//prefix_//'Adams-Bashforth multi-step schemes class'//NL - desc = desc//prefix_//' Supported schemes:'//NL - do s=lbound(supported_schemes_, dim=1), ubound(supported_schemes_, dim=1) - 1 - desc = desc//prefix_//' + '//supported_schemes_(s)//NL - enddo - desc = desc//prefix_//' + '//supported_schemes_(ubound(supported_schemes_, dim=1)) - endfunction description - - elemental function has_fast_mode(self) - !< Return .true. if the integrator class has *fast mode* integrate. - class(integrator_adams_bashforth), intent(in) :: self !< Integrator. - logical :: has_fast_mode !< Inquire result. - - has_fast_mode = has_fast_mode_ - endfunction has_fast_mode - - pure subroutine integr_assign_integr(lhs, rhs) - !< Operator `=`. - class(integrator_adams_bashforth), intent(inout) :: lhs !< Left hand side. - class(integrator_object), intent(in) :: rhs !< Right hand side. - - call lhs%assign_abstract(rhs=rhs) - select type(rhs) - class is (integrator_adams_bashforth) - lhs%steps = rhs%steps - if (allocated(rhs%b)) lhs%b = rhs%b - endselect - endsubroutine integr_assign_integr - - elemental function is_multistage(self) - !< Return .true. for multistage integrator. - class(integrator_adams_bashforth), intent(in) :: self !< Integrator. - logical :: is_multistage !< Inquire result. - - is_multistage = is_multistage_ - endfunction is_multistage - - elemental function is_multistep(self) - !< Return .true. for multistage integrator. - class(integrator_adams_bashforth), intent(in) :: self !< Integrator. - logical :: is_multistep !< Inquire result. - - is_multistep = is_multistep_ - endfunction is_multistep - - elemental function is_supported(self, scheme) - !< Return .true. if the integrator class support the given scheme. - class(integrator_adams_bashforth), intent(in) :: self !< Integrator. - character(*), intent(in) :: scheme !< Selected scheme. - logical :: is_supported !< Inquire result. - integer(I_P) :: s !< Counter. - - is_supported = .false. - do s=lbound(supported_schemes_, dim=1), ubound(supported_schemes_, dim=1) - if (trim(adjustl(scheme)) == trim(adjustl(supported_schemes_(s)))) then - is_supported = .true. - return - endif - enddo - endfunction is_supported - - elemental function stages_number(self) - !< Return number of stages used. - class(integrator_adams_bashforth), intent(in) :: self !< Integrator. - integer(I_P) :: stages_number !< Number of stages used. - - stages_number = 0 - endfunction stages_number - - elemental function steps_number(self) - !< Return number of steps used. - class(integrator_adams_bashforth), intent(in) :: self !< Integrator. - integer(I_P) :: steps_number !< Number of steps used. - - steps_number = self%steps - endfunction steps_number - - pure function supported_schemes(self) result(schemes) - !< Return the list of supported schemes. - class(integrator_adams_bashforth), intent(in) :: self !< Integrator. - character(len=99), allocatable :: schemes(:) !< Queried scheme. - - allocate(schemes(lbound(supported_schemes_, dim=1):ubound(supported_schemes_, dim=1))) - schemes = supported_schemes_ - endfunction supported_schemes - - ! public methods - elemental subroutine destroy(self) - !< Destroy the integrator. - class(integrator_adams_bashforth), intent(inout) :: self !< Integrator. - - call self%destroy_abstract - self%steps = 0 - if (allocated(self%b)) deallocate(self%b) - endsubroutine destroy - - subroutine initialize(self, scheme) - !< Create the actual Adams-Bashforth integrator: initialize the *b* coefficients. - !< - !< @note If the integrator is initialized with a bad (unsupported) number of required time steps the initialization fails and - !< the integrator error status is updated consistently for external-provided errors handling. - class(integrator_adams_bashforth), intent(inout) :: self !< Integrator. - character(*), intent(in) :: scheme !< Selected scheme. - - if (self%is_supported(scheme=scheme)) then - call self%destroy - select case(trim(adjustl(scheme))) - case('adams_bashforth_1') - self%steps = 1 ; allocate(self%b(1:self%steps)) ; self%b = 0.0_R_P - self%b(1) = 1.0_R_P - case('adams_bashforth_2') - self%steps = 2 ; allocate(self%b(1:self%steps)) ; self%b = 0.0_R_P - self%b(1) = -1.0_R_P/2.0_R_P - self%b(2) = 3.0_R_P/2.0_R_P - case('adams_bashforth_3') - self%steps = 3 ; allocate(self%b(1:self%steps)) ; self%b = 0.0_R_P - self%b(1) = 5.0_R_P/12.0_R_P - self%b(2) = -16.0_R_P/12.0_R_P - self%b(3) = 23.0_R_P/12.0_R_P - case('adams_bashforth_4') - self%steps = 4 ; allocate(self%b(1:self%steps)) ; self%b = 0.0_R_P - self%b(1) = -9.0_R_P/24.0_R_P - self%b(2) = 37.0_R_P/24.0_R_P - self%b(3) = -59.0_R_P/24.0_R_P - self%b(4) = 55.0_R_P/24.0_R_P - case('adams_bashforth_5') - self%steps = 5 ; allocate(self%b(1:self%steps)) ; self%b = 0.0_R_P - self%b(1) = 251.0_R_P/720.0_R_P - self%b(2) = -1274.0_R_P/720.0_R_P - self%b(3) = 2616.0_R_P/720.0_R_P - self%b(4) = -2774.0_R_P/720.0_R_P - self%b(5) = 1901.0_R_P/720.0_R_P - case('adams_bashforth_6') - self%steps = 6 ; allocate(self%b(1:self%steps)) ; self%b = 0.0_R_P - self%b(1) = -475.0_R_P/1440.0_R_P - self%b(2) = 2877.0_R_P/1440.0_R_P - self%b(3) = -7298.0_R_P/1440.0_R_P - self%b(4) = 9982.0_R_P/1440.0_R_P - self%b(5) = -7923.0_R_P/1440.0_R_P - self%b(6) = 4277.0_R_P/1440.0_R_P - case('adams_bashforth_7') - self%steps = 7 ; allocate(self%b(1:self%steps)) ; self%b = 0.0_R_P - self%b(1) = 19087.0_R_P/60480.0_R_P - self%b(2) = -134472.0_R_P/60480.0_R_P - self%b(3) = 407139.0_R_P/60480.0_R_P - self%b(4) = -688256.0_R_P/60480.0_R_P - self%b(5) = 705549.0_R_P/60480.0_R_P - self%b(6) = -447288.0_R_P/60480.0_R_P - self%b(7) = 198721.0_R_P/60480.0_R_P - case('adams_bashforth_8') - self%steps = 8 ; allocate(self%b(1:self%steps)) ; self%b = 0.0_R_P - self%b(1) = -36799.0_R_P/120960.0_R_P - self%b(2) = 295767.0_R_P/120960.0_R_P - self%b(3) = -1041723.0_R_P/120960.0_R_P - self%b(4) = 2102243.0_R_P/120960.0_R_P - self%b(5) = -2664477.0_R_P/120960.0_R_P - self%b(6) = 2183877.0_R_P/120960.0_R_P - self%b(7) = -1152169.0_R_P/120960.0_R_P - self%b(8) = 434241.0_R_P/120960.0_R_P - case('adams_bashforth_9') - self%steps = 9 ; allocate(self%b(1:self%steps)) ; self%b = 0.0_R_P - self%b(1) = 1070017.0_R_P/3628800.0_R_P - self%b(2) = -9664106.0_R_P/3628800.0_R_P - self%b(3) = 38833486.0_R_P/3628800.0_R_P - self%b(4) = -91172642.0_R_P/3628800.0_R_P - self%b(5) = 137968480.0_R_P/3628800.0_R_P - self%b(6) = -139855262.0_R_P/3628800.0_R_P - self%b(7) = 95476786.0_R_P/3628800.0_R_P - self%b(8) = -43125206.0_R_P/3628800.0_R_P - self%b(9) = 14097247.0_R_P/3628800.0_R_P - case('adams_bashforth_10') - self%steps = 10 ; allocate(self%b(1:self%steps)) ; self%b = 0.0_R_P - self%b(1) = -2082753.0_R_P/7257600.0_R_P - self%b(2) = 20884811.0_R_P/7257600.0_R_P - self%b(3) = -94307320.0_R_P/7257600.0_R_P - self%b(4) = 252618224.0_R_P/7257600.0_R_P - self%b(5) = -444772162.0_R_P/7257600.0_R_P - self%b(6) = 538363838.0_R_P/7257600.0_R_P - self%b(7) = -454661776.0_R_P/7257600.0_R_P - self%b(8) = 265932680.0_R_P/7257600.0_R_P - self%b(9) = -104995189.0_R_P/7257600.0_R_P - self%b(10) = 30277247.0_R_P/7257600.0_R_P - case('adams_bashforth_11') - self%steps = 11 ; allocate(self%b(1:self%steps)) ; self%b = 0.0_R_P - self%b(1) = 134211265.0_R_P/479001600.0_R_P - self%b(2) = -1479574348.0_R_P/479001600.0_R_P - self%b(3) = 7417904451.0_R_P/479001600.0_R_P - self%b(4) = -22329634920.0_R_P/479001600.0_R_P - self%b(5) = 44857168434.0_R_P/479001600.0_R_P - self%b(6) = -63176201472.0_R_P/479001600.0_R_P - self%b(7) = 63716378958.0_R_P/479001600.0_R_P - self%b(8) = -46113029016.0_R_P/479001600.0_R_P - self%b(9) = 23591063805.0_R_P/479001600.0_R_P - self%b(10) = -8271795124.0_R_P/479001600.0_R_P - self%b(11) = 2132509567.0_R_P/479001600.0_R_P - case('adams_bashforth_12') - self%steps = 12 ; allocate(self%b(1:self%steps)) ; self%b = 0.0_R_P - self%b(1) = -262747265.0_R_P/958003200.0_R_P - self%b(2) = 3158642445.0_R_P/958003200.0_R_P - self%b(3) = -17410248271.0_R_P/958003200.0_R_P - self%b(4) = 58189107627.0_R_P/958003200.0_R_P - self%b(5) = -131365867290.0_R_P/958003200.0_R_P - self%b(6) = 211103573298.0_R_P/958003200.0_R_P - self%b(7) = -247741639374.0_R_P/958003200.0_R_P - self%b(8) = 214139355366.0_R_P/958003200.0_R_P - self%b(9) = -135579356757.0_R_P/958003200.0_R_P - self%b(10) = 61633227185.0_R_P/958003200.0_R_P - self%b(11) = -19433810163.0_R_P/958003200.0_R_P - self%b(12) = 4527766399.0_R_P/958003200.0_R_P - case('adams_bashforth_13') - self%steps = 13 ; allocate(self%b(1:self%steps)) ; self%b = 0.0_R_P - self%b(1) = 703604254357.0_R_P/2615348736000.0_R_P - self%b(2) = -9160551085734.0_R_P/2615348736000.0_R_P - self%b(3) = 55060974662412.0_R_P/2615348736000.0_R_P - self%b(4) = -202322913738370.0_R_P/2615348736000.0_R_P - self%b(5) = 507140369728425.0_R_P/2615348736000.0_R_P - self%b(6) = -915883387152444.0_R_P/2615348736000.0_R_P - self%b(7) = 1226443086129408.0_R_P/2615348736000.0_R_P - self%b(8) = -1233589244941764.0_R_P/2615348736000.0_R_P - self%b(9) = 932884546055895.0_R_P/2615348736000.0_R_P - self%b(10) = -524924579905150.0_R_P/2615348736000.0_R_P - self%b(11) = 214696591002612.0_R_P/2615348736000.0_R_P - self%b(12) = -61497552797274.0_R_P/2615348736000.0_R_P - self%b(13) = 13064406523627.0_R_P/2615348736000.0_R_P - case('adams_bashforth_14') - self%steps = 14 ; allocate(self%b(1:self%steps)) ; self%b = 0.0_R_P - self%b(1) = -1382741929621.0_R_P/5230697472000.0_R_P - self%b(2) = 19382853593787.0_R_P/5230697472000.0_R_P - self%b(3) = -126174972681906.0_R_P/5230697472000.0_R_P - self%b(4) = 505586141196430.0_R_P/5230697472000.0_R_P - self%b(5) = -1393306307155755.0_R_P/5230697472000.0_R_P - self%b(6) = 2793869602879077.0_R_P/5230697472000.0_R_P - self%b(7) = -4204551925534524.0_R_P/5230697472000.0_R_P - self%b(8) = 4825671323488452.0_R_P/5230697472000.0_R_P - self%b(9) = -4246767353305755.0_R_P/5230697472000.0_R_P - self%b(10) = 2854429571790805.0_R_P/5230697472000.0_R_P - self%b(11) = -1445313351681906.0_R_P/5230697472000.0_R_P - self%b(12) = 537247052515662.0_R_P/5230697472000.0_R_P - self%b(13) = -140970750679621.0_R_P/5230697472000.0_R_P - self%b(14) = 27511554976875.0_R_P/5230697472000.0_R_P - case('adams_bashforth_15') - self%steps = 15 ; allocate(self%b(1:self%steps)) ; self%b = 0.0_R_P - self%b(1) = 8164168737599.0_R_P/31384184832000.0_R_P - self%b(2) = -122594813904112.0_R_P/31384184832000.0_R_P - self%b(3) = 859236476684231.0_R_P/31384184832000.0_R_P - self%b(4) = -3728807256577472.0_R_P/31384184832000.0_R_P - self%b(5) = 11205849753515179.0_R_P/31384184832000.0_R_P - self%b(6) = -24704503655607728.0_R_P/31384184832000.0_R_P - self%b(7) = 41280216336284259.0_R_P/31384184832000.0_R_P - self%b(8) = -53246738660646912.0_R_P/31384184832000.0_R_P - self%b(9) = 53471026659940509.0_R_P/31384184832000.0_R_P - self%b(10) = -41825269932507728.0_R_P/31384184832000.0_R_P - self%b(11) = 25298910337081429.0_R_P/31384184832000.0_R_P - self%b(12) = -11643637530577472.0_R_P/31384184832000.0_R_P - self%b(13) = 3966421670215481.0_R_P/31384184832000.0_R_P - self%b(14) = -960122866404112.0_R_P/31384184832000.0_R_P - self%b(15) = 173233498598849.0_R_P/31384184832000.0_R_P - case('adams_bashforth_16') - self%steps = 16 ; allocate(self%b(1:self%steps)) ; self%b = 0.0_R_P - self%b(1) = -16088129229375.0_R_P/62768369664000.0_R_P - self%b(2) = 257650275915823.0_R_P/62768369664000.0_R_P - self%b(3) = -1934443196892599.0_R_P/62768369664000.0_R_P - self%b(4) = 9038571752734087.0_R_P/62768369664000.0_R_P - self%b(5) = -29417910911251819.0_R_P/62768369664000.0_R_P - self%b(6) = 70724351582843483.0_R_P/62768369664000.0_R_P - self%b(7) = -129930094104237331.0_R_P/62768369664000.0_R_P - self%b(8) = 186087544263596643.0_R_P/62768369664000.0_R_P - self%b(9) = -210020588912321949.0_R_P/62768369664000.0_R_P - self%b(10) = 187463140112902893.0_R_P/62768369664000.0_R_P - self%b(11) = -131963191940828581.0_R_P/62768369664000.0_R_P - self%b(12) = 72558117072259733.0_R_P/62768369664000.0_R_P - self%b(13) = -30607373860520569.0_R_P/62768369664000.0_R_P - self%b(14) = 9622096909515337.0_R_P/62768369664000.0_R_P - self%b(15) = -2161567671248849.0_R_P/62768369664000.0_R_P - self%b(16) = 362555126427073.0_R_P/62768369664000.0_R_P - endselect - else - call self%trigger_error(error=ERROR_UNSUPPORTED_SCHEME, & - error_message='"'//trim(adjustl(scheme))//'" unsupported scheme', & - is_severe=.true.) - endif - endsubroutine initialize - - subroutine integrate(self, U, previous, Dt, t, autoupdate) - !< Integrate field with Adams-Bashforth class scheme. - class(integrator_adams_bashforth), intent(in) :: self !< Integrator. - class(integrand_object), intent(inout) :: U !< Field to be integrated. - class(integrand_object), intent(inout) :: previous(1:) !< Previous time steps solutions of integrand field. - real(R_P), intent(in) :: Dt !< Time steps. - real(R_P), intent(in) :: t(:) !< Times. - logical, optional, intent(in) :: autoupdate !< Perform cyclic autoupdate of previous time steps. - logical :: autoupdate_ !< Perform cyclic autoupdate of previous time steps, dummy var. - integer(I_P) :: s !< Steps counter. - - autoupdate_ = .true. ; if (present(autoupdate)) autoupdate_ = autoupdate - do s=1, self%steps - U = U + (previous(s)%t(t=t(s)) * (Dt * self%b(s))) - enddo - if (autoupdate_) call self%update_previous(U=U, previous=previous) - endsubroutine integrate - - subroutine integrate_fast(self, U, previous, buffer, Dt, t, autoupdate) - !< Integrate field with Adams-Bashforth class scheme. - class(integrator_adams_bashforth), intent(in) :: self !< Integrator. - class(integrand_object), intent(inout) :: U !< Field to be integrated. - class(integrand_object), intent(inout) :: previous(1:) !< Previous time steps solutions of integrand field. - class(integrand_object), intent(inout) :: buffer !< Temporary buffer for doing fast operation. - real(R_P), intent(in) :: Dt !< Time steps. - real(R_P), intent(in) :: t(:) !< Times. - logical, optional, intent(in) :: autoupdate !< Perform cyclic autoupdate of previous time steps. - logical :: autoupdate_ !< Perform cyclic autoupdate of previous time steps, dummy var. - integer(I_P) :: s !< Steps counter. - - autoupdate_ = .true. ; if (present(autoupdate)) autoupdate_ = autoupdate - do s=1, self%steps - buffer = previous(s) - call buffer%t_fast(t=t(s)) - call buffer%multiply_fast(lhs=buffer, rhs=Dt * self%b(s)) - call U%add_fast(lhs=U, rhs=buffer) - enddo - if (autoupdate_) call self%update_previous(U=U, previous=previous) - endsubroutine integrate_fast - - subroutine update_previous(self, U, previous) - !< Cyclic update previous time steps. - class(integrator_adams_bashforth), intent(in) :: self !< Integrator. - class(integrand_object), intent(in) :: U !< Field to be integrated. - class(integrand_object), intent(inout) :: previous(1:) !< Previous time steps solutions of integrand field. - integer(I_P) :: s !< Steps counter. - - do s=1, self%steps - 1 - previous(s) = previous(s + 1) - enddo - previous(self%steps) = U - endsubroutine update_previous + ! deferred methods + pure function class_name(self) + !< Return the class name of schemes. + class(integrator_adams_bashforth), intent(in) :: self !< Integrator. + character(len=99) :: class_name !< Class name. + + class_name = trim(adjustl(class_name_)) + endfunction class_name + + pure function description(self, prefix) result(desc) + !< Return a pretty-formatted object description. + class(integrator_adams_bashforth), intent(in) :: self !< Integrator. + character(*), intent(in), optional :: prefix !< Prefixing string. + character(len=:), allocatable :: desc !< Description. + character(len=:), allocatable :: prefix_ !< Prefixing string, local variable. + character(len=1), parameter :: NL=new_line('a') !< New line character. + integer(I_P) :: s !< Counter. + + prefix_ = '' ; if (present(prefix)) prefix_ = prefix + desc = '' + desc = desc//prefix_//'Adams-Bashforth multi-step schemes class'//NL + desc = desc//prefix_//' Supported schemes:'//NL + do s=lbound(supported_schemes_, dim=1), ubound(supported_schemes_, dim=1) - 1 + desc = desc//prefix_//' + '//supported_schemes_(s)//NL + enddo + desc = desc//prefix_//' + '//supported_schemes_(ubound(supported_schemes_, dim=1)) + endfunction description + + elemental function has_fast_mode(self) + !< Return .true. if the integrator class has *fast mode* integrate. + class(integrator_adams_bashforth), intent(in) :: self !< Integrator. + logical :: has_fast_mode !< Inquire result. + + has_fast_mode = has_fast_mode_ + endfunction has_fast_mode + + pure subroutine integr_assign_integr(lhs, rhs) + !< Operator `=`. + class(integrator_adams_bashforth), intent(inout) :: lhs !< Left hand side. + class(integrator_object), intent(in) :: rhs !< Right hand side. + + call lhs%assign_abstract(rhs=rhs) + select type(rhs) + class is (integrator_adams_bashforth) + lhs%steps = rhs%steps + if (allocated(rhs%b)) lhs%b = rhs%b + endselect + endsubroutine integr_assign_integr + + subroutine integrate(self, U, previous, Dt, t, autoupdate) + !< Integrate field with Adams-Bashforth class scheme. + class(integrator_adams_bashforth), intent(in) :: self !< Integrator. + class(integrand_object), intent(inout) :: U !< Field to be integrated. + class(integrand_object), intent(inout) :: previous(1:) !< Previous time steps solutions of integrand field. + real(R_P), intent(in) :: Dt !< Time steps. + real(R_P), intent(in) :: t(:) !< Times. + logical, optional, intent(in) :: autoupdate !< Perform cyclic autoupdate of previous time steps. + logical :: autoupdate_ !< Perform cyclic autoupdate of previous time steps, dummy var. + integer(I_P) :: s !< Steps counter. + + autoupdate_ = .true. ; if (present(autoupdate)) autoupdate_ = autoupdate + do s=1, self%steps + U = U + (previous(s)%t(t=t(s)) * (Dt * self%b(s))) + enddo + if (autoupdate_) call self%update_previous(U=U, previous=previous) + endsubroutine integrate + + subroutine integrate_fast(self, U, previous, buffer, Dt, t, autoupdate) + !< Integrate field with Adams-Bashforth class scheme. + class(integrator_adams_bashforth), intent(in) :: self !< Integrator. + class(integrand_object), intent(inout) :: U !< Field to be integrated. + class(integrand_object), intent(inout) :: previous(1:) !< Previous time steps solutions of integrand field. + class(integrand_object), intent(inout) :: buffer !< Temporary buffer for doing fast operation. + real(R_P), intent(in) :: Dt !< Time steps. + real(R_P), intent(in) :: t(:) !< Times. + logical, optional, intent(in) :: autoupdate !< Perform cyclic autoupdate of previous time steps. + logical :: autoupdate_ !< Perform cyclic autoupdate of previous time steps, dummy var. + integer(I_P) :: s !< Steps counter. + + autoupdate_ = .true. ; if (present(autoupdate)) autoupdate_ = autoupdate + do s=1, self%steps + buffer = previous(s) + call buffer%t_fast(t=t(s)) + call buffer%multiply_fast(lhs=buffer, rhs=Dt * self%b(s)) + call U%add_fast(lhs=U, rhs=buffer) + enddo + if (autoupdate_) call self%update_previous(U=U, previous=previous) + endsubroutine integrate_fast + + elemental function is_supported(self, scheme) + !< Return .true. if the integrator class support the given scheme. + class(integrator_adams_bashforth), intent(in) :: self !< Integrator. + character(*), intent(in) :: scheme !< Selected scheme. + logical :: is_supported !< Inquire result. + integer(I_P) :: s !< Counter. + + is_supported = .false. + do s=lbound(supported_schemes_, dim=1), ubound(supported_schemes_, dim=1) + if (trim(adjustl(scheme)) == trim(adjustl(supported_schemes_(s)))) then + is_supported = .true. + return + endif + enddo + endfunction is_supported + + pure function supported_schemes(self) result(schemes) + !< Return the list of supported schemes. + class(integrator_adams_bashforth), intent(in) :: self !< Integrator. + character(len=99), allocatable :: schemes(:) !< Queried scheme. + + allocate(schemes(lbound(supported_schemes_, dim=1):ubound(supported_schemes_, dim=1))) + schemes = supported_schemes_ + endfunction supported_schemes + + ! public methods + elemental subroutine destroy(self) + !< Destroy the integrator. + class(integrator_adams_bashforth), intent(inout) :: self !< Integrator. + + call self%destroy_multistep + if (allocated(self%b)) deallocate(self%b) + endsubroutine destroy + + subroutine initialize(self, scheme) + !< Create the actual Adams-Bashforth integrator: initialize the *b* coefficients. + !< + !< @note If the integrator is initialized with a bad (unsupported) number of required time steps the initialization fails and + !< the integrator error status is updated consistently for external-provided errors handling. + class(integrator_adams_bashforth), intent(inout) :: self !< Integrator. + character(*), intent(in) :: scheme !< Selected scheme. + + if (self%is_supported(scheme=scheme)) then + call self%destroy + select case(trim(adjustl(scheme))) + case('adams_bashforth_1') + self%steps = 1 ; allocate(self%b(1:self%steps)) ; self%b = 0.0_R_P + self%b(1) = 1.0_R_P + case('adams_bashforth_2') + self%steps = 2 ; allocate(self%b(1:self%steps)) ; self%b = 0.0_R_P + self%b(1) = -1.0_R_P/2.0_R_P + self%b(2) = 3.0_R_P/2.0_R_P + case('adams_bashforth_3') + self%steps = 3 ; allocate(self%b(1:self%steps)) ; self%b = 0.0_R_P + self%b(1) = 5.0_R_P/12.0_R_P + self%b(2) = -16.0_R_P/12.0_R_P + self%b(3) = 23.0_R_P/12.0_R_P + case('adams_bashforth_4') + self%steps = 4 ; allocate(self%b(1:self%steps)) ; self%b = 0.0_R_P + self%b(1) = -9.0_R_P/24.0_R_P + self%b(2) = 37.0_R_P/24.0_R_P + self%b(3) = -59.0_R_P/24.0_R_P + self%b(4) = 55.0_R_P/24.0_R_P + case('adams_bashforth_5') + self%steps = 5 ; allocate(self%b(1:self%steps)) ; self%b = 0.0_R_P + self%b(1) = 251.0_R_P/720.0_R_P + self%b(2) = -1274.0_R_P/720.0_R_P + self%b(3) = 2616.0_R_P/720.0_R_P + self%b(4) = -2774.0_R_P/720.0_R_P + self%b(5) = 1901.0_R_P/720.0_R_P + case('adams_bashforth_6') + self%steps = 6 ; allocate(self%b(1:self%steps)) ; self%b = 0.0_R_P + self%b(1) = -475.0_R_P/1440.0_R_P + self%b(2) = 2877.0_R_P/1440.0_R_P + self%b(3) = -7298.0_R_P/1440.0_R_P + self%b(4) = 9982.0_R_P/1440.0_R_P + self%b(5) = -7923.0_R_P/1440.0_R_P + self%b(6) = 4277.0_R_P/1440.0_R_P + case('adams_bashforth_7') + self%steps = 7 ; allocate(self%b(1:self%steps)) ; self%b = 0.0_R_P + self%b(1) = 19087.0_R_P/60480.0_R_P + self%b(2) = -134472.0_R_P/60480.0_R_P + self%b(3) = 407139.0_R_P/60480.0_R_P + self%b(4) = -688256.0_R_P/60480.0_R_P + self%b(5) = 705549.0_R_P/60480.0_R_P + self%b(6) = -447288.0_R_P/60480.0_R_P + self%b(7) = 198721.0_R_P/60480.0_R_P + case('adams_bashforth_8') + self%steps = 8 ; allocate(self%b(1:self%steps)) ; self%b = 0.0_R_P + self%b(1) = -36799.0_R_P/120960.0_R_P + self%b(2) = 295767.0_R_P/120960.0_R_P + self%b(3) = -1041723.0_R_P/120960.0_R_P + self%b(4) = 2102243.0_R_P/120960.0_R_P + self%b(5) = -2664477.0_R_P/120960.0_R_P + self%b(6) = 2183877.0_R_P/120960.0_R_P + self%b(7) = -1152169.0_R_P/120960.0_R_P + self%b(8) = 434241.0_R_P/120960.0_R_P + case('adams_bashforth_9') + self%steps = 9 ; allocate(self%b(1:self%steps)) ; self%b = 0.0_R_P + self%b(1) = 1070017.0_R_P/3628800.0_R_P + self%b(2) = -9664106.0_R_P/3628800.0_R_P + self%b(3) = 38833486.0_R_P/3628800.0_R_P + self%b(4) = -91172642.0_R_P/3628800.0_R_P + self%b(5) = 137968480.0_R_P/3628800.0_R_P + self%b(6) = -139855262.0_R_P/3628800.0_R_P + self%b(7) = 95476786.0_R_P/3628800.0_R_P + self%b(8) = -43125206.0_R_P/3628800.0_R_P + self%b(9) = 14097247.0_R_P/3628800.0_R_P + case('adams_bashforth_10') + self%steps = 10 ; allocate(self%b(1:self%steps)) ; self%b = 0.0_R_P + self%b(1) = -2082753.0_R_P/7257600.0_R_P + self%b(2) = 20884811.0_R_P/7257600.0_R_P + self%b(3) = -94307320.0_R_P/7257600.0_R_P + self%b(4) = 252618224.0_R_P/7257600.0_R_P + self%b(5) = -444772162.0_R_P/7257600.0_R_P + self%b(6) = 538363838.0_R_P/7257600.0_R_P + self%b(7) = -454661776.0_R_P/7257600.0_R_P + self%b(8) = 265932680.0_R_P/7257600.0_R_P + self%b(9) = -104995189.0_R_P/7257600.0_R_P + self%b(10) = 30277247.0_R_P/7257600.0_R_P + case('adams_bashforth_11') + self%steps = 11 ; allocate(self%b(1:self%steps)) ; self%b = 0.0_R_P + self%b(1) = 134211265.0_R_P/479001600.0_R_P + self%b(2) = -1479574348.0_R_P/479001600.0_R_P + self%b(3) = 7417904451.0_R_P/479001600.0_R_P + self%b(4) = -22329634920.0_R_P/479001600.0_R_P + self%b(5) = 44857168434.0_R_P/479001600.0_R_P + self%b(6) = -63176201472.0_R_P/479001600.0_R_P + self%b(7) = 63716378958.0_R_P/479001600.0_R_P + self%b(8) = -46113029016.0_R_P/479001600.0_R_P + self%b(9) = 23591063805.0_R_P/479001600.0_R_P + self%b(10) = -8271795124.0_R_P/479001600.0_R_P + self%b(11) = 2132509567.0_R_P/479001600.0_R_P + case('adams_bashforth_12') + self%steps = 12 ; allocate(self%b(1:self%steps)) ; self%b = 0.0_R_P + self%b(1) = -262747265.0_R_P/958003200.0_R_P + self%b(2) = 3158642445.0_R_P/958003200.0_R_P + self%b(3) = -17410248271.0_R_P/958003200.0_R_P + self%b(4) = 58189107627.0_R_P/958003200.0_R_P + self%b(5) = -131365867290.0_R_P/958003200.0_R_P + self%b(6) = 211103573298.0_R_P/958003200.0_R_P + self%b(7) = -247741639374.0_R_P/958003200.0_R_P + self%b(8) = 214139355366.0_R_P/958003200.0_R_P + self%b(9) = -135579356757.0_R_P/958003200.0_R_P + self%b(10) = 61633227185.0_R_P/958003200.0_R_P + self%b(11) = -19433810163.0_R_P/958003200.0_R_P + self%b(12) = 4527766399.0_R_P/958003200.0_R_P + case('adams_bashforth_13') + self%steps = 13 ; allocate(self%b(1:self%steps)) ; self%b = 0.0_R_P + self%b(1) = 703604254357.0_R_P/2615348736000.0_R_P + self%b(2) = -9160551085734.0_R_P/2615348736000.0_R_P + self%b(3) = 55060974662412.0_R_P/2615348736000.0_R_P + self%b(4) = -202322913738370.0_R_P/2615348736000.0_R_P + self%b(5) = 507140369728425.0_R_P/2615348736000.0_R_P + self%b(6) = -915883387152444.0_R_P/2615348736000.0_R_P + self%b(7) = 1226443086129408.0_R_P/2615348736000.0_R_P + self%b(8) = -1233589244941764.0_R_P/2615348736000.0_R_P + self%b(9) = 932884546055895.0_R_P/2615348736000.0_R_P + self%b(10) = -524924579905150.0_R_P/2615348736000.0_R_P + self%b(11) = 214696591002612.0_R_P/2615348736000.0_R_P + self%b(12) = -61497552797274.0_R_P/2615348736000.0_R_P + self%b(13) = 13064406523627.0_R_P/2615348736000.0_R_P + case('adams_bashforth_14') + self%steps = 14 ; allocate(self%b(1:self%steps)) ; self%b = 0.0_R_P + self%b(1) = -1382741929621.0_R_P/5230697472000.0_R_P + self%b(2) = 19382853593787.0_R_P/5230697472000.0_R_P + self%b(3) = -126174972681906.0_R_P/5230697472000.0_R_P + self%b(4) = 505586141196430.0_R_P/5230697472000.0_R_P + self%b(5) = -1393306307155755.0_R_P/5230697472000.0_R_P + self%b(6) = 2793869602879077.0_R_P/5230697472000.0_R_P + self%b(7) = -4204551925534524.0_R_P/5230697472000.0_R_P + self%b(8) = 4825671323488452.0_R_P/5230697472000.0_R_P + self%b(9) = -4246767353305755.0_R_P/5230697472000.0_R_P + self%b(10) = 2854429571790805.0_R_P/5230697472000.0_R_P + self%b(11) = -1445313351681906.0_R_P/5230697472000.0_R_P + self%b(12) = 537247052515662.0_R_P/5230697472000.0_R_P + self%b(13) = -140970750679621.0_R_P/5230697472000.0_R_P + self%b(14) = 27511554976875.0_R_P/5230697472000.0_R_P + case('adams_bashforth_15') + self%steps = 15 ; allocate(self%b(1:self%steps)) ; self%b = 0.0_R_P + self%b(1) = 8164168737599.0_R_P/31384184832000.0_R_P + self%b(2) = -122594813904112.0_R_P/31384184832000.0_R_P + self%b(3) = 859236476684231.0_R_P/31384184832000.0_R_P + self%b(4) = -3728807256577472.0_R_P/31384184832000.0_R_P + self%b(5) = 11205849753515179.0_R_P/31384184832000.0_R_P + self%b(6) = -24704503655607728.0_R_P/31384184832000.0_R_P + self%b(7) = 41280216336284259.0_R_P/31384184832000.0_R_P + self%b(8) = -53246738660646912.0_R_P/31384184832000.0_R_P + self%b(9) = 53471026659940509.0_R_P/31384184832000.0_R_P + self%b(10) = -41825269932507728.0_R_P/31384184832000.0_R_P + self%b(11) = 25298910337081429.0_R_P/31384184832000.0_R_P + self%b(12) = -11643637530577472.0_R_P/31384184832000.0_R_P + self%b(13) = 3966421670215481.0_R_P/31384184832000.0_R_P + self%b(14) = -960122866404112.0_R_P/31384184832000.0_R_P + self%b(15) = 173233498598849.0_R_P/31384184832000.0_R_P + case('adams_bashforth_16') + self%steps = 16 ; allocate(self%b(1:self%steps)) ; self%b = 0.0_R_P + self%b(1) = -16088129229375.0_R_P/62768369664000.0_R_P + self%b(2) = 257650275915823.0_R_P/62768369664000.0_R_P + self%b(3) = -1934443196892599.0_R_P/62768369664000.0_R_P + self%b(4) = 9038571752734087.0_R_P/62768369664000.0_R_P + self%b(5) = -29417910911251819.0_R_P/62768369664000.0_R_P + self%b(6) = 70724351582843483.0_R_P/62768369664000.0_R_P + self%b(7) = -129930094104237331.0_R_P/62768369664000.0_R_P + self%b(8) = 186087544263596643.0_R_P/62768369664000.0_R_P + self%b(9) = -210020588912321949.0_R_P/62768369664000.0_R_P + self%b(10) = 187463140112902893.0_R_P/62768369664000.0_R_P + self%b(11) = -131963191940828581.0_R_P/62768369664000.0_R_P + self%b(12) = 72558117072259733.0_R_P/62768369664000.0_R_P + self%b(13) = -30607373860520569.0_R_P/62768369664000.0_R_P + self%b(14) = 9622096909515337.0_R_P/62768369664000.0_R_P + self%b(15) = -2161567671248849.0_R_P/62768369664000.0_R_P + self%b(16) = 362555126427073.0_R_P/62768369664000.0_R_P + endselect + else + call self%trigger_error(error=ERROR_UNSUPPORTED_SCHEME, & + error_message='"'//trim(adjustl(scheme))//'" unsupported scheme', & + is_severe=.true.) + endif + endsubroutine initialize endmodule foodie_integrator_adams_bashforth diff --git a/src/lib/foodie_integrator_adams_bashforth_moulton.f90 b/src/lib/foodie_integrator_adams_bashforth_moulton.f90 index 43cad9db..1a013352 100644 --- a/src/lib/foodie_integrator_adams_bashforth_moulton.f90 +++ b/src/lib/foodie_integrator_adams_bashforth_moulton.f90 @@ -80,6 +80,7 @@ module foodie_integrator_adams_bashforth_moulton use foodie_integrand_object, only : integrand_object use foodie_integrator_adams_bashforth, only : integrator_adams_bashforth use foodie_integrator_adams_moulton, only : integrator_adams_moulton +use foodie_integrator_multistep_implicit_object, only : integrator_multistep_implicit_object use foodie_integrator_object, only : integrator_object use penf, only : I_P, R_P @@ -106,15 +107,12 @@ module foodie_integrator_adams_bashforth_moulton trim(class_name_)//'_16'] !< List of supported schemes. logical, parameter :: has_fast_mode_=.true. !< Flag to check if integrator provides *fast mode* integrate. -logical, parameter :: is_multistage_=.false. !< Flag to check if integrator is multistage. -logical, parameter :: is_multistep_=.true. !< Flag to check if integrator is multistep. -type, extends(integrator_object) :: integrator_adams_bashforth_moulton +type, extends(integrator_multistep_implicit_object) :: integrator_adams_bashforth_moulton !< FOODIE integrator: provide an explicit class of Adams-Bashforth-Moulton multi-step schemes, from 1st to 4rd order accurate. !< !< @note The integrator must be created or initialized (predictor and corrector schemes selection) before used. private - integer(I_P) :: steps=0 !< Number of time steps. type(integrator_adams_bashforth) :: predictor !< Predictor solver. type(integrator_adams_moulton) :: corrector !< Corrector solver. contains @@ -123,18 +121,14 @@ module foodie_integrator_adams_bashforth_moulton procedure, pass(self) :: description !< Return pretty-printed object description. procedure, pass(self) :: has_fast_mode !< Return .true. if the integrator class has *fast mode* integrate. procedure, pass(lhs) :: integr_assign_integr !< Operator `=`. - procedure, pass(self) :: is_multistage !< Return .true. for multistage integrator. - procedure, pass(self) :: is_multistep !< Return .true. for multistep integrator. + procedure, pass(self) :: integrate !< Integrate integrand field. + procedure, pass(self) :: integrate_fast !< Integrate integrand field. procedure, pass(self) :: is_supported !< Return .true. if the integrator class support the given scheme. - procedure, pass(self) :: stages_number !< Return number of stages used. - procedure, pass(self) :: steps_number !< Return number of steps used. procedure, pass(self) :: supported_schemes !< Return the list of supported schemes. ! public methods - procedure, pass(self) :: destroy !< Destroy the integrator. - procedure, pass(self) :: initialize !< Initialize (create) the integrator. - procedure, pass(self) :: integrate !< Integrate integrand field. - procedure, pass(self) :: integrate_fast !< Integrate integrand field. - procedure, pass(self) :: scheme_number !< Return the scheme number in the list of supported schemes. + procedure, pass(self) :: destroy !< Destroy the integrator. + procedure, pass(self) :: initialize !< Initialize (create) the integrator. + procedure, pass(self) :: scheme_number !< Return the scheme number in the list of supported schemes. endtype integrator_adams_bashforth_moulton contains @@ -188,21 +182,44 @@ pure subroutine integr_assign_integr(lhs, rhs) endselect endsubroutine integr_assign_integr - elemental function is_multistage(self) - !< Return .true. for multistage integrator. - class(integrator_adams_bashforth_moulton), intent(in) :: self !< Integrator. - logical :: is_multistage !< Inquire result. + subroutine integrate(self, U, previous, Dt, t, iterations, autoupdate) + !< Integrate field with Adams-Bashforth-Moulton class scheme. + class(integrator_adams_bashforth_moulton), intent(in) :: self !< Integrator. + class(integrand_object), intent(inout) :: U !< Field to be integrated. + class(integrand_object), intent(inout) :: previous(1:) !< Previous time steps solutions of integrand. + real(R_P), intent(in) :: Dt !< Time steps. + real(R_P), intent(in) :: t(:) !< Times. + integer(I_P), intent(in), optional :: iterations !< Fixed point iterations of AM scheme. + logical, intent(in), optional :: autoupdate !< Cyclic autoupdate of previous time steps flag. + logical :: autoupdate_ !< Cyclic autoupdate of previous time steps flag,i + !< local variable. - is_multistage = is_multistage_ - endfunction is_multistage + autoupdate_ = .true. ; if (present(autoupdate)) autoupdate_ = autoupdate + call self%predictor%integrate(U=U, previous=previous, Dt=Dt, t=t, autoupdate=.false.) + call self%corrector%integrate(U=U, previous=previous(2:), Dt=Dt, t=t, iterations=iterations, autoupdate=.false.) + call self%predictor%update_previous(U=U, previous=previous) + if (autoupdate_) call self%predictor%update_previous(U=U, previous=previous) + endsubroutine integrate - elemental function is_multistep(self) - !< Return .true. for multistage integrator. - class(integrator_adams_bashforth_moulton), intent(in) :: self !< Integrator. - logical :: is_multistep !< Inquire result. + subroutine integrate_fast(self, U, previous, buffer, Dt, t, iterations, autoupdate) + !< Integrate field with Adams-Bashforth-Moulton class scheme, fast mode. + class(integrator_adams_bashforth_moulton), intent(in) :: self !< Integrator. + class(integrand_object), intent(inout) :: U !< Field to be integrated. + class(integrand_object), intent(inout) :: previous(1:) !< Previous time steps solutions of integrand. + class(integrand_object), intent(inout) :: buffer !< Temporary buffer for doing fast operation. + real(R_P), intent(in) :: Dt !< Time steps. + real(R_P), intent(in) :: t(:) !< Times. + integer(I_P), intent(in), optional :: iterations !< Fixed point iterations of AM scheme. + logical, intent(in), optional :: autoupdate !< Cyclic autoupdate of previous time steps flag. + logical :: autoupdate_ !< Cyclic autoupdate of previous time steps flag,i + !< local variable. - is_multistep = is_multistep_ - endfunction is_multistep + autoupdate_ = .true. ; if (present(autoupdate)) autoupdate_ = autoupdate + call self%predictor%integrate_fast(U=U, previous=previous, buffer=buffer, Dt=Dt, t=t, autoupdate=.false.) + call self%corrector%integrate_fast(U=U, previous=previous(2:), buffer=buffer, Dt=Dt, t=t, iterations=iterations, & + autoupdate=.false.) + if (autoupdate_) call self%predictor%update_previous(U=U, previous=previous) + endsubroutine integrate_fast elemental function is_supported(self, scheme) !< Return .true. if the integrator class support the given scheme. @@ -220,22 +237,6 @@ elemental function is_supported(self, scheme) enddo endfunction is_supported - elemental function stages_number(self) - !< Return number of stages used. - class(integrator_adams_bashforth_moulton), intent(in) :: self !< Integrator. - integer(I_P) :: stages_number !< Number of stages used. - - stages_number = 0 - endfunction stages_number - - elemental function steps_number(self) - !< Return number of steps used. - class(integrator_adams_bashforth_moulton), intent(in) :: self !< Integrator. - integer(I_P) :: steps_number !< Number of steps used. - - steps_number = self%steps - endfunction steps_number - pure function supported_schemes(self) result(schemes) !< Return the list of supported schemes. class(integrator_adams_bashforth_moulton), intent(in) :: self !< Integrator. @@ -250,8 +251,7 @@ elemental subroutine destroy(self) !< Destroy the integrator. class(integrator_adams_bashforth_moulton), intent(inout) :: self !< Integrator. - call self%destroy_abstract - self%steps = 0 + call self%destroy_multistep call self%predictor%destroy call self%corrector%destroy endsubroutine destroy @@ -279,36 +279,6 @@ subroutine initialize(self, scheme) endif endsubroutine initialize - subroutine integrate(self, U, previous, Dt, t, iterations) - !< Integrate field with Adams-Bashforth-Moulton class scheme. - class(integrator_adams_bashforth_moulton), intent(in) :: self !< Integrator. - class(integrand_object), intent(inout) :: U !< Field to be integrated. - class(integrand_object), intent(inout) :: previous(1:) !< Previous time steps solutions of integrand. - real(R_P), intent(in) :: Dt !< Time steps. - real(R_P), intent(in) :: t(:) !< Times. - integer(I_P), intent(in), optional :: iterations !< Fixed point iterations of AM scheme. - - call self%predictor%integrate(U=U, previous=previous, Dt=Dt, t=t, autoupdate=.false.) - call self%corrector%integrate(U=U, previous=previous(2:), Dt=Dt, t=t, iterations=iterations, autoupdate=.false.) - call self%predictor%update_previous(U=U, previous=previous) - endsubroutine integrate - - subroutine integrate_fast(self, U, previous, buffer, Dt, t, iterations) - !< Integrate field with Adams-Bashforth-Moulton class scheme, fast mode. - class(integrator_adams_bashforth_moulton), intent(in) :: self !< Integrator. - class(integrand_object), intent(inout) :: U !< Field to be integrated. - class(integrand_object), intent(inout) :: previous(1:) !< Previous time steps solutions of integrand. - class(integrand_object), intent(inout) :: buffer !< Temporary buffer for doing fast operation. - real(R_P), intent(in) :: Dt !< Time steps. - real(R_P), intent(in) :: t(:) !< Times. - integer(I_P), intent(in), optional :: iterations !< Fixed point iterations of AM scheme. - - call self%predictor%integrate_fast(U=U, previous=previous, buffer=buffer, Dt=Dt, t=t, autoupdate=.false.) - call self%corrector%integrate_fast(U=U, previous=previous(2:), buffer=buffer, Dt=Dt, t=t, iterations=iterations, & - autoupdate=.false.) - call self%predictor%update_previous(U=U, previous=previous) - endsubroutine integrate_fast - elemental function scheme_number(self, scheme) !< Return the scheme number in the list of supported schemes. class(integrator_adams_bashforth_moulton), intent(in) :: self !< Integrator. diff --git a/src/lib/foodie_integrator_adams_moulton.f90 b/src/lib/foodie_integrator_adams_moulton.f90 index 88b67ba0..13b8bf0d 100644 --- a/src/lib/foodie_integrator_adams_moulton.f90 +++ b/src/lib/foodie_integrator_adams_moulton.f90 @@ -29,6 +29,7 @@ module foodie_integrator_adams_moulton use foodie_error_codes, only : ERROR_UNSUPPORTED_SCHEME use foodie_integrand_object, only : integrand_object +use foodie_integrator_multistep_implicit_object, only : integrator_multistep_implicit_object use foodie_integrator_object, only : integrator_object use penf, only : I_P, R_P @@ -55,34 +56,26 @@ module foodie_integrator_adams_moulton trim(class_name_)//'_15'] !< List of supported schemes. logical, parameter :: has_fast_mode_=.true. !< Flag to check if integrator provides *fast mode* integrate. -logical, parameter :: is_multistage_=.false. !< Flag to check if integrator is multistage. -logical, parameter :: is_multistep_=.true. !< Flag to check if integrator is multistep. -type, extends(integrator_object) :: integrator_adams_moulton +type, extends(integrator_multistep_implicit_object) :: integrator_adams_moulton !< FOODIE integrator: provide an explicit class of Adams-Moulton multi-step schemes, from 1st to 16th order accurate. !< !< @note The integrator must be created or initialized (initialize the *b* coefficients) before used. private - integer(I_P) :: steps=-1 !< Number of time steps. - real(R_P), allocatable :: b(:) !< \(b\) coefficients. + real(R_P), allocatable :: b(:) !< \(b\) coefficients. contains ! deferred methods procedure, pass(self) :: class_name !< Return the class name of schemes. procedure, pass(self) :: description !< Return pretty-printed object description. procedure, pass(lhs) :: integr_assign_integr !< Operator `=`. procedure, pass(self) :: has_fast_mode !< Return .true. if the integrator class has *fast mode* integrate. - procedure, pass(self) :: is_multistage !< Return .true. for multistage integrator. - procedure, pass(self) :: is_multistep !< Return .true. for multistep integrator. + procedure, pass(self) :: integrate !< Integrate integrand field. + procedure, pass(self) :: integrate_fast !< Integrate integrand field, fast mode. procedure, pass(self) :: is_supported !< Return .true. if the integrator class support the given scheme. - procedure, pass(self) :: stages_number !< Return number of stages used. - procedure, pass(self) :: steps_number !< Return number of steps used. procedure, pass(self) :: supported_schemes !< Return the list of supported schemes. ! public methods - procedure, pass(self) :: destroy !< Destroy the integrator. - procedure, pass(self) :: initialize !< Initialize (create) the integrator. - procedure, pass(self) :: integrate !< Integrate integrand field. - procedure, pass(self) :: integrate_fast !< Integrate integrand field, fast mode. - procedure, pass(self) :: update_previous !< Cyclic update previous time steps. + procedure, pass(self) :: destroy !< Destroy the integrator. + procedure, pass(self) :: initialize !< Initialize (create) the integrator. endtype integrator_adams_moulton contains @@ -135,21 +128,93 @@ pure subroutine integr_assign_integr(lhs, rhs) endselect endsubroutine integr_assign_integr - elemental function is_multistage(self) - !< Return .true. for multistage integrator. - class(integrator_adams_moulton), intent(in) :: self !< Integrator. - logical :: is_multistage !< Inquire result. + subroutine integrate(self, U, previous, Dt, t, iterations, autoupdate) + !< Integrate field with Adams-Moulton class scheme. + class(integrator_adams_moulton), intent(in) :: self !< Integrator. + class(integrand_object), intent(inout) :: U !< Field to be integrated. + class(integrand_object), intent(inout) :: previous(1:) !< Previous time steps solutions of integrand field. + real(R_P), intent(in) :: Dt !< Time steps. + real(R_P), intent(in) :: t(:) !< Times. + integer(I_P), intent(in), optional :: iterations !< Fixed point iterations. + logical, intent(in), optional :: autoupdate !< Cyclic autoupdate of previous time steps flag. + logical :: autoupdate_ !< Cyclic autoupdate of previous time steps flag, dummy var. + class(integrand_object), allocatable :: delta !< Delta RHS for fixed point iterations. + integer(I_P) :: s !< Steps counter. - is_multistage = is_multistage_ - endfunction is_multistage + autoupdate_ = .true. ; if (present(autoupdate)) autoupdate_ = autoupdate + if (self%steps>0) then + if (present(iterations)) then ! perform fixed point iterations + allocate(delta, mold=U) + delta = previous(self%steps) + do s=0, self%steps - 1 + delta = delta + (previous(s+1)%t(t=t(s+1)) * (Dt * self%b(s))) + enddo + do s=1, iterations + U = delta + (U%t(t=t(self%steps) + Dt) * (Dt * self%b(self%steps))) + enddo + else + U = previous(self%steps) + (U%t(t=t(self%steps) + Dt) * (Dt * self%b(self%steps))) + do s=0, self%steps - 1 + U = U + (previous(s+1)%t(t=t(s+1)) * (Dt * self%b(s))) + enddo + endif + if (autoupdate_) call self%update_previous(U=U, previous=previous) + else + U = U + (U%t(t=t(1)) * (Dt * self%b(0))) + endif + endsubroutine integrate - elemental function is_multistep(self) - !< Return .true. for multistage integrator. - class(integrator_adams_moulton), intent(in) :: self !< Integrator. - logical :: is_multistep !< Inquire result. + subroutine integrate_fast(self, U, previous, buffer, Dt, t, iterations, autoupdate) + !< Integrate field with Adams-Moulton class scheme, fast mode. + class(integrator_adams_moulton), intent(in) :: self !< Integrator. + class(integrand_object), intent(inout) :: U !< Field to be integrated. + class(integrand_object), intent(inout) :: previous(1:) !< Previous time steps solutions of integrand field. + class(integrand_object), intent(inout) :: buffer !< Temporary buffer for doing fast operation. + real(R_P), intent(in) :: Dt !< Time steps. + real(R_P), intent(in) :: t(:) !< Times. + integer(I_P), intent(in), optional :: iterations !< Fixed point iterations. + logical, intent(in), optional :: autoupdate !< Cyclic autoupdate of previous time steps flag. + logical :: autoupdate_ !< Cyclic autoupdate of previous time steps flag, dummy var. + class(integrand_object), allocatable :: delta !< Delta RHS for fixed point iterations. + integer(I_P) :: s !< Steps counter. - is_multistep = is_multistep_ - endfunction is_multistep + autoupdate_ = .true. ; if (present(autoupdate)) autoupdate_ = autoupdate + if (self%steps>0) then + if (present(iterations)) then ! perform fixed point iterations + allocate(delta, mold=U) + delta = previous(self%steps) + do s=0, self%steps - 1 + buffer = previous(s+1) + call buffer%t_fast(t=t(s+1)) + call buffer%multiply_fast(lhs=buffer, rhs=Dt * self%b(s)) + call delta%add_fast(lhs=delta, rhs=buffer) + enddo + do s=1, iterations + buffer = U + call buffer%t_fast(t=t(self%steps) + Dt) + call buffer%multiply_fast(lhs=buffer, rhs=Dt * self%b(self%steps)) + call U%add_fast(lhs=delta, rhs=buffer) + enddo + else + buffer = U + call buffer%t_fast(t=t(self%steps) + Dt) + call buffer%multiply_fast(lhs=buffer, rhs=Dt * self%b(self%steps)) + call U%add_fast(lhs=previous(self%steps), rhs=buffer) + do s=0, self%steps - 1 + buffer = previous(s+1) + call buffer%t_fast(t=t(s+1)) + call buffer%multiply_fast(lhs=buffer, rhs=Dt * self%b(s)) + call U%add_fast(lhs=U, rhs=buffer) + enddo + endif + if (autoupdate_) call self%update_previous(U=U, previous=previous) + else + buffer = U + call buffer%t_fast(t=t(1)) + call buffer%multiply_fast(lhs=buffer, rhs=Dt * self%b(0)) + call U%add_fast(lhs=U, rhs=buffer) + endif + endsubroutine integrate_fast elemental function is_supported(self, scheme) !< Return .true. if the integrator class support the given scheme. @@ -167,22 +232,6 @@ elemental function is_supported(self, scheme) enddo endfunction is_supported - elemental function stages_number(self) - !< Return number of stages used. - class(integrator_adams_moulton), intent(in) :: self !< Integrator. - integer(I_P) :: stages_number !< Number of stages used. - - stages_number = 0 - endfunction stages_number - - elemental function steps_number(self) - !< Return number of steps used. - class(integrator_adams_moulton), intent(in) :: self !< Integrator. - integer(I_P) :: steps_number !< Number of steps used. - - steps_number = self%steps - endfunction steps_number - pure function supported_schemes(self) result(schemes) !< Return the list of supported schemes. class(integrator_adams_moulton), intent(in) :: self !< Integrator. @@ -197,8 +246,7 @@ elemental subroutine destroy(self) !< Destroy the integrator. class(integrator_adams_moulton), intent(INOUT) :: self !< Integrator. - call self%destroy_abstract - self%steps = -1 + call self%destroy_multistep if (allocated(self%b)) deallocate(self%b) endsubroutine destroy @@ -385,107 +433,4 @@ subroutine initialize(self, scheme) is_severe=.true.) endif endsubroutine initialize - - subroutine integrate(self, U, previous, Dt, t, iterations, autoupdate) - !< Integrate field with Adams-Moulton class scheme. - class(integrator_adams_moulton), intent(in) :: self !< Integrator. - class(integrand_object), intent(inout) :: U !< Field to be integrated. - class(integrand_object), intent(inout) :: previous(1:) !< Previous time steps solutions of integrand field. - real(R_P), intent(in) :: Dt !< Time steps. - real(R_P), intent(in) :: t(:) !< Times. - integer(I_P), intent(in), optional :: iterations !< Fixed point iterations. - logical, intent(in), optional :: autoupdate !< Cyclic autoupdate of previous time steps flag. - logical :: autoupdate_ !< Cyclic autoupdate of previous time steps flag, dummy var. - class(integrand_object), allocatable :: delta !< Delta RHS for fixed point iterations. - integer(I_P) :: s !< Steps counter. - - autoupdate_ = .true. ; if (present(autoupdate)) autoupdate_ = autoupdate - if (self%steps>0) then - if (present(iterations)) then ! perform fixed point iterations - allocate(delta, mold=U) - delta = previous(self%steps) - do s=0, self%steps - 1 - delta = delta + (previous(s+1)%t(t=t(s+1)) * (Dt * self%b(s))) - enddo - do s=1, iterations - U = delta + (U%t(t=t(self%steps) + Dt) * (Dt * self%b(self%steps))) - enddo - else - U = previous(self%steps) + (U%t(t=t(self%steps) + Dt) * (Dt * self%b(self%steps))) - do s=0, self%steps - 1 - U = U + (previous(s+1)%t(t=t(s+1)) * (Dt * self%b(s))) - enddo - endif - if (autoupdate_) call self%update_previous(U=U, previous=previous) - else - U = U + (U%t(t=t(1)) * (Dt * self%b(0))) - endif - endsubroutine integrate - - subroutine integrate_fast(self, U, previous, buffer, Dt, t, iterations, autoupdate) - !< Integrate field with Adams-Moulton class scheme, fast mode. - class(integrator_adams_moulton), intent(in) :: self !< Integrator. - class(integrand_object), intent(inout) :: U !< Field to be integrated. - class(integrand_object), intent(inout) :: previous(1:) !< Previous time steps solutions of integrand field. - class(integrand_object), intent(inout) :: buffer !< Temporary buffer for doing fast operation. - real(R_P), intent(in) :: Dt !< Time steps. - real(R_P), intent(in) :: t(:) !< Times. - integer(I_P), intent(in), optional :: iterations !< Fixed point iterations. - logical, intent(in), optional :: autoupdate !< Cyclic autoupdate of previous time steps flag. - logical :: autoupdate_ !< Cyclic autoupdate of previous time steps flag, dummy var. - class(integrand_object), allocatable :: delta !< Delta RHS for fixed point iterations. - integer(I_P) :: s !< Steps counter. - - autoupdate_ = .true. ; if (present(autoupdate)) autoupdate_ = autoupdate - if (self%steps>0) then - if (present(iterations)) then ! perform fixed point iterations - allocate(delta, mold=U) - delta = previous(self%steps) - do s=0, self%steps - 1 - buffer = previous(s+1) - call buffer%t_fast(t=t(s+1)) - call buffer%multiply_fast(lhs=buffer, rhs=Dt * self%b(s)) - call delta%add_fast(lhs=delta, rhs=buffer) - enddo - do s=1, iterations - buffer = U - call buffer%t_fast(t=t(self%steps) + Dt) - call buffer%multiply_fast(lhs=buffer, rhs=Dt * self%b(self%steps)) - call U%add_fast(lhs=delta, rhs=buffer) - enddo - else - buffer = U - call buffer%t_fast(t=t(self%steps) + Dt) - call buffer%multiply_fast(lhs=buffer, rhs=Dt * self%b(self%steps)) - call U%add_fast(lhs=previous(self%steps), rhs=buffer) - do s=0, self%steps - 1 - buffer = previous(s+1) - call buffer%t_fast(t=t(s+1)) - call buffer%multiply_fast(lhs=buffer, rhs=Dt * self%b(s)) - call U%add_fast(lhs=U, rhs=buffer) - enddo - endif - if (autoupdate_) call self%update_previous(U=U, previous=previous) - else - buffer = U - call buffer%t_fast(t=t(1)) - call buffer%multiply_fast(lhs=buffer, rhs=Dt * self%b(0)) - call U%add_fast(lhs=U, rhs=buffer) - endif - endsubroutine integrate_fast - - subroutine update_previous(self, U, previous) - !< Cyclic update previous time steps. - class(integrator_adams_moulton), intent(in) :: self !< Integrator. - class(integrand_object), intent(in) :: U !< Field to be integrated. - class(integrand_object), intent(inout) :: previous(1:) !< Previous time steps solutions of integrand field. - integer(I_P) :: s !< Steps counter. - - if (self%steps>0) then - do s=0, self%steps - 2 - previous(s + 1) = previous(s + 2) - enddo - previous(self%steps) = U - endif - endsubroutine update_previous endmodule foodie_integrator_adams_moulton diff --git a/src/lib/foodie_integrator_backward_differentiation_formula.f90 b/src/lib/foodie_integrator_backward_differentiation_formula.f90 index 07d37d8b..fc16fac1 100644 --- a/src/lib/foodie_integrator_backward_differentiation_formula.f90 +++ b/src/lib/foodie_integrator_backward_differentiation_formula.f90 @@ -35,6 +35,7 @@ module foodie_integrator_backward_differentiation_formula use foodie_error_codes, only : ERROR_UNSUPPORTED_SCHEME use foodie_integrand_object, only : integrand_object +use foodie_integrator_multistep_implicit_object, only : integrator_multistep_implicit_object use foodie_integrator_object, only : integrator_object use penf, only : I_P, R_P @@ -51,16 +52,13 @@ module foodie_integrator_backward_differentiation_formula trim(class_name_)//'_6'] !< List of supported schemes. logical, parameter :: has_fast_mode_=.true. !< Flag to check if integrator provides *fast mode* integrate. -logical, parameter :: is_multistage_=.false. !< Flag to check if integrator is multistage. -logical, parameter :: is_multistep_=.true. !< Flag to check if integrator is multistep. -type, extends(integrator_object) :: integrator_back_df +type, extends(integrator_multistep_implicit_object) :: integrator_back_df !< FOODIE integrator: provide an implicit class of Backward-Differentiation-Formula multi-step schemes, from 1st to 6th order !< accurate. !< !< @note The integrator must be created or initialized (initialize the *alpha* and *beta* coefficients) before used. private - integer(I_P) :: steps=0 !< Number of time steps. real(R_P), allocatable :: a(:) !< \(\alpha\) coefficients. real(R_P) :: b=0.0_R_P !< \(\beta\) coefficient. contains @@ -69,18 +67,13 @@ module foodie_integrator_backward_differentiation_formula procedure, pass(self) :: description !< Return pretty-printed object description. procedure, pass(self) :: has_fast_mode !< Return .true. if the integrator class has *fast mode* integrate. procedure, pass(lhs) :: integr_assign_integr !< Operator `=`. - procedure, pass(self) :: is_multistage !< Return .true. for multistage integrator. - procedure, pass(self) :: is_multistep !< Return .true. for multistep integrator. + procedure, pass(self) :: integrate !< Integrate integrand field. + procedure, pass(self) :: integrate_fast !< Integrate integrand field, fast mode. procedure, pass(self) :: is_supported !< Return .true. if the integrator class support the given scheme. - procedure, pass(self) :: stages_number !< Return number of stages used. - procedure, pass(self) :: steps_number !< Return number of steps used. procedure, pass(self) :: supported_schemes !< Return the list of supported schemes. ! public methods - procedure, pass(self) :: destroy !< Destroy the integrator. - procedure, pass(self) :: initialize !< Initialize (create) the integrator. - procedure, pass(self) :: integrate !< Integrate integrand field. - procedure, pass(self) :: integrate_fast !< Integrate integrand field, fast mode. - procedure, pass(self) :: update_previous !< Cyclic update previous time steps. + procedure, pass(self) :: destroy !< Destroy the integrator. + procedure, pass(self) :: initialize !< Initialize (create) the integrator. endtype integrator_back_df contains @@ -134,21 +127,64 @@ pure subroutine integr_assign_integr(lhs, rhs) endselect endsubroutine integr_assign_integr - elemental function is_multistage(self) - !< Return .true. for multistage integrator. - class(integrator_back_df), intent(in) :: self !< Integrator. - logical :: is_multistage !< Inquire result. + subroutine integrate(self, U, previous, Dt, t, iterations, autoupdate) + !< Integrate field with BDF class scheme. + class(integrator_back_df), intent(in) :: self !< Integrator. + class(integrand_object), intent(inout) :: U !< Field to be integrated. + class(integrand_object), intent(inout) :: previous(1:) !< Previous time steps solutions of integrand field. + real(R_P), intent(in) :: Dt !< Time steps. + real(R_P), intent(in) :: t(:) !< Times. + integer(I_P), optional, intent(in) :: iterations !< Fixed point iterations. + logical, optional, intent(in) :: autoupdate !< Perform cyclic autoupdate of previous time steps. + integer(I_P) :: iterations_ !< Fixed point iterations. + logical :: autoupdate_ !< Perform cyclic autoupdate of previous time steps, dummy var. + class(integrand_object), allocatable :: delta !< Delta RHS for fixed point iterations. + integer(I_P) :: s !< Steps counter. - is_multistage = is_multistage_ - endfunction is_multistage + autoupdate_ = .true. ; if (present(autoupdate)) autoupdate_ = autoupdate + iterations_ = 1 ; if (present(iterations)) iterations_ = iterations + allocate(delta, mold=U) + delta = previous(self%steps) * (-self%a(self%steps)) + do s=1, self%steps - 1 + delta = delta + (previous(s) * (-self%a(s))) + enddo + do s=1, iterations_ + U = delta + (U%t(t=t(self%steps) + Dt) * (Dt * self%b)) + enddo + if (autoupdate_) call self%update_previous(U=U, previous=previous, is_like_explicit=.true.) + endsubroutine integrate - elemental function is_multistep(self) - !< Return .true. for multistage integrator. - class(integrator_back_df), intent(in) :: self !< Integrator. - logical :: is_multistep !< Inquire result. + subroutine integrate_fast(self, U, previous, buffer, Dt, t, iterations, autoupdate) + !< Integrate field with BDF class scheme. + class(integrator_back_df), intent(in) :: self !< Integrator. + class(integrand_object), intent(inout) :: U !< Field to be integrated. + class(integrand_object), intent(inout) :: previous(1:) !< Previous time steps solutions of integrand field. + class(integrand_object), intent(inout) :: buffer !< Temporary buffer for doing fast operation. + real(R_P), intent(in) :: Dt !< Time steps. + real(R_P), intent(in) :: t(:) !< Times. + integer(I_P), optional, intent(in) :: iterations !< Fixed point iterations. + logical, optional, intent(in) :: autoupdate !< Perform cyclic autoupdate of previous time steps. + integer(I_P) :: iterations_ !< Fixed point iterations. + logical :: autoupdate_ !< Perform cyclic autoupdate of previous time steps, dummy var. + class(integrand_object), allocatable :: delta !< Delta RHS for fixed point iterations. + integer(I_P) :: s !< Steps counter. - is_multistep = is_multistep_ - endfunction is_multistep + autoupdate_ = .true. ; if (present(autoupdate)) autoupdate_ = autoupdate + iterations_ = 1 ; if (present(iterations)) iterations_ = iterations + allocate(delta, mold=U) + call delta%multiply_fast(lhs=previous(self%steps), rhs=-self%a(self%steps)) + do s=1, self%steps - 1 + call buffer%multiply_fast(lhs=previous(s), rhs=-self%a(s)) + call delta%add_fast(lhs=delta, rhs=buffer) + enddo + do s=1, iterations + buffer = U + call buffer%t_fast(t=t(self%steps) + Dt) + call buffer%multiply_fast(lhs=buffer, rhs=Dt * self%b) + call U%add_fast(lhs=delta, rhs=buffer) + enddo + if (autoupdate_) call self%update_previous(U=U, previous=previous, is_like_explicit=.true.) + endsubroutine integrate_fast elemental function is_supported(self, scheme) !< Return .true. if the integrator class support the given scheme. @@ -166,22 +202,6 @@ elemental function is_supported(self, scheme) enddo endfunction is_supported - elemental function stages_number(self) - !< Return number of stages used. - class(integrator_back_df), intent(in) :: self !< Integrator. - integer(I_P) :: stages_number !< Number of stages used. - - stages_number = 0 - endfunction stages_number - - elemental function steps_number(self) - !< Return number of steps used. - class(integrator_back_df), intent(in) :: self !< Integrator. - integer(I_P) :: steps_number !< Number of steps used. - - steps_number = self%steps - endfunction steps_number - pure function supported_schemes(self) result(schemes) !< Return the list of supported schemes. class(integrator_back_df), intent(in) :: self !< Integrator. @@ -196,8 +216,7 @@ elemental subroutine destroy(self) !< Destroy the integrator. class(integrator_back_df), intent(inout) :: self !< Integrator. - call self%destroy_abstract - self%steps = 0 + call self%destroy_multistep if (allocated(self%a)) deallocate(self%a) self%b = 0.0_R_P endsubroutine destroy @@ -257,76 +276,4 @@ subroutine initialize(self, scheme) is_severe=.true.) endif endsubroutine initialize - - subroutine integrate(self, U, previous, Dt, t, iterations, autoupdate) - !< Integrate field with BDF class scheme. - class(integrator_back_df), intent(in) :: self !< Integrator. - class(integrand_object), intent(inout) :: U !< Field to be integrated. - class(integrand_object), intent(inout) :: previous(1:) !< Previous time steps solutions of integrand field. - real(R_P), intent(in) :: Dt !< Time steps. - real(R_P), intent(in) :: t(:) !< Times. - integer(I_P), optional, intent(in) :: iterations !< Fixed point iterations. - logical, optional, intent(in) :: autoupdate !< Perform cyclic autoupdate of previous time steps. - integer(I_P) :: iterations_ !< Fixed point iterations. - logical :: autoupdate_ !< Perform cyclic autoupdate of previous time steps, dummy var. - class(integrand_object), allocatable :: delta !< Delta RHS for fixed point iterations. - integer(I_P) :: s !< Steps counter. - - autoupdate_ = .true. ; if (present(autoupdate)) autoupdate_ = autoupdate - iterations_ = 1 ; if (present(iterations)) iterations_ = iterations - allocate(delta, mold=U) - delta = previous(self%steps) * (-self%a(self%steps)) - do s=1, self%steps - 1 - delta = delta + (previous(s) * (-self%a(s))) - enddo - do s=1, iterations_ - U = delta + (U%t(t=t(self%steps) + Dt) * (Dt * self%b)) - enddo - if (autoupdate_) call self%update_previous(U=U, previous=previous) - endsubroutine integrate - - subroutine integrate_fast(self, U, previous, buffer, Dt, t, iterations, autoupdate) - !< Integrate field with BDF class scheme. - class(integrator_back_df), intent(in) :: self !< Integrator. - class(integrand_object), intent(inout) :: U !< Field to be integrated. - class(integrand_object), intent(inout) :: previous(1:) !< Previous time steps solutions of integrand field. - class(integrand_object), intent(inout) :: buffer !< Temporary buffer for doing fast operation. - real(R_P), intent(in) :: Dt !< Time steps. - real(R_P), intent(in) :: t(:) !< Times. - integer(I_P), optional, intent(in) :: iterations !< Fixed point iterations. - logical, optional, intent(in) :: autoupdate !< Perform cyclic autoupdate of previous time steps. - integer(I_P) :: iterations_ !< Fixed point iterations. - logical :: autoupdate_ !< Perform cyclic autoupdate of previous time steps, dummy var. - class(integrand_object), allocatable :: delta !< Delta RHS for fixed point iterations. - integer(I_P) :: s !< Steps counter. - - autoupdate_ = .true. ; if (present(autoupdate)) autoupdate_ = autoupdate - iterations_ = 1 ; if (present(iterations)) iterations_ = iterations - allocate(delta, mold=U) - call delta%multiply_fast(lhs=previous(self%steps), rhs=-self%a(self%steps)) - do s=1, self%steps - 1 - call buffer%multiply_fast(lhs=previous(s), rhs=-self%a(s)) - call delta%add_fast(lhs=delta, rhs=buffer) - enddo - do s=1, iterations - buffer = U - call buffer%t_fast(t=t(self%steps) + Dt) - call buffer%multiply_fast(lhs=buffer, rhs=Dt * self%b) - call U%add_fast(lhs=delta, rhs=buffer) - enddo - if (autoupdate_) call self%update_previous(U=U, previous=previous) - endsubroutine integrate_fast - - subroutine update_previous(self, U, previous) - !< Cyclic update previous time steps. - class(integrator_back_df), intent(in) :: self !< Integrator. - class(integrand_object), intent(in) :: U !< Field to be integrated. - class(integrand_object), intent(inout) :: previous(1:) !< Previous time steps solutions of integrand field. - integer(I_P) :: s !< Steps counter. - - do s=1, self%steps - 1 - previous(s) = previous(s + 1) - enddo - previous(self%steps) = U - endsubroutine update_previous endmodule foodie_integrator_backward_differentiation_formula diff --git a/src/lib/foodie_integrator_lmm_ssp.f90 b/src/lib/foodie_integrator_lmm_ssp.f90 index 07f90dd7..effe063a 100644 --- a/src/lib/foodie_integrator_lmm_ssp.f90 +++ b/src/lib/foodie_integrator_lmm_ssp.f90 @@ -28,6 +28,7 @@ module foodie_integrator_lmm_ssp use foodie_error_codes, only : ERROR_UNSUPPORTED_SCHEME use foodie_integrand_object, only : integrand_object +use foodie_integrator_multistep_explicit_object, only : integrator_multistep_explicit_object use foodie_integrator_object, only : integrator_object use penf, only : I_P, R_P @@ -41,36 +42,28 @@ module foodie_integrator_lmm_ssp trim(class_name_)//'_steps_5_order_3'] !< List of supported schemes. logical, parameter :: has_fast_mode_=.true. !< Flag to check if integrator provides *fast mode* integrate. -logical, parameter :: is_multistage_=.false. !< Flag to check if integrator is multistage. -logical, parameter :: is_multistep_=.true. !< Flag to check if integrator is multistep. -type, extends(integrator_object) :: integrator_lmm_ssp +type, extends(integrator_multistep_explicit_object) :: integrator_lmm_ssp !< FOODIE integrator: provide an explicit class of Linear Multi-step Methods (LLM) with Strong Stability Preserving property, !< from 2nd to 3rd order accurate. !< !< @note The integrator must be created or initialized (initialize the *a,b* coefficients) before used. private - integer(I_P) :: steps=0 !< Number of time steps. - real(R_P), allocatable :: a(:) !< *a* coefficients. - real(R_P), allocatable :: b(:) !< *b* coefficients. + real(R_P), allocatable :: a(:) !< *a* coefficients. + real(R_P), allocatable :: b(:) !< *b* coefficients. contains ! deferred methods procedure, pass(self) :: class_name !< Return the class name of schemes. procedure, pass(self) :: description !< Return pretty-printed object description. procedure, pass(self) :: has_fast_mode !< Return .true. if the integrator class has *fast mode* integrate. procedure, pass(lhs) :: integr_assign_integr !< Operator `=`. - procedure, pass(self) :: is_multistage !< Return .true. for multistage integrator. - procedure, pass(self) :: is_multistep !< Return .true. for multistep integrator. + procedure, pass(self) :: integrate !< Integrate integrand field. + procedure, pass(self) :: integrate_fast !< Integrate integrand field, fast mode. procedure, pass(self) :: is_supported !< Return .true. if the integrator class support the given scheme. - procedure, pass(self) :: stages_number !< Return number of stages used. - procedure, pass(self) :: steps_number !< Return number of steps used. procedure, pass(self) :: supported_schemes !< Return the list of supported schemes. ! public methods - procedure, pass(self) :: destroy !< Destroy the integrator. - procedure, pass(self) :: initialize !< Initialize (create) the integrator. - procedure, pass(self) :: integrate !< Integrate integrand field. - procedure, pass(self) :: integrate_fast !< Integrate integrand field, fast mode. - procedure, pass(self) :: update_previous !< Cyclic update previous time steps. + procedure, pass(self) :: destroy !< Destroy the integrator. + procedure, pass(self) :: initialize !< Initialize (create) the integrator. endtype integrator_lmm_ssp contains @@ -124,21 +117,54 @@ pure subroutine integr_assign_integr(lhs, rhs) endselect endsubroutine integr_assign_integr - elemental function is_multistage(self) - !< Return .true. for multistage integrator. - class(integrator_lmm_ssp), intent(in) :: self !< Integrator. - logical :: is_multistage !< Inquire result. + subroutine integrate(self, U, previous, Dt, t, autoupdate) + !< Integrate field with LMM-SSP class scheme. + class(integrator_lmm_ssp), intent(in) :: self !< Integrator. + class(integrand_object), intent(inout) :: U !< Field to be integrated. + class(integrand_object), intent(inout) :: previous(1:) !< Previous time steps solutions of integrand field. + real(R_P), intent(in) :: Dt !< Time steps. + real(R_P), intent(in) :: t(:) !< Times. + logical, optional, intent(in) :: autoupdate !< Perform cyclic autoupdate of previous time steps. + logical :: autoupdate_ !< Perform cyclic autoupdate of previous time steps, dummy var. + integer(I_P) :: s !< Steps counter. - is_multistage = is_multistage_ - endfunction is_multistage + autoupdate_ = .true. ; if (present(autoupdate)) autoupdate_ = autoupdate + U = U * 0._R_P + do s=1, self%steps + if (self%a(s) /= 0._R_P) U = U + (previous(s) * self%a(s)) + if (self%b(s) /= 0._R_P) U = U + (previous(s)%t(t=t(s)) * (Dt * self%b(s))) + enddo + if (autoupdate_) call self%update_previous(U=U, previous=previous) + endsubroutine integrate - elemental function is_multistep(self) - !< Return .true. for multistage integrator. - class(integrator_lmm_ssp), intent(in) :: self !< Integrator. - logical :: is_multistep !< Inquire result. + subroutine integrate_fast(self, U, previous, buffer, Dt, t, autoupdate) + !< Integrate field with LMM-SSP class scheme, fast mode. + class(integrator_lmm_ssp), intent(in) :: self !< Integrator. + class(integrand_object), intent(inout) :: U !< Field to be integrated. + class(integrand_object), intent(inout) :: previous(1:) !< Previous time steps solutions of integrand field. + class(integrand_object), intent(inout) :: buffer !< Temporary buffer for doing fast operation. + real(R_P), intent(in) :: Dt !< Time steps. + real(R_P), intent(in) :: t(:) !< Times. + logical, optional, intent(in) :: autoupdate !< Perform cyclic autoupdate of previous time steps. + logical :: autoupdate_ !< Perform cyclic autoupdate of previous time steps, dummy var. + integer(I_P) :: s !< Steps counter. - is_multistep = is_multistep_ - endfunction is_multistep + autoupdate_ = .true. ; if (present(autoupdate)) autoupdate_ = autoupdate + call U%multiply_fast(lhs=U, rhs=0._R_P) + do s=1, self%steps + if (self%a(s) /= 0._R_P) then + call buffer%multiply_fast(lhs=previous(s), rhs=self%a(s)) + call U%add_fast(lhs=U, rhs=buffer) + endif + if (self%b(s) /= 0._R_P) then + buffer = previous(s) + call buffer%t_fast(t=t(s)) + call buffer%multiply_fast(lhs=buffer, rhs=self%b(s)) + call U%add_fast(lhs=U, rhs=buffer) + endif + enddo + if (autoupdate_) call self%update_previous(U=U, previous=previous) + endsubroutine integrate_fast elemental function is_supported(self, scheme) !< Return .true. if the integrator class support the given scheme. @@ -156,22 +182,6 @@ elemental function is_supported(self, scheme) enddo endfunction is_supported - elemental function stages_number(self) - !< Return number of stages used. - class(integrator_lmm_ssp), intent(in) :: self !< Integrator. - integer(I_P) :: stages_number !< Number of stages used. - - stages_number = 0 - endfunction stages_number - - elemental function steps_number(self) - !< Return number of steps used. - class(integrator_lmm_ssp), intent(in) :: self !< Integrator. - integer(I_P) :: steps_number !< Number of steps used. - - steps_number = self%steps - endfunction steps_number - pure function supported_schemes(self) result(schemes) !< Return the list of supported schemes. class(integrator_lmm_ssp), intent(in) :: self !< Integrator. @@ -186,8 +196,7 @@ elemental subroutine destroy(self) !< Destroy the integrator. class(integrator_lmm_ssp), intent(inout) :: self !< Integrator. - call self%destroy_abstract - self%steps = 0 + call self%destroy_multistep if (allocated(self%a)) deallocate(self%a) if (allocated(self%b)) deallocate(self%b) endsubroutine destroy @@ -249,66 +258,4 @@ subroutine initialize(self, scheme) is_severe=.true.) endif endsubroutine initialize - - subroutine integrate(self, U, previous, Dt, t, autoupdate) - !< Integrate field with LMM-SSP class scheme. - class(integrator_lmm_ssp), intent(in) :: self !< Integrator. - class(integrand_object), intent(inout) :: U !< Field to be integrated. - class(integrand_object), intent(inout) :: previous(1:) !< Previous time steps solutions of integrand field. - real(R_P), intent(in) :: Dt !< Time steps. - real(R_P), intent(in) :: t(:) !< Times. - logical, optional, intent(in) :: autoupdate !< Perform cyclic autoupdate of previous time steps. - logical :: autoupdate_ !< Perform cyclic autoupdate of previous time steps, dummy var. - integer(I_P) :: s !< Steps counter. - - autoupdate_ = .true. ; if (present(autoupdate)) autoupdate_ = autoupdate - U = U * 0._R_P - do s=1, self%steps - if (self%a(s) /= 0._R_P) U = U + (previous(s) * self%a(s)) - if (self%b(s) /= 0._R_P) U = U + (previous(s)%t(t=t(s)) * (Dt * self%b(s))) - enddo - if (autoupdate_) call self%update_previous(U=U, previous=previous) - endsubroutine integrate - - subroutine integrate_fast(self, U, previous, buffer, Dt, t, autoupdate) - !< Integrate field with LMM-SSP class scheme, fast mode. - class(integrator_lmm_ssp), intent(in) :: self !< Integrator. - class(integrand_object), intent(inout) :: U !< Field to be integrated. - class(integrand_object), intent(inout) :: previous(1:) !< Previous time steps solutions of integrand field. - class(integrand_object), intent(inout) :: buffer !< Temporary buffer for doing fast operation. - real(R_P), intent(in) :: Dt !< Time steps. - real(R_P), intent(in) :: t(:) !< Times. - logical, optional, intent(in) :: autoupdate !< Perform cyclic autoupdate of previous time steps. - logical :: autoupdate_ !< Perform cyclic autoupdate of previous time steps, dummy var. - integer(I_P) :: s !< Steps counter. - - autoupdate_ = .true. ; if (present(autoupdate)) autoupdate_ = autoupdate - call U%multiply_fast(lhs=U, rhs=0._R_P) - do s=1, self%steps - if (self%a(s) /= 0._R_P) then - call buffer%multiply_fast(lhs=previous(s), rhs=self%a(s)) - call U%add_fast(lhs=U, rhs=buffer) - endif - if (self%b(s) /= 0._R_P) then - buffer = previous(s) - call buffer%t_fast(t=t(s)) - call buffer%multiply_fast(lhs=buffer, rhs=self%b(s)) - call U%add_fast(lhs=U, rhs=buffer) - endif - enddo - if (autoupdate_) call self%update_previous(U=U, previous=previous) - endsubroutine integrate_fast - - subroutine update_previous(self, U, previous) - !< Cyclic update previous time steps. - class(integrator_lmm_ssp), intent(in) :: self !< Integrator. - class(integrand_object), intent(in) :: U !< Field to be integrated. - class(integrand_object), intent(inout) :: previous(1:) !< Previous time steps solutions of integrand field. - integer(I_P) :: s !< Steps counter. - - do s=1, self%steps - 1 - previous(s) = previous(s + 1) - enddo - previous(self%steps) = U - endsubroutine update_previous endmodule foodie_integrator_lmm_ssp diff --git a/src/lib/foodie_integrator_multistage_explicit_object.f90 b/src/lib/foodie_integrator_multistage_explicit_object.f90 new file mode 100644 index 00000000..bd6f88a0 --- /dev/null +++ b/src/lib/foodie_integrator_multistage_explicit_object.f90 @@ -0,0 +1,99 @@ +!< Define the abstract type [[integrator_multistage_explicit_object]] of FOODIE ODE integrators. + +module foodie_integrator_multistage_explicit_object +!< Define the abstract type [[integrator_multistage_explicit_object]] of FOODIE ODE integrators. + +use, intrinsic :: iso_fortran_env, only : stderr=>error_unit +use foodie_integrand_object, only : integrand_object +use foodie_integrator_object, only : integrator_object +use penf, only : I_P, R_P + +implicit none +private +public :: integrator_multistage_explicit_object + +type, extends(integrator_object), abstract :: integrator_multistage_explicit_object + !< Abstract type of FOODIE ODE integrators of the multistage family. + integer(I_P) :: stages=0 !< Number of stages. + contains + ! deferred methods + procedure(integrate_interface), pass(self), deferred :: integrate !< Integrate integrand field. + procedure(integrate_fast_interface), pass(self), deferred :: integrate_fast !< Integrate integrand field, fast mode. + ! implemented deferred methods of parent + procedure, pass(self) :: is_multistage !< Return .true. for multistage integrator. + procedure, pass(self) :: is_multistep !< Return .true. for multistep integrator. + procedure, pass(self) :: stages_number !< Return number of stages used. + procedure, pass(self) :: steps_number !< Return number of steps used. + ! public methods + procedure, pass(self) :: destroy_multistage !< Destroy the integrator. +endtype integrator_multistage_explicit_object + +abstract interface + !< Abstract interfaces of deferred methods of [[integrator_object]]. + subroutine integrate_interface(self, U, stage, Dt, t, new_Dt) + !< Integrate integrand field. + import :: integrand_object, integrator_multistage_explicit_object, R_P + class(integrator_multistage_explicit_object), intent(in) :: self !< Integrator. + class(integrand_object), intent(inout) :: U !< Integrand. + class(integrand_object), intent(inout) :: stage(1:) !< Runge-Kutta stages. + real(R_P), intent(in) :: Dt !< Time step. + real(R_P), intent(in) :: t !< Time. + real(R_P), optional, intent(out) :: new_Dt !< New adapted time step. + endsubroutine integrate_interface + + subroutine integrate_fast_interface(self, U, stage, buffer, Dt, t, new_Dt) + !< Integrate integrand field, fast mode. + import :: integrand_object, integrator_multistage_explicit_object, R_P + class(integrator_multistage_explicit_object), intent(in) :: self !< Integrator. + class(integrand_object), intent(inout) :: U !< Field to be integrated. + class(integrand_object), intent(inout) :: stage(1:) !< Runge-Kutta stages. + class(integrand_object), intent(inout) :: buffer !< Temporary buffer for doing fast operation. + real(R_P), intent(in) :: Dt !< Time step. + real(R_P), intent(in) :: t !< Time. + real(R_P), optional, intent(out) :: new_Dt !< New adapted time step. + endsubroutine integrate_fast_interface +endinterface + +contains + ! deferred methods + elemental function is_multistage(self) + !< Return .true. for multistage integrator. + class(integrator_multistage_explicit_object), intent(in) :: self !< Integrator. + logical :: is_multistage !< Inquire result. + + is_multistage = .true. + endfunction is_multistage + + elemental function is_multistep(self) + !< Return .true. for multistage integrator. + class(integrator_multistage_explicit_object), intent(in) :: self !< Integrator. + logical :: is_multistep !< Inquire result. + + is_multistep = .false. + endfunction is_multistep + + elemental function stages_number(self) + !< Return number of stages used. + class(integrator_multistage_explicit_object), intent(in) :: self !< Integrator. + integer(I_P) :: stages_number !< Number of stages used. + + stages_number = self%stages + endfunction stages_number + + elemental function steps_number(self) + !< Return number of steps used. + class(integrator_multistage_explicit_object), intent(in) :: self !< Integrator. + integer(I_P) :: steps_number !< Number of steps used. + + steps_number = 0 + endfunction steps_number + + ! public methods + elemental subroutine destroy_multistage(self) + !< Destroy the integrator. + class(integrator_multistage_explicit_object), intent(inout) :: self !< Integrator. + + call self%destroy_abstract + self%stages = 0 + endsubroutine destroy_multistage +endmodule foodie_integrator_multistage_explicit_object diff --git a/src/lib/foodie_integrator_multistep_explicit_object.f90 b/src/lib/foodie_integrator_multistep_explicit_object.f90 new file mode 100644 index 00000000..5cb07427 --- /dev/null +++ b/src/lib/foodie_integrator_multistep_explicit_object.f90 @@ -0,0 +1,113 @@ +!< Define the abstract type [[integrator_multistep_explicit_object]] of FOODIE ODE integrators. + +module foodie_integrator_multistep_explicit_object +!< Define the abstract type [[integrator_multistep_explicit_object]] of FOODIE ODE integrators. + +use, intrinsic :: iso_fortran_env, only : stderr=>error_unit +use foodie_integrand_object, only : integrand_object +use foodie_integrator_object, only : integrator_object +use penf, only : I_P, R_P + +implicit none +private +public :: integrator_multistep_explicit_object + +type, extends(integrator_object), abstract :: integrator_multistep_explicit_object + !< Abstract type of FOODIE ODE integrators of the multistep family. + integer(I_P) :: steps=0 !< Number of time steps. + contains + ! deferred methods + procedure(integrate_interface), pass(self), deferred :: integrate !< Integrate integrand field. + procedure(integrate_fast_interface), pass(self), deferred :: integrate_fast !< Integrate integrand field, fast mode. + ! implemented deferred methods of parent + procedure, pass(self) :: is_multistage !< Return .true. for multistage integrator. + procedure, pass(self) :: is_multistep !< Return .true. for multistep integrator. + procedure, pass(self) :: stages_number !< Return number of stages used. + procedure, pass(self) :: steps_number !< Return number of steps used. + ! public methods + procedure, pass(self) :: destroy_multistep !< Destroy the integrator. + procedure, pass(self) :: update_previous !< Cyclic update previous time steps. +endtype integrator_multistep_explicit_object + +abstract interface + !< Abstract interfaces of deferred methods of [[integrator_multistep_explicit_object]]. + subroutine integrate_interface(self, U, previous, Dt, t, autoupdate) + !< Integrate integrand field. + import :: integrand_object, integrator_multistep_explicit_object, R_P + class(integrator_multistep_explicit_object), intent(in) :: self !< Integrator. + class(integrand_object), intent(inout) :: U !< Integrand. + class(integrand_object), intent(inout) :: previous(1:) !< Previous time steps solutions of integrand field. + real(R_P), intent(in) :: Dt !< Time steps. + real(R_P), intent(in) :: t(:) !< Times. + logical, optional, intent(in) :: autoupdate !< Perform cyclic autoupdate of previous time steps. + endsubroutine integrate_interface + + subroutine integrate_fast_interface(self, U, previous, buffer, Dt, t, autoupdate) + !< Integrate integrand field, fast mode. + import :: integrand_object, integrator_multistep_explicit_object, R_P + class(integrator_multistep_explicit_object), intent(in) :: self !< Integrator. + class(integrand_object), intent(inout) :: U !< Field to be integrated. + class(integrand_object), intent(inout) :: previous(1:) !< Previous time steps solutions of integrand field. + class(integrand_object), intent(inout) :: buffer !< Temporary buffer for doing fast operation. + real(R_P), intent(in) :: Dt !< Time steps. + real(R_P), intent(in) :: t(:) !< Times. + logical, optional, intent(in) :: autoupdate !< Perform cyclic autoupdate of previous time steps. + endsubroutine integrate_fast_interface +endinterface + +contains + ! deferred methods + elemental function is_multistage(self) + !< Return .true. for multistage integrator. + class(integrator_multistep_explicit_object), intent(in) :: self !< Integrator. + logical :: is_multistage !< Inquire result. + + is_multistage = .false. + endfunction is_multistage + + elemental function is_multistep(self) + !< Return .true. for multistage integrator. + class(integrator_multistep_explicit_object), intent(in) :: self !< Integrator. + logical :: is_multistep !< Inquire result. + + is_multistep = .true. + endfunction is_multistep + + elemental function stages_number(self) + !< Return number of stages used. + class(integrator_multistep_explicit_object), intent(in) :: self !< Integrator. + integer(I_P) :: stages_number !< Number of stages used. + + stages_number = 0 + endfunction stages_number + + elemental function steps_number(self) + !< Return number of steps used. + class(integrator_multistep_explicit_object), intent(in) :: self !< Integrator. + integer(I_P) :: steps_number !< Number of steps used. + + steps_number = self%steps + endfunction steps_number + + ! public methods + elemental subroutine destroy_multistep(self) + !< Destroy the integrator. + class(integrator_multistep_explicit_object), intent(inout) :: self !< Integrator. + + call self%destroy_abstract + self%steps = 0 + endsubroutine destroy_multistep + + subroutine update_previous(self, U, previous) + !< Cyclic update previous time steps. + class(integrator_multistep_explicit_object), intent(in) :: self !< Integrator. + class(integrand_object), intent(in) :: U !< Field to be integrated. + class(integrand_object), intent(inout) :: previous(1:) !< Previous time steps solutions of integrand field. + integer(I_P) :: s !< Steps counter. + + do s=1, self%steps - 1 + previous(s) = previous(s + 1) + enddo + previous(self%steps) = U + endsubroutine update_previous +endmodule foodie_integrator_multistep_explicit_object diff --git a/src/lib/foodie_integrator_multistep_implicit_object.f90 b/src/lib/foodie_integrator_multistep_implicit_object.f90 new file mode 100644 index 00000000..62951d90 --- /dev/null +++ b/src/lib/foodie_integrator_multistep_implicit_object.f90 @@ -0,0 +1,127 @@ +!< Define the abstract type [[integrator_multistep_implicit_object]] of FOODIE ODE integrators. + +module foodie_integrator_multistep_implicit_object +!< Define the abstract type [[integrator_multistep_implicit_object]] of FOODIE ODE integrators. + +use, intrinsic :: iso_fortran_env, only : stderr=>error_unit +use foodie_integrand_object, only : integrand_object +use foodie_integrator_object, only : integrator_object +use penf, only : I_P, R_P + +implicit none +private +public :: integrator_multistep_implicit_object + +type, extends(integrator_object), abstract :: integrator_multistep_implicit_object + !< Abstract type of FOODIE ODE integrators of the multistep-implicit family. + integer(I_P) :: steps=-1 !< Number of time steps. + contains + ! deferred methods + procedure(integrate_interface), pass(self), deferred :: integrate !< Integrate integrand field. + procedure(integrate_fast_interface), pass(self), deferred :: integrate_fast !< Integrate integrand field, fast mode. + ! implemented deferred methods of parent + procedure, pass(self) :: is_multistage !< Return .true. for multistage integrator. + procedure, pass(self) :: is_multistep !< Return .true. for multistep integrator. + procedure, pass(self) :: stages_number !< Return number of stages used. + procedure, pass(self) :: steps_number !< Return number of steps used. + ! public methods + procedure, pass(self) :: destroy_multistep !< Destroy the integrator. + procedure, pass(self) :: update_previous !< Cyclic update previous time steps. +endtype integrator_multistep_implicit_object + +abstract interface + !< Abstract interfaces of deferred methods of [[integrator_multistep_implicit_object]]. + subroutine integrate_interface(self, U, previous, Dt, t, iterations, autoupdate) + !< Integrate integrand field. + import :: integrand_object, integrator_multistep_implicit_object, I_P, R_P + class(integrator_multistep_implicit_object), intent(in) :: self !< Integrator. + class(integrand_object), intent(inout) :: U !< Integrand. + class(integrand_object), intent(inout) :: previous(1:) !< Previous time steps solutions of integrand field. + real(R_P), intent(in) :: Dt !< Time steps. + real(R_P), intent(in) :: t(:) !< Times. + integer(I_P), optional, intent(in) :: iterations !< Fixed point iterations. + logical, optional, intent(in) :: autoupdate !< Perform cyclic autoupdate of previous time steps. + endsubroutine integrate_interface + + subroutine integrate_fast_interface(self, U, previous, buffer, Dt, t, iterations, autoupdate) + !< Integrate integrand field, fast mode. + import :: integrand_object, integrator_multistep_implicit_object, I_P, R_P + class(integrator_multistep_implicit_object), intent(in) :: self !< Integrator. + class(integrand_object), intent(inout) :: U !< Field to be integrated. + class(integrand_object), intent(inout) :: previous(1:) !< Previous time steps solutions of integrand field. + class(integrand_object), intent(inout) :: buffer !< Temporary buffer for doing fast operation. + real(R_P), intent(in) :: Dt !< Time steps. + real(R_P), intent(in) :: t(:) !< Times. + integer(I_P), optional, intent(in) :: iterations !< Fixed point iterations. + logical, optional, intent(in) :: autoupdate !< Perform cyclic autoupdate of previous time steps. + endsubroutine integrate_fast_interface +endinterface + +contains + ! deferred methods + elemental function is_multistage(self) + !< Return .true. for multistage integrator. + class(integrator_multistep_implicit_object), intent(in) :: self !< Integrator. + logical :: is_multistage !< Inquire result. + + is_multistage = .false. + endfunction is_multistage + + elemental function is_multistep(self) + !< Return .true. for multistage integrator. + class(integrator_multistep_implicit_object), intent(in) :: self !< Integrator. + logical :: is_multistep !< Inquire result. + + is_multistep = .true. + endfunction is_multistep + + elemental function stages_number(self) + !< Return number of stages used. + class(integrator_multistep_implicit_object), intent(in) :: self !< Integrator. + integer(I_P) :: stages_number !< Number of stages used. + + stages_number = 0 + endfunction stages_number + + elemental function steps_number(self) + !< Return number of steps used. + class(integrator_multistep_implicit_object), intent(in) :: self !< Integrator. + integer(I_P) :: steps_number !< Number of steps used. + + steps_number = self%steps + endfunction steps_number + + ! public methods + elemental subroutine destroy_multistep(self) + !< Destroy the integrator. + class(integrator_multistep_implicit_object), intent(inout) :: self !< Integrator. + + call self%destroy_abstract + self%steps = -1 + endsubroutine destroy_multistep + + subroutine update_previous(self, U, previous, is_like_explicit) + !< Cyclic update previous time steps. + class(integrator_multistep_implicit_object), intent(in) :: self !< Integrator. + class(integrand_object), intent(in) :: U !< Field to be integrated. + class(integrand_object), intent(inout) :: previous(1:) !< Previous time steps solutions of integrand. + logical, optional, intent(in) :: is_like_explicit !< Use explicit-like update. + logical :: is_like_explicit_ !< Use explicit-like update, local variable. + integer(I_P) :: s !< Steps counter. + + is_like_explicit_ = .false. ; if (present(is_like_explicit)) is_like_explicit_ = is_like_explicit + if (is_like_explicit_) then + do s=1, self%steps - 1 + previous(s) = previous(s + 1) + enddo + previous(self%steps) = U + else + if (self%steps > 0) then + do s=0, self%steps - 2 + previous(s + 1) = previous(s + 2) + enddo + previous(self%steps) = U + endif + endif + endsubroutine update_previous +endmodule foodie_integrator_multistep_implicit_object diff --git a/src/lib/foodie_integrator_runge_kutta_embedded.f90 b/src/lib/foodie_integrator_runge_kutta_embedded.f90 index 46a00e61..85bcf49c 100644 --- a/src/lib/foodie_integrator_runge_kutta_embedded.f90 +++ b/src/lib/foodie_integrator_runge_kutta_embedded.f90 @@ -268,6 +268,7 @@ module foodie_integrator_runge_kutta_emd use foodie_error_codes, only : ERROR_UNSUPPORTED_SCHEME use foodie_integrand_object, only : integrand_object +use foodie_integrator_multistage_explicit_object, only : integrator_multistage_explicit_object use foodie_integrator_object, only : integrator_object use penf, only : I_P, R_P @@ -285,14 +286,13 @@ module foodie_integrator_runge_kutta_emd logical, parameter :: is_multistage_=.true. !< Flag to check if integrator is multistage. logical, parameter :: is_multistep_=.false. !< Flag to check if integrator is multistep. -type, extends(integrator_object) :: integrator_runge_kutta_emd +type, extends(integrator_multistage_explicit_object) :: integrator_runge_kutta_emd !< FOODIE integrator: provide an explicit class of embedded Runge-Kutta schemes, from 2nd to 10th order accurate. !< !< @note The integrator must be created or initialized (initialize the RK coefficients) before used. private real(R_P) :: tolerance=0._R_P !< Tolerance on the local truncation error. real(R_P) :: pp1_inv=0._R_P !< \(1/(p+1)\) where p is the accuracy order of the lower accurate scheme of the pair. - integer(I_P) :: stages=0 !< Number of stages. real(R_P), allocatable :: alph(:,:) !< \(\alpha\) Butcher's coefficients. real(R_P), allocatable :: beta(:,:) !< \(\beta\) Butcher's coefficients. real(R_P), allocatable :: gamm(:) !< \(\gamma\) Butcher's coefficients. @@ -302,17 +302,13 @@ module foodie_integrator_runge_kutta_emd procedure, pass(self) :: description !< Return pretty-printed object description. procedure, pass(self) :: has_fast_mode !< Return .true. if the integrator class has *fast mode* integrate. procedure, pass(lhs) :: integr_assign_integr !< Operator `=`. - procedure, pass(self) :: is_multistage !< Return .true. for multistage integrator. - procedure, pass(self) :: is_multistep !< Return .true. for multistep integrator. + procedure, pass(self) :: integrate !< Integrate integrand field. + procedure, pass(self) :: integrate_fast !< Integrate integrand field, fast mode. procedure, pass(self) :: is_supported !< Return .true. if the integrator class support the given scheme. - procedure, pass(self) :: stages_number !< Return number of stages used. - procedure, pass(self) :: steps_number !< Return number of steps used. procedure, pass(self) :: supported_schemes !< Return the list of supported schemes. ! public methods - procedure, pass(self) :: destroy !< Destroy the integrator. - procedure, pass(self) :: initialize !< Initialize (create) the integrator. - procedure, pass(self) :: integrate !< Integrate integrand field. - procedure, pass(self) :: integrate_fast !< Integrate integrand field, fast mode. + procedure, pass(self) :: destroy !< Destroy the integrator. + procedure, pass(self) :: initialize !< Initialize (create) the integrator. ! private methods procedure, pass(self), private :: new_Dt !< Compute new estimation of the time step Dt. endtype integrator_runge_kutta_emd @@ -370,21 +366,97 @@ pure subroutine integr_assign_integr(lhs, rhs) endselect endsubroutine integr_assign_integr - elemental function is_multistage(self) - !< Return .true. for multistage integrator. - class(integrator_runge_kutta_emd), intent(in) :: self !< Integrator. - logical :: is_multistage !< Inquire result. + subroutine integrate(self, U, stage, Dt, t, new_Dt) + !< Integrate field with explicit embedded Runge-Kutta scheme. + !< + !< The time steps is adaptively resized using the local truncation error estimation by means of the embedded pairs of RK schemes. + class(integrator_runge_kutta_emd), intent(in) :: self !< Integrator. + class(integrand_object), intent(inout) :: U !< Field to be integrated. + class(integrand_object), intent(inout) :: stage(1:) !< Runge-Kutta stages [1:stages]. + real(R_P), intent(in) :: Dt !< Time step. + real(R_P), intent(in) :: t !< Time. + real(R_P), optional, intent(out) :: new_Dt !< New adapted time step. + real(R_P) :: Dt_ !< Time step, local variable. + class(integrand_object), allocatable :: U1 !< First U evaluation. + class(integrand_object), allocatable :: U2 !< Second U evaluation. + real(R_P) :: error !< Local truncation error estimation. + integer(I_P) :: s !< First stages counter. + integer(I_P) :: ss !< Second stages counter. - is_multistage = is_multistage_ - endfunction is_multistage + Dt_ = Dt + allocate(U1, mold=U) ; U1 = U + allocate(U2, mold=U) ; U2 = U + do + ! compute stages + do s=1, self%stages + stage(s) = U + do ss=1, s - 1 + stage(s) = stage(s) + (stage(ss) * (Dt_ * self%alph(s, ss))) + enddo + stage(s) = stage(s)%t(t=t + self%gamm(s) * Dt_) + enddo + ! compute new time step + U1 = U + U2 = U + do s=1, self%stages + U1 = U1 + (stage(s) * (Dt_ * self%beta(s, 1))) + U2 = U2 + (stage(s) * (Dt_ * self%beta(s, 2))) + enddo + error = U2.lterror.U1 + if (error <= self%tolerance) exit + call self%new_Dt(error=error, Dt=Dt_) + enddo + U = U1 + if (present(new_Dt)) new_Dt = Dt_ + endsubroutine integrate - elemental function is_multistep(self) - !< Return .true. for multistage integrator. - class(integrator_runge_kutta_emd), intent(in) :: self !< Integrator. - logical :: is_multistep !< Inquire result. + subroutine integrate_fast(self, U, stage, buffer, Dt, t, new_Dt) + !< Integrate field with explicit embedded Runge-Kutta scheme, fast mode. + !< + !< The time steps is adaptively resized using the local truncation error estimation by means of the embedded pairs of RK schemes. + class(integrator_runge_kutta_emd), intent(in) :: self !< Integrator. + class(integrand_object), intent(inout) :: U !< Field to be integrated. + class(integrand_object), intent(inout) :: stage(1:) !< Runge-Kutta stages [1:stages]. + class(integrand_object), intent(inout) :: buffer !< Temporary buffer for doing fast operation. + real(R_P), intent(in) :: Dt !< Time step. + real(R_P), intent(in) :: t !< Time. + real(R_P), optional, intent(out) :: new_Dt !< New adapted time step. + real(R_P) :: Dt_ !< Time step, local variable. + class(integrand_object), allocatable :: U1 !< First U evaluation. + class(integrand_object), allocatable :: U2 !< Second U evaluation. + real(R_P) :: error !< Local truncation error estimation. + integer(I_P) :: s !< First stages counter. + integer(I_P) :: ss !< Second stages counter. - is_multistep = is_multistep_ - endfunction is_multistep + Dt_ = Dt + allocate(U1, mold=U) ; U1 = U + allocate(U2, mold=U) ; U2 = U + do + ! compute stages + do s=1, self%stages + stage(s) = U + do ss=1, s - 1 + call buffer%multiply_fast(lhs=stage(ss), rhs=Dt_ * self%alph(s, ss)) + call stage(s)%add_fast(lhs=stage(s), rhs=buffer) + enddo + call stage(s)%t_fast(t=t + self%gamm(s) * Dt_) + enddo + ! compute new time step + U1 = U + U2 = U + do s=1, self%stages + call buffer%multiply_fast(lhs=stage(s), rhs=Dt_ * self%beta(s, 1)) + call U1%add_fast(lhs=U1, rhs=buffer) + call buffer%multiply_fast(lhs=stage(s), rhs=Dt_ * self%beta(s, 2)) + call U2%add_fast(lhs=U2, rhs=buffer) + enddo + error = U2.lterror.U1 + if (error <= self%tolerance) exit + call self%new_Dt(error=error, Dt=Dt_) + enddo + U = U1 + if (present(new_Dt)) new_Dt = Dt_ + endsubroutine integrate_fast elemental function is_supported(self, scheme) !< Return .true. if the integrator class support the given scheme. @@ -402,22 +474,6 @@ elemental function is_supported(self, scheme) enddo endfunction is_supported - elemental function stages_number(self) - !< Return number of stages used. - class(integrator_runge_kutta_emd), intent(in) :: self !< Integrator. - integer(I_P) :: stages_number !< Number of stages used. - - stages_number = self%stages - endfunction stages_number - - elemental function steps_number(self) - !< Return number of steps used. - class(integrator_runge_kutta_emd), intent(in) :: self !< Integrator. - integer(I_P) :: steps_number !< Number of steps used. - - steps_number = 0 - endfunction steps_number - pure function supported_schemes(self) result(schemes) !< Return the list of supported schemes. class(integrator_runge_kutta_emd), intent(in) :: self !< Integrator. @@ -432,10 +488,9 @@ elemental subroutine destroy(self) !< Destroy the integrator. class(integrator_runge_kutta_emd), intent(inout) :: self !< Integrator. - call self%destroy_abstract + call self%destroy_multistage self%tolerance = 0._R_P self%pp1_inv = 0._R_P - self%stages = 0 if (allocated(self%alph)) deallocate(self%alph) if (allocated(self%beta)) deallocate(self%beta) if (allocated(self%gamm)) deallocate(self%gamm) @@ -712,90 +767,6 @@ subroutine initialize(self, scheme, tolerance, stop_on_fail) endif endsubroutine initialize - subroutine integrate(self, U, stage, Dt, t) - !< Integrate field with explicit embedded Runge-Kutta scheme. - !< - !< The time steps is adaptively resized using the local truncation error estimation by means of the embedded pairs of RK schemes. - class(integrator_runge_kutta_emd), intent(in) :: self !< Integrator. - class(integrand_object), intent(inout) :: U !< Field to be integrated. - class(integrand_object), intent(inout) :: stage(1:) !< Runge-Kutta stages [1:stages]. - real(R_P), intent(inout) :: Dt !< Time step. - real(R_P), intent(in) :: t !< Time. - class(integrand_object), allocatable :: U1 !< First U evaluation. - class(integrand_object), allocatable :: U2 !< Second U evaluation. - real(R_P) :: error !< Local truncation error estimation. - integer(I_P) :: s !< First stages counter. - integer(I_P) :: ss !< Second stages counter. - - allocate(U1, mold=U) ; U1 = U - allocate(U2, mold=U) ; U2 = U - error = 1e6 - do while(error>self%tolerance) - ! compute stages - do s=1, self%stages - stage(s) = U - do ss=1, s - 1 - stage(s) = stage(s) + (stage(ss) * (Dt * self%alph(s, ss))) - enddo - stage(s) = stage(s)%t(t=t + self%gamm(s) * Dt) - enddo - ! compute new time step - U1 = U - U2 = U - do s=1, self%stages - U1 = U1 + (stage(s) * (Dt * self%beta(s, 1))) - U2 = U2 + (stage(s) * (Dt * self%beta(s, 2))) - enddo - error = U2.lterror.U1 - call self%new_Dt(error=error, Dt=Dt) - enddo - U = U1 - endsubroutine integrate - - subroutine integrate_fast(self, U, stage, buffer, Dt, t) - !< Integrate field with explicit embedded Runge-Kutta scheme, fast mode. - !< - !< The time steps is adaptively resized using the local truncation error estimation by means of the embedded pairs of RK schemes. - class(integrator_runge_kutta_emd), intent(in) :: self !< Integrator. - class(integrand_object), intent(inout) :: U !< Field to be integrated. - class(integrand_object), intent(inout) :: stage(1:) !< Runge-Kutta stages [1:stages]. - class(integrand_object), intent(inout) :: buffer !< Temporary buffer for doing fast operation. - real(R_P), intent(inout) :: Dt !< Time step. - real(R_P), intent(in) :: t !< Time. - class(integrand_object), allocatable :: U1 !< First U evaluation. - class(integrand_object), allocatable :: U2 !< Second U evaluation. - real(R_P) :: error !< Local truncation error estimation. - integer(I_P) :: s !< First stages counter. - integer(I_P) :: ss !< Second stages counter. - - allocate(U1, mold=U) ; U1 = U - allocate(U2, mold=U) ; U2 = U - error = 1e6 - do while(error>self%tolerance) - ! compute stages - do s=1, self%stages - stage(s) = U - do ss=1, s - 1 - call buffer%multiply_fast(lhs=stage(ss), rhs=Dt * self%alph(s, ss)) - call stage(s)%add_fast(lhs=stage(s), rhs=buffer) - enddo - call stage(s)%t_fast(t=t + self%gamm(s) * Dt) - enddo - ! compute new time step - U1 = U - U2 = U - do s=1, self%stages - call buffer%multiply_fast(lhs=stage(s), rhs=Dt * self%beta(s, 1)) - call U1%add_fast(lhs=U1, rhs=buffer) - call buffer%multiply_fast(lhs=stage(s), rhs=Dt * self%beta(s, 2)) - call U2%add_fast(lhs=U2, rhs=buffer) - enddo - error = U2.lterror.U1 - call self%new_Dt(error=error, Dt=Dt) - enddo - U = U1 - endsubroutine integrate_fast - ! private methods elemental subroutine new_Dt(self, error, Dt) !< Compute new estimation of the time step Dt. diff --git a/src/lib/foodie_integrator_runge_kutta_low_storage.f90 b/src/lib/foodie_integrator_runge_kutta_low_storage.f90 index e99c7481..9d4d49eb 100644 --- a/src/lib/foodie_integrator_runge_kutta_low_storage.f90 +++ b/src/lib/foodie_integrator_runge_kutta_low_storage.f90 @@ -149,8 +149,8 @@ module foodie_integrator_runge_kutta_low_storage use foodie_error_codes, only : ERROR_UNSUPPORTED_SCHEME use foodie_integrand_object, only : integrand_object +use foodie_integrator_multistage_explicit_object, only : integrator_multistage_explicit_object use foodie_integrator_object, only : integrator_object -use foodie_integrator_runge_kutta_object, only : integrator_runge_kutta_object use penf, only : I_P, I8P, R_P implicit none @@ -170,30 +170,27 @@ module foodie_integrator_runge_kutta_low_storage logical, parameter :: has_fast_mode_=.true. !< Flag to check if integrator provides *fast mode* integrate. -type, extends(integrator_runge_kutta_object) :: integrator_runge_kutta_ls +type, extends(integrator_multistage_explicit_object) :: integrator_runge_kutta_ls !< FOODIE integrator: provide an explicit class of low storage Runge-Kutta schemes, from 1st to 4th order accurate. !< !< @note The integrator must be created or initialized (initialize the RK coefficients) before used. private - integer(I_P) :: stages=0 !< Number of stages. - real(R_P), allocatable :: A(:) !< Low storage *A* coefficients. - real(R_P), allocatable :: B(:) !< Low storage *B* coefficients. - real(R_P), allocatable :: C(:) !< Low storage *C* coefficients. + real(R_P), allocatable :: A(:) !< Low storage *A* coefficients. + real(R_P), allocatable :: B(:) !< Low storage *B* coefficients. + real(R_P), allocatable :: C(:) !< Low storage *C* coefficients. contains ! deferred methods procedure, pass(self) :: class_name !< Return the class name of schemes. procedure, pass(self) :: description !< Return pretty-printed object description. procedure, pass(self) :: has_fast_mode !< Return .true. if the integrator class has *fast mode* integrate. procedure, pass(lhs) :: integr_assign_integr !< Operator `=`. + procedure, pass(self) :: integrate !< Integrate integrand field. + procedure, pass(self) :: integrate_fast !< Integrate integrand field, fast mode. procedure, pass(self) :: is_supported !< Return .true. if the integrator class support the given scheme. - procedure, pass(self) :: stages_number !< Return number of stages used. - procedure, pass(self) :: steps_number !< Return number of steps used. procedure, pass(self) :: supported_schemes !< Return the list of supported schemes. ! public methods procedure, pass(self) :: destroy !< Destroy the integrator. procedure, pass(self) :: initialize !< Initialize (create) the integrator. - procedure, pass(self) :: integrate !< Integrate integrand field. - procedure, pass(self) :: integrate_fast !< Integrate integrand field, fast mode. procedure, nopass :: registers_number !< Return the number of registers used. endtype integrator_runge_kutta_ls @@ -249,6 +246,54 @@ pure subroutine integr_assign_integr(lhs, rhs) endselect endsubroutine integr_assign_integr + subroutine integrate(self, U, stage, Dt, t, new_Dt) + !< Integrate field with explicit low storage Runge-Kutta scheme. + class(integrator_runge_kutta_ls), intent(in) :: self !< Integrator. + class(integrand_object), intent(inout) :: U !< Field to be integrated. + class(integrand_object), intent(inout) :: stage(1:) !< Runge-Kutta registers. + real(R_P), intent(in) :: Dt !< Time step. + real(R_P), intent(in) :: t !< Time. + real(R_P), optional, intent(out) :: new_Dt !< New adapted time step. + integer(I_P) :: s !< First stages counter. + + ! computing stages + stage(1) = U + stage(2) = U * 0._R_P + do s=1, self%stages + stage(2) = (stage(2) * self%A(s)) + (stage(1)%t(t=t + self%C(s) * Dt) * Dt) + stage(1) = stage(1) + (stage(2) * self%B(s)) + enddo + U = stage(1) + if (present(new_Dt)) new_Dt = Dt + endsubroutine integrate + + subroutine integrate_fast(self, U, stage, buffer, Dt, t, new_Dt) + !< Integrate field with explicit low storage Runge-Kutta scheme, fast mode. + class(integrator_runge_kutta_ls), intent(in) :: self !< Integrator. + class(integrand_object), intent(inout) :: U !< Field to be integrated. + class(integrand_object), intent(inout) :: stage(1:) !< Runge-Kutta registers. + class(integrand_object), intent(inout) :: buffer !< Temporary buffer for doing fast operation. + real(R_P), intent(in) :: Dt !< Time step. + real(R_P), intent(in) :: t !< Time. + real(R_P), optional, intent(out) :: new_Dt !< New adapted time step. + integer(I_P) :: s !< First stages counter. + + ! computing stages + stage(1) = U + call stage(2)%multiply_fast(lhs=U, rhs=0._R_P) + do s=1, self%stages + buffer = stage(1) + call buffer%t_fast(t=t + self%C(s) * Dt) + call buffer%multiply_fast(lhs=buffer, rhs=Dt) + call stage(2)%multiply_fast(lhs=stage(2), rhs=self%A(s)) + call stage(2)%add_fast(lhs=stage(2), rhs=buffer) + call buffer%multiply_fast(lhs=stage(2), rhs=self%B(s)) + call stage(1)%add_fast(lhs=stage(1), rhs=buffer) + enddo + U = stage(1) + if (present(new_Dt)) new_Dt = Dt + endsubroutine integrate_fast + elemental function is_supported(self, scheme) !< Return .true. if the integrator class support the given scheme. class(integrator_runge_kutta_ls), intent(in) :: self !< Integrator. @@ -265,22 +310,6 @@ elemental function is_supported(self, scheme) enddo endfunction is_supported - elemental function stages_number(self) - !< Return number of stages used. - class(integrator_runge_kutta_ls), intent(in) :: self !< Integrator. - integer(I_P) :: stages_number !< Number of stages used. - - stages_number = self%stages - endfunction stages_number - - elemental function steps_number(self) - !< Return number of steps used. - class(integrator_runge_kutta_ls), intent(in) :: self !< Integrator. - integer(I_P) :: steps_number !< Number of steps used. - - steps_number = 0 - endfunction steps_number - pure function supported_schemes(self) result(schemes) !< Return the list of supported schemes. class(integrator_runge_kutta_ls), intent(in) :: self !< Integrator. @@ -295,8 +324,7 @@ elemental subroutine destroy(self) !< Destroy the integrator. class(integrator_runge_kutta_ls), intent(inout) :: self !< Integrator. - call self%destroy_abstract - self%stages = 0 + call self%destroy_multistage if (allocated(self%A)) deallocate(self%A) if (allocated(self%B)) deallocate(self%B) if (allocated(self%C)) deallocate(self%C) @@ -431,50 +459,6 @@ subroutine initialize(self, scheme, stop_on_fail) endif endsubroutine initialize - subroutine integrate(self, U, stage, Dt, t) - !< Integrate field with explicit low storage Runge-Kutta scheme. - class(integrator_runge_kutta_ls), intent(in) :: self !< Integrator. - class(integrand_object), intent(inout) :: U !< Field to be integrated. - class(integrand_object), intent(inout) :: stage(1:) !< Runge-Kutta registers. - real(R_P), intent(in) :: Dt !< Time step. - real(R_P), intent(in) :: t !< Time. - integer(I_P) :: s !< First stages counter. - - ! computing stages - stage(1) = U - stage(2) = U * 0._R_P - do s=1, self%stages - stage(2) = (stage(2) * self%A(s)) + (stage(1)%t(t=t + self%C(s) * Dt) * Dt) - stage(1) = stage(1) + (stage(2) * self%B(s)) - enddo - U = stage(1) - endsubroutine integrate - - subroutine integrate_fast(self, U, stage, buffer, Dt, t) - !< Integrate field with explicit low storage Runge-Kutta scheme, fast mode. - class(integrator_runge_kutta_ls), intent(in) :: self !< Integrator. - class(integrand_object), intent(inout) :: U !< Field to be integrated. - class(integrand_object), intent(inout) :: stage(1:) !< Runge-Kutta registers. - class(integrand_object), intent(inout) :: buffer !< Temporary buffer for doing fast operation. - real(R_P), intent(in) :: Dt !< Time step. - real(R_P), intent(in) :: t !< Time. - integer(I_P) :: s !< First stages counter. - - ! computing stages - stage(1) = U - call stage(2)%multiply_fast(lhs=U, rhs=0._R_P) - do s=1, self%stages - buffer = stage(1) - call buffer%t_fast(t=t + self%C(s) * Dt) - call buffer%multiply_fast(lhs=buffer, rhs=Dt) - call stage(2)%multiply_fast(lhs=stage(2), rhs=self%A(s)) - call stage(2)%add_fast(lhs=stage(2), rhs=buffer) - call buffer%multiply_fast(lhs=stage(2), rhs=self%B(s)) - call stage(1)%add_fast(lhs=stage(1), rhs=buffer) - enddo - U = stage(1) - endsubroutine integrate_fast - pure function registers_number() !< Return the number of registers used. integer(I_P) :: registers_number !< Number of registers used. diff --git a/src/lib/foodie_integrator_runge_kutta_lssp.f90 b/src/lib/foodie_integrator_runge_kutta_lssp.f90 index 55334383..390fbb37 100644 --- a/src/lib/foodie_integrator_runge_kutta_lssp.f90 +++ b/src/lib/foodie_integrator_runge_kutta_lssp.f90 @@ -64,8 +64,8 @@ module foodie_integrator_runge_kutta_lssp use foodie_error_codes, only : ERROR_UNSUPPORTED_SCHEME use foodie_integrand_object, only : integrand_object +use foodie_integrator_multistage_explicit_object, only : integrator_multistage_explicit_object use foodie_integrator_object, only : integrator_object -use foodie_integrator_runge_kutta_object, only : integrator_runge_kutta_object use penf, only : I_P, R_P implicit none @@ -78,12 +78,11 @@ module foodie_integrator_runge_kutta_lssp logical, parameter :: has_fast_mode_=.true. !< Flag to check if integrator provides *fast mode* integrate. -type, extends(integrator_runge_kutta_object) :: integrator_runge_kutta_lssp +type, extends(integrator_multistage_explicit_object) :: integrator_runge_kutta_lssp !< FOODIE integrator: provide an explicit class of Linear SSP Runge-Kutta schemes, from 1st to s-th order accurate. !< !< @note The integrator must be created or initialized (initialize the RK coefficients) before used. private - integer(I_P) :: stages=0 !< Number of stages. real(R_P), allocatable :: alpha(:) !< \(\alpha\) coefficients. procedure(integrate_interface), pointer :: integrate_ => integrate_order_s_1 !< Integrate integrand field. procedure(integrate_fast_interface), pointer :: integrate_fast_ => integrate_order_s_1_fast !< Integrate integrand field, fast. @@ -93,15 +92,13 @@ module foodie_integrator_runge_kutta_lssp procedure, pass(self) :: description !< Return pretty-printed object description. procedure, pass(self) :: has_fast_mode !< Return .true. if the integrator class has *fast mode* integrate. procedure, pass(lhs) :: integr_assign_integr !< Operator `=`. + procedure, pass(self) :: integrate !< Integrate integrand field. + procedure, pass(self) :: integrate_fast !< Integrate integrand field, fast mode. procedure, pass(self) :: is_supported !< Return .true. if the integrator class support the given scheme. - procedure, pass(self) :: stages_number !< Return number of stages used. - procedure, pass(self) :: steps_number !< Return number of steps used. procedure, pass(self) :: supported_schemes !< Return the list of supported schemes. ! public methods procedure, pass(self) :: destroy !< Destroy the integrator. procedure, pass(self) :: initialize !< Initialize (create) the integrator. - procedure, pass(self) :: integrate !< Integrate integrand field. - procedure, pass(self) :: integrate_fast !< Integrate integrand field, fast mode. ! private methods procedure, pass(self), private :: initialize_order_s_1 !< Integrate integrator for (s-1)-th order formula. procedure, pass(self), private :: initialize_order_s !< Integrate integrator for s-th order formula. @@ -183,6 +180,35 @@ pure subroutine integr_assign_integr(lhs, rhs) endselect endsubroutine integr_assign_integr + subroutine integrate(self, U, stage, Dt, t, new_Dt) + !< Integrate integrand field by Linear SSP Runge-Kutta methods. + !< + !< @note This method can be used **after** the integrator is created (i.e. the RK coefficients are initialized). + class(integrator_runge_kutta_lssp), intent(in) :: self !< Integrator. + class(integrand_object), intent(inout) :: U !< Field to be integrated. + class(integrand_object), intent(inout) :: stage(1:) !< Runge-Kutta stages [1:stages]. + real(R_P), intent(in) :: Dt !< Time step. + real(R_P), intent(in) :: t !< Time. + real(R_P), optional, intent(out) :: new_Dt !< New adapted time step. + + call self%integrate_(U=U, stage=stage, Dt=Dt, t=t) + if (present(new_Dt)) new_Dt = Dt + endsubroutine integrate + + subroutine integrate_fast(self, U, stage, buffer, Dt, t, new_Dt) + !< Integrate integrand field by Linear SSP Runge-Kutta methods. + class(integrator_runge_kutta_lssp), intent(in) :: self !< Integrator. + class(integrand_object), intent(inout) :: U !< Field to be integrated. + class(integrand_object), intent(inout) :: stage(1:) !< Runge-Kutta stages [1:stages]. + class(integrand_object), intent(inout) :: buffer !< Temporary buffer for doing fast operation. + real(R_P), intent(in) :: Dt !< Time step. + real(R_P), intent(in) :: t !< Time. + real(R_P), optional, intent(out) :: new_Dt !< New adapted time step. + + call self%integrate_fast_(U=U, stage=stage, buffer=buffer, Dt=Dt, t=t) + if (present(new_Dt)) new_Dt = Dt + endsubroutine integrate_fast + elemental function is_supported(self, scheme) !< Return .true. if the integrator class support the given scheme. class(integrator_runge_kutta_lssp), intent(in) :: self !< Integrator. @@ -199,22 +225,6 @@ elemental function is_supported(self, scheme) enddo endfunction is_supported - elemental function stages_number(self) - !< Return number of stages used. - class(integrator_runge_kutta_lssp), intent(in) :: self !< Integrator. - integer(I_P) :: stages_number !< Number of stages used. - - stages_number = self%stages - endfunction stages_number - - elemental function steps_number(self) - !< Return number of steps used. - class(integrator_runge_kutta_lssp), intent(in) :: self !< Integrator. - integer(I_P) :: steps_number !< Number of steps used. - - steps_number = 0 - endfunction steps_number - pure function supported_schemes(self) result(schemes) !< Return the list of supported schemes. class(integrator_runge_kutta_lssp), intent(in) :: self !< Integrator. @@ -229,8 +239,7 @@ elemental subroutine destroy(self) !< Destroy the integrator. class(integrator_runge_kutta_lssp), intent(inout) :: self !< Integrator. - call self%destroy_abstract - self%stages = 0 + call self%destroy_multistage if (allocated(self%alpha)) deallocate(self%alpha) self%integrate_ => integrate_order_s_1 endsubroutine destroy @@ -271,31 +280,6 @@ subroutine initialize(self, scheme, stages, stop_on_fail) endif endsubroutine initialize - subroutine integrate(self, U, stage, Dt, t) - !< Integrate integrand field by Linear SSP Runge-Kutta methods. - !< - !< @note This method can be used **after** the integrator is created (i.e. the RK coefficients are initialized). - class(integrator_runge_kutta_lssp), intent(in) :: self !< Integrator. - class(integrand_object), intent(inout) :: U !< Field to be integrated. - class(integrand_object), intent(inout) :: stage(1:) !< Runge-Kutta stages [1:stages]. - real(R_P), intent(in) :: Dt !< Time step. - real(R_P), intent(in) :: t !< Time. - - call self%integrate_(U=U, stage=stage, Dt=Dt, t=t) - endsubroutine integrate - - subroutine integrate_fast(self, U, stage, buffer, Dt, t) - !< Integrate integrand field by Linear SSP Runge-Kutta methods. - class(integrator_runge_kutta_lssp), intent(in) :: self !< Integrator. - class(integrand_object), intent(inout) :: U !< Field to be integrated. - class(integrand_object), intent(inout) :: stage(1:) !< Runge-Kutta stages [1:stages]. - class(integrand_object), intent(inout) :: buffer !< Temporary buffer for doing fast operation. - real(R_P), intent(in) :: Dt !< Time step. - real(R_P), intent(in) :: t !< Time. - - call self%integrate_fast_(U=U, stage=stage, buffer=buffer, Dt=Dt, t=t) - endsubroutine integrate_fast - ! private methods elemental subroutine initialize_order_s_1(self) !< Initialize integrator for (s-1)-th order formula. diff --git a/src/lib/foodie_integrator_runge_kutta_object.f90 b/src/lib/foodie_integrator_runge_kutta_object.f90 deleted file mode 100644 index d5cdcf21..00000000 --- a/src/lib/foodie_integrator_runge_kutta_object.f90 +++ /dev/null @@ -1,70 +0,0 @@ -!< Define the abstract type [[integrator_runge_kutta_object]] of FOODIE ODE integrators. - -module foodie_integrator_runge_kutta_object -!< Define the abstract type [[integrator_runge_kutta_object]] of FOODIE ODE integrators. - -use, intrinsic :: iso_fortran_env, only : stderr=>error_unit -use foodie_integrand_object, only : integrand_object -use foodie_integrator_object, only : integrator_object -use penf, only : I_P, R_P - -implicit none -private -public :: integrator_runge_kutta_object - -logical, parameter :: is_multistage_=.true. !< Flag to check if integrator is multistage. -logical, parameter :: is_multistep_=.false. !< Flag to check if integrator is multistep. - -type, extends(integrator_object), abstract :: integrator_runge_kutta_object - !< Abstract type of FOODIE ODE integrators of the family Runge-Kutta. - contains - ! deferred methods - procedure(integrate_interface), pass(self), deferred :: integrate !< Integrate integrand field. - procedure(integrate_fast_interface), pass(self), deferred :: integrate_fast !< Integrate integrand field, fast mode. - ! deferred methods of parent - procedure, pass(self) :: is_multistage !< Return .true. for multistage integrator. - procedure, pass(self) :: is_multistep !< Return .true. for multistep integrator. -endtype integrator_runge_kutta_object - -abstract interface - !< Abstract interfaces of deferred methods of [[integrator_object]]. - subroutine integrate_interface(self, U, stage, Dt, t) - !< Integrate integrand field. - import :: integrand_object, integrator_runge_kutta_object, R_P - class(integrator_runge_kutta_object), intent(in) :: self !< Integrator. - class(integrand_object), intent(inout) :: U !< Integrand. - class(integrand_object), intent(inout) :: stage(1:) !< Runge-Kutta stages. - real(R_P), intent(in) :: Dt !< Time step. - real(R_P), intent(in) :: t !< Time. - endsubroutine integrate_interface - - subroutine integrate_fast_interface(self, U, stage, buffer, Dt, t) - !< Integrate integrand field, fast mode. - import :: integrand_object, integrator_runge_kutta_object, R_P - class(integrator_runge_kutta_object), intent(in) :: self !< Integrator. - class(integrand_object), intent(inout) :: U !< Field to be integrated. - class(integrand_object), intent(inout) :: stage(1:) !< Runge-Kutta stages. - class(integrand_object), intent(inout) :: buffer !< Temporary buffer for doing fast operation. - real(R_P), intent(in) :: Dt !< Time step. - real(R_P), intent(in) :: t !< Time. - endsubroutine integrate_fast_interface -endinterface - -contains - ! public methods - elemental function is_multistage(self) - !< Return .true. for multistage integrator. - class(integrator_runge_kutta_object), intent(in) :: self !< Integrator. - logical :: is_multistage !< Inquire result. - - is_multistage = is_multistage_ - endfunction is_multistage - - elemental function is_multistep(self) - !< Return .true. for multistage integrator. - class(integrator_runge_kutta_object), intent(in) :: self !< Integrator. - logical :: is_multistep !< Inquire result. - - is_multistep = is_multistep_ - endfunction is_multistep -endmodule foodie_integrator_runge_kutta_object diff --git a/src/lib/foodie_integrator_runge_kutta_ssp.f90 b/src/lib/foodie_integrator_runge_kutta_ssp.f90 index 6e7319ae..0d07af90 100644 --- a/src/lib/foodie_integrator_runge_kutta_ssp.f90 +++ b/src/lib/foodie_integrator_runge_kutta_ssp.f90 @@ -102,8 +102,8 @@ module foodie_integrator_runge_kutta_ssp use foodie_error_codes, only : ERROR_UNSUPPORTED_SCHEME use foodie_integrand_object, only : integrand_object +use foodie_integrator_multistage_explicit_object, only : integrator_multistage_explicit_object use foodie_integrator_object, only : integrator_object -use foodie_integrator_runge_kutta_object, only : integrator_runge_kutta_object use penf, only : I_P, R_P implicit none @@ -118,12 +118,11 @@ module foodie_integrator_runge_kutta_ssp logical, parameter :: has_fast_mode_=.true. !< Flag to check if integrator provides *fast mode* integrate. -type, extends(integrator_runge_kutta_object) :: integrator_runge_kutta_ssp +type, extends(integrator_multistage_explicit_object) :: integrator_runge_kutta_ssp !< FOODIE integrator: provide an explicit class of SSP Runge-Kutta schemes, from 1st to 4th order accurate. !< !< @note The integrator must be created or initialized (initialize the RK coefficients) before used. private - integer(I_P) :: stages=0 !< Number of stages. real(R_P), allocatable :: alph(:,:) !< \(\alpha\) Butcher's coefficients. real(R_P), allocatable :: beta(:) !< \(\beta\) Butcher's coefficients. real(R_P), allocatable :: gamm(:) !< \(\gamma\) Butcher's coefficients. @@ -133,15 +132,13 @@ module foodie_integrator_runge_kutta_ssp procedure, pass(self) :: description !< Return pretty-printed object description. procedure, pass(self) :: has_fast_mode !< Return .true. if the integrator class has *fast mode* integrate. procedure, pass(lhs) :: integr_assign_integr !< Operator `=`. + procedure, pass(self) :: integrate !< Integrate integrand field. + procedure, pass(self) :: integrate_fast !< Integrate integrand field, fast mode. procedure, pass(self) :: is_supported !< Return .true. if the integrator class support the given scheme. - procedure, pass(self) :: stages_number !< Return number of stages used. - procedure, pass(self) :: steps_number !< Return number of steps used. procedure, pass(self) :: supported_schemes !< Return the list of supported schemes. ! public methods procedure, pass(self) :: destroy !< Destroy the integrator. procedure, pass(self) :: initialize !< Initialize (create) the integrator. - procedure, pass(self) :: integrate !< Integrate integrand field. - procedure, pass(self) :: integrate_fast !< Integrate integrand field, fast mode. endtype integrator_runge_kutta_ssp contains @@ -196,6 +193,62 @@ pure subroutine integr_assign_integr(lhs, rhs) endselect endsubroutine integr_assign_integr + subroutine integrate(self, U, stage, Dt, t, new_Dt) + !< Integrate field with explicit SSP Runge-Kutta scheme. + class(integrator_runge_kutta_ssp), intent(in) :: self !< Integrator. + class(integrand_object), intent(inout) :: U !< Field to be integrated. + class(integrand_object), intent(inout) :: stage(1:) !< Runge-Kutta stages [1:stages]. + real(R_P), intent(in) :: Dt !< Time step. + real(R_P), intent(in) :: t !< Time. + real(R_P), optional, intent(out) :: new_Dt !< New adapted time step. + integer(I_P) :: s !< First stages counter. + integer(I_P) :: ss !< Second stages counter. + + ! computing stages + do s=1, self%stages + stage(s) = U + do ss=1, s - 1 + stage(s) = stage(s) + (stage(ss) * (Dt * self%alph(s, ss))) + enddo + stage(s) = stage(s)%t(t=t + self%gamm(s) * Dt) + enddo + ! computing new time step + do s=1, self%stages + U = U + (stage(s) * (Dt * self%beta(s))) + enddo + if (present(new_Dt)) new_Dt = Dt + endsubroutine integrate + + subroutine integrate_fast(self, U, stage, buffer, Dt, t, new_Dt) + !< Integrate field with explicit SSP Runge-Kutta scheme. + class(integrator_runge_kutta_ssp), intent(in) :: self !< Integrator. + class(integrand_object), intent(inout) :: U !< Field to be integrated. + class(integrand_object), intent(inout) :: stage(1:) !< Runge-Kutta stages [1:stages]. + class(integrand_object), intent(inout) :: buffer !< Temporary buffer for doing fast operation. + real(R_P), intent(in) :: Dt !< Time step. + real(R_P), intent(in) :: t !< Time. + real(R_P), optional, intent(out) :: new_Dt !< New adapted time step. + integer(I_P) :: s !< First stages counter. + integer(I_P) :: ss !< Second stages counter. + + ! computing stages + buffer = U + do s=1, self%stages + stage(s) = U + do ss=1, s - 1 + call buffer%multiply_fast(lhs=stage(ss), rhs=Dt * self%alph(s, ss)) + call stage(s)%add_fast(lhs=stage(s), rhs=buffer) + enddo + call stage(s)%t_fast(t=t + self%gamm(s) * Dt) + enddo + ! computing new time step + do s=1, self%stages + call buffer%multiply_fast(lhs=stage(s), rhs=Dt * self%beta(s)) + call U%add_fast(lhs=U, rhs=buffer) + enddo + if (present(new_Dt)) new_Dt = Dt + endsubroutine integrate_fast + elemental function is_supported(self, scheme) !< Return .true. if the integrator class support the given scheme. class(integrator_runge_kutta_ssp), intent(in) :: self !< Integrator. @@ -212,22 +265,6 @@ elemental function is_supported(self, scheme) enddo endfunction is_supported - elemental function stages_number(self) - !< Return number of stages used. - class(integrator_runge_kutta_ssp), intent(in) :: self !< Integrator. - integer(I_P) :: stages_number !< Number of stages used. - - stages_number = self%stages - endfunction stages_number - - elemental function steps_number(self) - !< Return number of steps used. - class(integrator_runge_kutta_ssp), intent(in) :: self !< Integrator. - integer(I_P) :: steps_number !< Number of steps used. - - steps_number = 0 - endfunction steps_number - pure function supported_schemes(self) result(schemes) !< Return the list of supported schemes. class(integrator_runge_kutta_ssp), intent(in) :: self !< Integrator. @@ -242,8 +279,7 @@ elemental subroutine destroy(self) !< Destroy the integrator. class(integrator_runge_kutta_ssp), intent(inout) :: self !< Integrator. - call self%destroy_abstract - self%stages = 0 + call self%destroy_multistage if (allocated(self%alph)) deallocate(self%alph) if (allocated(self%beta)) deallocate(self%beta) if (allocated(self%gamm)) deallocate(self%gamm) @@ -321,56 +357,4 @@ subroutine initialize(self, scheme, stop_on_fail) is_severe=stop_on_fail) endif endsubroutine initialize - - subroutine integrate(self, U, stage, Dt, t) - !< Integrate field with explicit SSP Runge-Kutta scheme. - class(integrator_runge_kutta_ssp), intent(in) :: self !< Integrator. - class(integrand_object), intent(inout) :: U !< Field to be integrated. - class(integrand_object), intent(inout) :: stage(1:) !< Runge-Kutta stages [1:stages]. - real(R_P), intent(in) :: Dt !< Time step. - real(R_P), intent(in) :: t !< Time. - integer(I_P) :: s !< First stages counter. - integer(I_P) :: ss !< Second stages counter. - - ! computing stages - do s=1, self%stages - stage(s) = U - do ss=1, s - 1 - stage(s) = stage(s) + (stage(ss) * (Dt * self%alph(s, ss))) - enddo - stage(s) = stage(s)%t(t=t + self%gamm(s) * Dt) - enddo - ! computing new time step - do s=1, self%stages - U = U + (stage(s) * (Dt * self%beta(s))) - enddo - endsubroutine integrate - - subroutine integrate_fast(self, U, stage, buffer, Dt, t) - !< Integrate field with explicit SSP Runge-Kutta scheme. - class(integrator_runge_kutta_ssp), intent(in) :: self !< Integrator. - class(integrand_object), intent(inout) :: U !< Field to be integrated. - class(integrand_object), intent(inout) :: stage(1:) !< Runge-Kutta stages [1:stages]. - class(integrand_object), intent(inout) :: buffer !< Temporary buffer for doing fast operation. - real(R_P), intent(in) :: Dt !< Time step. - real(R_P), intent(in) :: t !< Time. - integer(I_P) :: s !< First stages counter. - integer(I_P) :: ss !< Second stages counter. - - ! computing stages - buffer = U - do s=1, self%stages - stage(s) = U - do ss=1, s - 1 - call buffer%multiply_fast(lhs=stage(ss), rhs=Dt * self%alph(s, ss)) - call stage(s)%add_fast(lhs=stage(s), rhs=buffer) - enddo - call stage(s)%t_fast(t=t + self%gamm(s) * Dt) - enddo - ! computing new time step - do s=1, self%stages - call buffer%multiply_fast(lhs=stage(s), rhs=Dt * self%beta(s)) - call U%add_fast(lhs=U, rhs=buffer) - enddo - endsubroutine integrate_fast endmodule foodie_integrator_runge_kutta_ssp diff --git a/src/tests/ladvection/foodie_test_integrand_ladvection.f90 b/src/tests/ladvection/foodie_test_integrand_ladvection.f90 index 12bd0023..5f1c2e4f 100644 --- a/src/tests/ladvection/foodie_test_integrand_ladvection.f90 +++ b/src/tests/ladvection/foodie_test_integrand_ladvection.f90 @@ -281,7 +281,7 @@ function local_error(lhs, rhs) result(error) class is (integrand_ladvection) error = 0._R_P do i=1, lhs%Ni - error = error + (lhs%u(i) - rhs%u(i)) ** 2 / lhs%u(i) ** 2 + error = error + (lhs%u(i) - rhs%u(i)) ** 2 enddo error = sqrt(error) endselect diff --git a/src/tests/ladvection/foodie_test_ladvection.f90 b/src/tests/ladvection/foodie_test_ladvection.f90 index d353eff5..a809fc2b 100644 --- a/src/tests/ladvection/foodie_test_ladvection.f90 +++ b/src/tests/ladvection/foodie_test_ladvection.f90 @@ -5,25 +5,27 @@ module foodie_test_ladvection_test use, intrinsic :: iso_fortran_env, only : stderr=>error_unit use flap, only : command_line_interface -use foodie, only : foodie_integrator_class_names, & - foodie_integrator_factory, & - foodie_integrator_schemes, & - integrand_object, & - integrator_adams_bashforth, & - integrator_adams_bashforth_moulton, & - integrator_adams_moulton, & - integrator_back_df, & - integrator_euler_explicit, & - integrator_leapfrog, & - integrator_lmm_ssp, & - integrator_lmm_ssp_vss, & - integrator_ms_runge_kutta_ssp, & - integrator_object, & - integrator_runge_kutta_emd, & - integrator_runge_kutta_ls, & - integrator_runge_kutta_lssp, & - integrator_runge_kutta_object, & - integrator_runge_kutta_ssp, & +use foodie, only : foodie_integrator_class_names, & + foodie_integrator_factory, & + foodie_integrator_schemes, & + integrand_object, & + integrator_adams_bashforth, & + integrator_adams_bashforth_moulton, & + integrator_adams_moulton, & + integrator_back_df, & + integrator_euler_explicit, & + integrator_leapfrog, & + integrator_lmm_ssp, & + integrator_lmm_ssp_vss, & + integrator_ms_runge_kutta_ssp, & + integrator_multistage_explicit_object, & + integrator_multistep_explicit_object, & + integrator_multistep_implicit_object, & + integrator_object, & + integrator_runge_kutta_emd, & + integrator_runge_kutta_ls, & + integrator_runge_kutta_lssp, & + integrator_runge_kutta_ssp, & is_available, is_class_available use foodie_test_integrand_ladvection, only : integrand_ladvection use penf, only : I_P, R_P, FR_P, str, strz @@ -200,28 +202,28 @@ subroutine integrate(scheme, integrand_0, final_step, final_time, iterations, st real(R_P), allocatable :: time(:) !< Time. real(R_P), allocatable :: Dt(:) !< Time steps. real(R_P) :: Dt_a !< Autoadptive time step. - integer :: step !< Time steps counter. - integer :: step_offset !< Time steps counter offset for slicing previous data array. + integer(I_P) :: step !< Time steps counter. + integer(I_P) :: step_offset !< Time steps counter offset for slicing previous data array. character(len=:), allocatable :: output_file_name !< File name of output results file. + integer(I_P) :: s !< Counter. - allocate(integrand, mold=integrand_0) - allocate(buffer, mold=integrand_0) - allocate(filter, mold=integrand_0) - - integrand = integrand_0 - - select type(integrand) - type is(integrand_ladvection) - output_file_name = trim(adjustl(output_base_name))//'-'//trim(adjustl(scheme))//'-'//trim(strz(integrand%Ni, 10))//'.dat' - endselect + allocate(integrand, mold=integrand_0) ; integrand = integrand_0 + allocate(buffer, mold=integrand_0) ; buffer = integrand_0 + allocate(filter, mold=integrand_0) ; filter = integrand_0 call foodie_integrator_factory(scheme=scheme, integrator=integrator, stages=stages, tolerance=1e2_R_P) if (is_fast) call check_scheme_has_fast_mode(scheme=trim(adjustl(scheme)), integrator=integrator) if (integrator%is_multistep()) then allocate(previous(1:integrator%steps_number()), mold=integrand_0) + do s=1, integrator%steps_number() + previous(s) = integrand_0 + enddo call integrator_start%initialize(scheme='runge_kutta_ssp_stages_5_order_4') allocate(stage_start(1:integrator_start%stages_number()), mold=integrand_0) + do s=1, integrator_start%stages_number() + stage_start(s) = integrand_0 + enddo if (integrator%steps_number()==0) then step_offset = 1 ! for 0 step-(a convention)-solver offset is 1 else @@ -230,165 +232,98 @@ subroutine integrate(scheme, integrand_0, final_step, final_time, iterations, st else step_offset = 1 ! for 0 step-(a convention)-solver offset is 1 endif - if (integrator%is_multistage()) allocate(stage(1:integrator%stages_number()), mold=integrand_0) + if (integrator%is_multistage()) then + allocate(stage(1:integrator%stages_number()), mold=integrand_0) + do s=1, integrator%stages_number() + stage(s) = integrand_0 + enddo + endif allocate(time(0:step_offset)) allocate(Dt(1:step_offset)) step = 0 time = 0._R_P - Dt = 0._R_P select type(integrand) type is(integrand_ladvection) + Dt = integrand%dt(final_step=final_step, final_time=final_time, t=0._R_P) + endselect + select type(integrand) + type is(integrand_ladvection) + output_file_name = trim(adjustl(output_base_name))//'-'//trim(adjustl(scheme))//'-'//trim(strz(integrand%Ni, 10))//'.dat' if (save_results) call integrand%export_tecplot(file_name=output_file_name, t=time(0)) endselect + select type(integrator) - class is(integrator_runge_kutta_object) + class is(integrator_multistage_explicit_object) do step = step + 1 - select type(integrand) - type is(integrand_ladvection) - Dt(step_offset) = integrand%dt(final_step=final_step, final_time=final_time, t=time(step_offset)) - endselect if (is_fast) then call integrator%integrate_fast(U=integrand, stage=stage, buffer=buffer, Dt=Dt(step_offset), t=time(step_offset)) else call integrator%integrate(U=integrand, stage=stage, Dt=Dt(step_offset), t=time(step_offset)) endif call update_previous_times - select type(integrand) - type is(integrand_ladvection) - if (save_results.and.mod(step, save_frequency)==0) call integrand%export_tecplot(t=time(step_offset)) - endselect - if ((time(step_offset) == final_time).or.(step == final_step)) exit + if ((time(step_offset) >= final_time).or.(step == final_step)) exit enddo - type is(integrator_adams_bashforth) + class is(integrator_multistep_explicit_object) do step = step + 1 if (integrator%steps_number() >= step) then - ! Dt(step) = integrand%dt(final_step=final_step, final_time=final_time, t=time(step)) call integrator_start%integrate(U=integrand, stage=stage_start, Dt=Dt(step), t=time(step)) previous(step) = integrand time(step) = time(step-1) + Dt(step) - ! if (save_results.and.mod(step, save_frequency)==0) call integrand%export_tecplot(t=time(step)) - if ((time(step) == final_time).or.(step == final_step)) exit else - ! Dt(step_offset) = integrand%dt(final_step=final_step, final_time=final_time, t=time(step_offset)) if (is_fast) then call integrator%integrate_fast(U=integrand, previous=previous, buffer=buffer, Dt=Dt(step_offset), t=time) else call integrator%integrate(U=integrand, previous=previous, Dt=Dt(step_offset), t=time) endif call update_previous_times - ! if (save_results.and.mod(step, save_frequency)==0) call integrand%export_tecplot(t=time(step_offset)) - if ((time(step_offset) == final_time).or.(step == final_step)) exit endif + if ((time(step_offset) >= final_time).or.(step == final_step)) exit enddo - type is(integrator_adams_bashforth_moulton) + class is(integrator_multistep_implicit_object) + select type(integrator) + type is(integrator_adams_moulton) + if (allocated(previous)) deallocate(previous) ; allocate(previous(1:integrator%steps_number()+1), mold=integrand_0) + endselect do step = step + 1 if (integrator%steps_number() >= step) then - ! Dt(step) = integrand%dt(final_step=final_step, final_time=final_time, t=time(step)) call integrator_start%integrate(U=integrand, stage=stage_start, Dt=Dt(step), t=time(step)) previous(step) = integrand time(step) = time(step-1) + Dt(step) - ! if (save_results.and.mod(step, save_frequency)==0) call integrand%export_tecplot(t=time(step)) - if ((time(step) == final_time).or.(step == final_step)) exit - else - ! Dt(step_offset) = integrand%dt(final_step=final_step, final_time=final_time, t=time(step_offset)) - if (is_fast) then - call integrator%integrate_fast(U=integrand, previous=previous, buffer=buffer, Dt=Dt(step_offset), t=time) - else - call integrator%integrate(U=integrand, previous=previous, Dt=Dt(step_offset), t=time) - endif - call update_previous_times - ! if (save_results.and.mod(step, save_frequency)==0) call integrand%export_tecplot(t=time(step_offset)) - if ((time(step_offset) == final_time).or.(step == final_step)) exit - endif - enddo - - type is(integrator_adams_moulton) - if (allocated(previous)) deallocate(previous) ; allocate(previous(1:integrator%steps_number()+1), mold=integrand_0) - do - step = step + 1 - ! Dt(step) = integrand%dt(final_step=final_step, final_time=final_time, t=time(step)) - if (integrator%steps_number() >= step) then - call integrator_start%integrate(U=integrand, stage=stage_start, Dt=Dt(step), t=time(step)) - previous(step) = integrand else if (is_fast) then if (iterations>1) then - call integrator%integrate_fast(U=integrand, & - previous=previous, & - buffer=buffer, & - Dt=Dt(step), & - t=time(step-step_offset:step-1), & + call integrator%integrate_fast(U=integrand, previous=previous, buffer=buffer, Dt=Dt(step), t=time, & iterations=iterations) else - call integrator%integrate_fast(U=integrand, & - previous=previous, & - buffer=buffer, & - Dt=Dt(step), & - t=time(step-step_offset:step-1)) + call integrator%integrate_fast(U=integrand, previous=previous, buffer=buffer, Dt=Dt(step), t=time) endif else if (iterations>1) then - call integrator%integrate(U=integrand, & - previous=previous, & - Dt=Dt(step), & - t=time(step-step_offset:step-1), & - iterations=iterations) + call integrator%integrate(U=integrand, previous=previous, Dt=Dt(step_offset), t=time, iterations=iterations) else - call integrator%integrate(U=integrand, & - previous=previous, & - Dt=Dt(step), & - t=time(step-step_offset:step-1)) + call integrator%integrate(U=integrand, previous=previous, Dt=Dt(step_offset), t=time) endif endif + call update_previous_times endif - time(step) = time(step-1) + Dt(step) - ! if (save_results.and.mod(step, save_frequency)==0) call integrand%export_tecplot(t=time(step)) - if ((time(step) == final_time).or.(step == final_step)) exit - enddo - - type is(integrator_back_df) - do - step = step + 1 - ! Dt(step) = integrand%dt(final_step=final_step, final_time=final_time, t=time(step)) - if (integrator%steps_number() >= step) then - call integrator_start%integrate(U=integrand, stage=stage_start, Dt=Dt(step), t=time(step)) - previous(step) = integrand - else - if (is_fast) then - call integrator%integrate_fast(U=integrand, & - previous=previous, & - buffer=buffer, & - Dt=Dt(step), & - t=time(step-integrator%steps_number():step-1)) - else - call integrator%integrate(U=integrand, & - previous=previous, & - Dt=Dt(step), & - t=time(step-integrator%steps_number():step-1)) - endif - endif - time(step) = time(step-1) + Dt(step) - ! if (save_results.and.mod(step, save_frequency)==0) call integrand%export_tecplot(t=time(step)) - if ((time(step) == final_time).or.(step == final_step)) exit + if ((time(step_offset) >= final_time).or.(step == final_step)) exit enddo type is(integrator_euler_explicit) do step = step + 1 - ! Dt(step_offset) = integrand%dt(final_step=final_step, final_time=final_time, t=time(step_offset)) if (is_fast) then call integrator%integrate_fast(U=integrand, buffer=buffer, Dt=Dt(step_offset), t=time(step_offset)) else call integrator%integrate(U=integrand, Dt=Dt(step_offset), t=time(step_offset)) endif call update_previous_times - ! if (save_results.and.mod(step, save_frequency)==0) call integrand%export_tecplot(t=time(step_offset)) if ((time(step_offset) == final_time).or.(step == final_step)) exit enddo @@ -396,14 +331,10 @@ subroutine integrate(scheme, integrand_0, final_step, final_time, iterations, st do step = step + 1 if (integrator%steps_number() >= step) then - ! Dt(step) = integrand%dt(final_step=final_step, final_time=final_time, t=time(step)) call integrator_start%integrate(U=integrand, stage=stage_start, Dt=Dt(step), t=time(step)) previous(step) = integrand time(step) = time(step-1) + Dt(step) - ! if (save_results.and.mod(step, save_frequency)==0) call integrand%export_tecplot(t=time(step)) - if ((time(step) == final_time).or.(step == final_step)) exit else - ! Dt(step_offset) = integrand%dt(final_step=final_step, final_time=final_time, t=time(step_offset)) if (index(scheme, 'raw') > 0 ) then if (is_fast) then call integrator%integrate_fast(U=integrand, previous=previous, buffer=buffer, Dt=Dt(step_offset), & @@ -420,110 +351,50 @@ subroutine integrate(scheme, integrand_0, final_step, final_time, iterations, st endif endif call update_previous_times - ! if (save_results.and.mod(step, save_frequency)==0) call integrand%export_tecplot(t=time(step_offset)) - if ((time(step_offset) == final_time).or.(step == final_step)) exit - endif - enddo - - type is(integrator_lmm_ssp) - do - step = step + 1 - ! Dt(step) = integrand%dt(final_step=final_step, final_time=final_time, t=time(step)) - if (integrator%steps_number() >= step) then - call integrator_start%integrate(U=integrand, stage=stage_start, Dt=Dt(step), t=time(step)) - previous(step) = integrand - else - if (is_fast) then - call integrator%integrate_fast(U=integrand, & - previous=previous, & - buffer=buffer, & - Dt=Dt(step), & - t=time(step-integrator%steps_number():step-1)) - else - call integrator%integrate(U=integrand, & - previous=previous, & - Dt=Dt(step), & - t=time(step-integrator%steps_number():step-1)) - endif endif - time(step) = time(step-1) + Dt(step) - ! if (save_results.and.mod(step, save_frequency)==0) call integrand%export_tecplot(t=time(step)) - if ((time(step) == final_time).or.(step == final_step)) exit + if ((time(step_offset) == final_time).or.(step == final_step)) exit enddo type is(integrator_lmm_ssp_vss) do step = step + 1 - ! Dt(step) = integrand%dt(final_step=final_step, final_time=final_time, t=time(step)) if (integrator%steps_number() >= step) then call integrator_start%integrate(U=integrand, stage=stage_start, Dt=Dt(step), t=time(step)) previous(step) = integrand + time(step) = time(step-1) + Dt(step) else if (is_fast) then - call integrator%integrate_fast(U=integrand, & - previous=previous, & - buffer=buffer, & - Dt=Dt(step-integrator%steps_number():step-1), & - t=time(step-integrator%steps_number():step-1)) + call integrator%integrate_fast(U=integrand, previous=previous, buffer=buffer, Dt=Dt, t=time) else - call integrator%integrate(U=integrand, & - previous=previous, & - Dt=Dt(step-integrator%steps_number():step-1), & - t=time(step-integrator%steps_number():step-1)) + call integrator%integrate(U=integrand, previous=previous, Dt=Dt, t=time) endif + call update_previous_times endif - time(step) = time(step-1) + Dt(step) - ! if (save_results.and.mod(step, save_frequency)==0) call integrand%export_tecplot(t=time(step)) if ((time(step) == final_time).or.(step == final_step)) exit enddo type is(integrator_ms_runge_kutta_ssp) do step = step + 1 - ! Dt(step) = integrand%dt(final_step=final_step, final_time=final_time, t=time(step)) if (integrator%steps_number() >= step) then call integrator_start%integrate(U=integrand, stage=stage_start, Dt=Dt(step), t=time(step)) previous(step) = integrand + time(step) = time(step-1) + Dt(step) else if (is_fast) then - call integrator%integrate_fast(U=integrand, & - previous=previous, & - stage=stage, & - buffer=buffer, & - Dt=Dt(step), & - t=time(step-integrator%steps_number():step-1)) + call integrator%integrate_fast(U=integrand, previous=previous, stage=stage, buffer=buffer, Dt=Dt(step_offset),t=time) else - call integrator%integrate(U=integrand, & - previous=previous, & - stage=stage, & - Dt=Dt(step), & - t=time(step-integrator%steps_number():step-1)) + call integrator%integrate(U=integrand, previous=previous, stage=stage, Dt=Dt(step_offset), t=time) endif + call update_previous_times endif - time(step) = time(step-1) + Dt(step) - ! if (save_results.and.mod(step, save_frequency)==0) call integrand%export_tecplot(t=time(step)) - if ((time(step) == final_time).or.(step == final_step)) exit - enddo - - type is(integrator_runge_kutta_emd) - do - step = step + 1 - ! Dt(step) = integrand%dt(final_step=final_step, final_time=final_time, t=time(step)) - Dt_a = Dt(step) - if (is_fast) then - call integrator%integrate_fast(U=integrand, stage=stage, buffer=buffer, Dt=Dt_a, t=time(step)) - else - call integrator%integrate(U=integrand, stage=stage, Dt=Dt_a, t=time(step)) - endif - time(step) = time(step-1) + Dt(step) - ! if (save_results.and.mod(step, save_frequency)==0) call integrand%export_tecplot(t=time(step)) if ((time(step) == final_time).or.(step == final_step)) exit enddo - endselect select type(integrand) type is(integrand_ladvection) + if (save_results) call integrand%export_tecplot(t=time(step_offset)) if (save_results) call integrand%export_tecplot(close_file=.true.) endselect contains From 3e5b50d94d3cea671727e17c63281decc1ec7a3a Mon Sep 17 00:00:00 2001 From: Stefano Zaghi Date: Tue, 16 May 2017 18:41:48 +0200 Subject: [PATCH 09/25] really generalize tester --- src/tests/{ladvection => tester}/fobos | 65 +--------- .../foodie_test_integrand_ladvection.f90 | 7 +- .../foodie_tester.f90} | 116 ++++++++++-------- 3 files changed, 68 insertions(+), 120 deletions(-) rename src/tests/{ladvection => tester}/fobos (53%) rename src/tests/{ladvection => tester}/foodie_test_integrand_ladvection.f90 (98%) rename src/tests/{ladvection/foodie_test_ladvection.f90 => tester/foodie_tester.f90} (82%) diff --git a/src/tests/ladvection/fobos b/src/tests/tester/fobos similarity index 53% rename from src/tests/ladvection/fobos rename to src/tests/tester/fobos index 07064a26..1a50ae85 100644 --- a/src/tests/ladvection/fobos +++ b/src/tests/tester/fobos @@ -1,9 +1,6 @@ [modes] modes = gnu gnu-debug gnu-coverage intel intel-debug - errors-analysis - gnu-pure gnu-debug-pure gnu-coverage-pure - intel-pure intel-debug-pure [common-variables] $CSTATIC_GNU = -cpp -c -frealloc-lhs @@ -54,72 +51,14 @@ cflags = $CSTATIC_INT $DEBUG_INT lflags = $DEBUG_INT template = template-common -[errors-analysis] -help = Build test in release mode (for errors analysis) with GNU gfortran -compiler = gnu -cflags = $CSTATIC_GNU $OPTIMIZE -lflags = $OPTIMIZE -cflags_heritage = True -target = src/tests/ladvection/foodie_test_ladvection.f90 -exclude_dirs = $EXDIRS -mod_dir = mod -obj_dir = obj -src = src/ -colors = True -quiet = False -log = True -jobs = 10 - -# pure modes for testing FOODIE ADT with "pure" procedures -[gnu-pure] -help = Build test in release mode with GNU gfortran -compiler = gnu -cflags = $CSTATIC_GNU $OPTIMIZE -lflags = $OPTIMIZE -preproc = -DPURE -template = template-common - -[gnu-debug-pure] -help = Build test in debug mode with GNU gfortran -compiler = gnu -cflags = $CSTATIC_GNU $DEBUG_GNU -lflags = $DEBUG_GNU -preproc = -DPURE -template = template-common - -[gnu-coverage-pure] -help = Build test in release coverage mode with GNU gfortran -compiler = gnu -cflags = $CSTATIC_GNU $OPTIMIZE -lflags = $OPTIMIZE -preproc = -DPURE -coverage = True -template = template-common - -[intel-pure] -help = Build test in release mode with Intel Fortran -compiler = intel -cflags = $CSTATIC_INT $OPTIMIZE -lflags = $OPTIMIZE -preproc = -DPURE -template = template-common - -[intel-debug-pure] -help = Build test in debug mode with Intel Fortran -compiler = intel -cflags = $CSTATIC_INT $DEBUG_INT -lflags = $DEBUG_INT -preproc = -DPURE -template = template-common - # templates [template-common] cflags_heritage = True -build_dir = build/tests/ladvection/ +build_dir = build/tests/tester/ mod_dir = mod obj_dir = obj src = src/ -target = src/tests/ladvection/foodie_test_ladvection.f90 +target = src/tests/tester/foodie_tester.f90 exclude_dirs = $EXDIRS colors = True quiet = False diff --git a/src/tests/ladvection/foodie_test_integrand_ladvection.f90 b/src/tests/tester/foodie_test_integrand_ladvection.f90 similarity index 98% rename from src/tests/ladvection/foodie_test_integrand_ladvection.f90 rename to src/tests/tester/foodie_test_integrand_ladvection.f90 index 5f1c2e4f..7af6f33d 100644 --- a/src/tests/ladvection/foodie_test_integrand_ladvection.f90 +++ b/src/tests/tester/foodie_test_integrand_ladvection.f90 @@ -134,11 +134,12 @@ pure function exact_solution(self, u0, t) result(exact) endfunction exact_solution - subroutine export_tecplot(self, file_name, t, close_file) + subroutine export_tecplot(self, file_name, t, scheme, close_file) !< Export integrand to Tecplot file. class(integrand_ladvection), intent(in) :: self !< Advection field. character(*), intent(in), optional :: file_name !< File name. real(R_P), intent(in), optional :: t !< Time. + character(*), intent(in), optional :: scheme !< Scheme used to integrate integrand. logical, intent(in), optional :: close_file !< Flag for closing file. logical, save :: is_open=.false. !< Flag for checking if file is open. integer(I_P), save :: file_unit !< File unit. @@ -156,8 +157,8 @@ subroutine export_tecplot(self, file_name, t, close_file) is_open = .true. write(unit=file_unit, fmt='(A)') 'VARIABLES="x" "u"' endif - if (present(t) .and. is_open) then - write(unit=file_unit, fmt='(A)') 'ZONE T="'//str(t)//'"' + if (present(t) .and. present(scheme) .and. is_open) then + write(unit=file_unit, fmt='(A)') 'ZONE T="'//str(t)//' '//trim(adjustl(scheme))//'"' do i=1, self%Ni write(unit=file_unit, fmt='(2('//FR_P//',1X))') self%Dx * i - 0.5_R_P * self%Dx, self%u(i) enddo diff --git a/src/tests/ladvection/foodie_test_ladvection.f90 b/src/tests/tester/foodie_tester.f90 similarity index 82% rename from src/tests/ladvection/foodie_test_ladvection.f90 rename to src/tests/tester/foodie_tester.f90 index a809fc2b..732f4e7f 100644 --- a/src/tests/ladvection/foodie_test_ladvection.f90 +++ b/src/tests/tester/foodie_tester.f90 @@ -1,7 +1,7 @@ -!< Test FOODIE with the integration of 1D linear advection PDE. +!< Tester factory of FOODIE integrators. -module foodie_test_ladvection_test -!< Oscillation test handler definition. +module foodie_test_object +!< Definition of [[test_object]] for FOODIE tester factory. use, intrinsic :: iso_fortran_env, only : stderr=>error_unit use flap, only : command_line_interface @@ -32,42 +32,44 @@ module foodie_test_ladvection_test implicit none private -public :: ladvection_test +public :: test_object -type :: ladvection_test - !< Class to handle 1D linear advection test(s). +type :: test_object + !< Generic FOODIE test object. !< !< Test is driven by the Command Line Interface (CLI) options. !< !< Test has only 1 public method `execute`: it executes test(s) accordingly to cli options. private - type(command_line_interface) :: cli !< Command line interface handler. - integer(I_P) :: error=0 !< Error handler. - character(99) :: scheme='' !< Scheme used. - logical :: is_fast=.false. !< Flag for activating fast schemes. - integer(I_P) :: implicit_iterations=0 !< Number of iterations (implicit solvers). - integer(I_P) :: stages=0 !< Number of stages. - integer(I_P) :: final_step=0 !< Maximum number of time steps. - real(R_P) :: final_time=0._R_P !< Final integration time. - logical :: save_results=.false. !< Flag for activating results saving. - integer(I_P) :: save_frequency=0 !< Output save frequency. - character(99) :: output='' !< Output files basename. - logical :: verbose=.false. !< Flag for activating verbose output. - type(integrand_ladvection) :: integrand_0 !< Initial conditions. + type(command_line_interface) :: cli !< Command line interface handler. + integer(I_P) :: error=0 !< Error handler. + character(99) :: test='' !< Test executed. + character(99) :: scheme='' !< Scheme used. + logical :: is_fast=.false. !< Flag for activating fast schemes. + integer(I_P) :: implicit_iterations=0 !< Number of iterations (implicit solvers). + integer(I_P) :: stages=0 !< Number of stages. + integer(I_P) :: final_step=0 !< Maximum number of time steps. + real(R_P) :: final_time=0._R_P !< Final integration time. + logical :: save_results=.false. !< Flag for activating results saving. + character(99) :: output='' !< Output files basename. + logical :: verbose=.false. !< Flag for activating verbose output. + type(integrand_ladvection) :: ladvection_0 !< Initial conditions for linear advection test. + class(integrand_object), allocatable :: integrand_0 !< Initial conditions. contains ! public methods procedure, pass(self) :: execute !< Execute selected test(s). ! private methods procedure, pass(self), private :: initialize !< Initialize test: set Command Line Interface, parse it and check its validity. -endtype ladvection_test +endtype test_object contains ! public methods subroutine execute(self) !< Execute test(s). - class(ladvection_test), intent(inout) :: self !< Test. - character(99), allocatable :: integrator_schemes(:) !< Name of FOODIE integrator schemes. - integer(I_P) :: s !< Counter. + class(test_object), intent(inout) :: self !< Test. + character(99), allocatable :: integrator_schemes(:) !< Name of FOODIE integrator schemes. + character(len=:), allocatable :: output_file_name !< File name of output results file. + integer(I_P) :: s !< Counter. call self%initialize if (trim(adjustl(self%scheme))/='all') then @@ -80,6 +82,13 @@ subroutine execute(self) integrator_schemes = foodie_integrator_schemes() endif do s=1, size(integrator_schemes, dim=1) + select type(integrand=>self%integrand_0) + type is(integrand_ladvection) + output_file_name = trim(adjustl(self%output))//'-'//& + trim(adjustl(self%test))//'-'//& + trim(adjustl(integrator_schemes(s)))//'-'//& + trim(strz(integrand%Ni, 10))//'.dat' + endselect call integrate(scheme=trim(integrator_schemes(s)), & integrand_0=self%integrand_0, & final_step=self%final_step, & @@ -88,15 +97,14 @@ subroutine execute(self) stages=self%stages, & is_fast=self%is_fast, & save_results=self%save_results, & - save_frequency=self%save_frequency, & - output_base_name=self%output) + output_file_name=output_file_name) enddo endsubroutine execute ! private methods subroutine initialize(self) !< Initialize test: set Command Line Interface, parse it and check its validity. - class(ladvection_test), intent(inout) :: self !< Test. + class(test_object), intent(inout) :: self !< Test. call set_cli call parse_cli @@ -105,12 +113,14 @@ subroutine set_cli() !< Set Command Line Interface. associate(cli => self%cli) - call cli%init(progname = 'foodie_test_ladvection', & - authors = 'Fortran-FOSS-Programmers', & - license = 'GNU GPLv3', & - description = 'Test FOODIE library on 1D linear advection PDE integration', & - examples = ["foodie_test_ladvection --scheme euler_explicit --save_results ", & - "foodie_test_ladvection --scheme all -r "]) + call cli%init(progname = 'foodie_tester', & + authors = 'Fortran-FOSS-Programmers', & + license = 'GNU GPLv3', & + description = 'Tester factory of FOODIE integrators', & + examples = ["foodie_tester --scheme euler_explicit --save_results ", & + "foodie_tester --scheme all -r "]) + call cli%add(switch='--test', switch_ab='-t', help='test executed', required=.false., def='linear_advection', & + act='store', choices='linear_advection') call cli%add(switch='--scheme', switch_ab='-s', help='integrator scheme used', required=.false., def='all', act='store') call cli%add(switch='--fast', help='activate fast solvers', required=.false., act='store_true', def='.false.') call cli%add(switch='--iterations', help='iterations number for implicit schemes', required=.false., act='store', def='5') @@ -118,11 +128,10 @@ subroutine set_cli() call cli%add(switch='--final_step', switch_ab='-fs', help='integration steps', required=.false., act='store', def='100') call cli%add(switch='--final_time', switch_ab='-ft', help='integration time', required=.false., def='0', act='store') call cli%add(switch='--save_results', switch_ab='-r',help='save result', required=.false., act='store_true', def='.false.') - call cli%add(switch='--save_frequency', help='output save frequency', required=.false., act='store', def='1') - call cli%add(switch='--output', help='output file basename', required=.false., act='store', def='foodie_test_ladvection') + call cli%add(switch='--output', help='output file basename', required=.false., act='store', def='foodie_test') call cli%add(switch='--verbose', help='Verbose output', required=.false., act='store_true', def='.false.') endassociate - call self%integrand_0%set_cli(cli=self%cli) + call self%ladvection_0%set_cli(cli=self%cli) endsubroutine set_cli subroutine parse_cli() @@ -133,6 +142,7 @@ subroutine parse_cli() integer(I_P) :: i !< Counter. call self%cli%parse(error=self%error) + call self%cli%get(switch='-t', val=self%test, error=self%error) ; if (self%error/=0) stop call self%cli%get(switch='-s', val=self%scheme, error=self%error) ; if (self%error/=0) stop call self%cli%get(switch='--fast', val=self%is_fast, error=self%error) ; if (self%error/=0) stop call self%cli%get(switch='--iterations', val=self%implicit_iterations, error=self%error) ; if (self%error/=0) stop @@ -140,10 +150,15 @@ subroutine parse_cli() call self%cli%get(switch='-fs', val=self%final_step, error=self%error) ; if (self%error/=0) stop call self%cli%get(switch='-ft', val=self%final_time, error=self%error) ; if (self%error/=0) stop call self%cli%get(switch='-r', val=self%save_results, error=self%error) ; if (self%error/=0) stop - call self%cli%get(switch='--save_frequency', val=self%save_frequency, error=self%error) ; if (self%error/=0) stop call self%cli%get(switch='--output', val=self%output, error=self%error) ; if (self%error/=0) stop call self%cli%get(switch='--verbose', val=self%verbose, error=self%error) ; if (self%error/=0) stop - call self%integrand_0%parse_cli(cli=self%cli) + call self%ladvection_0%parse_cli(cli=self%cli) + + select case(trim(adjustl(self%test))) + case('linear_advection') + allocate(integrand_ladvection :: self%integrand_0) + self%integrand_0 = self%ladvection_0 + endselect if (self%final_time > 0._R_P) self%final_step = 0 @@ -178,8 +193,7 @@ subroutine check_scheme_has_fast_mode(scheme, integrator) endif endsubroutine check_scheme_has_fast_mode - subroutine integrate(scheme, integrand_0, final_step, final_time, iterations, stages, is_fast, & - save_results, save_frequency, output_base_name) + subroutine integrate(scheme, integrand_0, final_step, final_time, iterations, stages, is_fast, save_results, output_file_name) !< Integrate integrand by means of the given scheme. character(*), intent(in) :: scheme !< Selected scheme. class(integrand_object), intent(in) :: integrand_0 !< Initial conditions. @@ -189,8 +203,7 @@ subroutine integrate(scheme, integrand_0, final_step, final_time, iterations, st integer(I_P), intent(in) :: stages !< Number of stages. logical, intent(in) :: is_fast !< Activate fast mode integration. logical, intent(in) :: save_results !< Save results. - integer(I_P), intent(in) :: save_frequency !< Save frequency as steps multiple. - character(*), intent(in) :: output_base_name !< Base name of output results file. + character(*), intent(in) :: output_file_name !< File name of output results file. class(integrator_object), allocatable :: integrator !< The integrator. type(integrator_runge_kutta_ssp) :: integrator_start !< The (auto) start integrator. class(integrand_object), allocatable :: integrand !< Integrand. @@ -204,7 +217,6 @@ subroutine integrate(scheme, integrand_0, final_step, final_time, iterations, st real(R_P) :: Dt_a !< Autoadptive time step. integer(I_P) :: step !< Time steps counter. integer(I_P) :: step_offset !< Time steps counter offset for slicing previous data array. - character(len=:), allocatable :: output_file_name !< File name of output results file. integer(I_P) :: s !< Counter. allocate(integrand, mold=integrand_0) ; integrand = integrand_0 @@ -246,11 +258,7 @@ subroutine integrate(scheme, integrand_0, final_step, final_time, iterations, st select type(integrand) type is(integrand_ladvection) Dt = integrand%dt(final_step=final_step, final_time=final_time, t=0._R_P) - endselect - select type(integrand) - type is(integrand_ladvection) - output_file_name = trim(adjustl(output_base_name))//'-'//trim(adjustl(scheme))//'-'//trim(strz(integrand%Ni, 10))//'.dat' - if (save_results) call integrand%export_tecplot(file_name=output_file_name, t=time(0)) + if (save_results) call integrand%export_tecplot(file_name=output_file_name, t=time(0), scheme=scheme) endselect select type(integrator) @@ -394,7 +402,7 @@ subroutine integrate(scheme, integrand_0, final_step, final_time, iterations, st select type(integrand) type is(integrand_ladvection) - if (save_results) call integrand%export_tecplot(t=time(step_offset)) + if (save_results) call integrand%export_tecplot(t=time(step_offset), scheme=scheme) if (save_results) call integrand%export_tecplot(close_file=.true.) endselect contains @@ -414,15 +422,15 @@ subroutine update_previous_times time(step_offset-1) = temporary endsubroutine update_previous_times endsubroutine integrate -endmodule foodie_test_ladvection_test +endmodule foodie_test_object -program foodie_test_ladvection -!< Test FOODIE with the integration of 1D linear advection PDE. +program foodie_tester +!< Tester factory of FOODIE integrators. -use foodie_test_ladvection_test, only : ladvection_test +use foodie_test_object, only : test_object implicit none -type(ladvection_test) :: test !< Linear advection test. +type(test_object) :: test !< FOODIE test. call test%execute -endprogram foodie_test_ladvection +endprogram foodie_tester From bfd788a8ef8b48ebf7794a3021aefa9dd8c4f875 Mon Sep 17 00:00:00 2001 From: Stefano Zaghi Date: Tue, 16 May 2017 18:57:31 +0200 Subject: [PATCH 10/25] add oscillation to generic tester --- .../foodie_test_integrand_ladvection.f90 | 40 +--- .../foodie_test_integrand_oscillation.f90 | 206 ++++++++++++------ src/tests/tester/foodie_tester.f90 | 15 +- 3 files changed, 158 insertions(+), 103 deletions(-) rename src/tests/{oscillation => tester}/foodie_test_integrand_oscillation.f90 (58%) diff --git a/src/tests/tester/foodie_test_integrand_ladvection.f90 b/src/tests/tester/foodie_test_integrand_ladvection.f90 index 7af6f33d..9c7fd876 100644 --- a/src/tests/tester/foodie_test_integrand_ladvection.f90 +++ b/src/tests/tester/foodie_test_integrand_ladvection.f90 @@ -52,8 +52,6 @@ module foodie_test_integrand_ladvection real(R_P) :: length=0._R_P !< Domain length. real(R_P) :: Dx=0._R_P !< Space step. real(R_P) :: a=0._R_P !< Advection coefficient. - character(3) :: BC_L='' !< Left boundary condition type. - character(3) :: BC_R='' !< Right boundary condition type. real(R_P), allocatable :: u(:) !< Integrand (state) variable. class(interpolator_object), allocatable :: interpolator !< WENO interpolator. contains @@ -415,8 +413,6 @@ pure subroutine assign_integrand(lhs, rhs) lhs%Ng = rhs%Ng lhs%Dx = rhs%Dx lhs%a = rhs%a - lhs%BC_L = rhs%BC_L - lhs%BC_R = rhs%BC_R if (allocated(rhs%u)) then lhs%u = rhs%u else @@ -447,35 +443,13 @@ pure subroutine impose_boundary_conditions(self, u) real(R_P), intent(inout) :: u(1-self%Ng:) !< Conservative variables. integer(I_P) :: i !< Space counter. - select case(trim(adjustl(self%BC_L))) - case('TRA') ! trasmissive (non reflective) BC - do i=1-self%Ng, 0 - u(i) = u(-i+1) - enddo - case('REF') ! reflective BC - do i=1-self%Ng, 0 - u(i) = - u(-i+1) - enddo - case('PER') ! periodic BC - do i=1-self%Ng, 0 - u(i) = u(self%Ni+i) - enddo - endselect + do i=1-self%Ng, 0 + u(i) = u(self%Ni+i) + enddo - select case(trim(adjustl(self%BC_R))) - case('TRA') ! trasmissive (non reflective) BC - do i=self%Ni+1, self%Ni+self%Ng - u(i) = u(self%Ni-(i-self%Ni-1)) - enddo - case('REF') ! reflective BC - do i=self%Ni+1, self%Ni+self%Ng - u(i) = - u(self%Ni-(i-self%Ni-1)) - enddo - case('PER') ! periodic BC - do i=self%Ni+1, self%Ni+self%Ng - u(i) = u(i-self%Ni) - enddo - endselect + do i=self%Ni+1, self%Ni+self%Ng + u(i) = u(i-self%Ni) + enddo endsubroutine impose_boundary_conditions subroutine reconstruct_interfaces(self, conservative, r_conservative) @@ -517,8 +491,6 @@ subroutine set_square_wave_initial_state(self) real(R_P) :: x(1:self%ni) !< Cell center x-abscissa values. integer(I_P) :: i !< Space counter. - self%BC_L = 'PER' - self%BC_R = 'PER' if (allocated(self%u)) deallocate(self%u) ; allocate(self%u(1-self%Ng:self%Ni+self%Ng)) do i=1, self%Ni x(i) = self%Dx * i - 0.5_R_P * self%Dx diff --git a/src/tests/oscillation/foodie_test_integrand_oscillation.f90 b/src/tests/tester/foodie_test_integrand_oscillation.f90 similarity index 58% rename from src/tests/oscillation/foodie_test_integrand_oscillation.f90 rename to src/tests/tester/foodie_test_integrand_oscillation.f90 index 8bb2e915..9aaf3364 100644 --- a/src/tests/oscillation/foodie_test_integrand_oscillation.f90 +++ b/src/tests/tester/foodie_test_integrand_oscillation.f90 @@ -3,81 +3,86 @@ module foodie_test_integrand_oscillation !< Define [[integrand_oscillation]], the Oscillation test field that is a concrete extension of the abstract integrand type. +use flap, only : command_line_interface use foodie, only : integrand_object -use penf, only : R_P, I_P +use penf, only : R_P, I_P, str implicit none private public :: integrand_oscillation type, extends(integrand_object) :: integrand_oscillation - !< The oscillation equations field. - !< - !< It is a FOODIE integrand class concrete extension. - !< - !<### Oscillation ODEs system - ! dU_dt !< Time derivative, residuals. - ! operators - procedure, pass(lhs), public :: local_error !<`||integrand_oscillation - integrand_oscillation||` operator. - ! + - procedure, pass(lhs), public :: integrand_add_integrand !< `+` operator. - procedure, pass(lhs), public :: integrand_add_real !< `+ real` operator. - procedure, pass(rhs), public :: real_add_integrand !< `real +` operator. - ! * - procedure, pass(lhs), public :: integrand_multiply_integrand !< `*` operator. - procedure, pass(lhs), public :: integrand_multiply_real !< `* real` operator. - procedure, pass(rhs), public :: real_multiply_integrand !< `real *` operator. - procedure, pass(lhs), public :: integrand_multiply_real_scalar !< `* real_scalar` operator. - procedure, pass(rhs), public :: real_scalar_multiply_integrand !< `real_scalar *` operator. - ! - - procedure, pass(lhs), public :: integrand_sub_integrand !< `-` operator. - procedure, pass(lhs), public :: integrand_sub_real !< `- real` operator. - procedure, pass(rhs), public :: real_sub_integrand !< `real -` operator. - ! = - procedure, pass(lhs), public :: assign_integrand !< `=` operator. - procedure, pass(lhs), public :: assign_real !< `= real` operator. - ! override fast operators - procedure, pass(self), public :: t_fast !< Time derivative, residuals, fast mode. - procedure, pass(opr), public :: integrand_add_integrand_fast !< `+` fast operator. - procedure, pass(opr), public :: integrand_multiply_integrand_fast !< `*` fast operator. - procedure, pass(opr), public :: integrand_multiply_real_scalar_fast !< `* real_scalar` fast operator. - procedure, pass(opr), public :: integrand_subtract_integrand_fast !< `-` fast operator. + !< The oscillation equations field. + !< + !< It is a FOODIE integrand class concrete extension. + !< + !<### Oscillation ODEs system + ! dU_dt !< Time derivative, residuals. + ! operators + procedure, pass(lhs), public :: local_error !<`||integrand_oscillation - integrand_oscillation||` operator. + ! + + procedure, pass(lhs), public :: integrand_add_integrand !< `+` operator. + procedure, pass(lhs), public :: integrand_add_real !< `+ real` operator. + procedure, pass(rhs), public :: real_add_integrand !< `real +` operator. + ! * + procedure, pass(lhs), public :: integrand_multiply_integrand !< `*` operator. + procedure, pass(lhs), public :: integrand_multiply_real !< `* real` operator. + procedure, pass(rhs), public :: real_multiply_integrand !< `real *` operator. + procedure, pass(lhs), public :: integrand_multiply_real_scalar !< `* real_scalar` operator. + procedure, pass(rhs), public :: real_scalar_multiply_integrand !< `real_scalar *` operator. + ! - + procedure, pass(lhs), public :: integrand_sub_integrand !< `-` operator. + procedure, pass(lhs), public :: integrand_sub_real !< `- real` operator. + procedure, pass(rhs), public :: real_sub_integrand !< `real -` operator. + ! = + procedure, pass(lhs), public :: assign_integrand !< `=` operator. + procedure, pass(lhs), public :: assign_real !< `= real` operator. + ! override fast operators + procedure, pass(self), public :: t_fast !< Time derivative, residuals, fast mode. + procedure, pass(opr), public :: integrand_add_integrand_fast !< `+` fast operator. + procedure, pass(opr), public :: integrand_multiply_integrand_fast !< `*` fast operator. + procedure, pass(opr), public :: integrand_multiply_real_scalar_fast !< `* real_scalar` fast operator. + procedure, pass(opr), public :: integrand_subtract_integrand_fast !< `-` fast operator. endtype integrand_oscillation contains @@ -92,6 +97,38 @@ pure function exact_solution(self, t) result(exact) exact(2) = self%U0(1) * sin(self%f * t) + self%U0(2) * cos(self%f * t) endfunction exact_solution + subroutine export_tecplot(self, file_name, t, scheme, close_file) + !< Export integrand to Tecplot file. + class(integrand_oscillation), intent(in) :: self !< Advection field. + character(*), intent(in), optional :: file_name !< File name. + real(R_P), intent(in), optional :: t !< Time. + character(*), intent(in), optional :: scheme !< Scheme used to integrate integrand. + logical, intent(in), optional :: close_file !< Flag for closing file. + logical, save :: is_open=.false. !< Flag for checking if file is open. + integer(I_P), save :: file_unit !< File unit. + integer(I_P) :: i !< Counter. + + if (present(close_file)) then + if (close_file .and. is_open) then + close(unit=file_unit) + is_open = .false. + endif + else + if (present(file_name)) then + if (is_open) close(unit=file_unit) + open(newunit=file_unit, file=trim(adjustl(file_name))) + is_open = .true. + ! write(unit=file_unit, fmt='(A)') 'VARIABLES="x" "u"' + endif + if (present(t) .and. present(scheme) .and. is_open) then + write(unit=file_unit, fmt='(A)') 'ZONE T="'//str(t)//' '//trim(adjustl(scheme))//'"' + ! do i=1, self%Ni + ! write(unit=file_unit, fmt='(2('//FR_P//',1X))') self%Dx * i - 0.5_R_P * self%Dx, self%u(i) + ! enddo + endif + endif + endsubroutine export_tecplot + pure subroutine initialize(self, U0, frequency) !< Initialize integrand. class(integrand_oscillation), intent(inout) :: self !< Integrand. @@ -111,6 +148,38 @@ pure function output(self) result(state) state = self%U endfunction output + subroutine parse_cli(self, cli) + !< Initialize from command line interface. + class(integrand_oscillation), intent(inout) :: self !< Advection field. + type(command_line_interface), intent(inout) :: cli !< Command line interface handler. + character(99) :: initial_state !< Initial state. + + ! call cli%get(switch='--cfl', val=self%CFL, error=cli%error) ; if (cli%error/=0) stop + ! call cli%get(switch='--w-scheme', val=self%w_scheme, error=cli%error) ; if (cli%error/=0) stop + ! call cli%get(switch='--weno-order', val=self%weno_order, error=cli%error) ; if (cli%error/=0) stop + ! call cli%get(switch='--weno-eps', val=self%weno_eps, error=cli%error) ; if (cli%error/=0) stop + ! call cli%get(switch='-a', val=self%a, error=cli%error) ; if (cli%error/=0) stop + ! call cli%get(switch='--length', val=self%length, error=cli%error) ; if (cli%error/=0) stop + ! call cli%get(switch='--Ni', val=self%Ni, error=cli%error) ; if (cli%error/=0) stop + ! call cli%get(switch='-is', val=initial_state, error=cli%error) ; if (cli%error/=0) stop + endsubroutine parse_cli + + subroutine set_cli(cli) + !< Set command line interface. + type(command_line_interface), intent(inout) :: cli !< Command line interface handler. + + ! call cli%add(switch='--w-scheme', help='WENO scheme', required=.false., act='store', def='reconstructor-JS', & + ! choices='reconstructor-JS,reconstructor-M-JS,reconstructor-M-Z,reconstructor-Z') + ! call cli%add(switch='--weno-order', help='WENO order', required=.false., act='store', def='1') + ! call cli%add(switch='--weno-eps', help='WENO epsilon parameter', required=.false., act='store', def='0.000001') + ! call cli%add(switch='--cfl', help='CFL value', required=.false., act='store', def='0.8') + ! call cli%add(switch='-a', help='advection coefficient', required=.false., act='store', def='1.0') + ! call cli%add(switch='--length', help='domain lenth', required=.false., act='store', def='1.0') + ! call cli%add(switch='--Ni', help='number finite volumes used', required=.false., act='store', def='100') + ! call cli%add(switch='--initial_state', switch_ab='-is', help='initial state', required=.false., act='store', & + ! def='square_wave', choices='square_wave') + endsubroutine set_cli + ! deferred methods pure function integrand_dimension(self) !< return integrand dimension. @@ -273,6 +342,7 @@ pure subroutine assign_integrand(lhs, rhs) lhs%U = rhs%U lhs%f = rhs%f lhs%U0 = rhs%U0 + lhs%Dt = rhs%Dt endselect endsubroutine assign_integrand diff --git a/src/tests/tester/foodie_tester.f90 b/src/tests/tester/foodie_tester.f90 index 732f4e7f..60307fb9 100644 --- a/src/tests/tester/foodie_tester.f90 +++ b/src/tests/tester/foodie_tester.f90 @@ -28,6 +28,7 @@ module foodie_test_object integrator_runge_kutta_ssp, & is_available, is_class_available use foodie_test_integrand_ladvection, only : integrand_ladvection +use foodie_test_integrand_oscillation, only : integrand_oscillation use penf, only : I_P, R_P, FR_P, str, strz implicit none @@ -54,6 +55,7 @@ module foodie_test_object character(99) :: output='' !< Output files basename. logical :: verbose=.false. !< Flag for activating verbose output. type(integrand_ladvection) :: ladvection_0 !< Initial conditions for linear advection test. + type(integrand_oscillation) :: oscillation_0 !< Initial conditions for oscillation test. class(integrand_object), allocatable :: integrand_0 !< Initial conditions. contains ! public methods @@ -120,7 +122,7 @@ subroutine set_cli() examples = ["foodie_tester --scheme euler_explicit --save_results ", & "foodie_tester --scheme all -r "]) call cli%add(switch='--test', switch_ab='-t', help='test executed', required=.false., def='linear_advection', & - act='store', choices='linear_advection') + act='store', choices='linear_advection,oscillation') call cli%add(switch='--scheme', switch_ab='-s', help='integrator scheme used', required=.false., def='all', act='store') call cli%add(switch='--fast', help='activate fast solvers', required=.false., act='store_true', def='.false.') call cli%add(switch='--iterations', help='iterations number for implicit schemes', required=.false., act='store', def='5') @@ -132,6 +134,7 @@ subroutine set_cli() call cli%add(switch='--verbose', help='Verbose output', required=.false., act='store_true', def='.false.') endassociate call self%ladvection_0%set_cli(cli=self%cli) + call self%oscillation_0%set_cli(cli=self%cli) endsubroutine set_cli subroutine parse_cli() @@ -153,11 +156,15 @@ subroutine parse_cli() call self%cli%get(switch='--output', val=self%output, error=self%error) ; if (self%error/=0) stop call self%cli%get(switch='--verbose', val=self%verbose, error=self%error) ; if (self%error/=0) stop call self%ladvection_0%parse_cli(cli=self%cli) + call self%oscillation_0%parse_cli(cli=self%cli) select case(trim(adjustl(self%test))) case('linear_advection') allocate(integrand_ladvection :: self%integrand_0) self%integrand_0 = self%ladvection_0 + case('oscillation') + allocate(integrand_oscillation :: self%integrand_0) + self%integrand_0 = self%oscillation_0 endselect if (self%final_time > 0._R_P) self%final_step = 0 @@ -259,6 +266,9 @@ subroutine integrate(scheme, integrand_0, final_step, final_time, iterations, st type is(integrand_ladvection) Dt = integrand%dt(final_step=final_step, final_time=final_time, t=0._R_P) if (save_results) call integrand%export_tecplot(file_name=output_file_name, t=time(0), scheme=scheme) + type is(integrand_oscillation) + Dt = integrand%dt + if (save_results) call integrand%export_tecplot(file_name=output_file_name, t=time(0), scheme=scheme) endselect select type(integrator) @@ -404,6 +414,9 @@ subroutine integrate(scheme, integrand_0, final_step, final_time, iterations, st type is(integrand_ladvection) if (save_results) call integrand%export_tecplot(t=time(step_offset), scheme=scheme) if (save_results) call integrand%export_tecplot(close_file=.true.) + type is(integrand_oscillation) + if (save_results) call integrand%export_tecplot(t=time(step_offset), scheme=scheme) + if (save_results) call integrand%export_tecplot(close_file=.true.) endselect contains subroutine update_previous_times From 701357ed4e82c18d28b9abefdd40774d9e979046 Mon Sep 17 00:00:00 2001 From: Stefano Zaghi Date: Wed, 17 May 2017 18:45:48 +0200 Subject: [PATCH 11/25] enable oscillation test into generic tester --- .../foodie_test_integrand_ladvection.f90 | 13 +- .../foodie_test_integrand_oscillation.f90 | 67 +++-- src/tests/tester/foodie_tester.f90 | 232 +++++++++++------- 3 files changed, 180 insertions(+), 132 deletions(-) diff --git a/src/tests/tester/foodie_test_integrand_ladvection.f90 b/src/tests/tester/foodie_test_integrand_ladvection.f90 index 9c7fd876..78c9fb11 100644 --- a/src/tests/tester/foodie_test_integrand_ladvection.f90 +++ b/src/tests/tester/foodie_test_integrand_ladvection.f90 @@ -107,17 +107,16 @@ pure subroutine destroy(self) self = fresh endsubroutine destroy - pure function compute_dt(self, final_step, final_time, t) result(Dt) + pure function compute_dt(self, final_time, t) result(Dt) !< Compute the current time step by means of CFL condition. - class(integrand_ladvection), intent(in) :: self !< Advection field. - integer(I_P), intent(in) :: final_step !< Maximun number of time steps. - real(R_P), intent(in) :: final_time !< Maximum integration time. - real(R_P), intent(in) :: t !< Time. - real(R_P) :: Dt !< Time step. + class(integrand_ladvection), intent(in) :: self !< Advection field. + real(R_P), intent(in) :: final_time !< Maximum integration time. + real(R_P), intent(in), optional :: t !< Time. + real(R_P) :: Dt !< Time step. associate(a=>self%a, Ni=>self%Ni, Dx=>self%Dx, CFL=>self%CFL) Dt = Dx * CFL / abs(a) - if (final_step <= 0 .and. final_time > 0._R_P) then + if (present(t)) then if ((t + Dt) > final_time) Dt = final_time - t endif endassociate diff --git a/src/tests/tester/foodie_test_integrand_oscillation.f90 b/src/tests/tester/foodie_test_integrand_oscillation.f90 index 9aaf3364..787c872c 100644 --- a/src/tests/tester/foodie_test_integrand_oscillation.f90 +++ b/src/tests/tester/foodie_test_integrand_oscillation.f90 @@ -5,7 +5,7 @@ module foodie_test_integrand_oscillation use flap, only : command_line_interface use foodie, only : integrand_object -use penf, only : R_P, I_P, str +use penf, only : FR_P, R_P, I_P, str implicit none private @@ -43,18 +43,18 @@ module foodie_test_integrand_oscillation !<#### State variables organization !< State variables are organized as an array (rank 1) of reals of *n=2* elements. private - real(R_P), public :: Dt=0._R_P !< Time step. - real(R_P) :: f=0._R_P !< Oscillation frequency (Hz). - real(R_P) :: U(1:2)=[0._R_P, 0._R_P] !< Integrand (state) variables. - real(R_P) :: U0(1:2)=[0._R_P, 0._R_P] !< Initial state. + real(R_P) :: f=0._R_P !< Oscillation frequency (Hz). + real(R_P) :: U0(1:2)=[0._R_P, 0._R_P] !< Initial state. + real(R_P) :: U(1:2)=[0._R_P, 0._R_P] !< Integrand (state) variables. contains ! auxiliary methods - procedure, pass(self), public :: exact_solution !< Return exact solution. - procedure, pass(self), public :: export_tecplot !< Export integrand to Tecplot file. - procedure, pass(self), public :: initialize !< Initialize integrand. - procedure, pass(self), public :: output !< Extract integrand state field. - procedure, pass(self), public :: parse_cli !< Initialize from command line interface. - procedure, nopass, public :: set_cli !< Set command line interface. + procedure, pass(self), public :: amplitude_phase !< Return amplitude and phase of the oscillation. + procedure, pass(self), public :: exact_solution !< Return exact solution. + procedure, pass(self), public :: export_tecplot !< Export integrand to Tecplot file. + procedure, pass(self), public :: initialize !< Initialize integrand. + procedure, pass(self), public :: output !< Extract integrand state field. + procedure, pass(self), public :: parse_cli !< Initialize from command line interface. + procedure, nopass, public :: set_cli !< Set command line interface. ! public deferred methods procedure, pass(self), public :: integrand_dimension !< Return integrand dimension. procedure, pass(self), public :: t => dU_dt !< Time derivative, residuals. @@ -87,6 +87,15 @@ module foodie_test_integrand_oscillation contains ! auxiliary methods + function amplitude_phase(self) result(ap) + !< Compute amplitude and phase of the oscillation. + class(integrand_oscillation), intent(in) :: self !< Advection field. + real(R_P) :: ap(1:2) !< Amplitude and phase. + + ap(1) = sqrt(self%U(1)**2 + self%U(2)**2) + ap(2) = atan(-self%U(1) / self%U(2)) + endfunction amplitude_phase + pure function exact_solution(self, t) result(exact) !< Return exact solution. class(integrand_oscillation), intent(in) :: self !< Integrand. @@ -118,13 +127,13 @@ subroutine export_tecplot(self, file_name, t, scheme, close_file) if (is_open) close(unit=file_unit) open(newunit=file_unit, file=trim(adjustl(file_name))) is_open = .true. - ! write(unit=file_unit, fmt='(A)') 'VARIABLES="x" "u"' + write(unit=file_unit, fmt='(A)') 'VARIABLES="t" "x" "y" "amplitude" "phase"' endif if (present(t) .and. present(scheme) .and. is_open) then - write(unit=file_unit, fmt='(A)') 'ZONE T="'//str(t)//' '//trim(adjustl(scheme))//'"' - ! do i=1, self%Ni - ! write(unit=file_unit, fmt='(2('//FR_P//',1X))') self%Dx * i - 0.5_R_P * self%Dx, self%u(i) - ! enddo + write(unit=file_unit, fmt='(A)') 'ZONE T="'//trim(adjustl(scheme))//'"' + write(unit=file_unit, fmt='(5('//FR_P//',1X))') t, self%U, self%amplitude_phase() + elseif (present(t) .and. is_open) then + write(unit=file_unit, fmt='(5('//FR_P//',1X))') t, self%U, self%amplitude_phase() endif endif endsubroutine export_tecplot @@ -154,30 +163,17 @@ subroutine parse_cli(self, cli) type(command_line_interface), intent(inout) :: cli !< Command line interface handler. character(99) :: initial_state !< Initial state. - ! call cli%get(switch='--cfl', val=self%CFL, error=cli%error) ; if (cli%error/=0) stop - ! call cli%get(switch='--w-scheme', val=self%w_scheme, error=cli%error) ; if (cli%error/=0) stop - ! call cli%get(switch='--weno-order', val=self%weno_order, error=cli%error) ; if (cli%error/=0) stop - ! call cli%get(switch='--weno-eps', val=self%weno_eps, error=cli%error) ; if (cli%error/=0) stop - ! call cli%get(switch='-a', val=self%a, error=cli%error) ; if (cli%error/=0) stop - ! call cli%get(switch='--length', val=self%length, error=cli%error) ; if (cli%error/=0) stop - ! call cli%get(switch='--Ni', val=self%Ni, error=cli%error) ; if (cli%error/=0) stop - ! call cli%get(switch='-is', val=initial_state, error=cli%error) ; if (cli%error/=0) stop + call cli%get(switch='-f', val=self%f, error=cli%error) ; if (cli%error/=0) stop + call cli%get(switch='-U0', val=self%U0, error=cli%error) ; if (cli%error/=0) stop + self%U = self%U0 endsubroutine parse_cli subroutine set_cli(cli) !< Set command line interface. type(command_line_interface), intent(inout) :: cli !< Command line interface handler. - ! call cli%add(switch='--w-scheme', help='WENO scheme', required=.false., act='store', def='reconstructor-JS', & - ! choices='reconstructor-JS,reconstructor-M-JS,reconstructor-M-Z,reconstructor-Z') - ! call cli%add(switch='--weno-order', help='WENO order', required=.false., act='store', def='1') - ! call cli%add(switch='--weno-eps', help='WENO epsilon parameter', required=.false., act='store', def='0.000001') - ! call cli%add(switch='--cfl', help='CFL value', required=.false., act='store', def='0.8') - ! call cli%add(switch='-a', help='advection coefficient', required=.false., act='store', def='1.0') - ! call cli%add(switch='--length', help='domain lenth', required=.false., act='store', def='1.0') - ! call cli%add(switch='--Ni', help='number finite volumes used', required=.false., act='store', def='100') - ! call cli%add(switch='--initial_state', switch_ab='-is', help='initial state', required=.false., act='store', & - ! def='square_wave', choices='square_wave') + call cli%add(switch='--frequency', switch_ab='-f', help='frequency', required=.false., def='1e-4', act='store') + call cli%add(switch='--U0', switch_ab='-U0', nargs='2', help='initial state', required=.false., def='0.0 1.0', act='store') endsubroutine set_cli ! deferred methods @@ -339,10 +335,9 @@ pure subroutine assign_integrand(lhs, rhs) select type(rhs) class is(integrand_oscillation) - lhs%U = rhs%U lhs%f = rhs%f lhs%U0 = rhs%U0 - lhs%Dt = rhs%Dt + lhs%U = rhs%U endselect endsubroutine assign_integrand diff --git a/src/tests/tester/foodie_tester.f90 b/src/tests/tester/foodie_tester.f90 index 60307fb9..8f925dc8 100644 --- a/src/tests/tester/foodie_tester.f90 +++ b/src/tests/tester/foodie_tester.f90 @@ -42,21 +42,22 @@ module foodie_test_object !< !< Test has only 1 public method `execute`: it executes test(s) accordingly to cli options. private - type(command_line_interface) :: cli !< Command line interface handler. - integer(I_P) :: error=0 !< Error handler. - character(99) :: test='' !< Test executed. - character(99) :: scheme='' !< Scheme used. - logical :: is_fast=.false. !< Flag for activating fast schemes. - integer(I_P) :: implicit_iterations=0 !< Number of iterations (implicit solvers). - integer(I_P) :: stages=0 !< Number of stages. - integer(I_P) :: final_step=0 !< Maximum number of time steps. - real(R_P) :: final_time=0._R_P !< Final integration time. - logical :: save_results=.false. !< Flag for activating results saving. - character(99) :: output='' !< Output files basename. - logical :: verbose=.false. !< Flag for activating verbose output. - type(integrand_ladvection) :: ladvection_0 !< Initial conditions for linear advection test. - type(integrand_oscillation) :: oscillation_0 !< Initial conditions for oscillation test. - class(integrand_object), allocatable :: integrand_0 !< Initial conditions. + type(command_line_interface) :: cli !< Command line interface handler. + integer(I_P) :: error !< Error handler. + character(99) :: test !< Test executed. + character(99) :: scheme !< Scheme used. + real(R_P), allocatable :: Dt(:) !< Time step(s) exercised. + logical :: is_fast !< Flag for activating fast schemes. + integer(I_P) :: implicit_iterations !< Number of iterations (implicit solvers). + integer(I_P) :: stages !< Number of stages. + real(R_P) :: final_time !< Final integration time. + logical :: save_results !< Flag for activating results saving. + character(99) :: output !< Output files basename. + integer(I_P) :: save_frequency !< Save frequency. + logical :: verbose !< Flag for activating verbose output. + type(integrand_ladvection) :: ladvection_0 !< Initial conditions for linear advection test. + type(integrand_oscillation) :: oscillation_0 !< Initial conditions for oscillation test. + class(integrand_object), allocatable :: integrand_0 !< Initial conditions. contains ! public methods procedure, pass(self) :: execute !< Execute selected test(s). @@ -72,6 +73,7 @@ subroutine execute(self) character(99), allocatable :: integrator_schemes(:) !< Name of FOODIE integrator schemes. character(len=:), allocatable :: output_file_name !< File name of output results file. integer(I_P) :: s !< Counter. + integer(I_P) :: t !< Counter. call self%initialize if (trim(adjustl(self%scheme))/='all') then @@ -84,22 +86,31 @@ subroutine execute(self) integrator_schemes = foodie_integrator_schemes() endif do s=1, size(integrator_schemes, dim=1) - select type(integrand=>self%integrand_0) - type is(integrand_ladvection) - output_file_name = trim(adjustl(self%output))//'-'//& - trim(adjustl(self%test))//'-'//& - trim(adjustl(integrator_schemes(s)))//'-'//& - trim(strz(integrand%Ni, 10))//'.dat' - endselect - call integrate(scheme=trim(integrator_schemes(s)), & - integrand_0=self%integrand_0, & - final_step=self%final_step, & - final_time=self%final_time, & - iterations=self%implicit_iterations, & - stages=self%stages, & - is_fast=self%is_fast, & - save_results=self%save_results, & - output_file_name=output_file_name) + do t=1, size(self%Dt) + select type(integrand=>self%integrand_0) + type is(integrand_ladvection) + output_file_name = trim(adjustl(self%output))//'-'//& + trim(adjustl(self%test))//'-'//& + trim(adjustl(integrator_schemes(s)))//'-'//& + trim(strz(integrand%Ni, 10))//'-steps_'//& + trim(strz(int(self%final_time/self%Dt(t)), 10))//'.dat' + type is(integrand_oscillation) + output_file_name = trim(adjustl(self%output))//'-'//& + trim(adjustl(self%test))//'-'//& + trim(adjustl(integrator_schemes(s)))//'-steps_'//& + trim(strz(int(self%final_time/self%Dt(t)), 10))//'.dat' + endselect + call integrate(scheme=trim(integrator_schemes(s)), & + integrand_0=self%integrand_0, & + Dt=self%Dt(t), & + final_time=self%final_time, & + iterations=self%implicit_iterations, & + stages=self%stages, & + is_fast=self%is_fast, & + save_results=self%save_results, & + output_file_name=output_file_name, & + save_frequency=self%save_frequency) + enddo enddo endsubroutine execute @@ -124,13 +135,14 @@ subroutine set_cli() call cli%add(switch='--test', switch_ab='-t', help='test executed', required=.false., def='linear_advection', & act='store', choices='linear_advection,oscillation') call cli%add(switch='--scheme', switch_ab='-s', help='integrator scheme used', required=.false., def='all', act='store') + call cli%add(switch='--time_step', switch_ab='-Dt', nargs='+', help='time step', required=.false., def='1e2', act='store') call cli%add(switch='--fast', help='activate fast solvers', required=.false., act='store_true', def='.false.') call cli%add(switch='--iterations', help='iterations number for implicit schemes', required=.false., act='store', def='5') call cli%add(switch='--stages', help='stages number', required=.false., def='2', act='store') - call cli%add(switch='--final_step', switch_ab='-fs', help='integration steps', required=.false., act='store', def='100') - call cli%add(switch='--final_time', switch_ab='-ft', help='integration time', required=.false., def='0', act='store') + call cli%add(switch='--final_time', switch_ab='-ft', help='integration time', required=.false., def='1', act='store') call cli%add(switch='--save_results', switch_ab='-r',help='save result', required=.false., act='store_true', def='.false.') call cli%add(switch='--output', help='output file basename', required=.false., act='store', def='foodie_test') + call cli%add(switch='--save_frequency', help='save frequency', required=.false., act='store', def='1') call cli%add(switch='--verbose', help='Verbose output', required=.false., act='store_true', def='.false.') endassociate call self%ladvection_0%set_cli(cli=self%cli) @@ -147,13 +159,14 @@ subroutine parse_cli() call self%cli%parse(error=self%error) call self%cli%get(switch='-t', val=self%test, error=self%error) ; if (self%error/=0) stop call self%cli%get(switch='-s', val=self%scheme, error=self%error) ; if (self%error/=0) stop + call self%cli%get_varying(switch='-Dt', val=self%Dt, error=self%error) ; if (self%error/=0) stop call self%cli%get(switch='--fast', val=self%is_fast, error=self%error) ; if (self%error/=0) stop call self%cli%get(switch='--iterations', val=self%implicit_iterations, error=self%error) ; if (self%error/=0) stop call self%cli%get(switch='--stages', val=self%stages, error=self%error) ; if (self%error/=0) stop - call self%cli%get(switch='-fs', val=self%final_step, error=self%error) ; if (self%error/=0) stop call self%cli%get(switch='-ft', val=self%final_time, error=self%error) ; if (self%error/=0) stop call self%cli%get(switch='-r', val=self%save_results, error=self%error) ; if (self%error/=0) stop call self%cli%get(switch='--output', val=self%output, error=self%error) ; if (self%error/=0) stop + call self%cli%get(switch='--save_frequency', val=self%save_frequency, error=self%error) ; if (self%error/=0) stop call self%cli%get(switch='--verbose', val=self%verbose, error=self%error) ; if (self%error/=0) stop call self%ladvection_0%parse_cli(cli=self%cli) call self%oscillation_0%parse_cli(cli=self%cli) @@ -167,25 +180,52 @@ subroutine parse_cli() self%integrand_0 = self%oscillation_0 endselect - if (self%final_time > 0._R_P) self%final_step = 0 + if (.not.is_dt_valid()) then + write(stderr, '(A)') 'error: the final integration time must be an exact multiple of the time step used' + write(stderr, '(A)') ' and time step must respect CFL condition, if any' + write(stderr, '(A)') 'Final integration time: '//str(self%final_time, .true.) + write(stderr, '(A)') 'Time step: '//str(self%Dt, .true.) + stop + endif if (trim(adjustl(self%scheme)) /= 'all') then if (.not.is_available(scheme=self%scheme)) then integrator_class_names = foodie_integrator_class_names() integrator_schemes = foodie_integrator_schemes() - print '(A)', 'Error: the scheme "'//trim(adjustl(self%scheme))//'" is unknown!' - print '(A)', 'Supported classes of schemes are:' + write(stderr, '(A)') 'error: the scheme "'//trim(adjustl(self%scheme))//'" is unknown!' + write(stderr, '(A)') 'Supported classes of schemes are:' do i=1, size(integrator_class_names, dim=1) - print '(A)', ' '//trim(integrator_class_names(i)) + write(stderr, '(A)') ' '//trim(integrator_class_names(i)) enddo - print '(A)', 'Supported schemes are:' + write(stderr, '(A)') 'Supported schemes are:' do i=1, size(integrator_schemes, dim=1) - print '(A)', ' '//trim(integrator_schemes(i)) + write(stderr, '(A)') ' '//trim(integrator_schemes(i)) enddo stop endif endif endsubroutine parse_cli + + function is_dt_valid() + !< Verify if the selected time step Dt is valid. + logical :: is_dt_valid !< Return true is the selected time step Dt is valid. + integer(I_P) :: t !< Counter. + + is_dt_valid = .true. + do t=1, size(self%Dt) + is_dt_valid = ((self%final_time - int(self%final_time/self%Dt(t), I_P)*self%Dt(t))==0) + if (is_dt_valid) then + select type(integrand=>self%integrand_0) + type is(integrand_ladvection) + is_dt_valid = is_dt_valid .and. self%Dt(t) <= integrand%Dt(final_time=self%final_time) + if (.not.is_dt_valid) then + write(stderr, '(A)') 'error: Dt violates CFL condition, Dt_max = '//str(integrand%Dt(final_time=self%final_time)) + endif + endselect + endif + if (.not.is_dt_valid) exit + enddo + endfunction is_dt_valid endsubroutine initialize ! non type bound procedures @@ -200,17 +240,19 @@ subroutine check_scheme_has_fast_mode(scheme, integrator) endif endsubroutine check_scheme_has_fast_mode - subroutine integrate(scheme, integrand_0, final_step, final_time, iterations, stages, is_fast, save_results, output_file_name) + subroutine integrate(scheme, integrand_0, Dt, final_time, iterations, stages, is_fast, save_results, output_file_name, & + save_frequency) !< Integrate integrand by means of the given scheme. character(*), intent(in) :: scheme !< Selected scheme. class(integrand_object), intent(in) :: integrand_0 !< Initial conditions. - integer(I_P), intent(in) :: final_step !< Final integration step. + real(R_P), intent(in) :: Dt !< Time step. real(R_P), intent(in) :: final_time !< Final integration time. integer(I_P), intent(in) :: iterations !< Number of fixed point iterations. integer(I_P), intent(in) :: stages !< Number of stages. logical, intent(in) :: is_fast !< Activate fast mode integration. logical, intent(in) :: save_results !< Save results. character(*), intent(in) :: output_file_name !< File name of output results file. + integer(I_P), intent(in) :: save_frequency !< Save frequency. class(integrator_object), allocatable :: integrator !< The integrator. type(integrator_runge_kutta_ssp) :: integrator_start !< The (auto) start integrator. class(integrand_object), allocatable :: integrand !< Integrand. @@ -220,8 +262,7 @@ subroutine integrate(scheme, integrand_0, final_step, final_time, iterations, st class(integrand_object), allocatable :: buffer !< Buffer oscillation field. class(integrand_object), allocatable :: filter !< Filter displacement. real(R_P), allocatable :: time(:) !< Time. - real(R_P), allocatable :: Dt(:) !< Time steps. - real(R_P) :: Dt_a !< Autoadptive time step. + real(R_P), allocatable :: Dts(:) !< Time steps. integer(I_P) :: step !< Time steps counter. integer(I_P) :: step_offset !< Time steps counter offset for slicing previous data array. integer(I_P) :: s !< Counter. @@ -258,16 +299,13 @@ subroutine integrate(scheme, integrand_0, final_step, final_time, iterations, st enddo endif allocate(time(0:step_offset)) - allocate(Dt(1:step_offset)) step = 0 time = 0._R_P select type(integrand) type is(integrand_ladvection) - Dt = integrand%dt(final_step=final_step, final_time=final_time, t=0._R_P) if (save_results) call integrand%export_tecplot(file_name=output_file_name, t=time(0), scheme=scheme) type is(integrand_oscillation) - Dt = integrand%dt if (save_results) call integrand%export_tecplot(file_name=output_file_name, t=time(0), scheme=scheme) endselect @@ -276,30 +314,32 @@ subroutine integrate(scheme, integrand_0, final_step, final_time, iterations, st do step = step + 1 if (is_fast) then - call integrator%integrate_fast(U=integrand, stage=stage, buffer=buffer, Dt=Dt(step_offset), t=time(step_offset)) + call integrator%integrate_fast(U=integrand, stage=stage, buffer=buffer, Dt=Dt, t=time(step_offset)) else - call integrator%integrate(U=integrand, stage=stage, Dt=Dt(step_offset), t=time(step_offset)) + call integrator%integrate(U=integrand, stage=stage, Dt=Dt, t=time(step_offset)) endif call update_previous_times - if ((time(step_offset) >= final_time).or.(step == final_step)) exit + if ((time(step_offset) >= final_time)) exit + call integrand_export_tecplot enddo class is(integrator_multistep_explicit_object) do step = step + 1 if (integrator%steps_number() >= step) then - call integrator_start%integrate(U=integrand, stage=stage_start, Dt=Dt(step), t=time(step)) + call integrator_start%integrate(U=integrand, stage=stage_start, Dt=Dt, t=time(step)) previous(step) = integrand - time(step) = time(step-1) + Dt(step) + time(step) = time(step-1) + Dt else if (is_fast) then - call integrator%integrate_fast(U=integrand, previous=previous, buffer=buffer, Dt=Dt(step_offset), t=time) + call integrator%integrate_fast(U=integrand, previous=previous, buffer=buffer, Dt=Dt, t=time) else - call integrator%integrate(U=integrand, previous=previous, Dt=Dt(step_offset), t=time) + call integrator%integrate(U=integrand, previous=previous, Dt=Dt, t=time) endif call update_previous_times endif - if ((time(step_offset) >= final_time).or.(step == final_step)) exit + if ((time(step_offset) >= final_time)) exit + call integrand_export_tecplot enddo class is(integrator_multistep_implicit_object) @@ -310,103 +350,109 @@ subroutine integrate(scheme, integrand_0, final_step, final_time, iterations, st do step = step + 1 if (integrator%steps_number() >= step) then - call integrator_start%integrate(U=integrand, stage=stage_start, Dt=Dt(step), t=time(step)) + call integrator_start%integrate(U=integrand, stage=stage_start, Dt=Dt, t=time(step)) previous(step) = integrand - time(step) = time(step-1) + Dt(step) + time(step) = time(step-1) + Dt else if (is_fast) then if (iterations>1) then - call integrator%integrate_fast(U=integrand, previous=previous, buffer=buffer, Dt=Dt(step), t=time, & + call integrator%integrate_fast(U=integrand, previous=previous, buffer=buffer, Dt=Dt, t=time, & iterations=iterations) else - call integrator%integrate_fast(U=integrand, previous=previous, buffer=buffer, Dt=Dt(step), t=time) + call integrator%integrate_fast(U=integrand, previous=previous, buffer=buffer, Dt=Dt, t=time) endif else if (iterations>1) then - call integrator%integrate(U=integrand, previous=previous, Dt=Dt(step_offset), t=time, iterations=iterations) + call integrator%integrate(U=integrand, previous=previous, Dt=Dt, t=time, iterations=iterations) else - call integrator%integrate(U=integrand, previous=previous, Dt=Dt(step_offset), t=time) + call integrator%integrate(U=integrand, previous=previous, Dt=Dt, t=time) endif endif call update_previous_times endif - if ((time(step_offset) >= final_time).or.(step == final_step)) exit + if ((time(step_offset) >= final_time)) exit + call integrand_export_tecplot enddo type is(integrator_euler_explicit) do step = step + 1 if (is_fast) then - call integrator%integrate_fast(U=integrand, buffer=buffer, Dt=Dt(step_offset), t=time(step_offset)) + call integrator%integrate_fast(U=integrand, buffer=buffer, Dt=Dt, t=time(step_offset)) else - call integrator%integrate(U=integrand, Dt=Dt(step_offset), t=time(step_offset)) + call integrator%integrate(U=integrand, Dt=Dt, t=time(step_offset)) endif call update_previous_times - if ((time(step_offset) == final_time).or.(step == final_step)) exit + if ((time(step_offset) >= final_time)) exit + call integrand_export_tecplot enddo type is(integrator_leapfrog) do step = step + 1 if (integrator%steps_number() >= step) then - call integrator_start%integrate(U=integrand, stage=stage_start, Dt=Dt(step), t=time(step)) + call integrator_start%integrate(U=integrand, stage=stage_start, Dt=Dt, t=time(step)) previous(step) = integrand - time(step) = time(step-1) + Dt(step) + time(step) = time(step-1) + Dt else if (index(scheme, 'raw') > 0 ) then if (is_fast) then - call integrator%integrate_fast(U=integrand, previous=previous, buffer=buffer, Dt=Dt(step_offset), & - t=time(step_offset), filter=filter) + call integrator%integrate_fast(U=integrand, previous=previous, buffer=buffer, Dt=Dt, t=time(step_offset), & + filter=filter) else - call integrator%integrate(U=integrand, previous=previous, Dt=Dt(step_offset), t=time(step_offset), filter=filter) + call integrator%integrate(U=integrand, previous=previous, Dt=Dt, t=time(step_offset), filter=filter) endif else if (is_fast) then - call integrator%integrate_fast(U=integrand, previous=previous, buffer=buffer, Dt=Dt(step_offset), & - t=time(step_offset)) + call integrator%integrate_fast(U=integrand, previous=previous, buffer=buffer, Dt=Dt, t=time(step_offset)) else - call integrator%integrate(U=integrand, previous=previous, Dt=Dt(step_offset), t=time(step_offset)) + call integrator%integrate(U=integrand, previous=previous, Dt=Dt, t=time(step_offset)) endif endif call update_previous_times endif - if ((time(step_offset) == final_time).or.(step == final_step)) exit + if ((time(step_offset) >= final_time)) exit + call integrand_export_tecplot enddo type is(integrator_lmm_ssp_vss) + allocate(Dts(1:step_offset)) + Dts = Dt do step = step + 1 if (integrator%steps_number() >= step) then - call integrator_start%integrate(U=integrand, stage=stage_start, Dt=Dt(step), t=time(step)) + call integrator_start%integrate(U=integrand, stage=stage_start, Dt=Dt, t=time(step)) previous(step) = integrand - time(step) = time(step-1) + Dt(step) + time(step) = time(step-1) + Dt else if (is_fast) then - call integrator%integrate_fast(U=integrand, previous=previous, buffer=buffer, Dt=Dt, t=time) + call integrator%integrate_fast(U=integrand, previous=previous, buffer=buffer, Dt=Dts, t=time) else - call integrator%integrate(U=integrand, previous=previous, Dt=Dt, t=time) + call integrator%integrate(U=integrand, previous=previous, Dt=Dts, t=time) endif call update_previous_times endif - if ((time(step) == final_time).or.(step == final_step)) exit + if ((time(step) >= final_time)) exit + call integrand_export_tecplot enddo type is(integrator_ms_runge_kutta_ssp) do step = step + 1 if (integrator%steps_number() >= step) then - call integrator_start%integrate(U=integrand, stage=stage_start, Dt=Dt(step), t=time(step)) + call integrator_start%integrate(U=integrand, stage=stage_start, Dt=Dt, t=time(step)) previous(step) = integrand - time(step) = time(step-1) + Dt(step) + time(step) = time(step-1) + Dt else if (is_fast) then - call integrator%integrate_fast(U=integrand, previous=previous, stage=stage, buffer=buffer, Dt=Dt(step_offset),t=time) + call integrator%integrate_fast(U=integrand, previous=previous, stage=stage, buffer=buffer, Dt=Dt,t=time) else - call integrator%integrate(U=integrand, previous=previous, stage=stage, Dt=Dt(step_offset), t=time) + call integrator%integrate(U=integrand, previous=previous, stage=stage, Dt=Dt, t=time) endif call update_previous_times endif - if ((time(step) == final_time).or.(step == final_step)) exit + if ((time(step) >= final_time)) exit + call integrand_export_tecplot enddo endselect @@ -415,20 +461,28 @@ subroutine integrate(scheme, integrand_0, final_step, final_time, iterations, st if (save_results) call integrand%export_tecplot(t=time(step_offset), scheme=scheme) if (save_results) call integrand%export_tecplot(close_file=.true.) type is(integrand_oscillation) - if (save_results) call integrand%export_tecplot(t=time(step_offset), scheme=scheme) + if (save_results) call integrand%export_tecplot(t=time(step_offset)) if (save_results) call integrand%export_tecplot(close_file=.true.) endselect contains + subroutine integrand_export_tecplot + !< Export current integrand solution to tecplot file. + + select type(integrand) + type is(integrand_ladvection) + if (save_results .and. mod(step, save_frequency)==0) call integrand%export_tecplot(t=time(step_offset), scheme=scheme) + type is(integrand_oscillation) + if (save_results .and. mod(step, save_frequency)==0) call integrand%export_tecplot(t=time(step_offset)) + endselect + endsubroutine integrand_export_tecplot + subroutine update_previous_times !< Update previous times. real(R_P) :: temporary !< Temporary buffer. integer(I_P) :: p !< Counter. - do p=1, step_offset - 1 - Dt(p) = Dt(p + 1) - enddo temporary = time(step_offset) - time(step_offset) = time(step_offset) + Dt(step_offset) + time(step_offset) = time(step_offset) + Dt do p=0, step_offset - 2 time(p) = time(p + 1) enddo From 008a00f09eeea6268d6a75b1a1490ea528644468 Mon Sep 17 00:00:00 2001 From: Stefano Zaghi Date: Fri, 19 May 2017 14:58:48 +0200 Subject: [PATCH 12/25] start stage/step/buffer entailing, not compile this! --- ..._integrator_multistage_explicit_object.f90 | 35 +-- ...foodie_integrator_runge_kutta_embedded.f90 | 168 +++++++------ ...die_integrator_runge_kutta_low_storage.f90 | 84 ++++--- .../foodie_integrator_runge_kutta_lssp.f90 | 232 +++++++++--------- 4 files changed, 260 insertions(+), 259 deletions(-) diff --git a/src/lib/foodie_integrator_multistage_explicit_object.f90 b/src/lib/foodie_integrator_multistage_explicit_object.f90 index bd6f88a0..c55fb015 100644 --- a/src/lib/foodie_integrator_multistage_explicit_object.f90 +++ b/src/lib/foodie_integrator_multistage_explicit_object.f90 @@ -14,7 +14,10 @@ module foodie_integrator_multistage_explicit_object type, extends(integrator_object), abstract :: integrator_multistage_explicit_object !< Abstract type of FOODIE ODE integrators of the multistage family. - integer(I_P) :: stages=0 !< Number of stages. + integer(I_P) :: registers !< Number of registers used for stages. + integer(I_P) :: stages !< Number of stages. + class(integrand_object), allocatable :: stage(:) !< Stages. + class(integrand_object), allocatable :: buffer !< Buffer used for fast integration. contains ! deferred methods procedure(integrate_interface), pass(self), deferred :: integrate !< Integrate integrand field. @@ -30,27 +33,24 @@ module foodie_integrator_multistage_explicit_object abstract interface !< Abstract interfaces of deferred methods of [[integrator_object]]. - subroutine integrate_interface(self, U, stage, Dt, t, new_Dt) + subroutine integrate_interface(self, U, Dt, t, new_Dt) !< Integrate integrand field. import :: integrand_object, integrator_multistage_explicit_object, R_P - class(integrator_multistage_explicit_object), intent(in) :: self !< Integrator. - class(integrand_object), intent(inout) :: U !< Integrand. - class(integrand_object), intent(inout) :: stage(1:) !< Runge-Kutta stages. - real(R_P), intent(in) :: Dt !< Time step. - real(R_P), intent(in) :: t !< Time. - real(R_P), optional, intent(out) :: new_Dt !< New adapted time step. + class(integrator_multistage_explicit_object), intent(inout) :: self !< Integrator. + class(integrand_object), intent(inout) :: U !< Integrand. + real(R_P), intent(in) :: Dt !< Time step. + real(R_P), intent(in) :: t !< Time. + real(R_P), intent(out), optional :: new_Dt !< New adapted time step. endsubroutine integrate_interface - subroutine integrate_fast_interface(self, U, stage, buffer, Dt, t, new_Dt) + subroutine integrate_fast_interface(self, U, Dt, t, new_Dt) !< Integrate integrand field, fast mode. import :: integrand_object, integrator_multistage_explicit_object, R_P - class(integrator_multistage_explicit_object), intent(in) :: self !< Integrator. - class(integrand_object), intent(inout) :: U !< Field to be integrated. - class(integrand_object), intent(inout) :: stage(1:) !< Runge-Kutta stages. - class(integrand_object), intent(inout) :: buffer !< Temporary buffer for doing fast operation. - real(R_P), intent(in) :: Dt !< Time step. - real(R_P), intent(in) :: t !< Time. - real(R_P), optional, intent(out) :: new_Dt !< New adapted time step. + class(integrator_multistage_explicit_object), intent(inout) :: self !< Integrator. + class(integrand_object), intent(inout) :: U !< Field to be integrated. + real(R_P), intent(in) :: Dt !< Time step. + real(R_P), intent(in) :: t !< Time. + real(R_P), intent(out), optional :: new_Dt !< New adapted time step. endsubroutine integrate_fast_interface endinterface @@ -94,6 +94,9 @@ elemental subroutine destroy_multistage(self) class(integrator_multistage_explicit_object), intent(inout) :: self !< Integrator. call self%destroy_abstract + self%registers = 0 self%stages = 0 + if (allocated(self%stage)) deallocate(self%stage) + if (allocated(self%buffer)) deallocate(self%buffer) endsubroutine destroy_multistage endmodule foodie_integrator_multistage_explicit_object diff --git a/src/lib/foodie_integrator_runge_kutta_embedded.f90 b/src/lib/foodie_integrator_runge_kutta_embedded.f90 index 85bcf49c..d4da17b4 100644 --- a/src/lib/foodie_integrator_runge_kutta_embedded.f90 +++ b/src/lib/foodie_integrator_runge_kutta_embedded.f90 @@ -291,11 +291,13 @@ module foodie_integrator_runge_kutta_emd !< !< @note The integrator must be created or initialized (initialize the RK coefficients) before used. private - real(R_P) :: tolerance=0._R_P !< Tolerance on the local truncation error. - real(R_P) :: pp1_inv=0._R_P !< \(1/(p+1)\) where p is the accuracy order of the lower accurate scheme of the pair. - real(R_P), allocatable :: alph(:,:) !< \(\alpha\) Butcher's coefficients. - real(R_P), allocatable :: beta(:,:) !< \(\beta\) Butcher's coefficients. - real(R_P), allocatable :: gamm(:) !< \(\gamma\) Butcher's coefficients. + real(R_P) :: tolerance !< Tolerance on the local truncation error. + real(R_P) :: pp1_inv !< \(1/(p+1)\) where p is the accuracy order of the lower accurate scheme. + real(R_P), allocatable :: alph(:,:) !< \(\alpha\) Butcher's coefficients. + real(R_P), allocatable :: beta(:,:) !< \(\beta\) Butcher's coefficients. + real(R_P), allocatable :: gamm(:) !< \(\gamma\) Butcher's coefficients. + class(integrand_object), allocatable :: U1 !< First U evaluation. + class(integrand_object), allocatable :: U2 !< Second U evaluation. contains ! deferred methods procedure, pass(self) :: class_name !< Return the class name of schemes. @@ -366,95 +368,88 @@ pure subroutine integr_assign_integr(lhs, rhs) endselect endsubroutine integr_assign_integr - subroutine integrate(self, U, stage, Dt, t, new_Dt) + subroutine integrate(self, U, Dt, t, new_Dt) !< Integrate field with explicit embedded Runge-Kutta scheme. !< !< The time steps is adaptively resized using the local truncation error estimation by means of the embedded pairs of RK schemes. - class(integrator_runge_kutta_emd), intent(in) :: self !< Integrator. - class(integrand_object), intent(inout) :: U !< Field to be integrated. - class(integrand_object), intent(inout) :: stage(1:) !< Runge-Kutta stages [1:stages]. - real(R_P), intent(in) :: Dt !< Time step. - real(R_P), intent(in) :: t !< Time. - real(R_P), optional, intent(out) :: new_Dt !< New adapted time step. - real(R_P) :: Dt_ !< Time step, local variable. - class(integrand_object), allocatable :: U1 !< First U evaluation. - class(integrand_object), allocatable :: U2 !< Second U evaluation. - real(R_P) :: error !< Local truncation error estimation. - integer(I_P) :: s !< First stages counter. - integer(I_P) :: ss !< Second stages counter. - - Dt_ = Dt - allocate(U1, mold=U) ; U1 = U - allocate(U2, mold=U) ; U2 = U - do - ! compute stages - do s=1, self%stages - stage(s) = U - do ss=1, s - 1 - stage(s) = stage(s) + (stage(ss) * (Dt_ * self%alph(s, ss))) - enddo - stage(s) = stage(s)%t(t=t + self%gamm(s) * Dt_) - enddo - ! compute new time step - U1 = U - U2 = U - do s=1, self%stages - U1 = U1 + (stage(s) * (Dt_ * self%beta(s, 1))) - U2 = U2 + (stage(s) * (Dt_ * self%beta(s, 2))) - enddo - error = U2.lterror.U1 - if (error <= self%tolerance) exit - call self%new_Dt(error=error, Dt=Dt_) - enddo - U = U1 + class(integrator_runge_kutta_emd), intent(inout) :: self !< Integrator. + class(integrand_object), intent(inout) :: U !< Field to be integrated. + real(R_P), intent(in) :: Dt !< Time step. + real(R_P), intent(in) :: t !< Time. + real(R_P), intent(out), optional :: new_Dt !< New adapted time step. + real(R_P) :: Dt_ !< Time step, local variable. + real(R_P) :: error !< Local truncation error estimation. + integer(I_P) :: s !< First stages counter. + integer(I_P) :: ss !< Second stages counter. + + associate(stage=>self%stage, U1=>self%U1, U2=>self%U2) + Dt_ = Dt + do + ! compute stages + do s=1, self%stages + stage(s) = U + do ss=1, s - 1 + stage(s) = stage(s) + (stage(ss) * (Dt_ * self%alph(s, ss))) + enddo + stage(s) = stage(s)%t(t=t + self%gamm(s) * Dt_) + enddo + ! compute new time step + U1 = U + U2 = U + do s=1, self%stages + U1 = U1 + (stage(s) * (Dt_ * self%beta(s, 1))) + U2 = U2 + (stage(s) * (Dt_ * self%beta(s, 2))) + enddo + error = U2.lterror.U1 + if (error <= self%tolerance) exit + call self%new_Dt(error=error, Dt=Dt_) + enddo + U = U1 + endassociate if (present(new_Dt)) new_Dt = Dt_ endsubroutine integrate - subroutine integrate_fast(self, U, stage, buffer, Dt, t, new_Dt) + subroutine integrate_fast(self, U, Dt, t, new_Dt) !< Integrate field with explicit embedded Runge-Kutta scheme, fast mode. !< !< The time steps is adaptively resized using the local truncation error estimation by means of the embedded pairs of RK schemes. - class(integrator_runge_kutta_emd), intent(in) :: self !< Integrator. - class(integrand_object), intent(inout) :: U !< Field to be integrated. - class(integrand_object), intent(inout) :: stage(1:) !< Runge-Kutta stages [1:stages]. - class(integrand_object), intent(inout) :: buffer !< Temporary buffer for doing fast operation. - real(R_P), intent(in) :: Dt !< Time step. - real(R_P), intent(in) :: t !< Time. - real(R_P), optional, intent(out) :: new_Dt !< New adapted time step. - real(R_P) :: Dt_ !< Time step, local variable. - class(integrand_object), allocatable :: U1 !< First U evaluation. - class(integrand_object), allocatable :: U2 !< Second U evaluation. - real(R_P) :: error !< Local truncation error estimation. - integer(I_P) :: s !< First stages counter. - integer(I_P) :: ss !< Second stages counter. - - Dt_ = Dt - allocate(U1, mold=U) ; U1 = U - allocate(U2, mold=U) ; U2 = U - do - ! compute stages - do s=1, self%stages - stage(s) = U - do ss=1, s - 1 - call buffer%multiply_fast(lhs=stage(ss), rhs=Dt_ * self%alph(s, ss)) - call stage(s)%add_fast(lhs=stage(s), rhs=buffer) - enddo - call stage(s)%t_fast(t=t + self%gamm(s) * Dt_) - enddo - ! compute new time step - U1 = U - U2 = U - do s=1, self%stages - call buffer%multiply_fast(lhs=stage(s), rhs=Dt_ * self%beta(s, 1)) - call U1%add_fast(lhs=U1, rhs=buffer) - call buffer%multiply_fast(lhs=stage(s), rhs=Dt_ * self%beta(s, 2)) - call U2%add_fast(lhs=U2, rhs=buffer) - enddo - error = U2.lterror.U1 - if (error <= self%tolerance) exit - call self%new_Dt(error=error, Dt=Dt_) - enddo - U = U1 + class(integrator_runge_kutta_emd), intent(inout) :: self !< Integrator. + class(integrand_object), intent(inout) :: U !< Field to be integrated. + real(R_P), intent(in) :: Dt !< Time step. + real(R_P), intent(in) :: t !< Time. + real(R_P), intent(out), optional :: new_Dt !< New adapted time step. + real(R_P) :: Dt_ !< Time step, local variable. + real(R_P) :: error !< Local truncation error estimation. + integer(I_P) :: s !< First stages counter. + integer(I_P) :: ss !< Second stages counter. + + associate(stage=>self%stage, U1=>self%U1, U2=>self%U2) + Dt_ = Dt + do + ! compute stages + do s=1, self%stages + stage(s) = U + do ss=1, s - 1 + call buffer%multiply_fast(lhs=stage(ss), rhs=Dt_ * self%alph(s, ss)) + call stage(s)%add_fast(lhs=stage(s), rhs=buffer) + enddo + call stage(s)%t_fast(t=t + self%gamm(s) * Dt_) + enddo + ! compute new time step + U1 = U + U2 = U + do s=1, self%stages + call buffer%multiply_fast(lhs=stage(s), rhs=Dt_ * self%beta(s, 1)) + call U1%add_fast(lhs=U1, rhs=buffer) + call buffer%multiply_fast(lhs=stage(s), rhs=Dt_ * self%beta(s, 2)) + call U2%add_fast(lhs=U2, rhs=buffer) + enddo + error = U2.lterror.U1 + if (error <= self%tolerance) exit + call self%new_Dt(error=error, Dt=Dt_) + enddo + U = U1 + endassociate if (present(new_Dt)) new_Dt = Dt_ endsubroutine integrate_fast @@ -760,6 +755,9 @@ subroutine initialize(self, scheme, tolerance, stop_on_fail) self%gamm(16) = 0.1_R_P self%gamm(17) = 1._R_P endselect + self%registers = self%stages + ! allocate(self%stage(1:self%register), mold=integrand) + ! allocate(self%buffer, mold=integrand) else call self%trigger_error(error=ERROR_UNSUPPORTED_SCHEME, & error_message='"'//trim(adjustl(scheme))//'" unsupported scheme', & diff --git a/src/lib/foodie_integrator_runge_kutta_low_storage.f90 b/src/lib/foodie_integrator_runge_kutta_low_storage.f90 index 9d4d49eb..edbe15c8 100644 --- a/src/lib/foodie_integrator_runge_kutta_low_storage.f90 +++ b/src/lib/foodie_integrator_runge_kutta_low_storage.f90 @@ -246,51 +246,52 @@ pure subroutine integr_assign_integr(lhs, rhs) endselect endsubroutine integr_assign_integr - subroutine integrate(self, U, stage, Dt, t, new_Dt) + subroutine integrate(self, U, Dt, t, new_Dt) !< Integrate field with explicit low storage Runge-Kutta scheme. - class(integrator_runge_kutta_ls), intent(in) :: self !< Integrator. - class(integrand_object), intent(inout) :: U !< Field to be integrated. - class(integrand_object), intent(inout) :: stage(1:) !< Runge-Kutta registers. - real(R_P), intent(in) :: Dt !< Time step. - real(R_P), intent(in) :: t !< Time. - real(R_P), optional, intent(out) :: new_Dt !< New adapted time step. - integer(I_P) :: s !< First stages counter. - - ! computing stages - stage(1) = U - stage(2) = U * 0._R_P - do s=1, self%stages - stage(2) = (stage(2) * self%A(s)) + (stage(1)%t(t=t + self%C(s) * Dt) * Dt) - stage(1) = stage(1) + (stage(2) * self%B(s)) - enddo - U = stage(1) + class(integrator_runge_kutta_ls), intent(inout) :: self !< Integrator. + class(integrand_object), intent(inout) :: U !< Field to be integrated. + real(R_P), intent(in) :: Dt !< Time step. + real(R_P), intent(in) :: t !< Time. + real(R_P), intent(out), optional :: new_Dt !< New adapted time step. + integer(I_P) :: s !< First stages counter. + + associate(stage=>self%stage) + ! computing stages + stage(1) = U + stage(2) = U * 0._R_P + do s=1, self%stages + stage(2) = (stage(2) * self%A(s)) + (stage(1)%t(t=t + self%C(s) * Dt) * Dt) + stage(1) = stage(1) + (stage(2) * self%B(s)) + enddo + U = stage(1) + endassociate if (present(new_Dt)) new_Dt = Dt endsubroutine integrate - subroutine integrate_fast(self, U, stage, buffer, Dt, t, new_Dt) + subroutine integrate_fast(self, U, Dt, t, new_Dt) !< Integrate field with explicit low storage Runge-Kutta scheme, fast mode. - class(integrator_runge_kutta_ls), intent(in) :: self !< Integrator. - class(integrand_object), intent(inout) :: U !< Field to be integrated. - class(integrand_object), intent(inout) :: stage(1:) !< Runge-Kutta registers. - class(integrand_object), intent(inout) :: buffer !< Temporary buffer for doing fast operation. - real(R_P), intent(in) :: Dt !< Time step. - real(R_P), intent(in) :: t !< Time. - real(R_P), optional, intent(out) :: new_Dt !< New adapted time step. - integer(I_P) :: s !< First stages counter. - - ! computing stages - stage(1) = U - call stage(2)%multiply_fast(lhs=U, rhs=0._R_P) - do s=1, self%stages - buffer = stage(1) - call buffer%t_fast(t=t + self%C(s) * Dt) - call buffer%multiply_fast(lhs=buffer, rhs=Dt) - call stage(2)%multiply_fast(lhs=stage(2), rhs=self%A(s)) - call stage(2)%add_fast(lhs=stage(2), rhs=buffer) - call buffer%multiply_fast(lhs=stage(2), rhs=self%B(s)) - call stage(1)%add_fast(lhs=stage(1), rhs=buffer) - enddo - U = stage(1) + class(integrator_runge_kutta_ls), intent(in) :: self !< Integrator. + class(integrand_object), intent(inout) :: U !< Field to be integrated. + real(R_P), intent(in) :: Dt !< Time step. + real(R_P), intent(in) :: t !< Time. + real(R_P), optional, intent(out) :: new_Dt !< New adapted time step. + integer(I_P) :: s !< First stages counter. + + associate(stage=>self%stage) + ! computing stages + stage(1) = U + call stage(2)%multiply_fast(lhs=U, rhs=0._R_P) + do s=1, self%stages + buffer = stage(1) + call buffer%t_fast(t=t + self%C(s) * Dt) + call buffer%multiply_fast(lhs=buffer, rhs=Dt) + call stage(2)%multiply_fast(lhs=stage(2), rhs=self%A(s)) + call stage(2)%add_fast(lhs=stage(2), rhs=buffer) + call buffer%multiply_fast(lhs=stage(2), rhs=self%B(s)) + call stage(1)%add_fast(lhs=stage(1), rhs=buffer) + enddo + U = stage(1) + endassociate if (present(new_Dt)) new_Dt = Dt endsubroutine integrate_fast @@ -452,6 +453,9 @@ subroutine initialize(self, scheme, stop_on_fail) self%A(13) = -0.9514200470875948_R_P ; self%B(13) = 0.0780348340049386_R_P ; self%C(13) = 0.8627060376969976_R_P self%A(14) = -7.1151571693922548_R_P ; self%B(14) = 5.5059777270269628_R_P ; self%C(14) = 0.8734213127600976_R_P endselect + self%registers = 2 + ! allocate(self%stage(1:self%register), mold=integrand) + ! allocate(self%buffer, mold=integrand) else call self%trigger_error(error=ERROR_UNSUPPORTED_SCHEME, & error_message='"'//trim(adjustl(scheme))//'" unsupported scheme', & diff --git a/src/lib/foodie_integrator_runge_kutta_lssp.f90 b/src/lib/foodie_integrator_runge_kutta_lssp.f90 index 390fbb37..2486ed78 100644 --- a/src/lib/foodie_integrator_runge_kutta_lssp.f90 +++ b/src/lib/foodie_integrator_runge_kutta_lssp.f90 @@ -108,25 +108,22 @@ module foodie_integrator_runge_kutta_lssp abstract interface !< Abstract interfaces of [[integrator_runge_kutta_lssp]] methods. - subroutine integrate_interface(self, U, stage, Dt, t) + subroutine integrate_interface(self, U, Dt, t) !< Integrate field with Linear SSP Runge-Kutta scheme. import :: integrand_object, integrator_runge_kutta_lssp, R_P - class(integrator_runge_kutta_lssp), intent(in) :: self !< Integrator. + class(integrator_runge_kutta_lssp), intent(inout) :: self !< Integrator. class(integrand_object), intent(inout) :: U !< Field to be integrated. - class(integrand_object), intent(inout) :: stage(1:) !< Runge-Kutta stages [1:stages]. real(R_P), intent(in) :: Dt !< Time steps. real(R_P), intent(in) :: t !< Times. endsubroutine integrate_interface - subroutine integrate_fast_interface(self, U, stage, buffer, Dt, t) + subroutine integrate_fast_interface(self, U, Dt, t) !< Integrate field with Linear SSP Runge-Kutta scheme, fast mode. import :: integrand_object, integrator_runge_kutta_lssp, R_P - class(integrator_runge_kutta_lssp), intent(in) :: self !< Integrator. - class(integrand_object), intent(inout) :: U !< Field to be integrated. - class(integrand_object), intent(inout) :: stage(1:) !< Runge-Kutta stages [1:stages]. - class(integrand_object), intent(inout) :: buffer !< Temporary buffer for doing fast operation. - real(R_P), intent(in) :: Dt !< Time steps. - real(R_P), intent(in) :: t !< Times. + class(integrator_runge_kutta_lssp), intent(inout) :: self !< Integrator. + class(integrand_object), intent(inout) :: U !< Field to be integrated. + real(R_P), intent(in) :: Dt !< Time steps. + real(R_P), intent(in) :: t !< Times. endsubroutine integrate_fast_interface endinterface @@ -180,32 +177,29 @@ pure subroutine integr_assign_integr(lhs, rhs) endselect endsubroutine integr_assign_integr - subroutine integrate(self, U, stage, Dt, t, new_Dt) + subroutine integrate(self, U, Dt, t, new_Dt) !< Integrate integrand field by Linear SSP Runge-Kutta methods. !< !< @note This method can be used **after** the integrator is created (i.e. the RK coefficients are initialized). - class(integrator_runge_kutta_lssp), intent(in) :: self !< Integrator. - class(integrand_object), intent(inout) :: U !< Field to be integrated. - class(integrand_object), intent(inout) :: stage(1:) !< Runge-Kutta stages [1:stages]. - real(R_P), intent(in) :: Dt !< Time step. - real(R_P), intent(in) :: t !< Time. - real(R_P), optional, intent(out) :: new_Dt !< New adapted time step. + class(integrator_runge_kutta_lssp), intent(inout) :: self !< Integrator. + class(integrand_object), intent(inout) :: U !< Field to be integrated. + real(R_P), intent(in) :: Dt !< Time step. + real(R_P), intent(in) :: t !< Time. + real(R_P), intent(out), optional :: new_Dt !< New adapted time step. - call self%integrate_(U=U, stage=stage, Dt=Dt, t=t) + call self%integrate_(U=U, Dt=Dt, t=t) if (present(new_Dt)) new_Dt = Dt endsubroutine integrate - subroutine integrate_fast(self, U, stage, buffer, Dt, t, new_Dt) + subroutine integrate_fast(self, U, Dt, t, new_Dt) !< Integrate integrand field by Linear SSP Runge-Kutta methods. - class(integrator_runge_kutta_lssp), intent(in) :: self !< Integrator. - class(integrand_object), intent(inout) :: U !< Field to be integrated. - class(integrand_object), intent(inout) :: stage(1:) !< Runge-Kutta stages [1:stages]. - class(integrand_object), intent(inout) :: buffer !< Temporary buffer for doing fast operation. - real(R_P), intent(in) :: Dt !< Time step. - real(R_P), intent(in) :: t !< Time. - real(R_P), optional, intent(out) :: new_Dt !< New adapted time step. + class(integrator_runge_kutta_lssp), intent(in) :: self !< Integrator. + class(integrand_object), intent(inout) :: U !< Field to be integrated. + real(R_P), intent(in) :: Dt !< Time step. + real(R_P), intent(in) :: t !< Time. + real(R_P), intent(out), optional :: new_Dt !< New adapted time step. - call self%integrate_fast_(U=U, stage=stage, buffer=buffer, Dt=Dt, t=t) + call self%integrate_fast_(U=U, Dt=Dt, t=t) if (present(new_Dt)) new_Dt = Dt endsubroutine integrate_fast @@ -325,107 +319,109 @@ elemental subroutine initialize_order_s(self) endsubroutine initialize_order_s - subroutine integrate_order_s_1(self, U, stage, Dt, t) + subroutine integrate_order_s_1(self, U, Dt, t) !< Integrate integrand field by (s-1)-th order formula. - class(integrator_runge_kutta_lssp), intent(in) :: self !< Integrator. - class(integrand_object), intent(inout) :: U !< Field to be integrated. - class(integrand_object), intent(inout) :: stage(1:) !< Runge-Kutta stages [1:stages]. - real(R_P), intent(in) :: Dt !< Time step. - real(R_P), intent(in) :: t !< Time. - integer(I_P) :: s !< First stages counter. - - ! computing stages - stage(1) = U - do s=2, self%stages - stage(s) = stage(s-1) + (stage(s-1)%t(t=t) * (Dt * 0.5_R_P)) - enddo - stage(self%stages) = stage(self%stages) + (stage(self%stages)%t(t=t) * (Dt * 0.5_R_P)) - ! computing new time step - U = U * 0._R_P - do s=1, self%stages - U = U + (stage(s) * self%alpha(s)) - enddo + class(integrator_runge_kutta_lssp), intent(inout) :: self !< Integrator. + class(integrand_object), intent(inout) :: U !< Field to be integrated. + real(R_P), intent(in) :: Dt !< Time step. + real(R_P), intent(in) :: t !< Time. + integer(I_P) :: s !< First stages counter. + + associate(stage=>self%stage) + ! computing stages + stage(1) = U + do s=2, self%stages + stage(s) = stage(s-1) + (stage(s-1)%t(t=t) * (Dt * 0.5_R_P)) + enddo + stage(self%stages) = stage(self%stages) + (stage(self%stages)%t(t=t) * (Dt * 0.5_R_P)) + ! computing new time step + U = U * 0._R_P + do s=1, self%stages + U = U + (stage(s) * self%alpha(s)) + enddo + endassociate endsubroutine integrate_order_s_1 - subroutine integrate_order_s(self, U, stage, Dt, t) + subroutine integrate_order_s(self, U, Dt, t) !< Integrate integrand field by s-th order formula. - class(integrator_runge_kutta_lssp), intent(in) :: self !< Integrator. - class(integrand_object), intent(inout) :: U !< Field to be integrated. - class(integrand_object), intent(inout) :: stage(1:) !< Runge-Kutta stages [1:stages]. - real(R_P), intent(in) :: Dt !< Time step. - real(R_P), intent(in) :: t !< Time. - integer(I_P) :: s !< First stages counter. - - ! computing stages - stage(1) = U - do s=2, self%stages - stage(s) = stage(s-1) + (stage(s-1)%t(t=t) * Dt) - enddo - stage(self%stages) = stage(self%stages) + (stage(self%stages)%t(t=t) * Dt) - ! computing new time step - U = U * 0._R_P - do s=1, self%stages - U = U + (stage(s) * self%alpha(s)) - enddo + class(integrator_runge_kutta_lssp), intent(inout) :: self !< Integrator. + class(integrand_object), intent(inout) :: U !< Field to be integrated. + real(R_P), intent(in) :: Dt !< Time step. + real(R_P), intent(in) :: t !< Time. + integer(I_P) :: s !< First stages counter. + + associate(stage=>self%stage) + ! computing stages + stage(1) = U + do s=2, self%stages + stage(s) = stage(s-1) + (stage(s-1)%t(t=t) * Dt) + enddo + stage(self%stages) = stage(self%stages) + (stage(self%stages)%t(t=t) * Dt) + ! computing new time step + U = U * 0._R_P + do s=1, self%stages + U = U + (stage(s) * self%alpha(s)) + enddo + endassociate endsubroutine integrate_order_s - subroutine integrate_order_s_1_fast(self, U, stage, buffer, Dt, t) + subroutine integrate_order_s_1_fast(self, U, Dt, t) !< Integrate integrand field by (s-1)-th order formula. - class(integrator_runge_kutta_lssp), intent(in) :: self !< Integrator. - class(integrand_object), intent(inout) :: U !< Field to be integrated. - class(integrand_object), intent(inout) :: stage(1:) !< Runge-Kutta stages [1:stages]. - class(integrand_object), intent(inout) :: buffer !< Temporary buffer for doing fast operation. - real(R_P), intent(in) :: Dt !< Time step. - real(R_P), intent(in) :: t !< Time. - integer(I_P) :: s !< First stages counter. - - ! computing stages - stage(1) = U - do s=2, self%stages - buffer = stage(s-1) - call buffer%t_fast(t=t) - call buffer%multiply_fast(lhs=buffer, rhs=Dt * 0.5_R_P) - call stage(s)%add_fast(lhs=stage(s-1), rhs=buffer) - enddo - buffer = stage(self%stages) - call buffer%t_fast(t=t) - call buffer%multiply_fast(lhs=buffer, rhs=Dt * 0.5_R_P) - call stage(self%stages)%add_fast(lhs=stage(self%stages), rhs=buffer) - ! computing new time step - call U%multiply_fast(lhs=U, rhs=0._R_P) - do s=1, self%stages - call buffer%multiply_fast(lhs=stage(s), rhs=self%alpha(s)) - call U%add_fast(lhs=U, rhs=buffer) - enddo + class(integrator_runge_kutta_lssp), intent(inout) :: self !< Integrator. + class(integrand_object), intent(inout) :: U !< Field to be integrated. + real(R_P), intent(in) :: Dt !< Time step. + real(R_P), intent(in) :: t !< Time. + integer(I_P) :: s !< First stages counter. + + associate(stage=>self%stage, buffer=>self%buffer) + ! computing stages + stage(1) = U + do s=2, self%stages + buffer = stage(s-1) + call buffer%t_fast(t=t) + call buffer%multiply_fast(lhs=buffer, rhs=Dt * 0.5_R_P) + call stage(s)%add_fast(lhs=stage(s-1), rhs=buffer) + enddo + buffer = stage(self%stages) + call buffer%t_fast(t=t) + call buffer%multiply_fast(lhs=buffer, rhs=Dt * 0.5_R_P) + call stage(self%stages)%add_fast(lhs=stage(self%stages), rhs=buffer) + ! computing new time step + call U%multiply_fast(lhs=U, rhs=0._R_P) + do s=1, self%stages + call buffer%multiply_fast(lhs=stage(s), rhs=self%alpha(s)) + call U%add_fast(lhs=U, rhs=buffer) + enddo + endassociate endsubroutine integrate_order_s_1_fast subroutine integrate_order_s_fast(self, U, stage, buffer, Dt, t) !< Integrate integrand field by s-th order formula, fast mode. - class(integrator_runge_kutta_lssp), intent(in) :: self !< Integrator. - class(integrand_object), intent(inout) :: U !< Field to be integrated. - class(integrand_object), intent(inout) :: stage(1:) !< Runge-Kutta stages [1:stages]. - class(integrand_object), intent(inout) :: buffer !< Temporary buffer for doing fast operation. - real(R_P), intent(in) :: Dt !< Time step. - real(R_P), intent(in) :: t !< Time. - integer(I_P) :: s !< First stages counter. - - ! computing stages - stage(1) = U - do s=2, self%stages - buffer = stage(s-1) - call buffer%t_fast(t=t) - call buffer%multiply_fast(lhs=buffer, rhs=Dt) - call stage(s)%add_fast(lhs=stage(s-1), rhs=buffer) - enddo - buffer = stage(self%stages) - call buffer%t_fast(t=t) - call buffer%multiply_fast(lhs=buffer, rhs=Dt) - call stage(self%stages)%add_fast(lhs=stage(self%stages), rhs=buffer) - ! computing new time step - call U%multiply_fast(lhs=U, rhs=0._R_P) - do s=1, self%stages - call buffer%multiply_fast(lhs=stage(s), rhs=self%alpha(s)) - call U%add_fast(lhs=U, rhs=buffer) - enddo + class(integrator_runge_kutta_lssp), intent(inout) :: self !< Integrator. + class(integrand_object), intent(inout) :: U !< Field to be integrated. + real(R_P), intent(in) :: Dt !< Time step. + real(R_P), intent(in) :: t !< Time. + integer(I_P) :: s !< First stages counter. + + associate(stage=>self%stage, buffer=>self%buffer) + ! computing stages + stage(1) = U + do s=2, self%stages + buffer = stage(s-1) + call buffer%t_fast(t=t) + call buffer%multiply_fast(lhs=buffer, rhs=Dt) + call stage(s)%add_fast(lhs=stage(s-1), rhs=buffer) + enddo + buffer = stage(self%stages) + call buffer%t_fast(t=t) + call buffer%multiply_fast(lhs=buffer, rhs=Dt) + call stage(self%stages)%add_fast(lhs=stage(self%stages), rhs=buffer) + ! computing new time step + call U%multiply_fast(lhs=U, rhs=0._R_P) + do s=1, self%stages + call buffer%multiply_fast(lhs=stage(s), rhs=self%alpha(s)) + call U%add_fast(lhs=U, rhs=buffer) + enddo + endassociate endsubroutine integrate_order_s_fast endmodule foodie_integrator_runge_kutta_lssp From c69d7bdacf8e69dc25bd8d0d4a6c242330d627f2 Mon Sep 17 00:00:00 2001 From: Stefano Zaghi Date: Mon, 22 May 2017 18:05:54 +0200 Subject: [PATCH 13/25] multistage integrators work with embedded stage/buffer --- ..._integrator_multistage_explicit_object.f90 | 74 ++++++--- ...foodie_integrator_runge_kutta_embedded.f90 | 148 +++++++++--------- ...die_integrator_runge_kutta_low_storage.f90 | 62 ++++---- .../foodie_integrator_runge_kutta_lssp.f90 | 129 +++++++-------- src/lib/foodie_integrator_runge_kutta_ssp.f90 | 60 +++---- src/tests/tester/foodie_tester.f90 | 21 +-- 6 files changed, 252 insertions(+), 242 deletions(-) diff --git a/src/lib/foodie_integrator_multistage_explicit_object.f90 b/src/lib/foodie_integrator_multistage_explicit_object.f90 index c55fb015..35a082f2 100644 --- a/src/lib/foodie_integrator_multistage_explicit_object.f90 +++ b/src/lib/foodie_integrator_multistage_explicit_object.f90 @@ -28,30 +28,40 @@ module foodie_integrator_multistage_explicit_object procedure, pass(self) :: stages_number !< Return number of stages used. procedure, pass(self) :: steps_number !< Return number of steps used. ! public methods - procedure, pass(self) :: destroy_multistage !< Destroy the integrator. + procedure, pass(self) :: allocate_integrand_members !< Allocate integrand members. + procedure, pass(self) :: destroy_multistage !< Destroy the integrator. endtype integrator_multistage_explicit_object abstract interface - !< Abstract interfaces of deferred methods of [[integrator_object]]. - subroutine integrate_interface(self, U, Dt, t, new_Dt) - !< Integrate integrand field. - import :: integrand_object, integrator_multistage_explicit_object, R_P - class(integrator_multistage_explicit_object), intent(inout) :: self !< Integrator. - class(integrand_object), intent(inout) :: U !< Integrand. - real(R_P), intent(in) :: Dt !< Time step. - real(R_P), intent(in) :: t !< Time. - real(R_P), intent(out), optional :: new_Dt !< New adapted time step. - endsubroutine integrate_interface - - subroutine integrate_fast_interface(self, U, Dt, t, new_Dt) - !< Integrate integrand field, fast mode. - import :: integrand_object, integrator_multistage_explicit_object, R_P - class(integrator_multistage_explicit_object), intent(inout) :: self !< Integrator. - class(integrand_object), intent(inout) :: U !< Field to be integrated. - real(R_P), intent(in) :: Dt !< Time step. - real(R_P), intent(in) :: t !< Time. - real(R_P), intent(out), optional :: new_Dt !< New adapted time step. - endsubroutine integrate_fast_interface + !< Abstract interfaces of deferred methods of [[integrator_multistage_explicit_object]]. + pure subroutine allocate_integrands_interface(self, U) + !< Allocate members of interpolator being of [[integrand_object]] class. + !< + !< @note It is assumed that the integrator has been properly initialized before calling this method. + import :: integrand_object, integrator_multistage_explicit_object + class(integrator_multistage_explicit_object), intent(inout) :: self !< Integrator. + class(integrand_object), intent(in) :: U !< Integrand. + endsubroutine allocate_integrands_interface + + subroutine integrate_interface(self, U, Dt, t, new_Dt) + !< Integrate integrand field. + import :: integrand_object, integrator_multistage_explicit_object, R_P + class(integrator_multistage_explicit_object), intent(inout) :: self !< Integrator. + class(integrand_object), intent(inout) :: U !< Integrand. + real(R_P), intent(in) :: Dt !< Time step. + real(R_P), intent(in) :: t !< Time. + real(R_P), intent(out), optional :: new_Dt !< New adapted time step. + endsubroutine integrate_interface + + subroutine integrate_fast_interface(self, U, Dt, t, new_Dt) + !< Integrate integrand field, fast mode. + import :: integrand_object, integrator_multistage_explicit_object, R_P + class(integrator_multistage_explicit_object), intent(inout) :: self !< Integrator. + class(integrand_object), intent(inout) :: U !< Field to be integrated. + real(R_P), intent(in) :: Dt !< Time step. + real(R_P), intent(in) :: t !< Time. + real(R_P), intent(out), optional :: new_Dt !< New adapted time step. + endsubroutine integrate_fast_interface endinterface contains @@ -89,6 +99,28 @@ elemental function steps_number(self) endfunction steps_number ! public methods + pure subroutine allocate_integrand_members(self, U) + !< Allocate members of interpolator being of [[integrand_object]] class. + !< + !< @note It is assumed that the integrator has been properly initialized before calling this method. + class(integrator_multistage_explicit_object), intent(inout) :: self !< Integrator. + class(integrand_object), intent(in) :: U !< Integrand. + integer(I_P) :: s !< Counter. + + if (self%is_multistage() .and. self%registers > 0) then + if (allocated(self%stage)) deallocate(self%stage) + allocate(self%stage(1:self%registers), mold=U) + do s=1, self%registers + self%stage(s) = U + enddo + endif + if (self%has_fast_mode()) then + if (allocated(self%buffer)) deallocate(self%buffer) + allocate(self%buffer, mold=U) + self%buffer = U + endif + endsubroutine allocate_integrand_members + elemental subroutine destroy_multistage(self) !< Destroy the integrator. class(integrator_multistage_explicit_object), intent(inout) :: self !< Integrator. diff --git a/src/lib/foodie_integrator_runge_kutta_embedded.f90 b/src/lib/foodie_integrator_runge_kutta_embedded.f90 index d4da17b4..1aee3b39 100644 --- a/src/lib/foodie_integrator_runge_kutta_embedded.f90 +++ b/src/lib/foodie_integrator_runge_kutta_embedded.f90 @@ -287,35 +287,35 @@ module foodie_integrator_runge_kutta_emd logical, parameter :: is_multistep_=.false. !< Flag to check if integrator is multistep. type, extends(integrator_multistage_explicit_object) :: integrator_runge_kutta_emd - !< FOODIE integrator: provide an explicit class of embedded Runge-Kutta schemes, from 2nd to 10th order accurate. - !< - !< @note The integrator must be created or initialized (initialize the RK coefficients) before used. - private - real(R_P) :: tolerance !< Tolerance on the local truncation error. - real(R_P) :: pp1_inv !< \(1/(p+1)\) where p is the accuracy order of the lower accurate scheme. - real(R_P), allocatable :: alph(:,:) !< \(\alpha\) Butcher's coefficients. - real(R_P), allocatable :: beta(:,:) !< \(\beta\) Butcher's coefficients. - real(R_P), allocatable :: gamm(:) !< \(\gamma\) Butcher's coefficients. - class(integrand_object), allocatable :: U1 !< First U evaluation. - class(integrand_object), allocatable :: U2 !< Second U evaluation. - contains - ! deferred methods - procedure, pass(self) :: class_name !< Return the class name of schemes. - procedure, pass(self) :: description !< Return pretty-printed object description. - procedure, pass(self) :: has_fast_mode !< Return .true. if the integrator class has *fast mode* integrate. - procedure, pass(lhs) :: integr_assign_integr !< Operator `=`. - procedure, pass(self) :: integrate !< Integrate integrand field. - procedure, pass(self) :: integrate_fast !< Integrate integrand field, fast mode. - procedure, pass(self) :: is_supported !< Return .true. if the integrator class support the given scheme. - procedure, pass(self) :: supported_schemes !< Return the list of supported schemes. - ! public methods - procedure, pass(self) :: destroy !< Destroy the integrator. - procedure, pass(self) :: initialize !< Initialize (create) the integrator. - ! private methods - procedure, pass(self), private :: new_Dt !< Compute new estimation of the time step Dt. + !< FOODIE integrator: provide an explicit class of embedded Runge-Kutta schemes, from 2nd to 10th order accurate. + !< + !< @note The integrator must be created or initialized (initialize the RK coefficients) before used. + private + real(R_P) :: tolerance !< Tolerance on the local truncation error. + real(R_P) :: pp1_inv !< \(1/(p+1)\) where p is the accuracy order of the lower accurate scheme. + real(R_P), allocatable :: alph(:,:) !< \(\alpha\) Butcher's coefficients. + real(R_P), allocatable :: beta(:,:) !< \(\beta\) Butcher's coefficients. + real(R_P), allocatable :: gamm(:) !< \(\gamma\) Butcher's coefficients. + class(integrand_object), allocatable :: U1 !< First U evaluation. + class(integrand_object), allocatable :: U2 !< Second U evaluation. + contains + ! deferred methods + procedure, pass(self) :: class_name !< Return the class name of schemes. + procedure, pass(self) :: description !< Return pretty-printed object description. + procedure, pass(self) :: has_fast_mode !< Return .true. if the integrator class has *fast mode* integrate. + procedure, pass(lhs) :: integr_assign_integr !< Operator `=`. + procedure, pass(self) :: integrate !< Integrate integrand field. + procedure, pass(self) :: integrate_fast !< Integrate integrand field, fast mode. + procedure, pass(self) :: is_supported !< Return .true. if the integrator class support the given scheme. + procedure, pass(self) :: supported_schemes !< Return the list of supported schemes. + ! public methods + procedure, pass(self) :: destroy !< Destroy the integrator. + procedure, pass(self) :: initialize !< Initialize (create) the integrator. + ! private methods + procedure, pass(self), private :: new_Dt !< Compute new estimation of the time step Dt. endtype integrator_runge_kutta_emd contains - ! deferred methods + ! deferred methods pure function class_name(self) !< Return the class name of schemes. class(integrator_runge_kutta_emd), intent(in) :: self !< Integrator. @@ -382,30 +382,28 @@ subroutine integrate(self, U, Dt, t, new_Dt) integer(I_P) :: s !< First stages counter. integer(I_P) :: ss !< Second stages counter. - associate(stage=>self%stage, U1=>self%U1, U2=>self%U2) - Dt_ = Dt - do - ! compute stages - do s=1, self%stages - stage(s) = U - do ss=1, s - 1 - stage(s) = stage(s) + (stage(ss) * (Dt_ * self%alph(s, ss))) - enddo - stage(s) = stage(s)%t(t=t + self%gamm(s) * Dt_) - enddo - ! compute new time step - U1 = U - U2 = U - do s=1, self%stages - U1 = U1 + (stage(s) * (Dt_ * self%beta(s, 1))) - U2 = U2 + (stage(s) * (Dt_ * self%beta(s, 2))) - enddo - error = U2.lterror.U1 - if (error <= self%tolerance) exit - call self%new_Dt(error=error, Dt=Dt_) + Dt_ = Dt + do + ! compute stages + do s=1, self%stages + self%stage(s) = U + do ss=1, s - 1 + self%stage(s) = self%stage(s) + (self%stage(ss) * (Dt_ * self%alph(s, ss))) + enddo + self%stage(s) = self%stage(s)%t(t=t + self%gamm(s) * Dt_) + enddo + ! compute new time step + self%U1 = U + self%U2 = U + do s=1, self%stages + self%U1 = self%U1 + (self%stage(s) * (Dt_ * self%beta(s, 1))) + self%U2 = self%U2 + (self%stage(s) * (Dt_ * self%beta(s, 2))) enddo - U = U1 - endassociate + error = self%U2.lterror.self%U1 + if (error <= self%tolerance) exit + call self%new_Dt(error=error, Dt=Dt_) + enddo + U = self%U1 if (present(new_Dt)) new_Dt = Dt_ endsubroutine integrate @@ -423,33 +421,31 @@ subroutine integrate_fast(self, U, Dt, t, new_Dt) integer(I_P) :: s !< First stages counter. integer(I_P) :: ss !< Second stages counter. - associate(stage=>self%stage, U1=>self%U1, U2=>self%U2) - Dt_ = Dt - do - ! compute stages - do s=1, self%stages - stage(s) = U - do ss=1, s - 1 - call buffer%multiply_fast(lhs=stage(ss), rhs=Dt_ * self%alph(s, ss)) - call stage(s)%add_fast(lhs=stage(s), rhs=buffer) - enddo - call stage(s)%t_fast(t=t + self%gamm(s) * Dt_) - enddo - ! compute new time step - U1 = U - U2 = U - do s=1, self%stages - call buffer%multiply_fast(lhs=stage(s), rhs=Dt_ * self%beta(s, 1)) - call U1%add_fast(lhs=U1, rhs=buffer) - call buffer%multiply_fast(lhs=stage(s), rhs=Dt_ * self%beta(s, 2)) - call U2%add_fast(lhs=U2, rhs=buffer) - enddo - error = U2.lterror.U1 - if (error <= self%tolerance) exit - call self%new_Dt(error=error, Dt=Dt_) + Dt_ = Dt + do + ! compute stages + do s=1, self%stages + self%stage(s) = U + do ss=1, s - 1 + call self%buffer%multiply_fast(lhs=self%stage(ss), rhs=Dt_ * self%alph(s, ss)) + call self%stage(s)%add_fast(lhs=self%stage(s), rhs=self%buffer) + enddo + call self%stage(s)%t_fast(t=t + self%gamm(s) * Dt_) enddo - U = U1 - endassociate + ! compute new time step + self%U1 = U + self%U2 = U + do s=1, self%stages + call self%buffer%multiply_fast(lhs=self%stage(s), rhs=Dt_ * self%beta(s, 1)) + call self%U1%add_fast(lhs=self%U1, rhs=self%buffer) + call self%buffer%multiply_fast(lhs=self%stage(s), rhs=Dt_ * self%beta(s, 2)) + call self%U2%add_fast(lhs=self%U2, rhs=self%buffer) + enddo + error = self%U2.lterror.self%U1 + if (error <= self%tolerance) exit + call self%new_Dt(error=error, Dt=Dt_) + enddo + U = self%U1 if (present(new_Dt)) new_Dt = Dt_ endsubroutine integrate_fast diff --git a/src/lib/foodie_integrator_runge_kutta_low_storage.f90 b/src/lib/foodie_integrator_runge_kutta_low_storage.f90 index edbe15c8..a861ba05 100644 --- a/src/lib/foodie_integrator_runge_kutta_low_storage.f90 +++ b/src/lib/foodie_integrator_runge_kutta_low_storage.f90 @@ -195,7 +195,7 @@ module foodie_integrator_runge_kutta_low_storage endtype integrator_runge_kutta_ls contains - ! deferred methods + ! deferred methods pure function class_name(self) !< Return the class name of schemes. class(integrator_runge_kutta_ls), intent(in) :: self !< Integrator. @@ -255,43 +255,39 @@ subroutine integrate(self, U, Dt, t, new_Dt) real(R_P), intent(out), optional :: new_Dt !< New adapted time step. integer(I_P) :: s !< First stages counter. - associate(stage=>self%stage) - ! computing stages - stage(1) = U - stage(2) = U * 0._R_P - do s=1, self%stages - stage(2) = (stage(2) * self%A(s)) + (stage(1)%t(t=t + self%C(s) * Dt) * Dt) - stage(1) = stage(1) + (stage(2) * self%B(s)) - enddo - U = stage(1) - endassociate + ! computing stages + self%stage(1) = U + self%stage(2) = U * 0._R_P + do s=1, self%stages + self%stage(2) = (self%stage(2) * self%A(s)) + (self%stage(1)%t(t=t + self%C(s) * Dt) * Dt) + self%stage(1) = self%stage(1) + (self%stage(2) * self%B(s)) + enddo + U = self%stage(1) if (present(new_Dt)) new_Dt = Dt endsubroutine integrate subroutine integrate_fast(self, U, Dt, t, new_Dt) !< Integrate field with explicit low storage Runge-Kutta scheme, fast mode. - class(integrator_runge_kutta_ls), intent(in) :: self !< Integrator. - class(integrand_object), intent(inout) :: U !< Field to be integrated. - real(R_P), intent(in) :: Dt !< Time step. - real(R_P), intent(in) :: t !< Time. - real(R_P), optional, intent(out) :: new_Dt !< New adapted time step. - integer(I_P) :: s !< First stages counter. - - associate(stage=>self%stage) - ! computing stages - stage(1) = U - call stage(2)%multiply_fast(lhs=U, rhs=0._R_P) - do s=1, self%stages - buffer = stage(1) - call buffer%t_fast(t=t + self%C(s) * Dt) - call buffer%multiply_fast(lhs=buffer, rhs=Dt) - call stage(2)%multiply_fast(lhs=stage(2), rhs=self%A(s)) - call stage(2)%add_fast(lhs=stage(2), rhs=buffer) - call buffer%multiply_fast(lhs=stage(2), rhs=self%B(s)) - call stage(1)%add_fast(lhs=stage(1), rhs=buffer) - enddo - U = stage(1) - endassociate + class(integrator_runge_kutta_ls), intent(inout) :: self !< Integrator. + class(integrand_object), intent(inout) :: U !< Field to be integrated. + real(R_P), intent(in) :: Dt !< Time step. + real(R_P), intent(in) :: t !< Time. + real(R_P), intent(out), optional :: new_Dt !< New adapted time step. + integer(I_P) :: s !< First stages counter. + + ! computing stages + self%stage(1) = U + call self%stage(2)%multiply_fast(lhs=U, rhs=0._R_P) + do s=1, self%stages + self%buffer = self%stage(1) + call self%buffer%t_fast(t=t + self%C(s) * Dt) + call self%buffer%multiply_fast(lhs=self%buffer, rhs=Dt) + call self%stage(2)%multiply_fast(lhs=self%stage(2), rhs=self%A(s)) + call self%stage(2)%add_fast(lhs=self%stage(2), rhs=self%buffer) + call self%buffer%multiply_fast(lhs=self%stage(2), rhs=self%B(s)) + call self%stage(1)%add_fast(lhs=self%stage(1), rhs=self%buffer) + enddo + U = self%stage(1) if (present(new_Dt)) new_Dt = Dt endsubroutine integrate_fast diff --git a/src/lib/foodie_integrator_runge_kutta_lssp.f90 b/src/lib/foodie_integrator_runge_kutta_lssp.f90 index 2486ed78..7cc09a47 100644 --- a/src/lib/foodie_integrator_runge_kutta_lssp.f90 +++ b/src/lib/foodie_integrator_runge_kutta_lssp.f90 @@ -193,7 +193,7 @@ subroutine integrate(self, U, Dt, t, new_Dt) subroutine integrate_fast(self, U, Dt, t, new_Dt) !< Integrate integrand field by Linear SSP Runge-Kutta methods. - class(integrator_runge_kutta_lssp), intent(in) :: self !< Integrator. + class(integrator_runge_kutta_lssp), intent(inout) :: self !< Integrator. class(integrand_object), intent(inout) :: U !< Field to be integrated. real(R_P), intent(in) :: Dt !< Time step. real(R_P), intent(in) :: t !< Time. @@ -316,7 +316,6 @@ elemental subroutine initialize_order_s(self) enddo enddo endassociate - endsubroutine initialize_order_s subroutine integrate_order_s_1(self, U, Dt, t) @@ -327,19 +326,17 @@ subroutine integrate_order_s_1(self, U, Dt, t) real(R_P), intent(in) :: t !< Time. integer(I_P) :: s !< First stages counter. - associate(stage=>self%stage) - ! computing stages - stage(1) = U - do s=2, self%stages - stage(s) = stage(s-1) + (stage(s-1)%t(t=t) * (Dt * 0.5_R_P)) - enddo - stage(self%stages) = stage(self%stages) + (stage(self%stages)%t(t=t) * (Dt * 0.5_R_P)) - ! computing new time step - U = U * 0._R_P - do s=1, self%stages - U = U + (stage(s) * self%alpha(s)) - enddo - endassociate + ! computing stages + self%stage(1) = U + do s=2, self%stages + self%stage(s) = self%stage(s-1) + (self%stage(s-1)%t(t=t) * (Dt * 0.5_R_P)) + enddo + self%stage(self%stages) = self%stage(self%stages) + (self%stage(self%stages)%t(t=t) * (Dt * 0.5_R_P)) + ! computing new time step + U = U * 0._R_P + do s=1, self%stages + U = U + (self%stage(s) * self%alpha(s)) + enddo endsubroutine integrate_order_s_1 subroutine integrate_order_s(self, U, Dt, t) @@ -350,19 +347,17 @@ subroutine integrate_order_s(self, U, Dt, t) real(R_P), intent(in) :: t !< Time. integer(I_P) :: s !< First stages counter. - associate(stage=>self%stage) - ! computing stages - stage(1) = U - do s=2, self%stages - stage(s) = stage(s-1) + (stage(s-1)%t(t=t) * Dt) - enddo - stage(self%stages) = stage(self%stages) + (stage(self%stages)%t(t=t) * Dt) - ! computing new time step - U = U * 0._R_P - do s=1, self%stages - U = U + (stage(s) * self%alpha(s)) - enddo - endassociate + ! computing stages + self%stage(1) = U + do s=2, self%stages + self%stage(s) = self%stage(s-1) + (self%stage(s-1)%t(t=t) * Dt) + enddo + self%stage(self%stages) = self%stage(self%stages) + (self%stage(self%stages)%t(t=t) * Dt) + ! computing new time step + U = U * 0._R_P + do s=1, self%stages + U = U + (self%stage(s) * self%alpha(s)) + enddo endsubroutine integrate_order_s subroutine integrate_order_s_1_fast(self, U, Dt, t) @@ -373,29 +368,27 @@ subroutine integrate_order_s_1_fast(self, U, Dt, t) real(R_P), intent(in) :: t !< Time. integer(I_P) :: s !< First stages counter. - associate(stage=>self%stage, buffer=>self%buffer) - ! computing stages - stage(1) = U - do s=2, self%stages - buffer = stage(s-1) - call buffer%t_fast(t=t) - call buffer%multiply_fast(lhs=buffer, rhs=Dt * 0.5_R_P) - call stage(s)%add_fast(lhs=stage(s-1), rhs=buffer) - enddo - buffer = stage(self%stages) - call buffer%t_fast(t=t) - call buffer%multiply_fast(lhs=buffer, rhs=Dt * 0.5_R_P) - call stage(self%stages)%add_fast(lhs=stage(self%stages), rhs=buffer) - ! computing new time step - call U%multiply_fast(lhs=U, rhs=0._R_P) - do s=1, self%stages - call buffer%multiply_fast(lhs=stage(s), rhs=self%alpha(s)) - call U%add_fast(lhs=U, rhs=buffer) - enddo - endassociate + ! computing stages + self%stage(1) = U + do s=2, self%stages + self%buffer = self%stage(s-1) + call self%buffer%t_fast(t=t) + call self%buffer%multiply_fast(lhs=self%buffer, rhs=Dt * 0.5_R_P) + call self%stage(s)%add_fast(lhs=self%stage(s-1), rhs=self%buffer) + enddo + self%buffer = self%stage(self%stages) + call self%buffer%t_fast(t=t) + call self%buffer%multiply_fast(lhs=self%buffer, rhs=Dt * 0.5_R_P) + call self%stage(self%stages)%add_fast(lhs=self%stage(self%stages), rhs=self%buffer) + ! computing new time step + call U%multiply_fast(lhs=U, rhs=0._R_P) + do s=1, self%stages + call self%buffer%multiply_fast(lhs=self%stage(s), rhs=self%alpha(s)) + call U%add_fast(lhs=U, rhs=self%buffer) + enddo endsubroutine integrate_order_s_1_fast - subroutine integrate_order_s_fast(self, U, stage, buffer, Dt, t) + subroutine integrate_order_s_fast(self, U, Dt, t) !< Integrate integrand field by s-th order formula, fast mode. class(integrator_runge_kutta_lssp), intent(inout) :: self !< Integrator. class(integrand_object), intent(inout) :: U !< Field to be integrated. @@ -403,25 +396,23 @@ subroutine integrate_order_s_fast(self, U, stage, buffer, Dt, t) real(R_P), intent(in) :: t !< Time. integer(I_P) :: s !< First stages counter. - associate(stage=>self%stage, buffer=>self%buffer) - ! computing stages - stage(1) = U - do s=2, self%stages - buffer = stage(s-1) - call buffer%t_fast(t=t) - call buffer%multiply_fast(lhs=buffer, rhs=Dt) - call stage(s)%add_fast(lhs=stage(s-1), rhs=buffer) - enddo - buffer = stage(self%stages) - call buffer%t_fast(t=t) - call buffer%multiply_fast(lhs=buffer, rhs=Dt) - call stage(self%stages)%add_fast(lhs=stage(self%stages), rhs=buffer) - ! computing new time step - call U%multiply_fast(lhs=U, rhs=0._R_P) - do s=1, self%stages - call buffer%multiply_fast(lhs=stage(s), rhs=self%alpha(s)) - call U%add_fast(lhs=U, rhs=buffer) - enddo - endassociate + ! computing stages + self%stage(1) = U + do s=2, self%stages + self%buffer = self%stage(s-1) + call self%buffer%t_fast(t=t) + call self%buffer%multiply_fast(lhs=self%buffer, rhs=Dt) + call self%stage(s)%add_fast(lhs=self%stage(s-1), rhs=self%buffer) + enddo + self%buffer = self%stage(self%stages) + call self%buffer%t_fast(t=t) + call self%buffer%multiply_fast(lhs=self%buffer, rhs=Dt) + call self%stage(self%stages)%add_fast(lhs=self%stage(self%stages), rhs=self%buffer) + ! computing new time step + call U%multiply_fast(lhs=U, rhs=0._R_P) + do s=1, self%stages + call self%buffer%multiply_fast(lhs=self%stage(s), rhs=self%alpha(s)) + call U%add_fast(lhs=U, rhs=self%buffer) + enddo endsubroutine integrate_order_s_fast endmodule foodie_integrator_runge_kutta_lssp diff --git a/src/lib/foodie_integrator_runge_kutta_ssp.f90 b/src/lib/foodie_integrator_runge_kutta_ssp.f90 index 0d07af90..c40a44b9 100644 --- a/src/lib/foodie_integrator_runge_kutta_ssp.f90 +++ b/src/lib/foodie_integrator_runge_kutta_ssp.f90 @@ -142,7 +142,7 @@ module foodie_integrator_runge_kutta_ssp endtype integrator_runge_kutta_ssp contains - ! deferred methods + ! deferred methods pure function class_name(self) !< Return the class name of schemes. class(integrator_runge_kutta_ssp), intent(in) :: self !< Integrator. @@ -193,11 +193,10 @@ pure subroutine integr_assign_integr(lhs, rhs) endselect endsubroutine integr_assign_integr - subroutine integrate(self, U, stage, Dt, t, new_Dt) + subroutine integrate(self, U, Dt, t, new_Dt) !< Integrate field with explicit SSP Runge-Kutta scheme. - class(integrator_runge_kutta_ssp), intent(in) :: self !< Integrator. + class(integrator_runge_kutta_ssp), intent(inout) :: self !< Integrator. class(integrand_object), intent(inout) :: U !< Field to be integrated. - class(integrand_object), intent(inout) :: stage(1:) !< Runge-Kutta stages [1:stages]. real(R_P), intent(in) :: Dt !< Time step. real(R_P), intent(in) :: t !< Time. real(R_P), optional, intent(out) :: new_Dt !< New adapted time step. @@ -206,45 +205,43 @@ subroutine integrate(self, U, stage, Dt, t, new_Dt) ! computing stages do s=1, self%stages - stage(s) = U - do ss=1, s - 1 - stage(s) = stage(s) + (stage(ss) * (Dt * self%alph(s, ss))) - enddo - stage(s) = stage(s)%t(t=t + self%gamm(s) * Dt) + self%stage(s) = U + do ss=1, s - 1 + self%stage(s) = self%stage(s) + (self%stage(ss) * (Dt * self%alph(s, ss))) + enddo + self%stage(s) = self%stage(s)%t(t=t + self%gamm(s) * Dt) enddo ! computing new time step do s=1, self%stages - U = U + (stage(s) * (Dt * self%beta(s))) + U = U + (self%stage(s) * (Dt * self%beta(s))) enddo if (present(new_Dt)) new_Dt = Dt endsubroutine integrate - subroutine integrate_fast(self, U, stage, buffer, Dt, t, new_Dt) + subroutine integrate_fast(self, U, Dt, t, new_Dt) !< Integrate field with explicit SSP Runge-Kutta scheme. - class(integrator_runge_kutta_ssp), intent(in) :: self !< Integrator. - class(integrand_object), intent(inout) :: U !< Field to be integrated. - class(integrand_object), intent(inout) :: stage(1:) !< Runge-Kutta stages [1:stages]. - class(integrand_object), intent(inout) :: buffer !< Temporary buffer for doing fast operation. - real(R_P), intent(in) :: Dt !< Time step. - real(R_P), intent(in) :: t !< Time. - real(R_P), optional, intent(out) :: new_Dt !< New adapted time step. - integer(I_P) :: s !< First stages counter. - integer(I_P) :: ss !< Second stages counter. + class(integrator_runge_kutta_ssp), intent(inout) :: self !< Integrator. + class(integrand_object), intent(inout) :: U !< Field to be integrated. + real(R_P), intent(in) :: Dt !< Time step. + real(R_P), intent(in) :: t !< Time. + real(R_P), optional, intent(out) :: new_Dt !< New adapted time step. + integer(I_P) :: s !< First stages counter. + integer(I_P) :: ss !< Second stages counter. ! computing stages - buffer = U + self%buffer = U do s=1, self%stages - stage(s) = U - do ss=1, s - 1 - call buffer%multiply_fast(lhs=stage(ss), rhs=Dt * self%alph(s, ss)) - call stage(s)%add_fast(lhs=stage(s), rhs=buffer) - enddo - call stage(s)%t_fast(t=t + self%gamm(s) * Dt) + self%stage(s) = U + do ss=1, s - 1 + call self%buffer%multiply_fast(lhs=self%stage(ss), rhs=Dt * self%alph(s, ss)) + call self%stage(s)%add_fast(lhs=self%stage(s), rhs=self%buffer) + enddo + call self%stage(s)%t_fast(t=t + self%gamm(s) * Dt) enddo ! computing new time step do s=1, self%stages - call buffer%multiply_fast(lhs=stage(s), rhs=Dt * self%beta(s)) - call U%add_fast(lhs=U, rhs=buffer) + call self%buffer%multiply_fast(lhs=self%stage(s), rhs=Dt * self%beta(s)) + call U%add_fast(lhs=U, rhs=self%buffer) enddo if (present(new_Dt)) new_Dt = Dt endsubroutine integrate_fast @@ -285,10 +282,11 @@ elemental subroutine destroy(self) if (allocated(self%gamm)) deallocate(self%gamm) endsubroutine destroy - subroutine initialize(self, scheme, stop_on_fail) + subroutine initialize(self, scheme, U, stop_on_fail) !< Create the actual RK integrator: initialize the Butcher' table coefficients. class(integrator_runge_kutta_ssp), intent(inout) :: self !< Integrator. character(*), intent(in) :: scheme !< Selected scheme. + class(integrand_object), intent(in), optional :: U !< Integrand molding prototype. logical, intent(in), optional :: stop_on_fail !< Stop execution if initialization fail. if (self%is_supported(scheme=scheme)) then @@ -351,6 +349,8 @@ subroutine initialize(self, scheme, stop_on_fail) self%gamm(4) = 0.47454236302687_R_P self%gamm(5) = 0.93501063100924_R_P endselect + self%registers = self%stages + if (present(U)) call self%allocate_integrand_members(U=U) else call self%trigger_error(error=ERROR_UNSUPPORTED_SCHEME, & error_message='"'//trim(adjustl(scheme))//'" unsupported scheme', & diff --git a/src/tests/tester/foodie_tester.f90 b/src/tests/tester/foodie_tester.f90 index 8f925dc8..ca2fa298 100644 --- a/src/tests/tester/foodie_tester.f90 +++ b/src/tests/tester/foodie_tester.f90 @@ -258,7 +258,6 @@ subroutine integrate(scheme, integrand_0, Dt, final_time, iterations, stages, is class(integrand_object), allocatable :: integrand !< Integrand. class(integrand_object), allocatable :: previous(:) !< Previous time steps solutions. class(integrand_object), allocatable :: stage(:) !< Runge-Kutta stages. - class(integrand_object), allocatable :: stage_start(:) !< Runge-Kutta (autor) start stages. class(integrand_object), allocatable :: buffer !< Buffer oscillation field. class(integrand_object), allocatable :: filter !< Filter displacement. real(R_P), allocatable :: time(:) !< Time. @@ -279,11 +278,7 @@ subroutine integrate(scheme, integrand_0, Dt, final_time, iterations, stages, is do s=1, integrator%steps_number() previous(s) = integrand_0 enddo - call integrator_start%initialize(scheme='runge_kutta_ssp_stages_5_order_4') - allocate(stage_start(1:integrator_start%stages_number()), mold=integrand_0) - do s=1, integrator_start%stages_number() - stage_start(s) = integrand_0 - enddo + call integrator_start%initialize(scheme='runge_kutta_ssp_stages_5_order_4', U=integrand_0) if (integrator%steps_number()==0) then step_offset = 1 ! for 0 step-(a convention)-solver offset is 1 else @@ -314,9 +309,9 @@ subroutine integrate(scheme, integrand_0, Dt, final_time, iterations, stages, is do step = step + 1 if (is_fast) then - call integrator%integrate_fast(U=integrand, stage=stage, buffer=buffer, Dt=Dt, t=time(step_offset)) + call integrator%integrate_fast(U=integrand, Dt=Dt, t=time(step_offset)) else - call integrator%integrate(U=integrand, stage=stage, Dt=Dt, t=time(step_offset)) + call integrator%integrate(U=integrand, Dt=Dt, t=time(step_offset)) endif call update_previous_times if ((time(step_offset) >= final_time)) exit @@ -327,7 +322,7 @@ subroutine integrate(scheme, integrand_0, Dt, final_time, iterations, stages, is do step = step + 1 if (integrator%steps_number() >= step) then - call integrator_start%integrate(U=integrand, stage=stage_start, Dt=Dt, t=time(step)) + call integrator_start%integrate(U=integrand, Dt=Dt, t=time(step)) previous(step) = integrand time(step) = time(step-1) + Dt else @@ -350,7 +345,7 @@ subroutine integrate(scheme, integrand_0, Dt, final_time, iterations, stages, is do step = step + 1 if (integrator%steps_number() >= step) then - call integrator_start%integrate(U=integrand, stage=stage_start, Dt=Dt, t=time(step)) + call integrator_start%integrate(U=integrand, Dt=Dt, t=time(step)) previous(step) = integrand time(step) = time(step-1) + Dt else @@ -391,7 +386,7 @@ subroutine integrate(scheme, integrand_0, Dt, final_time, iterations, stages, is do step = step + 1 if (integrator%steps_number() >= step) then - call integrator_start%integrate(U=integrand, stage=stage_start, Dt=Dt, t=time(step)) + call integrator_start%integrate(U=integrand, Dt=Dt, t=time(step)) previous(step) = integrand time(step) = time(step-1) + Dt else @@ -421,7 +416,7 @@ subroutine integrate(scheme, integrand_0, Dt, final_time, iterations, stages, is do step = step + 1 if (integrator%steps_number() >= step) then - call integrator_start%integrate(U=integrand, stage=stage_start, Dt=Dt, t=time(step)) + call integrator_start%integrate(U=integrand, Dt=Dt, t=time(step)) previous(step) = integrand time(step) = time(step-1) + Dt else @@ -440,7 +435,7 @@ subroutine integrate(scheme, integrand_0, Dt, final_time, iterations, stages, is do step = step + 1 if (integrator%steps_number() >= step) then - call integrator_start%integrate(U=integrand, stage=stage_start, Dt=Dt, t=time(step)) + call integrator_start%integrate(U=integrand, Dt=Dt, t=time(step)) previous(step) = integrand time(step) = time(step-1) + Dt else From 5369053afe84ab5aa68caf0af12b9ab4729a0573 Mon Sep 17 00:00:00 2001 From: Stefano Zaghi Date: Tue, 23 May 2017 18:09:11 +0200 Subject: [PATCH 14/25] start modify multistep schemes integrate --- src/lib/foodie.f90 | 15 +-- src/lib/foodie_integrator_adams_bashforth.f90 | 61 ++++++------ ...die_integrator_adams_bashforth_moulton.f90 | 53 +++++----- src/lib/foodie_integrator_adams_moulton.f90 | 97 +++++++++---------- ...rator_backward_differentiation_formula.f90 | 51 +++++----- src/lib/foodie_integrator_lmm_ssp.f90 | 55 +++++------ ...e_integrator_multistep_explicit_object.f90 | 62 ++++++++---- ...e_integrator_multistep_implicit_object.f90 | 66 +++++++++---- src/tests/tester/foodie_tester.f90 | 2 +- 9 files changed, 251 insertions(+), 211 deletions(-) diff --git a/src/lib/foodie.f90 b/src/lib/foodie.f90 index 97b35c2b..2daa7509 100644 --- a/src/lib/foodie.f90 +++ b/src/lib/foodie.f90 @@ -146,7 +146,7 @@ pure function foodie_integrator_class_names() result(names) names = [names, int_runge_kutta_ssp % class_name()] endfunction foodie_integrator_class_names - subroutine foodie_integrator_factory(scheme, integrator, stages, tolerance, nu, alpha) + subroutine foodie_integrator_factory(scheme, integrator, stages, tolerance, nu, alpha, U) !< Return a concrete instance of [[integrator_object]] given a scheme selection. !< !< This is the FOODIE integrators factory. @@ -154,10 +154,11 @@ subroutine foodie_integrator_factory(scheme, integrator, stages, tolerance, nu, !< @note If an error occurs the error status of [[integrator_object]] is updated. character(*), intent(in) :: scheme !< Selected integrator given. class(integrator_object), allocatable, intent(out) :: integrator !< The FOODIE integrator. - integer(I_P), optional, intent(in) :: stages !< Stages of multi-stage methods. - real(R_P), optional, intent(in) :: tolerance !< Tolerance on the local truncation error. - real(R_P), optional, intent(in) :: nu !< Williams-Robert-Asselin filter coefficient. - real(R_P), optional, intent(in) :: alpha !< Robert-Asselin filter coefficient. + integer(I_P), optional, intent(in) :: stages !< Stages of multi-stage methods. + real(R_P), optional, intent(in) :: tolerance !< Tolerance on the local truncation error. + real(R_P), optional, intent(in) :: nu !< Williams-Robert-Asselin filter coefficient. + real(R_P), optional, intent(in) :: alpha !< Robert-Asselin filter coefficient. + class(integrand_object), optional, intent(in) :: U !< Integrand molding prototype. type(integrator_adams_bashforth) :: int_adams_bashforth !< Integrator Adams Bashforth. type(integrator_adams_bashforth_moulton) :: int_adams_bashforth_moulton !< Integrator Adams Bashforth Moulton. type(integrator_adams_moulton) :: int_adams_moulton !< Integrator Adams Moulton. @@ -182,7 +183,7 @@ subroutine foodie_integrator_factory(scheme, integrator, stages, tolerance, nu, allocate(integrator_adams_bashforth :: integrator) select type(integrator) type is(integrator_adams_bashforth) - call integrator%initialize(scheme=scheme) + call integrator%initialize(scheme=scheme, U=U) endselect elseif (index(trim(adjustl(scheme)), trim(int_adams_moulton%class_name())) > 0) then allocate(integrator_adams_moulton :: integrator) @@ -244,7 +245,7 @@ subroutine foodie_integrator_factory(scheme, integrator, stages, tolerance, nu, allocate(integrator_runge_kutta_ssp :: integrator) select type(integrator) type is(integrator_runge_kutta_ssp) - call integrator%initialize(scheme=scheme) + call integrator%initialize(scheme=scheme, U=U) endselect else write(stderr, '(A)')'error: "'//trim(adjustl(scheme))//'" scheme is unknown!' diff --git a/src/lib/foodie_integrator_adams_bashforth.f90 b/src/lib/foodie_integrator_adams_bashforth.f90 index 4f84b140..43ae728b 100644 --- a/src/lib/foodie_integrator_adams_bashforth.f90 +++ b/src/lib/foodie_integrator_adams_bashforth.f90 @@ -127,44 +127,41 @@ pure subroutine integr_assign_integr(lhs, rhs) endselect endsubroutine integr_assign_integr - subroutine integrate(self, U, previous, Dt, t, autoupdate) + subroutine integrate(self, U, Dt, t, autoupdate) !< Integrate field with Adams-Bashforth class scheme. - class(integrator_adams_bashforth), intent(in) :: self !< Integrator. - class(integrand_object), intent(inout) :: U !< Field to be integrated. - class(integrand_object), intent(inout) :: previous(1:) !< Previous time steps solutions of integrand field. - real(R_P), intent(in) :: Dt !< Time steps. - real(R_P), intent(in) :: t(:) !< Times. - logical, optional, intent(in) :: autoupdate !< Perform cyclic autoupdate of previous time steps. - logical :: autoupdate_ !< Perform cyclic autoupdate of previous time steps, dummy var. - integer(I_P) :: s !< Steps counter. + class(integrator_adams_bashforth), intent(inout) :: self !< Integrator. + class(integrand_object), intent(inout) :: U !< Field to be integrated. + real(R_P), intent(in) :: Dt !< Time steps. + real(R_P), intent(in) :: t(:) !< Times. + logical, optional, intent(in) :: autoupdate !< Perform cyclic autoupdate of previous time steps. + logical :: autoupdate_ !< Perform cyclic autoupdate of previous time steps, dummy var. + integer(I_P) :: s !< Steps counter. autoupdate_ = .true. ; if (present(autoupdate)) autoupdate_ = autoupdate do s=1, self%steps - U = U + (previous(s)%t(t=t(s)) * (Dt * self%b(s))) + U = U + (self%previous(s)%t(t=t(s)) * (Dt * self%b(s))) enddo - if (autoupdate_) call self%update_previous(U=U, previous=previous) + if (autoupdate_) call self%update_previous(U=U, previous=self%previous) endsubroutine integrate - subroutine integrate_fast(self, U, previous, buffer, Dt, t, autoupdate) + subroutine integrate_fast(self, U, Dt, t, autoupdate) !< Integrate field with Adams-Bashforth class scheme. - class(integrator_adams_bashforth), intent(in) :: self !< Integrator. - class(integrand_object), intent(inout) :: U !< Field to be integrated. - class(integrand_object), intent(inout) :: previous(1:) !< Previous time steps solutions of integrand field. - class(integrand_object), intent(inout) :: buffer !< Temporary buffer for doing fast operation. - real(R_P), intent(in) :: Dt !< Time steps. - real(R_P), intent(in) :: t(:) !< Times. - logical, optional, intent(in) :: autoupdate !< Perform cyclic autoupdate of previous time steps. - logical :: autoupdate_ !< Perform cyclic autoupdate of previous time steps, dummy var. - integer(I_P) :: s !< Steps counter. + class(integrator_adams_bashforth), intent(inout) :: self !< Integrator. + class(integrand_object), intent(inout) :: U !< Field to be integrated. + real(R_P), intent(in) :: Dt !< Time steps. + real(R_P), intent(in) :: t(:) !< Times. + logical, optional, intent(in) :: autoupdate !< Perform cyclic autoupdate of previous time steps. + logical :: autoupdate_ !< Perform cyclic autoupdate of previous time steps, dummy var. + integer(I_P) :: s !< Steps counter. autoupdate_ = .true. ; if (present(autoupdate)) autoupdate_ = autoupdate do s=1, self%steps - buffer = previous(s) - call buffer%t_fast(t=t(s)) - call buffer%multiply_fast(lhs=buffer, rhs=Dt * self%b(s)) - call U%add_fast(lhs=U, rhs=buffer) + self%buffer = self%previous(s) + call self%buffer%t_fast(t=t(s)) + call self%buffer%multiply_fast(lhs=self%buffer, rhs=Dt * self%b(s)) + call U%add_fast(lhs=U, rhs=self%buffer) enddo - if (autoupdate_) call self%update_previous(U=U, previous=previous) + if (autoupdate_) call self%update_previous(U=U, previous=self%previous) endsubroutine integrate_fast elemental function is_supported(self, scheme) @@ -201,13 +198,15 @@ elemental subroutine destroy(self) if (allocated(self%b)) deallocate(self%b) endsubroutine destroy - subroutine initialize(self, scheme) + subroutine initialize(self, scheme, U, stop_on_fail) !< Create the actual Adams-Bashforth integrator: initialize the *b* coefficients. !< !< @note If the integrator is initialized with a bad (unsupported) number of required time steps the initialization fails and !< the integrator error status is updated consistently for external-provided errors handling. - class(integrator_adams_bashforth), intent(inout) :: self !< Integrator. - character(*), intent(in) :: scheme !< Selected scheme. + class(integrator_adams_bashforth), intent(inout) :: self !< Integrator. + character(*), intent(in) :: scheme !< Selected scheme. + class(integrand_object), intent(in), optional :: U !< Integrand molding prototype. + logical, intent(in), optional :: stop_on_fail !< Stop execution if initialization fail. if (self%is_supported(scheme=scheme)) then call self%destroy @@ -381,10 +380,12 @@ subroutine initialize(self, scheme) self%b(15) = -2161567671248849.0_R_P/62768369664000.0_R_P self%b(16) = 362555126427073.0_R_P/62768369664000.0_R_P endselect + self%registers = self%steps + if (present(U)) call self%allocate_integrand_members(U=U) else call self%trigger_error(error=ERROR_UNSUPPORTED_SCHEME, & error_message='"'//trim(adjustl(scheme))//'" unsupported scheme', & - is_severe=.true.) + is_severe=stop_on_fail) endif endsubroutine initialize endmodule foodie_integrator_adams_bashforth diff --git a/src/lib/foodie_integrator_adams_bashforth_moulton.f90 b/src/lib/foodie_integrator_adams_bashforth_moulton.f90 index 1a013352..e2a3aece 100644 --- a/src/lib/foodie_integrator_adams_bashforth_moulton.f90 +++ b/src/lib/foodie_integrator_adams_bashforth_moulton.f90 @@ -182,43 +182,38 @@ pure subroutine integr_assign_integr(lhs, rhs) endselect endsubroutine integr_assign_integr - subroutine integrate(self, U, previous, Dt, t, iterations, autoupdate) + subroutine integrate(self, U, Dt, t, iterations, autoupdate) !< Integrate field with Adams-Bashforth-Moulton class scheme. - class(integrator_adams_bashforth_moulton), intent(in) :: self !< Integrator. - class(integrand_object), intent(inout) :: U !< Field to be integrated. - class(integrand_object), intent(inout) :: previous(1:) !< Previous time steps solutions of integrand. - real(R_P), intent(in) :: Dt !< Time steps. - real(R_P), intent(in) :: t(:) !< Times. - integer(I_P), intent(in), optional :: iterations !< Fixed point iterations of AM scheme. - logical, intent(in), optional :: autoupdate !< Cyclic autoupdate of previous time steps flag. - logical :: autoupdate_ !< Cyclic autoupdate of previous time steps flag,i - !< local variable. + class(integrator_adams_bashforth_moulton), intent(inout) :: self !< Integrator. + class(integrand_object), intent(inout) :: U !< Field to be integrated. + real(R_P), intent(in) :: Dt !< Time steps. + real(R_P), intent(in) :: t(:) !< Times. + integer(I_P), intent(in), optional :: iterations !< Fixed point iterations of AM scheme. + logical, intent(in), optional :: autoupdate !< Cyclic autoupdate of previous time steps flag. + logical :: autoupdate_ !< Cyclic autoupdate of previous time steps flag,i + !< local variable. autoupdate_ = .true. ; if (present(autoupdate)) autoupdate_ = autoupdate - call self%predictor%integrate(U=U, previous=previous, Dt=Dt, t=t, autoupdate=.false.) - call self%corrector%integrate(U=U, previous=previous(2:), Dt=Dt, t=t, iterations=iterations, autoupdate=.false.) - call self%predictor%update_previous(U=U, previous=previous) - if (autoupdate_) call self%predictor%update_previous(U=U, previous=previous) + call self%predictor%integrate(U=U, Dt=Dt, t=t, autoupdate=.false.) + call self%corrector%integrate(U=U, Dt=Dt, t=t, iterations=iterations, autoupdate=.false.) + ! if (autoupdate_) call self%predictor%update_previous(U=U, previous=previous) endsubroutine integrate - subroutine integrate_fast(self, U, previous, buffer, Dt, t, iterations, autoupdate) + subroutine integrate_fast(self, U, Dt, t, iterations, autoupdate) !< Integrate field with Adams-Bashforth-Moulton class scheme, fast mode. - class(integrator_adams_bashforth_moulton), intent(in) :: self !< Integrator. - class(integrand_object), intent(inout) :: U !< Field to be integrated. - class(integrand_object), intent(inout) :: previous(1:) !< Previous time steps solutions of integrand. - class(integrand_object), intent(inout) :: buffer !< Temporary buffer for doing fast operation. - real(R_P), intent(in) :: Dt !< Time steps. - real(R_P), intent(in) :: t(:) !< Times. - integer(I_P), intent(in), optional :: iterations !< Fixed point iterations of AM scheme. - logical, intent(in), optional :: autoupdate !< Cyclic autoupdate of previous time steps flag. - logical :: autoupdate_ !< Cyclic autoupdate of previous time steps flag,i - !< local variable. + class(integrator_adams_bashforth_moulton), intent(inout) :: self !< Integrator. + class(integrand_object), intent(inout) :: U !< Field to be integrated. + real(R_P), intent(in) :: Dt !< Time steps. + real(R_P), intent(in) :: t(:) !< Times. + integer(I_P), intent(in), optional :: iterations !< Fixed point iterations of AM scheme. + logical, intent(in), optional :: autoupdate !< Cyclic autoupdate of previous time steps flag. + logical :: autoupdate_ !< Cyclic autoupdate of previous time steps flag, + !< local variable. autoupdate_ = .true. ; if (present(autoupdate)) autoupdate_ = autoupdate - call self%predictor%integrate_fast(U=U, previous=previous, buffer=buffer, Dt=Dt, t=t, autoupdate=.false.) - call self%corrector%integrate_fast(U=U, previous=previous(2:), buffer=buffer, Dt=Dt, t=t, iterations=iterations, & - autoupdate=.false.) - if (autoupdate_) call self%predictor%update_previous(U=U, previous=previous) + call self%predictor%integrate_fast(U=U, Dt=Dt, t=t, autoupdate=.false.) + call self%corrector%integrate_fast(U=U, Dt=Dt, t=t, iterations=iterations, autoupdate=.false.) + ! if (autoupdate_) call self%predictor%update_previous(U=U, previous=previous) endsubroutine integrate_fast elemental function is_supported(self, scheme) diff --git a/src/lib/foodie_integrator_adams_moulton.f90 b/src/lib/foodie_integrator_adams_moulton.f90 index 13b8bf0d..226bc3a3 100644 --- a/src/lib/foodie_integrator_adams_moulton.f90 +++ b/src/lib/foodie_integrator_adams_moulton.f90 @@ -128,91 +128,88 @@ pure subroutine integr_assign_integr(lhs, rhs) endselect endsubroutine integr_assign_integr - subroutine integrate(self, U, previous, Dt, t, iterations, autoupdate) + subroutine integrate(self, U, Dt, t, iterations, autoupdate) !< Integrate field with Adams-Moulton class scheme. - class(integrator_adams_moulton), intent(in) :: self !< Integrator. - class(integrand_object), intent(inout) :: U !< Field to be integrated. - class(integrand_object), intent(inout) :: previous(1:) !< Previous time steps solutions of integrand field. - real(R_P), intent(in) :: Dt !< Time steps. - real(R_P), intent(in) :: t(:) !< Times. - integer(I_P), intent(in), optional :: iterations !< Fixed point iterations. - logical, intent(in), optional :: autoupdate !< Cyclic autoupdate of previous time steps flag. - logical :: autoupdate_ !< Cyclic autoupdate of previous time steps flag, dummy var. - class(integrand_object), allocatable :: delta !< Delta RHS for fixed point iterations. - integer(I_P) :: s !< Steps counter. + class(integrator_adams_moulton), intent(inout) :: self !< Integrator. + class(integrand_object), intent(inout) :: U !< Field to be integrated. + real(R_P), intent(in) :: Dt !< Time steps. + real(R_P), intent(in) :: t(:) !< Times. + integer(I_P), intent(in), optional :: iterations !< Fixed point iterations. + logical, intent(in), optional :: autoupdate !< Cyclic autoupdate of previous time steps flag. + logical :: autoupdate_ !< Cyclic autoupdate of previous time steps flag, dummy var. + class(integrand_object), allocatable :: delta !< Delta RHS for fixed point iterations. + integer(I_P) :: s !< Steps counter. autoupdate_ = .true. ; if (present(autoupdate)) autoupdate_ = autoupdate if (self%steps>0) then if (present(iterations)) then ! perform fixed point iterations allocate(delta, mold=U) - delta = previous(self%steps) + delta = self%previous(self%steps) do s=0, self%steps - 1 - delta = delta + (previous(s+1)%t(t=t(s+1)) * (Dt * self%b(s))) + delta = delta + (self%previous(s+1)%t(t=t(s+1)) * (Dt * self%b(s))) enddo do s=1, iterations U = delta + (U%t(t=t(self%steps) + Dt) * (Dt * self%b(self%steps))) enddo else - U = previous(self%steps) + (U%t(t=t(self%steps) + Dt) * (Dt * self%b(self%steps))) + U = self%previous(self%steps) + (U%t(t=t(self%steps) + Dt) * (Dt * self%b(self%steps))) do s=0, self%steps - 1 - U = U + (previous(s+1)%t(t=t(s+1)) * (Dt * self%b(s))) + U = U + (self%previous(s+1)%t(t=t(s+1)) * (Dt * self%b(s))) enddo endif - if (autoupdate_) call self%update_previous(U=U, previous=previous) + if (autoupdate_) call self%update_previous(U=U, previous=self%previous) else U = U + (U%t(t=t(1)) * (Dt * self%b(0))) endif endsubroutine integrate - subroutine integrate_fast(self, U, previous, buffer, Dt, t, iterations, autoupdate) + subroutine integrate_fast(self, U, Dt, t, iterations, autoupdate) !< Integrate field with Adams-Moulton class scheme, fast mode. - class(integrator_adams_moulton), intent(in) :: self !< Integrator. - class(integrand_object), intent(inout) :: U !< Field to be integrated. - class(integrand_object), intent(inout) :: previous(1:) !< Previous time steps solutions of integrand field. - class(integrand_object), intent(inout) :: buffer !< Temporary buffer for doing fast operation. - real(R_P), intent(in) :: Dt !< Time steps. - real(R_P), intent(in) :: t(:) !< Times. - integer(I_P), intent(in), optional :: iterations !< Fixed point iterations. - logical, intent(in), optional :: autoupdate !< Cyclic autoupdate of previous time steps flag. - logical :: autoupdate_ !< Cyclic autoupdate of previous time steps flag, dummy var. - class(integrand_object), allocatable :: delta !< Delta RHS for fixed point iterations. - integer(I_P) :: s !< Steps counter. + class(integrator_adams_moulton), intent(inout) :: self !< Integrator. + class(integrand_object), intent(inout) :: U !< Field to be integrated. + real(R_P), intent(in) :: Dt !< Time steps. + real(R_P), intent(in) :: t(:) !< Times. + integer(I_P), intent(in), optional :: iterations !< Fixed point iterations. + logical, intent(in), optional :: autoupdate !< Cyclic autoupdate of previous time steps flag. + logical :: autoupdate_ !< Cyclic autoupdate of previous time steps flag, dummy var. + class(integrand_object), allocatable :: delta !< Delta RHS for fixed point iterations. + integer(I_P) :: s !< Steps counter. autoupdate_ = .true. ; if (present(autoupdate)) autoupdate_ = autoupdate if (self%steps>0) then if (present(iterations)) then ! perform fixed point iterations allocate(delta, mold=U) - delta = previous(self%steps) + delta = self%previous(self%steps) do s=0, self%steps - 1 - buffer = previous(s+1) - call buffer%t_fast(t=t(s+1)) - call buffer%multiply_fast(lhs=buffer, rhs=Dt * self%b(s)) - call delta%add_fast(lhs=delta, rhs=buffer) + self%buffer = self%previous(s+1) + call self%buffer%t_fast(t=t(s+1)) + call self%buffer%multiply_fast(lhs=self%buffer, rhs=Dt * self%b(s)) + call delta%add_fast(lhs=delta, rhs=self%buffer) enddo do s=1, iterations - buffer = U - call buffer%t_fast(t=t(self%steps) + Dt) - call buffer%multiply_fast(lhs=buffer, rhs=Dt * self%b(self%steps)) - call U%add_fast(lhs=delta, rhs=buffer) + self%buffer = U + call self%buffer%t_fast(t=t(self%steps) + Dt) + call self%buffer%multiply_fast(lhs=self%buffer, rhs=Dt * self%b(self%steps)) + call U%add_fast(lhs=delta, rhs=self%buffer) enddo else - buffer = U - call buffer%t_fast(t=t(self%steps) + Dt) - call buffer%multiply_fast(lhs=buffer, rhs=Dt * self%b(self%steps)) - call U%add_fast(lhs=previous(self%steps), rhs=buffer) + self%buffer = U + call self%buffer%t_fast(t=t(self%steps) + Dt) + call self%buffer%multiply_fast(lhs=self%buffer, rhs=Dt * self%b(self%steps)) + call U%add_fast(lhs=self%previous(self%steps), rhs=self%buffer) do s=0, self%steps - 1 - buffer = previous(s+1) - call buffer%t_fast(t=t(s+1)) - call buffer%multiply_fast(lhs=buffer, rhs=Dt * self%b(s)) - call U%add_fast(lhs=U, rhs=buffer) + self%buffer = self%previous(s+1) + call self%buffer%t_fast(t=t(s+1)) + call self%buffer%multiply_fast(lhs=self%buffer, rhs=Dt * self%b(s)) + call U%add_fast(lhs=U, rhs=self%buffer) enddo endif - if (autoupdate_) call self%update_previous(U=U, previous=previous) + if (autoupdate_) call self%update_previous(U=U, previous=self%previous) else - buffer = U - call buffer%t_fast(t=t(1)) - call buffer%multiply_fast(lhs=buffer, rhs=Dt * self%b(0)) - call U%add_fast(lhs=U, rhs=buffer) + self%buffer = U + call self%buffer%t_fast(t=t(1)) + call self%buffer%multiply_fast(lhs=self%buffer, rhs=Dt * self%b(0)) + call U%add_fast(lhs=U, rhs=self%buffer) endif endsubroutine integrate_fast diff --git a/src/lib/foodie_integrator_backward_differentiation_formula.f90 b/src/lib/foodie_integrator_backward_differentiation_formula.f90 index fc16fac1..5def63e0 100644 --- a/src/lib/foodie_integrator_backward_differentiation_formula.f90 +++ b/src/lib/foodie_integrator_backward_differentiation_formula.f90 @@ -127,39 +127,36 @@ pure subroutine integr_assign_integr(lhs, rhs) endselect endsubroutine integr_assign_integr - subroutine integrate(self, U, previous, Dt, t, iterations, autoupdate) + subroutine integrate(self, U, Dt, t, iterations, autoupdate) !< Integrate field with BDF class scheme. - class(integrator_back_df), intent(in) :: self !< Integrator. - class(integrand_object), intent(inout) :: U !< Field to be integrated. - class(integrand_object), intent(inout) :: previous(1:) !< Previous time steps solutions of integrand field. - real(R_P), intent(in) :: Dt !< Time steps. - real(R_P), intent(in) :: t(:) !< Times. - integer(I_P), optional, intent(in) :: iterations !< Fixed point iterations. - logical, optional, intent(in) :: autoupdate !< Perform cyclic autoupdate of previous time steps. - integer(I_P) :: iterations_ !< Fixed point iterations. - logical :: autoupdate_ !< Perform cyclic autoupdate of previous time steps, dummy var. - class(integrand_object), allocatable :: delta !< Delta RHS for fixed point iterations. - integer(I_P) :: s !< Steps counter. + class(integrator_back_df), intent(inout) :: self !< Integrator. + class(integrand_object), intent(inout) :: U !< Field to be integrated. + real(R_P), intent(in) :: Dt !< Time steps. + real(R_P), intent(in) :: t(:) !< Times. + integer(I_P), optional, intent(in) :: iterations !< Fixed point iterations. + logical, optional, intent(in) :: autoupdate !< Perform cyclic autoupdate of previous time steps. + integer(I_P) :: iterations_ !< Fixed point iterations. + logical :: autoupdate_ !< Perform cyclic autoupdate of previous time steps, dummy var. + class(integrand_object), allocatable :: delta !< Delta RHS for fixed point iterations. + integer(I_P) :: s !< Steps counter. autoupdate_ = .true. ; if (present(autoupdate)) autoupdate_ = autoupdate iterations_ = 1 ; if (present(iterations)) iterations_ = iterations allocate(delta, mold=U) - delta = previous(self%steps) * (-self%a(self%steps)) + delta = self%previous(self%steps) * (-self%a(self%steps)) do s=1, self%steps - 1 - delta = delta + (previous(s) * (-self%a(s))) + delta = delta + (self%previous(s) * (-self%a(s))) enddo do s=1, iterations_ U = delta + (U%t(t=t(self%steps) + Dt) * (Dt * self%b)) enddo - if (autoupdate_) call self%update_previous(U=U, previous=previous, is_like_explicit=.true.) + if (autoupdate_) call self%update_previous(U=U, previous=self%previous, is_like_explicit=.true.) endsubroutine integrate - subroutine integrate_fast(self, U, previous, buffer, Dt, t, iterations, autoupdate) + subroutine integrate_fast(self, U, Dt, t, iterations, autoupdate) !< Integrate field with BDF class scheme. - class(integrator_back_df), intent(in) :: self !< Integrator. + class(integrator_back_df), intent(inout) :: self !< Integrator. class(integrand_object), intent(inout) :: U !< Field to be integrated. - class(integrand_object), intent(inout) :: previous(1:) !< Previous time steps solutions of integrand field. - class(integrand_object), intent(inout) :: buffer !< Temporary buffer for doing fast operation. real(R_P), intent(in) :: Dt !< Time steps. real(R_P), intent(in) :: t(:) !< Times. integer(I_P), optional, intent(in) :: iterations !< Fixed point iterations. @@ -172,18 +169,18 @@ subroutine integrate_fast(self, U, previous, buffer, Dt, t, iterations, autoupda autoupdate_ = .true. ; if (present(autoupdate)) autoupdate_ = autoupdate iterations_ = 1 ; if (present(iterations)) iterations_ = iterations allocate(delta, mold=U) - call delta%multiply_fast(lhs=previous(self%steps), rhs=-self%a(self%steps)) + call delta%multiply_fast(lhs=self%previous(self%steps), rhs=-self%a(self%steps)) do s=1, self%steps - 1 - call buffer%multiply_fast(lhs=previous(s), rhs=-self%a(s)) - call delta%add_fast(lhs=delta, rhs=buffer) + call self%buffer%multiply_fast(lhs=self%previous(s), rhs=-self%a(s)) + call delta%add_fast(lhs=delta, rhs=self%buffer) enddo do s=1, iterations - buffer = U - call buffer%t_fast(t=t(self%steps) + Dt) - call buffer%multiply_fast(lhs=buffer, rhs=Dt * self%b) - call U%add_fast(lhs=delta, rhs=buffer) + self%buffer = U + call self%buffer%t_fast(t=t(self%steps) + Dt) + call self%buffer%multiply_fast(lhs=self%buffer, rhs=Dt * self%b) + call U%add_fast(lhs=delta, rhs=self%buffer) enddo - if (autoupdate_) call self%update_previous(U=U, previous=previous, is_like_explicit=.true.) + if (autoupdate_) call self%update_previous(U=U, previous=self%previous, is_like_explicit=.true.) endsubroutine integrate_fast elemental function is_supported(self, scheme) diff --git a/src/lib/foodie_integrator_lmm_ssp.f90 b/src/lib/foodie_integrator_lmm_ssp.f90 index effe063a..f8c69728 100644 --- a/src/lib/foodie_integrator_lmm_ssp.f90 +++ b/src/lib/foodie_integrator_lmm_ssp.f90 @@ -117,53 +117,50 @@ pure subroutine integr_assign_integr(lhs, rhs) endselect endsubroutine integr_assign_integr - subroutine integrate(self, U, previous, Dt, t, autoupdate) + subroutine integrate(self, U, Dt, t, autoupdate) !< Integrate field with LMM-SSP class scheme. - class(integrator_lmm_ssp), intent(in) :: self !< Integrator. - class(integrand_object), intent(inout) :: U !< Field to be integrated. - class(integrand_object), intent(inout) :: previous(1:) !< Previous time steps solutions of integrand field. - real(R_P), intent(in) :: Dt !< Time steps. - real(R_P), intent(in) :: t(:) !< Times. - logical, optional, intent(in) :: autoupdate !< Perform cyclic autoupdate of previous time steps. - logical :: autoupdate_ !< Perform cyclic autoupdate of previous time steps, dummy var. - integer(I_P) :: s !< Steps counter. + class(integrator_lmm_ssp), intent(inout) :: self !< Integrator. + class(integrand_object), intent(inout) :: U !< Field to be integrated. + real(R_P), intent(in) :: Dt !< Time steps. + real(R_P), intent(in) :: t(:) !< Times. + logical, optional, intent(in) :: autoupdate !< Perform cyclic autoupdate of previous time steps. + logical :: autoupdate_ !< Perform cyclic autoupdate of previous time steps, dummy var. + integer(I_P) :: s !< Steps counter. autoupdate_ = .true. ; if (present(autoupdate)) autoupdate_ = autoupdate U = U * 0._R_P do s=1, self%steps - if (self%a(s) /= 0._R_P) U = U + (previous(s) * self%a(s)) - if (self%b(s) /= 0._R_P) U = U + (previous(s)%t(t=t(s)) * (Dt * self%b(s))) + if (self%a(s) /= 0._R_P) U = U + (self%previous(s) * self%a(s)) + if (self%b(s) /= 0._R_P) U = U + (self%previous(s)%t(t=t(s)) * (Dt * self%b(s))) enddo - if (autoupdate_) call self%update_previous(U=U, previous=previous) + if (autoupdate_) call self%update_previous(U=U, previous=self%previous) endsubroutine integrate - subroutine integrate_fast(self, U, previous, buffer, Dt, t, autoupdate) + subroutine integrate_fast(self, U, Dt, t, autoupdate) !< Integrate field with LMM-SSP class scheme, fast mode. - class(integrator_lmm_ssp), intent(in) :: self !< Integrator. - class(integrand_object), intent(inout) :: U !< Field to be integrated. - class(integrand_object), intent(inout) :: previous(1:) !< Previous time steps solutions of integrand field. - class(integrand_object), intent(inout) :: buffer !< Temporary buffer for doing fast operation. - real(R_P), intent(in) :: Dt !< Time steps. - real(R_P), intent(in) :: t(:) !< Times. - logical, optional, intent(in) :: autoupdate !< Perform cyclic autoupdate of previous time steps. - logical :: autoupdate_ !< Perform cyclic autoupdate of previous time steps, dummy var. - integer(I_P) :: s !< Steps counter. + class(integrator_lmm_ssp), intent(inout) :: self !< Integrator. + class(integrand_object), intent(inout) :: U !< Field to be integrated. + real(R_P), intent(in) :: Dt !< Time steps. + real(R_P), intent(in) :: t(:) !< Times. + logical, optional, intent(in) :: autoupdate !< Perform cyclic autoupdate of previous time steps. + logical :: autoupdate_ !< Perform cyclic autoupdate of previous time steps, dummy var. + integer(I_P) :: s !< Steps counter. autoupdate_ = .true. ; if (present(autoupdate)) autoupdate_ = autoupdate call U%multiply_fast(lhs=U, rhs=0._R_P) do s=1, self%steps if (self%a(s) /= 0._R_P) then - call buffer%multiply_fast(lhs=previous(s), rhs=self%a(s)) - call U%add_fast(lhs=U, rhs=buffer) + call self%buffer%multiply_fast(lhs=self%previous(s), rhs=self%a(s)) + call U%add_fast(lhs=U, rhs=self%buffer) endif if (self%b(s) /= 0._R_P) then - buffer = previous(s) - call buffer%t_fast(t=t(s)) - call buffer%multiply_fast(lhs=buffer, rhs=self%b(s)) - call U%add_fast(lhs=U, rhs=buffer) + self%buffer = self%previous(s) + call self%buffer%t_fast(t=t(s)) + call self%buffer%multiply_fast(lhs=self%buffer, rhs=self%b(s)) + call U%add_fast(lhs=U, rhs=self%buffer) endif enddo - if (autoupdate_) call self%update_previous(U=U, previous=previous) + if (autoupdate_) call self%update_previous(U=U, previous=self%previous) endsubroutine integrate_fast elemental function is_supported(self, scheme) diff --git a/src/lib/foodie_integrator_multistep_explicit_object.f90 b/src/lib/foodie_integrator_multistep_explicit_object.f90 index 5cb07427..6c9d5751 100644 --- a/src/lib/foodie_integrator_multistep_explicit_object.f90 +++ b/src/lib/foodie_integrator_multistep_explicit_object.f90 @@ -14,7 +14,10 @@ module foodie_integrator_multistep_explicit_object type, extends(integrator_object), abstract :: integrator_multistep_explicit_object !< Abstract type of FOODIE ODE integrators of the multistep family. - integer(I_P) :: steps=0 !< Number of time steps. + integer(I_P) :: registers !< Number of registers used for stages. + integer(I_P) :: steps !< Number of time steps. + class(integrand_object), allocatable :: previous(:) !< Previous steps. + class(integrand_object), allocatable :: buffer !< Buffer used for fast integration. contains ! deferred methods procedure(integrate_interface), pass(self), deferred :: integrate !< Integrate integrand field. @@ -25,33 +28,31 @@ module foodie_integrator_multistep_explicit_object procedure, pass(self) :: stages_number !< Return number of stages used. procedure, pass(self) :: steps_number !< Return number of steps used. ! public methods - procedure, pass(self) :: destroy_multistep !< Destroy the integrator. - procedure, pass(self) :: update_previous !< Cyclic update previous time steps. + procedure, pass(self) :: allocate_integrand_members !< Allocate integrand members. + procedure, pass(self) :: destroy_multistep !< Destroy the integrator. + procedure, pass(self) :: update_previous !< Cyclic update previous time steps. endtype integrator_multistep_explicit_object abstract interface !< Abstract interfaces of deferred methods of [[integrator_multistep_explicit_object]]. - subroutine integrate_interface(self, U, previous, Dt, t, autoupdate) + subroutine integrate_interface(self, U, Dt, t, autoupdate) !< Integrate integrand field. import :: integrand_object, integrator_multistep_explicit_object, R_P - class(integrator_multistep_explicit_object), intent(in) :: self !< Integrator. - class(integrand_object), intent(inout) :: U !< Integrand. - class(integrand_object), intent(inout) :: previous(1:) !< Previous time steps solutions of integrand field. - real(R_P), intent(in) :: Dt !< Time steps. - real(R_P), intent(in) :: t(:) !< Times. - logical, optional, intent(in) :: autoupdate !< Perform cyclic autoupdate of previous time steps. + class(integrator_multistep_explicit_object), intent(inout) :: self !< Integrator. + class(integrand_object), intent(inout) :: U !< Integrand. + real(R_P), intent(in) :: Dt !< Time steps. + real(R_P), intent(in) :: t(:) !< Times. + logical, optional, intent(in) :: autoupdate !< Perform cyclic autoupdate of previous time steps. endsubroutine integrate_interface - subroutine integrate_fast_interface(self, U, previous, buffer, Dt, t, autoupdate) + subroutine integrate_fast_interface(self, U, Dt, t, autoupdate) !< Integrate integrand field, fast mode. import :: integrand_object, integrator_multistep_explicit_object, R_P - class(integrator_multistep_explicit_object), intent(in) :: self !< Integrator. - class(integrand_object), intent(inout) :: U !< Field to be integrated. - class(integrand_object), intent(inout) :: previous(1:) !< Previous time steps solutions of integrand field. - class(integrand_object), intent(inout) :: buffer !< Temporary buffer for doing fast operation. - real(R_P), intent(in) :: Dt !< Time steps. - real(R_P), intent(in) :: t(:) !< Times. - logical, optional, intent(in) :: autoupdate !< Perform cyclic autoupdate of previous time steps. + class(integrator_multistep_explicit_object), intent(inout) :: self !< Integrator. + class(integrand_object), intent(inout) :: U !< Field to be integrated. + real(R_P), intent(in) :: Dt !< Time steps. + real(R_P), intent(in) :: t(:) !< Times. + logical, optional, intent(in) :: autoupdate !< Perform cyclic autoupdate of previous time steps. endsubroutine integrate_fast_interface endinterface @@ -90,12 +91,37 @@ elemental function steps_number(self) endfunction steps_number ! public methods + pure subroutine allocate_integrand_members(self, U) + !< Allocate members of interpolator being of [[integrand_object]] class. + !< + !< @note It is assumed that the integrator has been properly initialized before calling this method. + class(integrator_multistep_explicit_object), intent(inout) :: self !< Integrator. + class(integrand_object), intent(in) :: U !< Integrand. + integer(I_P) :: s !< Counter. + + if (self%is_multistep() .and. self%registers > 0) then + if (allocated(self%previous)) deallocate(self%previous) + allocate(self%previous(1:self%registers), mold=U) + do s=1, self%registers + self%previous(s) = U + enddo + endif + if (self%has_fast_mode()) then + if (allocated(self%buffer)) deallocate(self%buffer) + allocate(self%buffer, mold=U) + self%buffer = U + endif + endsubroutine allocate_integrand_members + elemental subroutine destroy_multistep(self) !< Destroy the integrator. class(integrator_multistep_explicit_object), intent(inout) :: self !< Integrator. call self%destroy_abstract + self%registers = 0 self%steps = 0 + if (allocated(self%previous)) deallocate(self%previous) + if (allocated(self%buffer)) deallocate(self%buffer) endsubroutine destroy_multistep subroutine update_previous(self, U, previous) diff --git a/src/lib/foodie_integrator_multistep_implicit_object.f90 b/src/lib/foodie_integrator_multistep_implicit_object.f90 index 62951d90..2bd19231 100644 --- a/src/lib/foodie_integrator_multistep_implicit_object.f90 +++ b/src/lib/foodie_integrator_multistep_implicit_object.f90 @@ -14,7 +14,10 @@ module foodie_integrator_multistep_implicit_object type, extends(integrator_object), abstract :: integrator_multistep_implicit_object !< Abstract type of FOODIE ODE integrators of the multistep-implicit family. - integer(I_P) :: steps=-1 !< Number of time steps. + integer(I_P) :: registers !< Number of registers used for stages. + integer(I_P) :: steps !< Number of time steps. + class(integrand_object), allocatable :: previous(:) !< Previous steps. + class(integrand_object), allocatable :: buffer !< Buffer used for fast integration. contains ! deferred methods procedure(integrate_interface), pass(self), deferred :: integrate !< Integrate integrand field. @@ -25,35 +28,33 @@ module foodie_integrator_multistep_implicit_object procedure, pass(self) :: stages_number !< Return number of stages used. procedure, pass(self) :: steps_number !< Return number of steps used. ! public methods - procedure, pass(self) :: destroy_multistep !< Destroy the integrator. - procedure, pass(self) :: update_previous !< Cyclic update previous time steps. + procedure, pass(self) :: allocate_integrand_members !< Allocate integrand members. + procedure, pass(self) :: destroy_multistep !< Destroy the integrator. + procedure, pass(self) :: update_previous !< Cyclic update previous time steps. endtype integrator_multistep_implicit_object abstract interface !< Abstract interfaces of deferred methods of [[integrator_multistep_implicit_object]]. - subroutine integrate_interface(self, U, previous, Dt, t, iterations, autoupdate) + subroutine integrate_interface(self, U, Dt, t, iterations, autoupdate) !< Integrate integrand field. import :: integrand_object, integrator_multistep_implicit_object, I_P, R_P - class(integrator_multistep_implicit_object), intent(in) :: self !< Integrator. - class(integrand_object), intent(inout) :: U !< Integrand. - class(integrand_object), intent(inout) :: previous(1:) !< Previous time steps solutions of integrand field. - real(R_P), intent(in) :: Dt !< Time steps. - real(R_P), intent(in) :: t(:) !< Times. - integer(I_P), optional, intent(in) :: iterations !< Fixed point iterations. - logical, optional, intent(in) :: autoupdate !< Perform cyclic autoupdate of previous time steps. + class(integrator_multistep_implicit_object), intent(inout) :: self !< Integrator. + class(integrand_object), intent(inout) :: U !< Integrand. + real(R_P), intent(in) :: Dt !< Time steps. + real(R_P), intent(in) :: t(:) !< Times. + integer(I_P), optional, intent(in) :: iterations !< Fixed point iterations. + logical, optional, intent(in) :: autoupdate !< Perform cyclic autoupdate of previous time steps. endsubroutine integrate_interface - subroutine integrate_fast_interface(self, U, previous, buffer, Dt, t, iterations, autoupdate) + subroutine integrate_fast_interface(self, U, Dt, t, iterations, autoupdate) !< Integrate integrand field, fast mode. import :: integrand_object, integrator_multistep_implicit_object, I_P, R_P - class(integrator_multistep_implicit_object), intent(in) :: self !< Integrator. - class(integrand_object), intent(inout) :: U !< Field to be integrated. - class(integrand_object), intent(inout) :: previous(1:) !< Previous time steps solutions of integrand field. - class(integrand_object), intent(inout) :: buffer !< Temporary buffer for doing fast operation. - real(R_P), intent(in) :: Dt !< Time steps. - real(R_P), intent(in) :: t(:) !< Times. - integer(I_P), optional, intent(in) :: iterations !< Fixed point iterations. - logical, optional, intent(in) :: autoupdate !< Perform cyclic autoupdate of previous time steps. + class(integrator_multistep_implicit_object), intent(inout) :: self !< Integrator. + class(integrand_object), intent(inout) :: U !< Field to be integrated. + real(R_P), intent(in) :: Dt !< Time steps. + real(R_P), intent(in) :: t(:) !< Times. + integer(I_P), optional, intent(in) :: iterations !< Fixed point iterations. + logical, optional, intent(in) :: autoupdate !< Perform cyclic autoupdate of previous time steps. endsubroutine integrate_fast_interface endinterface @@ -92,12 +93,37 @@ elemental function steps_number(self) endfunction steps_number ! public methods + pure subroutine allocate_integrand_members(self, U) + !< Allocate members of interpolator being of [[integrand_object]] class. + !< + !< @note It is assumed that the integrator has been properly initialized before calling this method. + class(integrator_multistep_implicit_object), intent(inout) :: self !< Integrator. + class(integrand_object), intent(in) :: U !< Integrand. + integer(I_P) :: s !< Counter. + + if (self%is_multistep() .and. self%registers > 0) then + if (allocated(self%previous)) deallocate(self%previous) + allocate(self%previous(1:self%registers), mold=U) + do s=1, self%registers + self%previous(s) = U + enddo + endif + if (self%has_fast_mode()) then + if (allocated(self%buffer)) deallocate(self%buffer) + allocate(self%buffer, mold=U) + self%buffer = U + endif + endsubroutine allocate_integrand_members + elemental subroutine destroy_multistep(self) !< Destroy the integrator. class(integrator_multistep_implicit_object), intent(inout) :: self !< Integrator. call self%destroy_abstract + self%registers = 0 self%steps = -1 + if (allocated(self%previous)) deallocate(self%previous) + if (allocated(self%buffer)) deallocate(self%buffer) endsubroutine destroy_multistep subroutine update_previous(self, U, previous, is_like_explicit) diff --git a/src/tests/tester/foodie_tester.f90 b/src/tests/tester/foodie_tester.f90 index ca2fa298..0b453d87 100644 --- a/src/tests/tester/foodie_tester.f90 +++ b/src/tests/tester/foodie_tester.f90 @@ -270,7 +270,7 @@ subroutine integrate(scheme, integrand_0, Dt, final_time, iterations, stages, is allocate(buffer, mold=integrand_0) ; buffer = integrand_0 allocate(filter, mold=integrand_0) ; filter = integrand_0 - call foodie_integrator_factory(scheme=scheme, integrator=integrator, stages=stages, tolerance=1e2_R_P) + call foodie_integrator_factory(scheme=scheme, integrator=integrator, stages=stages, tolerance=1e2_R_P, U=integrand_0) if (is_fast) call check_scheme_has_fast_mode(scheme=trim(adjustl(scheme)), integrator=integrator) if (integrator%is_multistep()) then From 19c965cb6744fc3f52245182c38fb6bf661792f5 Mon Sep 17 00:00:00 2001 From: Stefano Zaghi Date: Wed, 24 May 2017 14:11:46 +0200 Subject: [PATCH 15/25] multistage, multistep explicit and implicit schemes work; remain special integrators (euler, leapfrog...) --- src/lib/foodie.f90 | 14 +- src/lib/foodie_integrator_adams_bashforth.f90 | 56 +++-- ...die_integrator_adams_bashforth_moulton.f90 | 74 +++++-- src/lib/foodie_integrator_adams_moulton.f90 | 94 ++++++--- ...rator_backward_differentiation_formula.f90 | 70 +++++-- src/lib/foodie_integrator_lmm_ssp.f90 | 70 +++++-- ...e_integrator_multistep_explicit_object.f90 | 33 ++- ...e_integrator_multistep_implicit_object.f90 | 35 +++- ...foodie_integrator_runge_kutta_embedded.f90 | 37 +++- ...die_integrator_runge_kutta_low_storage.f90 | 7 +- .../foodie_integrator_runge_kutta_lssp.f90 | 5 +- src/tests/tester/foodie_tester.f90 | 198 ++++++++---------- 12 files changed, 471 insertions(+), 222 deletions(-) diff --git a/src/lib/foodie.f90 b/src/lib/foodie.f90 index 2daa7509..832c0f45 100644 --- a/src/lib/foodie.f90 +++ b/src/lib/foodie.f90 @@ -177,7 +177,7 @@ subroutine foodie_integrator_factory(scheme, integrator, stages, tolerance, nu, allocate(integrator_adams_bashforth_moulton :: integrator) select type(integrator) type is(integrator_adams_bashforth_moulton) - call integrator%initialize(scheme=scheme) + call integrator%initialize(scheme=scheme, U=U) endselect elseif (index(trim(adjustl(scheme)), trim(int_adams_bashforth%class_name())) > 0) then allocate(integrator_adams_bashforth :: integrator) @@ -189,13 +189,13 @@ subroutine foodie_integrator_factory(scheme, integrator, stages, tolerance, nu, allocate(integrator_adams_moulton :: integrator) select type(integrator) type is(integrator_adams_moulton) - call integrator%initialize(scheme=scheme) + call integrator%initialize(scheme=scheme, U=U) endselect elseif (index(trim(adjustl(scheme)), trim(int_back_df%class_name())) > 0) then allocate(integrator_back_df :: integrator) select type(integrator) type is(integrator_back_df) - call integrator%initialize(scheme=scheme) + call integrator%initialize(scheme=scheme, U=U) endselect elseif (index(trim(adjustl(scheme)), trim(int_euler_explicit%class_name())) > 0) then allocate(integrator_euler_explicit :: integrator) @@ -215,7 +215,7 @@ subroutine foodie_integrator_factory(scheme, integrator, stages, tolerance, nu, allocate(integrator_lmm_ssp :: integrator) select type(integrator) type is(integrator_lmm_ssp) - call integrator%initialize(scheme=scheme) + call integrator%initialize(scheme=scheme, U=U) endselect elseif (index(trim(adjustl(scheme)), trim(int_ms_runge_kutta_ssp%class_name())) > 0) then allocate(integrator_ms_runge_kutta_ssp :: integrator) @@ -227,19 +227,19 @@ subroutine foodie_integrator_factory(scheme, integrator, stages, tolerance, nu, allocate(integrator_runge_kutta_emd :: integrator) select type(integrator) type is(integrator_runge_kutta_emd) - call integrator%initialize(scheme=scheme, tolerance=tolerance) + call integrator%initialize(scheme=scheme, tolerance=tolerance, U=U) endselect elseif (index(trim(adjustl(scheme)), trim(int_runge_kutta_lssp%class_name())) > 0) then allocate(integrator_runge_kutta_lssp :: integrator) select type(integrator) type is(integrator_runge_kutta_lssp) - call integrator%initialize(scheme=scheme, stages=stages) + call integrator%initialize(scheme=scheme, stages=stages, U=U) endselect elseif (index(trim(adjustl(scheme)), trim(int_runge_kutta_ls%class_name())) > 0) then allocate(integrator_runge_kutta_ls :: integrator) select type(integrator) type is(integrator_runge_kutta_ls) - call integrator%initialize(scheme=scheme) + call integrator%initialize(scheme=scheme, U=U) endselect elseif (index(trim(adjustl(scheme)), trim(int_runge_kutta_ssp%class_name())) > 0) then allocate(integrator_runge_kutta_ssp :: integrator) diff --git a/src/lib/foodie_integrator_adams_bashforth.f90 b/src/lib/foodie_integrator_adams_bashforth.f90 index 43ae728b..05db92a5 100644 --- a/src/lib/foodie_integrator_adams_bashforth.f90 +++ b/src/lib/foodie_integrator_adams_bashforth.f90 @@ -70,6 +70,8 @@ module foodie_integrator_adams_bashforth procedure, pass(lhs) :: integr_assign_integr !< Operator `=`. procedure, pass(self) :: integrate !< Integrate integrand field. procedure, pass(self) :: integrate_fast !< Integrate integrand field, fast mode. + procedure, pass(self) :: integrate_ub !< Integrate integrand field, unbuffered. + procedure, pass(self) :: integrate_ub_fast !< Integrate integrand field, fast mode, unbuffered. procedure, pass(self) :: is_supported !< Return .true. if the integrator class support the given scheme. procedure, pass(self) :: supported_schemes !< Return the list of supported schemes. ! public methods @@ -129,40 +131,68 @@ pure subroutine integr_assign_integr(lhs, rhs) subroutine integrate(self, U, Dt, t, autoupdate) !< Integrate field with Adams-Bashforth class scheme. + !< + !< @note This method uses integrand previous-steps-buffer stored inside integrator. class(integrator_adams_bashforth), intent(inout) :: self !< Integrator. class(integrand_object), intent(inout) :: U !< Field to be integrated. real(R_P), intent(in) :: Dt !< Time steps. real(R_P), intent(in) :: t(:) !< Times. logical, optional, intent(in) :: autoupdate !< Perform cyclic autoupdate of previous time steps. - logical :: autoupdate_ !< Perform cyclic autoupdate of previous time steps, dummy var. - integer(I_P) :: s !< Steps counter. - autoupdate_ = .true. ; if (present(autoupdate)) autoupdate_ = autoupdate - do s=1, self%steps - U = U + (self%previous(s)%t(t=t(s)) * (Dt * self%b(s))) - enddo - if (autoupdate_) call self%update_previous(U=U, previous=self%previous) + call self%integrate_ub(U=U, previous=self%previous, Dt=Dt, t=t, autoupdate=autoupdate) endsubroutine integrate subroutine integrate_fast(self, U, Dt, t, autoupdate) - !< Integrate field with Adams-Bashforth class scheme. + !< Integrate field with Adams-Bashforth class scheme, fast mode. + !< + !< @note This method uses integrand previous-steps-buffer stored inside integrator. class(integrator_adams_bashforth), intent(inout) :: self !< Integrator. class(integrand_object), intent(inout) :: U !< Field to be integrated. real(R_P), intent(in) :: Dt !< Time steps. real(R_P), intent(in) :: t(:) !< Times. logical, optional, intent(in) :: autoupdate !< Perform cyclic autoupdate of previous time steps. - logical :: autoupdate_ !< Perform cyclic autoupdate of previous time steps, dummy var. - integer(I_P) :: s !< Steps counter. + + call self%integrate_ub_fast(U=U, previous=self%previous, Dt=Dt, t=t, autoupdate=autoupdate) + endsubroutine integrate_fast + + subroutine integrate_ub(self, U, previous, Dt, t, autoupdate) + !< Integrate field with Adams-Bashforth class scheme, unbuffered. + class(integrator_adams_bashforth), intent(in) :: self !< Integrator. + class(integrand_object), intent(inout) :: U !< Field to be integrated. + class(integrand_object), intent(inout) :: previous(1:) !< Integrand. + real(R_P), intent(in) :: Dt !< Time steps. + real(R_P), intent(in) :: t(:) !< Times. + logical, optional, intent(in) :: autoupdate !< Perform cyclic autoupdate of previous time steps. + logical :: autoupdate_ !< Perform cyclic autoupdate of previous time steps, dummy var. + integer(I_P) :: s !< Steps counter. autoupdate_ = .true. ; if (present(autoupdate)) autoupdate_ = autoupdate do s=1, self%steps - self%buffer = self%previous(s) + U = U + (previous(s)%t(t=t(s)) * (Dt * self%b(s))) + enddo + if (autoupdate_) call self%update_previous(U=U, previous=previous) + endsubroutine integrate_ub + + subroutine integrate_ub_fast(self, U, previous, Dt, t, autoupdate) + !< Integrate field with Adams-Bashforth class scheme, unbuffered, fast mode. + class(integrator_adams_bashforth), intent(inout) :: self !< Integrator. + class(integrand_object), intent(inout) :: U !< Field to be integrated. + class(integrand_object), intent(inout) :: previous(1:) !< Integrand. + real(R_P), intent(in) :: Dt !< Time steps. + real(R_P), intent(in) :: t(:) !< Times. + logical, optional, intent(in) :: autoupdate !< Perform cyclic autoupdate of previous time steps. + logical :: autoupdate_ !< Perform cyclic autoupdate of previous time steps, dummy var. + integer(I_P) :: s !< Steps counter. + + autoupdate_ = .true. ; if (present(autoupdate)) autoupdate_ = autoupdate + do s=1, self%steps + self%buffer = previous(s) call self%buffer%t_fast(t=t(s)) call self%buffer%multiply_fast(lhs=self%buffer, rhs=Dt * self%b(s)) call U%add_fast(lhs=U, rhs=self%buffer) enddo - if (autoupdate_) call self%update_previous(U=U, previous=self%previous) - endsubroutine integrate_fast + if (autoupdate_) call self%update_previous(U=U, previous=previous) + endsubroutine integrate_ub_fast elemental function is_supported(self, scheme) !< Return .true. if the integrator class support the given scheme. diff --git a/src/lib/foodie_integrator_adams_bashforth_moulton.f90 b/src/lib/foodie_integrator_adams_bashforth_moulton.f90 index e2a3aece..f434f613 100644 --- a/src/lib/foodie_integrator_adams_bashforth_moulton.f90 +++ b/src/lib/foodie_integrator_adams_bashforth_moulton.f90 @@ -123,6 +123,8 @@ module foodie_integrator_adams_bashforth_moulton procedure, pass(lhs) :: integr_assign_integr !< Operator `=`. procedure, pass(self) :: integrate !< Integrate integrand field. procedure, pass(self) :: integrate_fast !< Integrate integrand field. + procedure, pass(self) :: integrate_ub !< Integrate integrand field, unbuffered. + procedure, pass(self) :: integrate_ub_fast !< Integrate integrand field, unbuffered, fast mode. procedure, pass(self) :: is_supported !< Return .true. if the integrator class support the given scheme. procedure, pass(self) :: supported_schemes !< Return the list of supported schemes. ! public methods @@ -184,38 +186,68 @@ pure subroutine integr_assign_integr(lhs, rhs) subroutine integrate(self, U, Dt, t, iterations, autoupdate) !< Integrate field with Adams-Bashforth-Moulton class scheme. + !< + !< @note This method uses integrand previous-steps-buffer stored inside integrator. class(integrator_adams_bashforth_moulton), intent(inout) :: self !< Integrator. class(integrand_object), intent(inout) :: U !< Field to be integrated. real(R_P), intent(in) :: Dt !< Time steps. real(R_P), intent(in) :: t(:) !< Times. integer(I_P), intent(in), optional :: iterations !< Fixed point iterations of AM scheme. logical, intent(in), optional :: autoupdate !< Cyclic autoupdate of previous time steps flag. - logical :: autoupdate_ !< Cyclic autoupdate of previous time steps flag,i - !< local variable. - autoupdate_ = .true. ; if (present(autoupdate)) autoupdate_ = autoupdate - call self%predictor%integrate(U=U, Dt=Dt, t=t, autoupdate=.false.) - call self%corrector%integrate(U=U, Dt=Dt, t=t, iterations=iterations, autoupdate=.false.) - ! if (autoupdate_) call self%predictor%update_previous(U=U, previous=previous) + call self%integrate_ub(U=U, previous=self%previous, Dt=Dt, t=t, iterations=iterations, autoupdate=autoupdate) endsubroutine integrate subroutine integrate_fast(self, U, Dt, t, iterations, autoupdate) !< Integrate field with Adams-Bashforth-Moulton class scheme, fast mode. + !< + !< @note This method uses integrand previous-steps-buffer stored inside integrator. class(integrator_adams_bashforth_moulton), intent(inout) :: self !< Integrator. class(integrand_object), intent(inout) :: U !< Field to be integrated. real(R_P), intent(in) :: Dt !< Time steps. real(R_P), intent(in) :: t(:) !< Times. integer(I_P), intent(in), optional :: iterations !< Fixed point iterations of AM scheme. logical, intent(in), optional :: autoupdate !< Cyclic autoupdate of previous time steps flag. - logical :: autoupdate_ !< Cyclic autoupdate of previous time steps flag, - !< local variable. - autoupdate_ = .true. ; if (present(autoupdate)) autoupdate_ = autoupdate - call self%predictor%integrate_fast(U=U, Dt=Dt, t=t, autoupdate=.false.) - call self%corrector%integrate_fast(U=U, Dt=Dt, t=t, iterations=iterations, autoupdate=.false.) - ! if (autoupdate_) call self%predictor%update_previous(U=U, previous=previous) + call self%integrate_ub_fast(U=U, previous=self%previous, Dt=Dt, t=t, iterations=iterations, autoupdate=autoupdate) endsubroutine integrate_fast + subroutine integrate_ub(self, U, previous, Dt, t, iterations, autoupdate) + !< Integrate field with Adams-Bashforth-Moulton class scheme, unbuffered. + class(integrator_adams_bashforth_moulton), intent(in) :: self !< Integrator. + class(integrand_object), intent(inout) :: U !< Field to be integrated. + class(integrand_object), intent(inout) :: previous(1:) !< Integrand. + real(R_P), intent(in) :: Dt !< Time steps. + real(R_P), intent(in) :: t(:) !< Times. + integer(I_P), intent(in), optional :: iterations !< Fixed point iterations of AM scheme. + logical, intent(in), optional :: autoupdate !< Cyclic autoupdate of previous time steps flag. + logical :: autoupdate_ !< Cyclic autoupdate of previous time steps flag, + !< local variable. + + autoupdate_ = .true. ; if (present(autoupdate)) autoupdate_ = autoupdate + call self%predictor%integrate_ub(U=U, previous=previous, Dt=Dt, t=t, autoupdate=.false.) + call self%corrector%integrate_ub(U=U, previous=previous(2:), Dt=Dt, t=t, iterations=iterations, autoupdate=.false.) + if (autoupdate_) call self%predictor%update_previous(U=U, previous=previous) + endsubroutine integrate_ub + + subroutine integrate_ub_fast(self, U, previous, Dt, t, iterations, autoupdate) + !< Integrate field with Adams-Bashforth-Moulton class scheme, unbuffered, fast mode. + class(integrator_adams_bashforth_moulton), intent(inout) :: self !< Integrator. + class(integrand_object), intent(inout) :: U !< Field to be integrated. + class(integrand_object), intent(inout) :: previous(1:) !< Integrand. + real(R_P), intent(in) :: Dt !< Time steps. + real(R_P), intent(in) :: t(:) !< Times. + integer(I_P), intent(in), optional :: iterations !< Fixed point iterations of AM scheme. + logical, intent(in), optional :: autoupdate !< Cyclic autoupdate of previous time steps flag. + logical :: autoupdate_ !< Cyclic autoupdate of previous time steps flag, + !< local variable. + + autoupdate_ = .true. ; if (present(autoupdate)) autoupdate_ = autoupdate + call self%predictor%integrate_ub_fast(U=U, previous=previous, Dt=Dt, t=t, autoupdate=.false.) + call self%corrector%integrate_ub_fast(U=U, previous=previous(2:), Dt=Dt, t=t, iterations=iterations, autoupdate=.false.) + if (autoupdate_) call self%predictor%update_previous(U=U, previous=previous) + endsubroutine integrate_ub_fast + elemental function is_supported(self, scheme) !< Return .true. if the integrator class support the given scheme. class(integrator_adams_bashforth_moulton), intent(in) :: self !< Integrator. @@ -251,13 +283,15 @@ elemental subroutine destroy(self) call self%corrector%destroy endsubroutine destroy - subroutine initialize(self, scheme) + subroutine initialize(self, scheme, U, stop_on_fail) !< Create the actual Adams-Bashforth-Moulton integrator: initialize the *b* coefficients. - class(integrator_adams_bashforth_moulton), intent(inout) :: self !< Integrator. - character(*), intent(in) :: scheme !< Selected scheme. - character(len=99), allocatable :: schemes_ab(:) !< Adams-Bashforth schemes. - character(len=99), allocatable :: schemes_am(:) !< Adams-Moulton schemes. - integer(I_P) :: scheme_number_ !< Scheme number in the list of supported schemes. + class(integrator_adams_bashforth_moulton), intent(inout) :: self !< Integrator. + character(*), intent(in) :: scheme !< Selected scheme. + class(integrand_object), intent(in), optional :: U !< Integrand molding prototype. + logical, intent(in), optional :: stop_on_fail !< Stop execution if initialization fail. + character(len=99), allocatable :: schemes_ab(:) !< Adams-Bashforth schemes. + character(len=99), allocatable :: schemes_am(:) !< Adams-Moulton schemes. + integer(I_P) :: scheme_number_ !< Scheme number in the list of supported schemes. if (self%is_supported(scheme=scheme)) then call self%destroy @@ -267,10 +301,12 @@ subroutine initialize(self, scheme) call self%predictor%initialize(scheme=schemes_ab(scheme_number_)) call self%corrector%initialize(scheme=schemes_am(scheme_number_)) self%steps = self%predictor%steps_number() + self%registers = self%steps + 1 + if (present(U)) call self%allocate_integrand_members(U=U) else call self%trigger_error(error=ERROR_UNSUPPORTED_SCHEME, & error_message='"'//trim(adjustl(scheme))//'" unsupported scheme', & - is_severe=.true.) + is_severe=stop_on_fail) endif endsubroutine initialize diff --git a/src/lib/foodie_integrator_adams_moulton.f90 b/src/lib/foodie_integrator_adams_moulton.f90 index 226bc3a3..3b0cc817 100644 --- a/src/lib/foodie_integrator_adams_moulton.f90 +++ b/src/lib/foodie_integrator_adams_moulton.f90 @@ -71,6 +71,8 @@ module foodie_integrator_adams_moulton procedure, pass(self) :: has_fast_mode !< Return .true. if the integrator class has *fast mode* integrate. procedure, pass(self) :: integrate !< Integrate integrand field. procedure, pass(self) :: integrate_fast !< Integrate integrand field, fast mode. + procedure, pass(self) :: integrate_ub !< Integrate integrand field, unbuffered. + procedure, pass(self) :: integrate_ub_fast !< Integrate integrand field, unbuffered, fast mode. procedure, pass(self) :: is_supported !< Return .true. if the integrator class support the given scheme. procedure, pass(self) :: supported_schemes !< Return the list of supported schemes. ! public methods @@ -130,58 +132,88 @@ pure subroutine integr_assign_integr(lhs, rhs) subroutine integrate(self, U, Dt, t, iterations, autoupdate) !< Integrate field with Adams-Moulton class scheme. + !< + !< @note This method uses integrand previous-steps-buffer stored inside integrator. + class(integrator_adams_moulton), intent(inout) :: self !< Integrator. + class(integrand_object), intent(inout) :: U !< Field to be integrated. + real(R_P), intent(in) :: Dt !< Time steps. + real(R_P), intent(in) :: t(:) !< Times. + integer(I_P), intent(in), optional :: iterations !< Fixed point iterations. + logical, intent(in), optional :: autoupdate !< Cyclic autoupdate of previous time steps flag. + + call self%integrate_ub(U=U, previous=self%previous, Dt=Dt, t=t, iterations=iterations, autoupdate=autoupdate) + endsubroutine integrate + + subroutine integrate_fast(self, U, Dt, t, iterations, autoupdate) + !< Integrate field with Adams-Moulton class scheme, fast mode. + !< + !< @note This method uses integrand previous-steps-buffer stored inside integrator. class(integrator_adams_moulton), intent(inout) :: self !< Integrator. class(integrand_object), intent(inout) :: U !< Field to be integrated. real(R_P), intent(in) :: Dt !< Time steps. real(R_P), intent(in) :: t(:) !< Times. integer(I_P), intent(in), optional :: iterations !< Fixed point iterations. logical, intent(in), optional :: autoupdate !< Cyclic autoupdate of previous time steps flag. - logical :: autoupdate_ !< Cyclic autoupdate of previous time steps flag, dummy var. - class(integrand_object), allocatable :: delta !< Delta RHS for fixed point iterations. - integer(I_P) :: s !< Steps counter. + + call self%integrate_ub_fast(U=U, previous=self%previous, Dt=Dt, t=t, iterations=iterations, autoupdate=autoupdate) + endsubroutine integrate_fast + + subroutine integrate_ub(self, U, previous, Dt, t, iterations, autoupdate) + !< Integrate field with Adams-Moulton class scheme. + class(integrator_adams_moulton), intent(in) :: self !< Integrator. + class(integrand_object), intent(inout) :: U !< Field to be integrated. + class(integrand_object), intent(inout) :: previous(1:) !< Integrand. + real(R_P), intent(in) :: Dt !< Time steps. + real(R_P), intent(in) :: t(:) !< Times. + integer(I_P), intent(in), optional :: iterations !< Fixed point iterations. + logical, intent(in), optional :: autoupdate !< Cyclic autoupdate of previous time steps flag. + logical :: autoupdate_ !< Cyclic autoupdate of previous time steps flag, dummy var. + class(integrand_object), allocatable :: delta !< Delta RHS for fixed point iterations. + integer(I_P) :: s !< Steps counter. autoupdate_ = .true. ; if (present(autoupdate)) autoupdate_ = autoupdate if (self%steps>0) then if (present(iterations)) then ! perform fixed point iterations allocate(delta, mold=U) - delta = self%previous(self%steps) + delta = previous(self%steps) do s=0, self%steps - 1 - delta = delta + (self%previous(s+1)%t(t=t(s+1)) * (Dt * self%b(s))) + delta = delta + (previous(s+1)%t(t=t(s+1)) * (Dt * self%b(s))) enddo do s=1, iterations U = delta + (U%t(t=t(self%steps) + Dt) * (Dt * self%b(self%steps))) enddo else - U = self%previous(self%steps) + (U%t(t=t(self%steps) + Dt) * (Dt * self%b(self%steps))) + U = previous(self%steps) + (U%t(t=t(self%steps) + Dt) * (Dt * self%b(self%steps))) do s=0, self%steps - 1 - U = U + (self%previous(s+1)%t(t=t(s+1)) * (Dt * self%b(s))) + U = U + (previous(s+1)%t(t=t(s+1)) * (Dt * self%b(s))) enddo endif - if (autoupdate_) call self%update_previous(U=U, previous=self%previous) + if (autoupdate_) call self%update_previous(U=U, previous=previous) else U = U + (U%t(t=t(1)) * (Dt * self%b(0))) endif - endsubroutine integrate + endsubroutine integrate_ub - subroutine integrate_fast(self, U, Dt, t, iterations, autoupdate) + subroutine integrate_ub_fast(self, U, previous, Dt, t, iterations, autoupdate) !< Integrate field with Adams-Moulton class scheme, fast mode. - class(integrator_adams_moulton), intent(inout) :: self !< Integrator. - class(integrand_object), intent(inout) :: U !< Field to be integrated. - real(R_P), intent(in) :: Dt !< Time steps. - real(R_P), intent(in) :: t(:) !< Times. - integer(I_P), intent(in), optional :: iterations !< Fixed point iterations. - logical, intent(in), optional :: autoupdate !< Cyclic autoupdate of previous time steps flag. - logical :: autoupdate_ !< Cyclic autoupdate of previous time steps flag, dummy var. - class(integrand_object), allocatable :: delta !< Delta RHS for fixed point iterations. - integer(I_P) :: s !< Steps counter. + class(integrator_adams_moulton), intent(inout) :: self !< Integrator. + class(integrand_object), intent(inout) :: U !< Field to be integrated. + class(integrand_object), intent(inout) :: previous(1:) !< Integrand. + real(R_P), intent(in) :: Dt !< Time steps. + real(R_P), intent(in) :: t(:) !< Times. + integer(I_P), intent(in), optional :: iterations !< Fixed point iterations. + logical, intent(in), optional :: autoupdate !< Cyclic autoupdate of previous time steps flag. + logical :: autoupdate_ !< Cyclic autoupdate of previous time steps flag, dummy var. + class(integrand_object), allocatable :: delta !< Delta RHS for fixed point iterations. + integer(I_P) :: s !< Steps counter. autoupdate_ = .true. ; if (present(autoupdate)) autoupdate_ = autoupdate if (self%steps>0) then if (present(iterations)) then ! perform fixed point iterations allocate(delta, mold=U) - delta = self%previous(self%steps) + delta = previous(self%steps) do s=0, self%steps - 1 - self%buffer = self%previous(s+1) + self%buffer = previous(s+1) call self%buffer%t_fast(t=t(s+1)) call self%buffer%multiply_fast(lhs=self%buffer, rhs=Dt * self%b(s)) call delta%add_fast(lhs=delta, rhs=self%buffer) @@ -196,22 +228,22 @@ subroutine integrate_fast(self, U, Dt, t, iterations, autoupdate) self%buffer = U call self%buffer%t_fast(t=t(self%steps) + Dt) call self%buffer%multiply_fast(lhs=self%buffer, rhs=Dt * self%b(self%steps)) - call U%add_fast(lhs=self%previous(self%steps), rhs=self%buffer) + call U%add_fast(lhs=previous(self%steps), rhs=self%buffer) do s=0, self%steps - 1 - self%buffer = self%previous(s+1) + self%buffer = previous(s+1) call self%buffer%t_fast(t=t(s+1)) call self%buffer%multiply_fast(lhs=self%buffer, rhs=Dt * self%b(s)) call U%add_fast(lhs=U, rhs=self%buffer) enddo endif - if (autoupdate_) call self%update_previous(U=U, previous=self%previous) + if (autoupdate_) call self%update_previous(U=U, previous=previous) else self%buffer = U call self%buffer%t_fast(t=t(1)) call self%buffer%multiply_fast(lhs=self%buffer, rhs=Dt * self%b(0)) call U%add_fast(lhs=U, rhs=self%buffer) endif - endsubroutine integrate_fast + endsubroutine integrate_ub_fast elemental function is_supported(self, scheme) !< Return .true. if the integrator class support the given scheme. @@ -247,10 +279,12 @@ elemental subroutine destroy(self) if (allocated(self%b)) deallocate(self%b) endsubroutine destroy - subroutine initialize(self, scheme) + subroutine initialize(self, scheme, U, stop_on_fail) !< Create the actual Adams-Moulton integrator: initialize the *b* coefficients. - class(integrator_adams_moulton), intent(inout) :: self !< Integrator. - character(*), intent(in) :: scheme !< Selected scheme. + class(integrator_adams_moulton), intent(inout) :: self !< Integrator. + character(*), intent(in) :: scheme !< Selected scheme. + class(integrand_object), intent(in), optional :: U !< Integrand molding prototype. + logical, intent(in), optional :: stop_on_fail !< Stop execution if initialization fail. if (self%is_supported(scheme=scheme)) then call self%destroy @@ -424,10 +458,12 @@ subroutine initialize(self, scheme) self%b(14) = 105145058757073.0_R_P/62768369664000.0_R_P self%b(15) = 16088129229375.0_R_P/62768369664000.0_R_P endselect + self%registers = self%steps + if (present(U)) call self%allocate_integrand_members(U=U) else call self%trigger_error(error=ERROR_UNSUPPORTED_SCHEME, & error_message='"'//trim(adjustl(scheme))//'" unsupported scheme', & - is_severe=.true.) + is_severe=stop_on_fail) endif endsubroutine initialize endmodule foodie_integrator_adams_moulton diff --git a/src/lib/foodie_integrator_backward_differentiation_formula.f90 b/src/lib/foodie_integrator_backward_differentiation_formula.f90 index 5def63e0..d0031cf1 100644 --- a/src/lib/foodie_integrator_backward_differentiation_formula.f90 +++ b/src/lib/foodie_integrator_backward_differentiation_formula.f90 @@ -69,6 +69,8 @@ module foodie_integrator_backward_differentiation_formula procedure, pass(lhs) :: integr_assign_integr !< Operator `=`. procedure, pass(self) :: integrate !< Integrate integrand field. procedure, pass(self) :: integrate_fast !< Integrate integrand field, fast mode. + procedure, pass(self) :: integrate_ub !< Integrate integrand field, unbuffered. + procedure, pass(self) :: integrate_ub_fast !< Integrate integrand field, unbuffered, fast mode. procedure, pass(self) :: is_supported !< Return .true. if the integrator class support the given scheme. procedure, pass(self) :: supported_schemes !< Return the list of supported schemes. ! public methods @@ -129,34 +131,64 @@ pure subroutine integr_assign_integr(lhs, rhs) subroutine integrate(self, U, Dt, t, iterations, autoupdate) !< Integrate field with BDF class scheme. + !< + !< @note This method uses integrand previous-steps-buffer stored inside integrator. class(integrator_back_df), intent(inout) :: self !< Integrator. class(integrand_object), intent(inout) :: U !< Field to be integrated. real(R_P), intent(in) :: Dt !< Time steps. real(R_P), intent(in) :: t(:) !< Times. integer(I_P), optional, intent(in) :: iterations !< Fixed point iterations. logical, optional, intent(in) :: autoupdate !< Perform cyclic autoupdate of previous time steps. - integer(I_P) :: iterations_ !< Fixed point iterations. - logical :: autoupdate_ !< Perform cyclic autoupdate of previous time steps, dummy var. - class(integrand_object), allocatable :: delta !< Delta RHS for fixed point iterations. - integer(I_P) :: s !< Steps counter. + + call self%integrate_ub(U=U, previous=self%previous, Dt=Dt, t=t, iterations=iterations, autoupdate=autoupdate) + endsubroutine integrate + + subroutine integrate_fast(self, U, Dt, t, iterations, autoupdate) + !< Integrate field with BDF class scheme. + !< + !< @note This method uses integrand previous-steps-buffer stored inside integrator. + class(integrator_back_df), intent(inout) :: self !< Integrator. + class(integrand_object), intent(inout) :: U !< Field to be integrated. + real(R_P), intent(in) :: Dt !< Time steps. + real(R_P), intent(in) :: t(:) !< Times. + integer(I_P), optional, intent(in) :: iterations !< Fixed point iterations. + logical, optional, intent(in) :: autoupdate !< Perform cyclic autoupdate of previous time steps. + + call self%integrate_ub_fast(U=U, previous=self%previous, Dt=Dt, t=t, iterations=iterations, autoupdate=autoupdate) + endsubroutine integrate_fast + + subroutine integrate_ub(self, U, previous, Dt, t, iterations, autoupdate) + !< Integrate field with BDF class scheme. + class(integrator_back_df), intent(in) :: self !< Integrator. + class(integrand_object), intent(inout) :: U !< Field to be integrated. + class(integrand_object), intent(inout) :: previous(1:) !< Integrand. + real(R_P), intent(in) :: Dt !< Time steps. + real(R_P), intent(in) :: t(:) !< Times. + integer(I_P), optional, intent(in) :: iterations !< Fixed point iterations. + logical, optional, intent(in) :: autoupdate !< Perform cyclic autoupdate of previous time steps. + integer(I_P) :: iterations_ !< Fixed point iterations. + logical :: autoupdate_ !< Perform cyclic autoupdate of previous time steps, dummy var. + class(integrand_object), allocatable :: delta !< Delta RHS for fixed point iterations. + integer(I_P) :: s !< Steps counter. autoupdate_ = .true. ; if (present(autoupdate)) autoupdate_ = autoupdate iterations_ = 1 ; if (present(iterations)) iterations_ = iterations allocate(delta, mold=U) - delta = self%previous(self%steps) * (-self%a(self%steps)) + delta = previous(self%steps) * (-self%a(self%steps)) do s=1, self%steps - 1 - delta = delta + (self%previous(s) * (-self%a(s))) + delta = delta + (previous(s) * (-self%a(s))) enddo do s=1, iterations_ U = delta + (U%t(t=t(self%steps) + Dt) * (Dt * self%b)) enddo - if (autoupdate_) call self%update_previous(U=U, previous=self%previous, is_like_explicit=.true.) - endsubroutine integrate + if (autoupdate_) call self%update_previous(U=U, previous=previous, is_like_explicit=.true.) + endsubroutine integrate_ub - subroutine integrate_fast(self, U, Dt, t, iterations, autoupdate) + subroutine integrate_ub_fast(self, U, previous, Dt, t, iterations, autoupdate) !< Integrate field with BDF class scheme. class(integrator_back_df), intent(inout) :: self !< Integrator. class(integrand_object), intent(inout) :: U !< Field to be integrated. + class(integrand_object), intent(inout) :: previous(1:) !< Integrand. real(R_P), intent(in) :: Dt !< Time steps. real(R_P), intent(in) :: t(:) !< Times. integer(I_P), optional, intent(in) :: iterations !< Fixed point iterations. @@ -169,9 +201,9 @@ subroutine integrate_fast(self, U, Dt, t, iterations, autoupdate) autoupdate_ = .true. ; if (present(autoupdate)) autoupdate_ = autoupdate iterations_ = 1 ; if (present(iterations)) iterations_ = iterations allocate(delta, mold=U) - call delta%multiply_fast(lhs=self%previous(self%steps), rhs=-self%a(self%steps)) + call delta%multiply_fast(lhs=previous(self%steps), rhs=-self%a(self%steps)) do s=1, self%steps - 1 - call self%buffer%multiply_fast(lhs=self%previous(s), rhs=-self%a(s)) + call self%buffer%multiply_fast(lhs=previous(s), rhs=-self%a(s)) call delta%add_fast(lhs=delta, rhs=self%buffer) enddo do s=1, iterations @@ -180,8 +212,8 @@ subroutine integrate_fast(self, U, Dt, t, iterations, autoupdate) call self%buffer%multiply_fast(lhs=self%buffer, rhs=Dt * self%b) call U%add_fast(lhs=delta, rhs=self%buffer) enddo - if (autoupdate_) call self%update_previous(U=U, previous=self%previous, is_like_explicit=.true.) - endsubroutine integrate_fast + if (autoupdate_) call self%update_previous(U=U, previous=previous, is_like_explicit=.true.) + endsubroutine integrate_ub_fast elemental function is_supported(self, scheme) !< Return .true. if the integrator class support the given scheme. @@ -218,10 +250,12 @@ elemental subroutine destroy(self) self%b = 0.0_R_P endsubroutine destroy - subroutine initialize(self, scheme) + subroutine initialize(self, scheme, U, stop_on_fail) !< Create the actual BDF integrator: initialize the *alpha* and *beta* coefficients. - class(integrator_back_df), intent(inout) :: self !< Integrator. - character(*), intent(in) :: scheme !< Selected scheme. + class(integrator_back_df), intent(inout) :: self !< Integrator. + character(*), intent(in) :: scheme !< Selected scheme. + class(integrand_object), intent(in), optional :: U !< Integrand molding prototype. + logical, intent(in), optional :: stop_on_fail !< Stop execution if initialization fail. if (self%is_supported(scheme=scheme)) then call self%destroy @@ -267,10 +301,12 @@ subroutine initialize(self, scheme) self%b = 60.0_R_P/147.0_R_P case default endselect + self%registers = self%steps + if (present(U)) call self%allocate_integrand_members(U=U) else call self%trigger_error(error=ERROR_UNSUPPORTED_SCHEME, & error_message='"'//trim(adjustl(scheme))//'" unsupported scheme', & - is_severe=.true.) + is_severe=stop_on_fail) endif endsubroutine initialize endmodule foodie_integrator_backward_differentiation_formula diff --git a/src/lib/foodie_integrator_lmm_ssp.f90 b/src/lib/foodie_integrator_lmm_ssp.f90 index f8c69728..70858f12 100644 --- a/src/lib/foodie_integrator_lmm_ssp.f90 +++ b/src/lib/foodie_integrator_lmm_ssp.f90 @@ -59,6 +59,8 @@ module foodie_integrator_lmm_ssp procedure, pass(lhs) :: integr_assign_integr !< Operator `=`. procedure, pass(self) :: integrate !< Integrate integrand field. procedure, pass(self) :: integrate_fast !< Integrate integrand field, fast mode. + procedure, pass(self) :: integrate_ub !< Integrate integrand field, unbuffered. + procedure, pass(self) :: integrate_ub_fast !< Integrate integrand field, fast mode, unbuffered. procedure, pass(self) :: is_supported !< Return .true. if the integrator class support the given scheme. procedure, pass(self) :: supported_schemes !< Return the list of supported schemes. ! public methods @@ -119,25 +121,21 @@ pure subroutine integr_assign_integr(lhs, rhs) subroutine integrate(self, U, Dt, t, autoupdate) !< Integrate field with LMM-SSP class scheme. + !< + !< @note This method uses integrand previous-steps-buffer stored inside integrator. class(integrator_lmm_ssp), intent(inout) :: self !< Integrator. class(integrand_object), intent(inout) :: U !< Field to be integrated. real(R_P), intent(in) :: Dt !< Time steps. real(R_P), intent(in) :: t(:) !< Times. logical, optional, intent(in) :: autoupdate !< Perform cyclic autoupdate of previous time steps. - logical :: autoupdate_ !< Perform cyclic autoupdate of previous time steps, dummy var. - integer(I_P) :: s !< Steps counter. - autoupdate_ = .true. ; if (present(autoupdate)) autoupdate_ = autoupdate - U = U * 0._R_P - do s=1, self%steps - if (self%a(s) /= 0._R_P) U = U + (self%previous(s) * self%a(s)) - if (self%b(s) /= 0._R_P) U = U + (self%previous(s)%t(t=t(s)) * (Dt * self%b(s))) - enddo - if (autoupdate_) call self%update_previous(U=U, previous=self%previous) + call self%integrate_ub(U=U, previous=self%previous, Dt=Dt, t=t, autoupdate=autoupdate) endsubroutine integrate subroutine integrate_fast(self, U, Dt, t, autoupdate) !< Integrate field with LMM-SSP class scheme, fast mode. + !< + !< @note This method uses integrand previous-steps-buffer stored inside integrator. class(integrator_lmm_ssp), intent(inout) :: self !< Integrator. class(integrand_object), intent(inout) :: U !< Field to be integrated. real(R_P), intent(in) :: Dt !< Time steps. @@ -146,22 +144,56 @@ subroutine integrate_fast(self, U, Dt, t, autoupdate) logical :: autoupdate_ !< Perform cyclic autoupdate of previous time steps, dummy var. integer(I_P) :: s !< Steps counter. + call self%integrate_ub_fast(U=U, previous=self%previous, Dt=Dt, t=t, autoupdate=autoupdate) + endsubroutine integrate_fast + + subroutine integrate_ub(self, U, previous, Dt, t, autoupdate) + !< Integrate field with LMM-SSP class scheme, unbuffered. + class(integrator_lmm_ssp), intent(in) :: self !< Integrator. + class(integrand_object), intent(inout) :: U !< Field to be integrated. + class(integrand_object), intent(inout) :: previous(1:) !< Integrand. + real(R_P), intent(in) :: Dt !< Time steps. + real(R_P), intent(in) :: t(:) !< Times. + logical, optional, intent(in) :: autoupdate !< Perform cyclic autoupdate of previous time steps. + logical :: autoupdate_ !< Perform cyclic autoupdate of previous time steps, dummy var. + integer(I_P) :: s !< Steps counter. + + autoupdate_ = .true. ; if (present(autoupdate)) autoupdate_ = autoupdate + U = U * 0._R_P + do s=1, self%steps + if (self%a(s) /= 0._R_P) U = U + (previous(s) * self%a(s)) + if (self%b(s) /= 0._R_P) U = U + (previous(s)%t(t=t(s)) * (Dt * self%b(s))) + enddo + if (autoupdate_) call self%update_previous(U=U, previous=previous) + endsubroutine integrate_ub + + subroutine integrate_ub_fast(self, U, previous, Dt, t, autoupdate) + !< Integrate field with LMM-SSP class scheme, unbuffered, fast mode. + class(integrator_lmm_ssp), intent(inout) :: self !< Integrator. + class(integrand_object), intent(inout) :: U !< Field to be integrated. + class(integrand_object), intent(inout) :: previous(1:) !< Integrand. + real(R_P), intent(in) :: Dt !< Time steps. + real(R_P), intent(in) :: t(:) !< Times. + logical, optional, intent(in) :: autoupdate !< Perform cyclic autoupdate of previous time steps. + logical :: autoupdate_ !< Perform cyclic autoupdate of previous time steps, dummy var. + integer(I_P) :: s !< Steps counter. + autoupdate_ = .true. ; if (present(autoupdate)) autoupdate_ = autoupdate call U%multiply_fast(lhs=U, rhs=0._R_P) do s=1, self%steps if (self%a(s) /= 0._R_P) then - call self%buffer%multiply_fast(lhs=self%previous(s), rhs=self%a(s)) + call self%buffer%multiply_fast(lhs=previous(s), rhs=self%a(s)) call U%add_fast(lhs=U, rhs=self%buffer) endif if (self%b(s) /= 0._R_P) then - self%buffer = self%previous(s) + self%buffer = previous(s) call self%buffer%t_fast(t=t(s)) call self%buffer%multiply_fast(lhs=self%buffer, rhs=self%b(s)) call U%add_fast(lhs=U, rhs=self%buffer) endif enddo - if (autoupdate_) call self%update_previous(U=U, previous=self%previous) - endsubroutine integrate_fast + if (autoupdate_) call self%update_previous(U=U, previous=previous) + endsubroutine integrate_ub_fast elemental function is_supported(self, scheme) !< Return .true. if the integrator class support the given scheme. @@ -198,13 +230,15 @@ elemental subroutine destroy(self) if (allocated(self%b)) deallocate(self%b) endsubroutine destroy - subroutine initialize(self, scheme) + subroutine initialize(self, scheme, U, stop_on_fail) !< Create the actual LMM-SSP integrator: initialize the *a,b* coefficients. !< !< @note If the integrator is initialized with a bad (unsupported) number of required time steps the initialization fails and !< the integrator error status is updated consistently for external-provided errors handling. - class(integrator_lmm_ssp), intent(inout) :: self !< Integrator. - character(*), intent(in) :: scheme !< Selected scheme. + class(integrator_lmm_ssp), intent(inout) :: self !< Integrator. + character(*), intent(in) :: scheme !< Selected scheme. + class(integrand_object), intent(in), optional :: U !< Integrand molding prototype. + logical, intent(in), optional :: stop_on_fail !< Stop execution if initialization fail. if (self%is_supported(scheme=scheme)) then call self%destroy @@ -249,10 +283,12 @@ subroutine initialize(self, scheme) self%b(4) = 0._R_P self%b(5) = 25._R_P/16._R_P endselect + self%registers = self%steps + if (present(U)) call self%allocate_integrand_members(U=U) else call self%trigger_error(error=ERROR_UNSUPPORTED_SCHEME, & error_message='"'//trim(adjustl(scheme))//'" unsupported scheme', & - is_severe=.true.) + is_severe=stop_on_fail) endif endsubroutine initialize endmodule foodie_integrator_lmm_ssp diff --git a/src/lib/foodie_integrator_multistep_explicit_object.f90 b/src/lib/foodie_integrator_multistep_explicit_object.f90 index 6c9d5751..1dbf182c 100644 --- a/src/lib/foodie_integrator_multistep_explicit_object.f90 +++ b/src/lib/foodie_integrator_multistep_explicit_object.f90 @@ -20,8 +20,11 @@ module foodie_integrator_multistep_explicit_object class(integrand_object), allocatable :: buffer !< Buffer used for fast integration. contains ! deferred methods - procedure(integrate_interface), pass(self), deferred :: integrate !< Integrate integrand field. - procedure(integrate_fast_interface), pass(self), deferred :: integrate_fast !< Integrate integrand field, fast mode. + procedure(integrate_interface), pass(self), deferred :: integrate !< Integrate integrand field. + procedure(integrate_fast_interface), pass(self), deferred :: integrate_fast !< Integrate integrand field, fast mode. + procedure(integrate_ub_interface), pass(self), deferred :: integrate_ub !< Integrate integrand field, unbuffered. + procedure(integrate_ub_fast_interface), pass(self), deferred :: integrate_ub_fast !< Integrate integrand field, fast mode, + !< unbuffered. ! implemented deferred methods of parent procedure, pass(self) :: is_multistage !< Return .true. for multistage integrator. procedure, pass(self) :: is_multistep !< Return .true. for multistep integrator. @@ -37,6 +40,8 @@ module foodie_integrator_multistep_explicit_object !< Abstract interfaces of deferred methods of [[integrator_multistep_explicit_object]]. subroutine integrate_interface(self, U, Dt, t, autoupdate) !< Integrate integrand field. + !< + !< @note This method uses integrand previous-steps-buffer stored inside integrator. import :: integrand_object, integrator_multistep_explicit_object, R_P class(integrator_multistep_explicit_object), intent(inout) :: self !< Integrator. class(integrand_object), intent(inout) :: U !< Integrand. @@ -47,6 +52,8 @@ subroutine integrate_interface(self, U, Dt, t, autoupdate) subroutine integrate_fast_interface(self, U, Dt, t, autoupdate) !< Integrate integrand field, fast mode. + !< + !< @note This method uses integrand previous-steps-buffer stored inside integrator. import :: integrand_object, integrator_multistep_explicit_object, R_P class(integrator_multistep_explicit_object), intent(inout) :: self !< Integrator. class(integrand_object), intent(inout) :: U !< Field to be integrated. @@ -54,6 +61,28 @@ subroutine integrate_fast_interface(self, U, Dt, t, autoupdate) real(R_P), intent(in) :: t(:) !< Times. logical, optional, intent(in) :: autoupdate !< Perform cyclic autoupdate of previous time steps. endsubroutine integrate_fast_interface + + subroutine integrate_ub_interface(self, U, previous, Dt, t, autoupdate) + !< Integrate integrand field, unbuffered. + import :: integrand_object, integrator_multistep_explicit_object, R_P + class(integrator_multistep_explicit_object), intent(in) :: self !< Integrator. + class(integrand_object), intent(inout) :: U !< Integrand. + class(integrand_object), intent(inout) :: previous(1:) !< Integrand. + real(R_P), intent(in) :: Dt !< Time steps. + real(R_P), intent(in) :: t(:) !< Times. + logical, optional, intent(in) :: autoupdate !< Perform cyclic autoupdate of previous time steps. + endsubroutine integrate_ub_interface + + subroutine integrate_ub_fast_interface(self, U, previous, Dt, t, autoupdate) + !< Integrate integrand field, unbuffered, fast mode. + import :: integrand_object, integrator_multistep_explicit_object, R_P + class(integrator_multistep_explicit_object), intent(inout) :: self !< Integrator. + class(integrand_object), intent(inout) :: U !< Field to be integrated. + class(integrand_object), intent(inout) :: previous(1:) !< Integrand. + real(R_P), intent(in) :: Dt !< Time steps. + real(R_P), intent(in) :: t(:) !< Times. + logical, optional, intent(in) :: autoupdate !< Perform cyclic autoupdate of previous time steps. + endsubroutine integrate_ub_fast_interface endinterface contains diff --git a/src/lib/foodie_integrator_multistep_implicit_object.f90 b/src/lib/foodie_integrator_multistep_implicit_object.f90 index 2bd19231..c4eff5a3 100644 --- a/src/lib/foodie_integrator_multistep_implicit_object.f90 +++ b/src/lib/foodie_integrator_multistep_implicit_object.f90 @@ -20,8 +20,11 @@ module foodie_integrator_multistep_implicit_object class(integrand_object), allocatable :: buffer !< Buffer used for fast integration. contains ! deferred methods - procedure(integrate_interface), pass(self), deferred :: integrate !< Integrate integrand field. - procedure(integrate_fast_interface), pass(self), deferred :: integrate_fast !< Integrate integrand field, fast mode. + procedure(integrate_interface), pass(self), deferred :: integrate !< Integrate integrand field. + procedure(integrate_fast_interface), pass(self), deferred :: integrate_fast !< Integrate integrand field, fast mode. + procedure(integrate_ub_interface), pass(self), deferred :: integrate_ub !< Integrate integrand field, unbuffered. + procedure(integrate_ub_fast_interface), pass(self), deferred :: integrate_ub_fast !< Integrate integrand field, fast mode, + !< unbuffered. ! implemented deferred methods of parent procedure, pass(self) :: is_multistage !< Return .true. for multistage integrator. procedure, pass(self) :: is_multistep !< Return .true. for multistep integrator. @@ -37,6 +40,8 @@ module foodie_integrator_multistep_implicit_object !< Abstract interfaces of deferred methods of [[integrator_multistep_implicit_object]]. subroutine integrate_interface(self, U, Dt, t, iterations, autoupdate) !< Integrate integrand field. + !< + !< @note This method uses integrand previous-steps-buffer stored inside integrator. import :: integrand_object, integrator_multistep_implicit_object, I_P, R_P class(integrator_multistep_implicit_object), intent(inout) :: self !< Integrator. class(integrand_object), intent(inout) :: U !< Integrand. @@ -48,6 +53,8 @@ subroutine integrate_interface(self, U, Dt, t, iterations, autoupdate) subroutine integrate_fast_interface(self, U, Dt, t, iterations, autoupdate) !< Integrate integrand field, fast mode. + !< + !< @note This method uses integrand previous-steps-buffer stored inside integrator. import :: integrand_object, integrator_multistep_implicit_object, I_P, R_P class(integrator_multistep_implicit_object), intent(inout) :: self !< Integrator. class(integrand_object), intent(inout) :: U !< Field to be integrated. @@ -56,6 +63,30 @@ subroutine integrate_fast_interface(self, U, Dt, t, iterations, autoupdate) integer(I_P), optional, intent(in) :: iterations !< Fixed point iterations. logical, optional, intent(in) :: autoupdate !< Perform cyclic autoupdate of previous time steps. endsubroutine integrate_fast_interface + + subroutine integrate_ub_interface(self, U, previous, Dt, t, iterations, autoupdate) + !< Integrate integrand field, unbuffered. + import :: integrand_object, integrator_multistep_implicit_object, I_P, R_P + class(integrator_multistep_implicit_object), intent(in) :: self !< Integrator. + class(integrand_object), intent(inout) :: U !< Integrand. + class(integrand_object), intent(inout) :: previous(1:) !< Integrand. + real(R_P), intent(in) :: Dt !< Time steps. + real(R_P), intent(in) :: t(:) !< Times. + integer(I_P), optional, intent(in) :: iterations !< Fixed point iterations. + logical, optional, intent(in) :: autoupdate !< Perform cyclic autoupdate of previous time steps. + endsubroutine integrate_ub_interface + + subroutine integrate_ub_fast_interface(self, U, previous, Dt, t, iterations, autoupdate) + !< Integrate integrand field, unbuffered, fast mode. + import :: integrand_object, integrator_multistep_implicit_object, I_P, R_P + class(integrator_multistep_implicit_object), intent(inout) :: self !< Integrator. + class(integrand_object), intent(inout) :: U !< Field to be integrated. + class(integrand_object), intent(inout) :: previous(1:) !< Integrand. + real(R_P), intent(in) :: Dt !< Time steps. + real(R_P), intent(in) :: t(:) !< Times. + integer(I_P), optional, intent(in) :: iterations !< Fixed point iterations. + logical, optional, intent(in) :: autoupdate !< Perform cyclic autoupdate of previous time steps. + endsubroutine integrate_ub_fast_interface endinterface contains diff --git a/src/lib/foodie_integrator_runge_kutta_embedded.f90 b/src/lib/foodie_integrator_runge_kutta_embedded.f90 index 1aee3b39..98f08ff0 100644 --- a/src/lib/foodie_integrator_runge_kutta_embedded.f90 +++ b/src/lib/foodie_integrator_runge_kutta_embedded.f90 @@ -311,6 +311,8 @@ module foodie_integrator_runge_kutta_emd ! public methods procedure, pass(self) :: destroy !< Destroy the integrator. procedure, pass(self) :: initialize !< Initialize (create) the integrator. + ! overridden public methods + procedure, pass(self) :: allocate_integrand_members !< Allocate integrand members. ! private methods procedure, pass(self), private :: new_Dt !< Compute new estimation of the time step Dt. endtype integrator_runge_kutta_emd @@ -487,10 +489,11 @@ elemental subroutine destroy(self) if (allocated(self%gamm)) deallocate(self%gamm) endsubroutine destroy - subroutine initialize(self, scheme, tolerance, stop_on_fail) + subroutine initialize(self, scheme, U, tolerance, stop_on_fail) !< Create the actual RK integrator: initialize the Butcher' table coefficients. class(integrator_runge_kutta_emd), intent(inout) :: self !< Integrator. character(*), intent(in) :: scheme !< Selected scheme. + class(integrand_object), intent(in), optional :: U !< Integrand molding prototype. real(R_P), intent(in), optional :: tolerance !< Tolerance on the local truncation error (default 0.01). logical, intent(in), optional :: stop_on_fail !< Stop execution if initialization fail. @@ -752,8 +755,7 @@ subroutine initialize(self, scheme, tolerance, stop_on_fail) self%gamm(17) = 1._R_P endselect self%registers = self%stages - ! allocate(self%stage(1:self%register), mold=integrand) - ! allocate(self%buffer, mold=integrand) + if (present(U)) call self%allocate_integrand_members(U=U) else call self%trigger_error(error=ERROR_UNSUPPORTED_SCHEME, & error_message='"'//trim(adjustl(scheme))//'" unsupported scheme', & @@ -761,6 +763,35 @@ subroutine initialize(self, scheme, tolerance, stop_on_fail) endif endsubroutine initialize + ! overridden public methods + pure subroutine allocate_integrand_members(self, U) + !< Allocate members of interpolator being of [[integrand_object]] class. + !< + !< @note It is assumed that the integrator has been properly initialized before calling this method. + class(integrator_runge_kutta_emd), intent(inout) :: self !< Integrator. + class(integrand_object), intent(in) :: U !< Integrand. + integer(I_P) :: s !< Counter. + + if (self%is_multistage() .and. self%registers > 0) then + if (allocated(self%stage)) deallocate(self%stage) + allocate(self%stage(1:self%registers), mold=U) + do s=1, self%registers + self%stage(s) = U + enddo + endif + if (self%has_fast_mode()) then + if (allocated(self%buffer)) deallocate(self%buffer) + allocate(self%buffer, mold=U) + self%buffer = U + endif + if (allocated(self%U1)) deallocate(self%U1) + allocate(self%U1, mold=U) + self%U1 = U + if (allocated(self%U2)) deallocate(self%U2) + allocate(self%U2, mold=U) + self%U2 = U + endsubroutine allocate_integrand_members + ! private methods elemental subroutine new_Dt(self, error, Dt) !< Compute new estimation of the time step Dt. diff --git a/src/lib/foodie_integrator_runge_kutta_low_storage.f90 b/src/lib/foodie_integrator_runge_kutta_low_storage.f90 index a861ba05..5b11619d 100644 --- a/src/lib/foodie_integrator_runge_kutta_low_storage.f90 +++ b/src/lib/foodie_integrator_runge_kutta_low_storage.f90 @@ -327,10 +327,11 @@ elemental subroutine destroy(self) if (allocated(self%C)) deallocate(self%C) endsubroutine destroy - subroutine initialize(self, scheme, stop_on_fail) + subroutine initialize(self, scheme, U, stop_on_fail) !< Create the actual RK integrator: initialize the Butcher' low storage table coefficients. class(integrator_runge_kutta_ls), intent(inout) :: self !< Integrator. character(*), intent(in) :: scheme !< Selected scheme. + class(integrand_object), intent(in), optional :: U !< Integrand molding prototype. logical, intent(in), optional :: stop_on_fail !< Stop execution if initialization fail. if (self%is_supported(scheme=scheme)) then @@ -450,8 +451,8 @@ subroutine initialize(self, scheme, stop_on_fail) self%A(14) = -7.1151571693922548_R_P ; self%B(14) = 5.5059777270269628_R_P ; self%C(14) = 0.8734213127600976_R_P endselect self%registers = 2 - ! allocate(self%stage(1:self%register), mold=integrand) - ! allocate(self%buffer, mold=integrand) + self%registers = self%stages + if (present(U)) call self%allocate_integrand_members(U=U) else call self%trigger_error(error=ERROR_UNSUPPORTED_SCHEME, & error_message='"'//trim(adjustl(scheme))//'" unsupported scheme', & diff --git a/src/lib/foodie_integrator_runge_kutta_lssp.f90 b/src/lib/foodie_integrator_runge_kutta_lssp.f90 index 7cc09a47..1417c95b 100644 --- a/src/lib/foodie_integrator_runge_kutta_lssp.f90 +++ b/src/lib/foodie_integrator_runge_kutta_lssp.f90 @@ -238,10 +238,11 @@ elemental subroutine destroy(self) self%integrate_ => integrate_order_s_1 endsubroutine destroy - subroutine initialize(self, scheme, stages, stop_on_fail) + subroutine initialize(self, scheme, U, stages, stop_on_fail) !< Create the actual RK integrator: initialize the Butcher' table coefficients. class(integrator_runge_kutta_lssp), intent(inout) :: self !< Integrator. character(*), intent(in) :: scheme !< Selected scheme. + class(integrand_object), intent(in), optional :: U !< Integrand molding prototype. integer(I_P), intent(in), optional :: stages !< Stages number. logical, intent(in), optional :: stop_on_fail !< Stop execution if initialization fail. @@ -267,6 +268,8 @@ subroutine initialize(self, scheme, stages, stop_on_fail) allocate(self%alpha(1:self%stages)) ; self%alpha = 0._R_P call self%initialize_order_s endselect + self%registers = self%stages + if (present(U)) call self%allocate_integrand_members(U=U) else call self%trigger_error(error=ERROR_UNSUPPORTED_SCHEME, & error_message='"'//trim(adjustl(scheme))//'" unsupported scheme', & diff --git a/src/tests/tester/foodie_tester.f90 b/src/tests/tester/foodie_tester.f90 index 0b453d87..a2b7f775 100644 --- a/src/tests/tester/foodie_tester.f90 +++ b/src/tests/tester/foodie_tester.f90 @@ -256,10 +256,7 @@ subroutine integrate(scheme, integrand_0, Dt, final_time, iterations, stages, is class(integrator_object), allocatable :: integrator !< The integrator. type(integrator_runge_kutta_ssp) :: integrator_start !< The (auto) start integrator. class(integrand_object), allocatable :: integrand !< Integrand. - class(integrand_object), allocatable :: previous(:) !< Previous time steps solutions. - class(integrand_object), allocatable :: stage(:) !< Runge-Kutta stages. - class(integrand_object), allocatable :: buffer !< Buffer oscillation field. - class(integrand_object), allocatable :: filter !< Filter displacement. + ! class(integrand_object), allocatable :: filter !< Filter displacement. real(R_P), allocatable :: time(:) !< Time. real(R_P), allocatable :: Dts(:) !< Time steps. integer(I_P) :: step !< Time steps counter. @@ -267,17 +264,11 @@ subroutine integrate(scheme, integrand_0, Dt, final_time, iterations, stages, is integer(I_P) :: s !< Counter. allocate(integrand, mold=integrand_0) ; integrand = integrand_0 - allocate(buffer, mold=integrand_0) ; buffer = integrand_0 - allocate(filter, mold=integrand_0) ; filter = integrand_0 call foodie_integrator_factory(scheme=scheme, integrator=integrator, stages=stages, tolerance=1e2_R_P, U=integrand_0) if (is_fast) call check_scheme_has_fast_mode(scheme=trim(adjustl(scheme)), integrator=integrator) if (integrator%is_multistep()) then - allocate(previous(1:integrator%steps_number()), mold=integrand_0) - do s=1, integrator%steps_number() - previous(s) = integrand_0 - enddo call integrator_start%initialize(scheme='runge_kutta_ssp_stages_5_order_4', U=integrand_0) if (integrator%steps_number()==0) then step_offset = 1 ! for 0 step-(a convention)-solver offset is 1 @@ -287,12 +278,6 @@ subroutine integrate(scheme, integrand_0, Dt, final_time, iterations, stages, is else step_offset = 1 ! for 0 step-(a convention)-solver offset is 1 endif - if (integrator%is_multistage()) then - allocate(stage(1:integrator%stages_number()), mold=integrand_0) - do s=1, integrator%stages_number() - stage(s) = integrand_0 - enddo - endif allocate(time(0:step_offset)) step = 0 @@ -323,13 +308,13 @@ subroutine integrate(scheme, integrand_0, Dt, final_time, iterations, stages, is step = step + 1 if (integrator%steps_number() >= step) then call integrator_start%integrate(U=integrand, Dt=Dt, t=time(step)) - previous(step) = integrand + integrator%previous(step) = integrand time(step) = time(step-1) + Dt else if (is_fast) then - call integrator%integrate_fast(U=integrand, previous=previous, buffer=buffer, Dt=Dt, t=time) + call integrator%integrate_fast(U=integrand, Dt=Dt, t=time) else - call integrator%integrate(U=integrand, previous=previous, Dt=Dt, t=time) + call integrator%integrate(U=integrand, Dt=Dt, t=time) endif call update_previous_times endif @@ -338,70 +323,24 @@ subroutine integrate(scheme, integrand_0, Dt, final_time, iterations, stages, is enddo class is(integrator_multistep_implicit_object) - select type(integrator) - type is(integrator_adams_moulton) - if (allocated(previous)) deallocate(previous) ; allocate(previous(1:integrator%steps_number()+1), mold=integrand_0) - endselect do step = step + 1 if (integrator%steps_number() >= step) then call integrator_start%integrate(U=integrand, Dt=Dt, t=time(step)) - previous(step) = integrand + integrator%previous(step) = integrand time(step) = time(step-1) + Dt else if (is_fast) then if (iterations>1) then - call integrator%integrate_fast(U=integrand, previous=previous, buffer=buffer, Dt=Dt, t=time, & - iterations=iterations) + call integrator%integrate_fast(U=integrand, Dt=Dt, t=time, iterations=iterations) else - call integrator%integrate_fast(U=integrand, previous=previous, buffer=buffer, Dt=Dt, t=time) + call integrator%integrate_fast(U=integrand, Dt=Dt, t=time) endif else if (iterations>1) then - call integrator%integrate(U=integrand, previous=previous, Dt=Dt, t=time, iterations=iterations) - else - call integrator%integrate(U=integrand, previous=previous, Dt=Dt, t=time) - endif - endif - call update_previous_times - endif - if ((time(step_offset) >= final_time)) exit - call integrand_export_tecplot - enddo - - type is(integrator_euler_explicit) - do - step = step + 1 - if (is_fast) then - call integrator%integrate_fast(U=integrand, buffer=buffer, Dt=Dt, t=time(step_offset)) - else - call integrator%integrate(U=integrand, Dt=Dt, t=time(step_offset)) - endif - call update_previous_times - if ((time(step_offset) >= final_time)) exit - call integrand_export_tecplot - enddo - - type is(integrator_leapfrog) - do - step = step + 1 - if (integrator%steps_number() >= step) then - call integrator_start%integrate(U=integrand, Dt=Dt, t=time(step)) - previous(step) = integrand - time(step) = time(step-1) + Dt - else - if (index(scheme, 'raw') > 0 ) then - if (is_fast) then - call integrator%integrate_fast(U=integrand, previous=previous, buffer=buffer, Dt=Dt, t=time(step_offset), & - filter=filter) + call integrator%integrate(U=integrand, Dt=Dt, t=time, iterations=iterations) else - call integrator%integrate(U=integrand, previous=previous, Dt=Dt, t=time(step_offset), filter=filter) - endif - else - if (is_fast) then - call integrator%integrate_fast(U=integrand, previous=previous, buffer=buffer, Dt=Dt, t=time(step_offset)) - else - call integrator%integrate(U=integrand, previous=previous, Dt=Dt, t=time(step_offset)) + call integrator%integrate(U=integrand, Dt=Dt, t=time) endif endif call update_previous_times @@ -410,45 +349,86 @@ subroutine integrate(scheme, integrand_0, Dt, final_time, iterations, stages, is call integrand_export_tecplot enddo - type is(integrator_lmm_ssp_vss) - allocate(Dts(1:step_offset)) - Dts = Dt - do - step = step + 1 - if (integrator%steps_number() >= step) then - call integrator_start%integrate(U=integrand, Dt=Dt, t=time(step)) - previous(step) = integrand - time(step) = time(step-1) + Dt - else - if (is_fast) then - call integrator%integrate_fast(U=integrand, previous=previous, buffer=buffer, Dt=Dts, t=time) - else - call integrator%integrate(U=integrand, previous=previous, Dt=Dts, t=time) - endif - call update_previous_times - endif - if ((time(step) >= final_time)) exit - call integrand_export_tecplot - enddo - - type is(integrator_ms_runge_kutta_ssp) - do - step = step + 1 - if (integrator%steps_number() >= step) then - call integrator_start%integrate(U=integrand, Dt=Dt, t=time(step)) - previous(step) = integrand - time(step) = time(step-1) + Dt - else - if (is_fast) then - call integrator%integrate_fast(U=integrand, previous=previous, stage=stage, buffer=buffer, Dt=Dt,t=time) - else - call integrator%integrate(U=integrand, previous=previous, stage=stage, Dt=Dt, t=time) - endif - call update_previous_times - endif - if ((time(step) >= final_time)) exit - call integrand_export_tecplot - enddo + ! type is(integrator_euler_explicit) + ! do + ! step = step + 1 + ! if (is_fast) then + ! call integrator%integrate_fast(U=integrand, buffer=buffer, Dt=Dt, t=time(step_offset)) + ! else + ! call integrator%integrate(U=integrand, Dt=Dt, t=time(step_offset)) + ! endif + ! call update_previous_times + ! if ((time(step_offset) >= final_time)) exit + ! call integrand_export_tecplot + ! enddo + + ! type is(integrator_leapfrog) + ! do + ! step = step + 1 + ! if (integrator%steps_number() >= step) then + ! call integrator_start%integrate(U=integrand, Dt=Dt, t=time(step)) + ! previous(step) = integrand + ! time(step) = time(step-1) + Dt + ! else + ! if (index(scheme, 'raw') > 0 ) then + ! if (is_fast) then + ! call integrator%integrate_fast(U=integrand, previous=previous, buffer=buffer, Dt=Dt, t=time(step_offset), & + ! filter=filter) + ! else + ! call integrator%integrate(U=integrand, previous=previous, Dt=Dt, t=time(step_offset), filter=filter) + ! endif + ! else + ! if (is_fast) then + ! call integrator%integrate_fast(U=integrand, previous=previous, buffer=buffer, Dt=Dt, t=time(step_offset)) + ! else + ! call integrator%integrate(U=integrand, previous=previous, Dt=Dt, t=time(step_offset)) + ! endif + ! endif + ! call update_previous_times + ! endif + ! if ((time(step_offset) >= final_time)) exit + ! call integrand_export_tecplot + ! enddo + + ! type is(integrator_lmm_ssp_vss) + ! allocate(Dts(1:step_offset)) + ! Dts = Dt + ! do + ! step = step + 1 + ! if (integrator%steps_number() >= step) then + ! call integrator_start%integrate(U=integrand, Dt=Dt, t=time(step)) + ! previous(step) = integrand + ! time(step) = time(step-1) + Dt + ! else + ! if (is_fast) then + ! call integrator%integrate_fast(U=integrand, previous=previous, buffer=buffer, Dt=Dts, t=time) + ! else + ! call integrator%integrate(U=integrand, previous=previous, Dt=Dts, t=time) + ! endif + ! call update_previous_times + ! endif + ! if ((time(step) >= final_time)) exit + ! call integrand_export_tecplot + ! enddo + + ! type is(integrator_ms_runge_kutta_ssp) + ! do + ! step = step + 1 + ! if (integrator%steps_number() >= step) then + ! call integrator_start%integrate(U=integrand, Dt=Dt, t=time(step)) + ! previous(step) = integrand + ! time(step) = time(step-1) + Dt + ! else + ! if (is_fast) then + ! call integrator%integrate_fast(U=integrand, previous=previous, stage=stage, buffer=buffer, Dt=Dt,t=time) + ! else + ! call integrator%integrate(U=integrand, previous=previous, stage=stage, Dt=Dt, t=time) + ! endif + ! call update_previous_times + ! endif + ! if ((time(step) >= final_time)) exit + ! call integrand_export_tecplot + ! enddo endselect select type(integrand) From ce9902cc186dc83938dcdca46e025432eada03fc Mon Sep 17 00:00:00 2001 From: Stefano Zaghi Date: Wed, 24 May 2017 18:33:52 +0200 Subject: [PATCH 16/25] almost all schemes are grouped! lmm_ssp_vss seems to have issues --- src/lib/foodie.f90 | 8 +- src/lib/foodie_integrator_adams_bashforth.f90 | 30 +- ...die_integrator_adams_bashforth_moulton.f90 | 21 +- src/lib/foodie_integrator_adams_moulton.f90 | 45 +-- ...rator_backward_differentiation_formula.f90 | 45 +-- src/lib/foodie_integrator_euler_explicit.f90 | 117 ++++---- src/lib/foodie_integrator_leapfrog.f90 | 258 ++++++++++-------- src/lib/foodie_integrator_lmm_ssp.f90 | 41 +-- src/lib/foodie_integrator_lmm_ssp_vss.f90 | 222 +++++++-------- ..._integrator_multistage_explicit_object.f90 | 36 ++- ...e_integrator_multistep_explicit_object.f90 | 46 +++- ...e_integrator_multistep_implicit_object.f90 | 18 +- src/lib/foodie_integrator_runge_kutta_ssp.f90 | 4 +- src/tests/tester/foodie_tester.f90 | 77 +----- 14 files changed, 489 insertions(+), 479 deletions(-) diff --git a/src/lib/foodie.f90 b/src/lib/foodie.f90 index 832c0f45..83c76efa 100644 --- a/src/lib/foodie.f90 +++ b/src/lib/foodie.f90 @@ -199,17 +199,21 @@ subroutine foodie_integrator_factory(scheme, integrator, stages, tolerance, nu, endselect elseif (index(trim(adjustl(scheme)), trim(int_euler_explicit%class_name())) > 0) then allocate(integrator_euler_explicit :: integrator) + select type(integrator) + type is(integrator_euler_explicit) + call integrator%initialize(scheme=scheme, U=U) + endselect elseif (index(trim(adjustl(scheme)), trim(int_leapfrog%class_name())) > 0) then allocate(integrator_leapfrog :: integrator) select type(integrator) type is(integrator_leapfrog) - call integrator%initialize(scheme=scheme, nu=nu, alpha=alpha) + call integrator%initialize(scheme=scheme, nu=nu, alpha=alpha, U=U) endselect elseif (index(trim(adjustl(scheme)), trim(int_lmm_ssp_vss%class_name())) > 0) then allocate(integrator_lmm_ssp_vss :: integrator) select type(integrator) type is(integrator_lmm_ssp_vss) - call integrator%initialize(scheme=scheme) + call integrator%initialize(scheme=scheme, U=U) endselect elseif (index(trim(adjustl(scheme)), trim(int_lmm_ssp%class_name())) > 0) then allocate(integrator_lmm_ssp :: integrator) diff --git a/src/lib/foodie_integrator_adams_bashforth.f90 b/src/lib/foodie_integrator_adams_bashforth.f90 index 05db92a5..52430d2e 100644 --- a/src/lib/foodie_integrator_adams_bashforth.f90 +++ b/src/lib/foodie_integrator_adams_bashforth.f90 @@ -60,6 +60,9 @@ module foodie_integrator_adams_bashforth !< FOODIE integrator: provide an explicit class of Adams-Bashforth multi-step schemes, from 1st to 16th order accurate. !< !< @note The integrator must be created or initialized (initialize the *b* coefficients) before used. + !< + !< @note The time steps `Dt(1:steps)` passed to the integrate methods must be identical: this integrator supports only + !< fixed time steps. private real(R_P), allocatable :: b(:) !< *b* coefficients. contains @@ -121,11 +124,10 @@ pure subroutine integr_assign_integr(lhs, rhs) class(integrator_adams_bashforth), intent(inout) :: lhs !< Left hand side. class(integrator_object), intent(in) :: rhs !< Right hand side. - call lhs%assign_abstract(rhs=rhs) + call lhs%assign_multistep(rhs=rhs) select type(rhs) class is (integrator_adams_bashforth) - lhs%steps = rhs%steps - if (allocated(rhs%b)) lhs%b = rhs%b + if (allocated(rhs%b)) lhs%b = rhs%b endselect endsubroutine integr_assign_integr @@ -135,8 +137,8 @@ subroutine integrate(self, U, Dt, t, autoupdate) !< @note This method uses integrand previous-steps-buffer stored inside integrator. class(integrator_adams_bashforth), intent(inout) :: self !< Integrator. class(integrand_object), intent(inout) :: U !< Field to be integrated. - real(R_P), intent(in) :: Dt !< Time steps. - real(R_P), intent(in) :: t(:) !< Times. + real(R_P), intent(in) :: Dt(1:) !< Time steps. + real(R_P), intent(in) :: t(1:) !< Times. logical, optional, intent(in) :: autoupdate !< Perform cyclic autoupdate of previous time steps. call self%integrate_ub(U=U, previous=self%previous, Dt=Dt, t=t, autoupdate=autoupdate) @@ -148,8 +150,8 @@ subroutine integrate_fast(self, U, Dt, t, autoupdate) !< @note This method uses integrand previous-steps-buffer stored inside integrator. class(integrator_adams_bashforth), intent(inout) :: self !< Integrator. class(integrand_object), intent(inout) :: U !< Field to be integrated. - real(R_P), intent(in) :: Dt !< Time steps. - real(R_P), intent(in) :: t(:) !< Times. + real(R_P), intent(in) :: Dt(1:) !< Time steps. + real(R_P), intent(in) :: t(1:) !< Times. logical, optional, intent(in) :: autoupdate !< Perform cyclic autoupdate of previous time steps. call self%integrate_ub_fast(U=U, previous=self%previous, Dt=Dt, t=t, autoupdate=autoupdate) @@ -157,18 +159,18 @@ subroutine integrate_fast(self, U, Dt, t, autoupdate) subroutine integrate_ub(self, U, previous, Dt, t, autoupdate) !< Integrate field with Adams-Bashforth class scheme, unbuffered. - class(integrator_adams_bashforth), intent(in) :: self !< Integrator. + class(integrator_adams_bashforth), intent(inout) :: self !< Integrator. class(integrand_object), intent(inout) :: U !< Field to be integrated. class(integrand_object), intent(inout) :: previous(1:) !< Integrand. - real(R_P), intent(in) :: Dt !< Time steps. - real(R_P), intent(in) :: t(:) !< Times. + real(R_P), intent(in) :: Dt(1:) !< Time steps. + real(R_P), intent(in) :: t(1:) !< Times. logical, optional, intent(in) :: autoupdate !< Perform cyclic autoupdate of previous time steps. logical :: autoupdate_ !< Perform cyclic autoupdate of previous time steps, dummy var. integer(I_P) :: s !< Steps counter. autoupdate_ = .true. ; if (present(autoupdate)) autoupdate_ = autoupdate do s=1, self%steps - U = U + (previous(s)%t(t=t(s)) * (Dt * self%b(s))) + U = U + (previous(s)%t(t=t(s)) * (Dt(s) * self%b(s))) enddo if (autoupdate_) call self%update_previous(U=U, previous=previous) endsubroutine integrate_ub @@ -178,8 +180,8 @@ subroutine integrate_ub_fast(self, U, previous, Dt, t, autoupdate) class(integrator_adams_bashforth), intent(inout) :: self !< Integrator. class(integrand_object), intent(inout) :: U !< Field to be integrated. class(integrand_object), intent(inout) :: previous(1:) !< Integrand. - real(R_P), intent(in) :: Dt !< Time steps. - real(R_P), intent(in) :: t(:) !< Times. + real(R_P), intent(in) :: Dt(1:) !< Time steps. + real(R_P), intent(in) :: t(1:) !< Times. logical, optional, intent(in) :: autoupdate !< Perform cyclic autoupdate of previous time steps. logical :: autoupdate_ !< Perform cyclic autoupdate of previous time steps, dummy var. integer(I_P) :: s !< Steps counter. @@ -188,7 +190,7 @@ subroutine integrate_ub_fast(self, U, previous, Dt, t, autoupdate) do s=1, self%steps self%buffer = previous(s) call self%buffer%t_fast(t=t(s)) - call self%buffer%multiply_fast(lhs=self%buffer, rhs=Dt * self%b(s)) + call self%buffer%multiply_fast(lhs=self%buffer, rhs=Dt(s) * self%b(s)) call U%add_fast(lhs=U, rhs=self%buffer) enddo if (autoupdate_) call self%update_previous(U=U, previous=previous) diff --git a/src/lib/foodie_integrator_adams_bashforth_moulton.f90 b/src/lib/foodie_integrator_adams_bashforth_moulton.f90 index f434f613..5d2624da 100644 --- a/src/lib/foodie_integrator_adams_bashforth_moulton.f90 +++ b/src/lib/foodie_integrator_adams_bashforth_moulton.f90 @@ -112,6 +112,9 @@ module foodie_integrator_adams_bashforth_moulton !< FOODIE integrator: provide an explicit class of Adams-Bashforth-Moulton multi-step schemes, from 1st to 4rd order accurate. !< !< @note The integrator must be created or initialized (predictor and corrector schemes selection) before used. + !< + !< @note The time steps `Dt(1:steps)` passed to the integrate methods must be identical: this integrator supports only + !< fixed time steps. private type(integrator_adams_bashforth) :: predictor !< Predictor solver. type(integrator_adams_moulton) :: corrector !< Corrector solver. @@ -190,8 +193,8 @@ subroutine integrate(self, U, Dt, t, iterations, autoupdate) !< @note This method uses integrand previous-steps-buffer stored inside integrator. class(integrator_adams_bashforth_moulton), intent(inout) :: self !< Integrator. class(integrand_object), intent(inout) :: U !< Field to be integrated. - real(R_P), intent(in) :: Dt !< Time steps. - real(R_P), intent(in) :: t(:) !< Times. + real(R_P), intent(in) :: Dt(1:) !< Time steps. + real(R_P), intent(in) :: t(1:) !< Times. integer(I_P), intent(in), optional :: iterations !< Fixed point iterations of AM scheme. logical, intent(in), optional :: autoupdate !< Cyclic autoupdate of previous time steps flag. @@ -204,8 +207,8 @@ subroutine integrate_fast(self, U, Dt, t, iterations, autoupdate) !< @note This method uses integrand previous-steps-buffer stored inside integrator. class(integrator_adams_bashforth_moulton), intent(inout) :: self !< Integrator. class(integrand_object), intent(inout) :: U !< Field to be integrated. - real(R_P), intent(in) :: Dt !< Time steps. - real(R_P), intent(in) :: t(:) !< Times. + real(R_P), intent(in) :: Dt(1:) !< Time steps. + real(R_P), intent(in) :: t(1:) !< Times. integer(I_P), intent(in), optional :: iterations !< Fixed point iterations of AM scheme. logical, intent(in), optional :: autoupdate !< Cyclic autoupdate of previous time steps flag. @@ -214,11 +217,11 @@ subroutine integrate_fast(self, U, Dt, t, iterations, autoupdate) subroutine integrate_ub(self, U, previous, Dt, t, iterations, autoupdate) !< Integrate field with Adams-Bashforth-Moulton class scheme, unbuffered. - class(integrator_adams_bashforth_moulton), intent(in) :: self !< Integrator. + class(integrator_adams_bashforth_moulton), intent(inout) :: self !< Integrator. class(integrand_object), intent(inout) :: U !< Field to be integrated. class(integrand_object), intent(inout) :: previous(1:) !< Integrand. - real(R_P), intent(in) :: Dt !< Time steps. - real(R_P), intent(in) :: t(:) !< Times. + real(R_P), intent(in) :: Dt(1:) !< Time steps. + real(R_P), intent(in) :: t(1:) !< Times. integer(I_P), intent(in), optional :: iterations !< Fixed point iterations of AM scheme. logical, intent(in), optional :: autoupdate !< Cyclic autoupdate of previous time steps flag. logical :: autoupdate_ !< Cyclic autoupdate of previous time steps flag, @@ -235,8 +238,8 @@ subroutine integrate_ub_fast(self, U, previous, Dt, t, iterations, autoupdate) class(integrator_adams_bashforth_moulton), intent(inout) :: self !< Integrator. class(integrand_object), intent(inout) :: U !< Field to be integrated. class(integrand_object), intent(inout) :: previous(1:) !< Integrand. - real(R_P), intent(in) :: Dt !< Time steps. - real(R_P), intent(in) :: t(:) !< Times. + real(R_P), intent(in) :: Dt(1:) !< Time steps. + real(R_P), intent(in) :: t(1:) !< Times. integer(I_P), intent(in), optional :: iterations !< Fixed point iterations of AM scheme. logical, intent(in), optional :: autoupdate !< Cyclic autoupdate of previous time steps flag. logical :: autoupdate_ !< Cyclic autoupdate of previous time steps flag, diff --git a/src/lib/foodie_integrator_adams_moulton.f90 b/src/lib/foodie_integrator_adams_moulton.f90 index 3b0cc817..61724ed4 100644 --- a/src/lib/foodie_integrator_adams_moulton.f90 +++ b/src/lib/foodie_integrator_adams_moulton.f90 @@ -61,6 +61,9 @@ module foodie_integrator_adams_moulton !< FOODIE integrator: provide an explicit class of Adams-Moulton multi-step schemes, from 1st to 16th order accurate. !< !< @note The integrator must be created or initialized (initialize the *b* coefficients) before used. + !< + !< @note The time steps `Dt(1:steps)` passed to the integrate methods must be identical: this integrator supports only + !< fixed time steps. private real(R_P), allocatable :: b(:) !< \(b\) coefficients. contains @@ -136,8 +139,8 @@ subroutine integrate(self, U, Dt, t, iterations, autoupdate) !< @note This method uses integrand previous-steps-buffer stored inside integrator. class(integrator_adams_moulton), intent(inout) :: self !< Integrator. class(integrand_object), intent(inout) :: U !< Field to be integrated. - real(R_P), intent(in) :: Dt !< Time steps. - real(R_P), intent(in) :: t(:) !< Times. + real(R_P), intent(in) :: Dt(1:) !< Time steps. + real(R_P), intent(in) :: t(1:) !< Times. integer(I_P), intent(in), optional :: iterations !< Fixed point iterations. logical, intent(in), optional :: autoupdate !< Cyclic autoupdate of previous time steps flag. @@ -150,8 +153,8 @@ subroutine integrate_fast(self, U, Dt, t, iterations, autoupdate) !< @note This method uses integrand previous-steps-buffer stored inside integrator. class(integrator_adams_moulton), intent(inout) :: self !< Integrator. class(integrand_object), intent(inout) :: U !< Field to be integrated. - real(R_P), intent(in) :: Dt !< Time steps. - real(R_P), intent(in) :: t(:) !< Times. + real(R_P), intent(in) :: Dt(1:) !< Time steps. + real(R_P), intent(in) :: t(1:) !< Times. integer(I_P), intent(in), optional :: iterations !< Fixed point iterations. logical, intent(in), optional :: autoupdate !< Cyclic autoupdate of previous time steps flag. @@ -160,11 +163,11 @@ subroutine integrate_fast(self, U, Dt, t, iterations, autoupdate) subroutine integrate_ub(self, U, previous, Dt, t, iterations, autoupdate) !< Integrate field with Adams-Moulton class scheme. - class(integrator_adams_moulton), intent(in) :: self !< Integrator. + class(integrator_adams_moulton), intent(inout) :: self !< Integrator. class(integrand_object), intent(inout) :: U !< Field to be integrated. class(integrand_object), intent(inout) :: previous(1:) !< Integrand. - real(R_P), intent(in) :: Dt !< Time steps. - real(R_P), intent(in) :: t(:) !< Times. + real(R_P), intent(in) :: Dt(1:) !< Time steps. + real(R_P), intent(in) :: t(1:) !< Times. integer(I_P), intent(in), optional :: iterations !< Fixed point iterations. logical, intent(in), optional :: autoupdate !< Cyclic autoupdate of previous time steps flag. logical :: autoupdate_ !< Cyclic autoupdate of previous time steps flag, dummy var. @@ -177,20 +180,20 @@ subroutine integrate_ub(self, U, previous, Dt, t, iterations, autoupdate) allocate(delta, mold=U) delta = previous(self%steps) do s=0, self%steps - 1 - delta = delta + (previous(s+1)%t(t=t(s+1)) * (Dt * self%b(s))) + delta = delta + (previous(s+1)%t(t=t(s+1)) * (Dt(s+1) * self%b(s))) enddo do s=1, iterations - U = delta + (U%t(t=t(self%steps) + Dt) * (Dt * self%b(self%steps))) + U = delta + (U%t(t=t(self%steps) + Dt(self%steps)) * (Dt(self%steps) * self%b(self%steps))) enddo else - U = previous(self%steps) + (U%t(t=t(self%steps) + Dt) * (Dt * self%b(self%steps))) + U = previous(self%steps) + (U%t(t=t(self%steps) + Dt(self%steps)) * (Dt(self%steps) * self%b(self%steps))) do s=0, self%steps - 1 - U = U + (previous(s+1)%t(t=t(s+1)) * (Dt * self%b(s))) + U = U + (previous(s+1)%t(t=t(s+1)) * (Dt(s+1) * self%b(s))) enddo endif if (autoupdate_) call self%update_previous(U=U, previous=previous) else - U = U + (U%t(t=t(1)) * (Dt * self%b(0))) + U = U + (U%t(t=t(1)) * (Dt(1) * self%b(0))) endif endsubroutine integrate_ub @@ -199,8 +202,8 @@ subroutine integrate_ub_fast(self, U, previous, Dt, t, iterations, autoupdate) class(integrator_adams_moulton), intent(inout) :: self !< Integrator. class(integrand_object), intent(inout) :: U !< Field to be integrated. class(integrand_object), intent(inout) :: previous(1:) !< Integrand. - real(R_P), intent(in) :: Dt !< Time steps. - real(R_P), intent(in) :: t(:) !< Times. + real(R_P), intent(in) :: Dt(1:) !< Time steps. + real(R_P), intent(in) :: t(1:) !< Times. integer(I_P), intent(in), optional :: iterations !< Fixed point iterations. logical, intent(in), optional :: autoupdate !< Cyclic autoupdate of previous time steps flag. logical :: autoupdate_ !< Cyclic autoupdate of previous time steps flag, dummy var. @@ -215,24 +218,24 @@ subroutine integrate_ub_fast(self, U, previous, Dt, t, iterations, autoupdate) do s=0, self%steps - 1 self%buffer = previous(s+1) call self%buffer%t_fast(t=t(s+1)) - call self%buffer%multiply_fast(lhs=self%buffer, rhs=Dt * self%b(s)) + call self%buffer%multiply_fast(lhs=self%buffer, rhs=Dt(s+1) * self%b(s)) call delta%add_fast(lhs=delta, rhs=self%buffer) enddo do s=1, iterations self%buffer = U - call self%buffer%t_fast(t=t(self%steps) + Dt) - call self%buffer%multiply_fast(lhs=self%buffer, rhs=Dt * self%b(self%steps)) + call self%buffer%t_fast(t=t(self%steps) + Dt(self%steps)) + call self%buffer%multiply_fast(lhs=self%buffer, rhs=Dt(self%steps) * self%b(self%steps)) call U%add_fast(lhs=delta, rhs=self%buffer) enddo else self%buffer = U - call self%buffer%t_fast(t=t(self%steps) + Dt) - call self%buffer%multiply_fast(lhs=self%buffer, rhs=Dt * self%b(self%steps)) + call self%buffer%t_fast(t=t(self%steps) + Dt(self%steps)) + call self%buffer%multiply_fast(lhs=self%buffer, rhs=Dt(self%steps) * self%b(self%steps)) call U%add_fast(lhs=previous(self%steps), rhs=self%buffer) do s=0, self%steps - 1 self%buffer = previous(s+1) call self%buffer%t_fast(t=t(s+1)) - call self%buffer%multiply_fast(lhs=self%buffer, rhs=Dt * self%b(s)) + call self%buffer%multiply_fast(lhs=self%buffer, rhs=Dt(s+1) * self%b(s)) call U%add_fast(lhs=U, rhs=self%buffer) enddo endif @@ -240,7 +243,7 @@ subroutine integrate_ub_fast(self, U, previous, Dt, t, iterations, autoupdate) else self%buffer = U call self%buffer%t_fast(t=t(1)) - call self%buffer%multiply_fast(lhs=self%buffer, rhs=Dt * self%b(0)) + call self%buffer%multiply_fast(lhs=self%buffer, rhs=Dt(1) * self%b(0)) call U%add_fast(lhs=U, rhs=self%buffer) endif endsubroutine integrate_ub_fast diff --git a/src/lib/foodie_integrator_backward_differentiation_formula.f90 b/src/lib/foodie_integrator_backward_differentiation_formula.f90 index d0031cf1..91d8a4c1 100644 --- a/src/lib/foodie_integrator_backward_differentiation_formula.f90 +++ b/src/lib/foodie_integrator_backward_differentiation_formula.f90 @@ -57,7 +57,10 @@ module foodie_integrator_backward_differentiation_formula !< FOODIE integrator: provide an implicit class of Backward-Differentiation-Formula multi-step schemes, from 1st to 6th order !< accurate. !< - !< @note The integrator must be created or initialized (initialize the *alpha* and *beta* coefficients) before used. + !< @note The integrator must be created or initialized (initialize the *a* and *b* coefficients) before used. + !< + !< @note The time steps `Dt(1:steps)` passed to the integrate methods must be identical: this integrator supports only + !< fixed time steps. private real(R_P), allocatable :: a(:) !< \(\alpha\) coefficients. real(R_P) :: b=0.0_R_P !< \(\beta\) coefficient. @@ -133,12 +136,12 @@ subroutine integrate(self, U, Dt, t, iterations, autoupdate) !< Integrate field with BDF class scheme. !< !< @note This method uses integrand previous-steps-buffer stored inside integrator. - class(integrator_back_df), intent(inout) :: self !< Integrator. - class(integrand_object), intent(inout) :: U !< Field to be integrated. - real(R_P), intent(in) :: Dt !< Time steps. - real(R_P), intent(in) :: t(:) !< Times. - integer(I_P), optional, intent(in) :: iterations !< Fixed point iterations. - logical, optional, intent(in) :: autoupdate !< Perform cyclic autoupdate of previous time steps. + class(integrator_back_df), intent(inout) :: self !< Integrator. + class(integrand_object), intent(inout) :: U !< Field to be integrated. + real(R_P), intent(in) :: Dt(1:) !< Time steps. + real(R_P), intent(in) :: t(1:) !< Times. + integer(I_P), optional, intent(in) :: iterations !< Fixed point iterations. + logical, optional, intent(in) :: autoupdate !< Perform cyclic autoupdate of previous time steps. call self%integrate_ub(U=U, previous=self%previous, Dt=Dt, t=t, iterations=iterations, autoupdate=autoupdate) endsubroutine integrate @@ -147,23 +150,23 @@ subroutine integrate_fast(self, U, Dt, t, iterations, autoupdate) !< Integrate field with BDF class scheme. !< !< @note This method uses integrand previous-steps-buffer stored inside integrator. - class(integrator_back_df), intent(inout) :: self !< Integrator. - class(integrand_object), intent(inout) :: U !< Field to be integrated. - real(R_P), intent(in) :: Dt !< Time steps. - real(R_P), intent(in) :: t(:) !< Times. - integer(I_P), optional, intent(in) :: iterations !< Fixed point iterations. - logical, optional, intent(in) :: autoupdate !< Perform cyclic autoupdate of previous time steps. + class(integrator_back_df), intent(inout) :: self !< Integrator. + class(integrand_object), intent(inout) :: U !< Field to be integrated. + real(R_P), intent(in) :: Dt(1:) !< Time steps. + real(R_P), intent(in) :: t(1:) !< Times. + integer(I_P), optional, intent(in) :: iterations !< Fixed point iterations. + logical, optional, intent(in) :: autoupdate !< Perform cyclic autoupdate of previous time steps. call self%integrate_ub_fast(U=U, previous=self%previous, Dt=Dt, t=t, iterations=iterations, autoupdate=autoupdate) endsubroutine integrate_fast subroutine integrate_ub(self, U, previous, Dt, t, iterations, autoupdate) !< Integrate field with BDF class scheme. - class(integrator_back_df), intent(in) :: self !< Integrator. + class(integrator_back_df), intent(inout) :: self !< Integrator. class(integrand_object), intent(inout) :: U !< Field to be integrated. class(integrand_object), intent(inout) :: previous(1:) !< Integrand. - real(R_P), intent(in) :: Dt !< Time steps. - real(R_P), intent(in) :: t(:) !< Times. + real(R_P), intent(in) :: Dt(1:) !< Time steps. + real(R_P), intent(in) :: t(1:) !< Times. integer(I_P), optional, intent(in) :: iterations !< Fixed point iterations. logical, optional, intent(in) :: autoupdate !< Perform cyclic autoupdate of previous time steps. integer(I_P) :: iterations_ !< Fixed point iterations. @@ -179,7 +182,7 @@ subroutine integrate_ub(self, U, previous, Dt, t, iterations, autoupdate) delta = delta + (previous(s) * (-self%a(s))) enddo do s=1, iterations_ - U = delta + (U%t(t=t(self%steps) + Dt) * (Dt * self%b)) + U = delta + (U%t(t=t(self%steps) + Dt(self%steps)) * (Dt(self%steps) * self%b)) enddo if (autoupdate_) call self%update_previous(U=U, previous=previous, is_like_explicit=.true.) endsubroutine integrate_ub @@ -189,8 +192,8 @@ subroutine integrate_ub_fast(self, U, previous, Dt, t, iterations, autoupdate) class(integrator_back_df), intent(inout) :: self !< Integrator. class(integrand_object), intent(inout) :: U !< Field to be integrated. class(integrand_object), intent(inout) :: previous(1:) !< Integrand. - real(R_P), intent(in) :: Dt !< Time steps. - real(R_P), intent(in) :: t(:) !< Times. + real(R_P), intent(in) :: Dt(1:) !< Time steps. + real(R_P), intent(in) :: t(1:) !< Times. integer(I_P), optional, intent(in) :: iterations !< Fixed point iterations. logical, optional, intent(in) :: autoupdate !< Perform cyclic autoupdate of previous time steps. integer(I_P) :: iterations_ !< Fixed point iterations. @@ -208,8 +211,8 @@ subroutine integrate_ub_fast(self, U, previous, Dt, t, iterations, autoupdate) enddo do s=1, iterations self%buffer = U - call self%buffer%t_fast(t=t(self%steps) + Dt) - call self%buffer%multiply_fast(lhs=self%buffer, rhs=Dt * self%b) + call self%buffer%t_fast(t=t(self%steps) + Dt(self%steps)) + call self%buffer%multiply_fast(lhs=self%buffer, rhs=Dt(self%steps) * self%b) call U%add_fast(lhs=delta, rhs=self%buffer) enddo if (autoupdate_) call self%update_previous(U=U, previous=previous, is_like_explicit=.true.) diff --git a/src/lib/foodie_integrator_euler_explicit.f90 b/src/lib/foodie_integrator_euler_explicit.f90 index 0d8856e3..d7c5fe86 100644 --- a/src/lib/foodie_integrator_euler_explicit.f90 +++ b/src/lib/foodie_integrator_euler_explicit.f90 @@ -14,7 +14,9 @@ module foodie_integrator_euler_explicit !< !< @note The value of \(\Delta t\) must be provided, it not being computed by the integrator. +use foodie_error_codes, only : ERROR_UNSUPPORTED_SCHEME use foodie_integrand_object, only : integrand_object +use foodie_integrator_multistage_explicit_object, only : integrator_multistage_explicit_object use foodie_integrator_object, only : integrator_object use penf, only : I_P, R_P @@ -25,30 +27,23 @@ module foodie_integrator_euler_explicit character(len=99), parameter :: class_name_='euler_explicit' !< Name of the class of schemes. character(len=99), parameter :: supported_schemes_(1:1)=[trim(class_name_)] !< List of supported schemes. -logical, parameter :: has_fast_mode_=.true. !< Flag to check if integrator provides *fast mode* integrate. -logical, parameter :: is_multistage_=.false. !< Flag to check if integrator is multistage. -logical, parameter :: is_multistep_=.false. !< Flag to check if integrator is multistep. +logical, parameter :: has_fast_mode_=.true. !< Flag to check if integrator provides *fast mode* integrate. -type, extends(integrator_object) :: integrator_euler_explicit +type, extends(integrator_multistage_explicit_object) :: integrator_euler_explicit !< FOODIE integrator: provide explicit Euler scheme, it being 1st order accurate. - !< - !< @note The integrator can be used directly without any initialization. contains ! deferred methods procedure, pass(self) :: class_name !< Return the class name of schemes. procedure, pass(self) :: description !< Return pretty-printed object description. procedure, pass(self) :: has_fast_mode !< Return .true. if the integrator class has *fast mode* integrate. procedure, pass(lhs) :: integr_assign_integr !< Operator `=`. - procedure, pass(self) :: is_multistage !< Return .true. for multistage integrator. - procedure, pass(self) :: is_multistep !< Return .true. for multistep integrator. + procedure, pass(self) :: integrate !< Integrate integrand field. + procedure, pass(self) :: integrate_fast !< Integrate integrand field, fast mode. procedure, pass(self) :: is_supported !< Return .true. if the integrator class support the given scheme. - procedure, pass(self) :: stages_number !< Return number of stages used. - procedure, pass(self) :: steps_number !< Return number of steps used. procedure, pass(self) :: supported_schemes !< Return the list of supported schemes. ! public methods - procedure, pass(self) :: destroy !< Destroy the integrator. - procedure, nopass :: integrate !< Integrate integrand field. - procedure, nopass :: integrate_fast !< Integrate integrand field, fast mode. + procedure, pass(self) :: destroy !< Destroy the integrator. + procedure, pass(self) :: initialize !< Initialize (create) the integrator. endtype integrator_euler_explicit contains ! deferred methods @@ -84,24 +79,35 @@ pure subroutine integr_assign_integr(lhs, rhs) class(integrator_euler_explicit), intent(inout) :: lhs !< Left hand side. class(integrator_object), intent(in) :: rhs !< Right hand side. - call lhs%assign_abstract(rhs=rhs) + call lhs%assign_multistage(rhs=rhs) endsubroutine integr_assign_integr - elemental function is_multistage(self) - !< Return .true. for multistage integrator. - class(integrator_euler_explicit), intent(in) :: self !< Integrator. - logical :: is_multistage !< Inquire result. - - is_multistage = is_multistage_ - endfunction is_multistage + subroutine integrate(self, U, Dt, t, new_Dt) + !< Integrate field with explicit Euler scheme, 1st order. + class(integrator_euler_explicit), intent(inout) :: self !< Integrator. + class(integrand_object), intent(inout) :: U !< Field to be integrated. + real(R_P), intent(in) :: Dt !< Time step. + real(R_P), intent(in) :: t !< Time. + real(R_P), optional, intent(out) :: new_Dt !< New adapted time step. - elemental function is_multistep(self) - !< Return .true. for multistage integrator. - class(integrator_euler_explicit), intent(in) :: self !< Integrator. - logical :: is_multistep !< Inquire result. + U = U + (U%t(t=t) * Dt) + if (present(new_Dt)) new_Dt = Dt + endsubroutine integrate - is_multistep = is_multistep_ - endfunction is_multistep + subroutine integrate_fast(self, U, Dt, t, new_Dt) + !< Integrate field with explicit Euler scheme, 1st order, fast mode. + class(integrator_euler_explicit), intent(inout) :: self !< Integrator. + class(integrand_object), intent(inout) :: U !< Field to be integrated. + real(R_P), intent(in) :: Dt !< Time step. + real(R_P), intent(in) :: t !< Time. + real(R_P), optional, intent(out) :: new_Dt !< New adapted time step. + + self%buffer = U + call self%buffer%t_fast(t=t) + call self%buffer%multiply_fast(lhs=self%buffer, rhs=Dt) + call U%add_fast(lhs=U, rhs=self%buffer) + if (present(new_Dt)) new_Dt = Dt + endsubroutine integrate_fast elemental function is_supported(self, scheme) !< Return .true. if the integrator class support the given scheme. @@ -119,22 +125,6 @@ elemental function is_supported(self, scheme) enddo endfunction is_supported - elemental function stages_number(self) - !< Return number of stages used. - class(integrator_euler_explicit), intent(in) :: self !< Integrator. - integer(I_P) :: stages_number !< Number of stages used. - - stages_number = 1 - endfunction stages_number - - elemental function steps_number(self) - !< Return number of steps used. - class(integrator_euler_explicit), intent(in) :: self !< Integrator. - integer(I_P) :: steps_number !< Number of steps used. - - steps_number = 1 - endfunction steps_number - pure function supported_schemes(self) result(schemes) !< Return the list of supported schemes. class(integrator_euler_explicit), intent(in) :: self !< Integrator. @@ -149,28 +139,25 @@ elemental subroutine destroy(self) !< Destroy the integrator. class(integrator_euler_explicit), intent(inout) :: self !< Integrator. - call self%destroy_abstract + call self%destroy_multistage endsubroutine destroy - subroutine integrate(U, Dt, t) - !< Integrate field with explicit Euler scheme, 1st order. - class(integrand_object), intent(inout) :: U !< Field to be integrated. - real(R_P), intent(in) :: Dt !< Time step. - real(R_P), optional, intent(in) :: t !< Time. - - U = U + (U%t(t=t) * Dt) - endsubroutine integrate - - subroutine integrate_fast(U, buffer, Dt, t) - !< Integrate field with explicit Euler scheme, 1st order, fast mode. - class(integrand_object), intent(inout) :: U !< Field to be integrated. - class(integrand_object), intent(inout) :: buffer !< Temporary buffer for doing fast operation. - real(R_P), intent(in) :: Dt !< Time step. - real(R_P), optional, intent(in) :: t !< Time. - - buffer = U - call buffer%t_fast(t=t) - call buffer%multiply_fast(lhs=buffer, rhs=Dt) - call U%add_fast(lhs=U, rhs=buffer) - endsubroutine integrate_fast + subroutine initialize(self, scheme, U, stop_on_fail) + !< Create the actual RK integrator: initialize the Butcher' table coefficients. + class(integrator_euler_explicit), intent(inout) :: self !< Integrator. + character(*), intent(in) :: scheme !< Selected scheme. + class(integrand_object), intent(in), optional :: U !< Integrand molding prototype. + logical, intent(in), optional :: stop_on_fail !< Stop execution if initialization fail. + + if (self%is_supported(scheme=scheme)) then + call self%destroy + self%stages = 0 + self%registers = self%stages + if (present(U)) call self%allocate_integrand_members(U=U) + else + call self%trigger_error(error=ERROR_UNSUPPORTED_SCHEME, & + error_message='"'//trim(adjustl(scheme))//'" unsupported scheme', & + is_severe=stop_on_fail) + endif + endsubroutine initialize endmodule foodie_integrator_euler_explicit diff --git a/src/lib/foodie_integrator_leapfrog.f90 b/src/lib/foodie_integrator_leapfrog.f90 index b3b72a1e..f582d0ae 100644 --- a/src/lib/foodie_integrator_leapfrog.f90 +++ b/src/lib/foodie_integrator_leapfrog.f90 @@ -38,6 +38,7 @@ module foodie_integrator_leapfrog use foodie_error_codes, only : ERROR_UNSUPPORTED_SCHEME use foodie_integrand_object, only : integrand_object +use foodie_integrator_multistep_explicit_object, only : integrator_multistep_explicit_object use foodie_integrator_object, only : integrator_object use penf, only : I_P, R_P @@ -50,35 +51,36 @@ module foodie_integrator_leapfrog trim(class_name_)//'_raw'] !< List of supported schemes. logical, parameter :: has_fast_mode_=.true. !< Flag to check if integrator provides *fast mode* integrate. -logical, parameter :: is_multistage_=.false. !< Flag to check if integrator is multistage. -logical, parameter :: is_multistep_=.true. !< Flag to check if integrator is multistep. -type, extends(integrator_object) :: integrator_leapfrog +type, extends(integrator_multistep_explicit_object) :: integrator_leapfrog !< FOODIE integrator: provide an explicit class of leapfrog multi-step schemes, 2nd order accurate. !< - !< @note The integrator could be used without initialialization (initialize the time filter coefficients) if the defulat values - !< are suitable for the problem. + !< @note The integrator must be initialized before used. + !< + !< @note The time steps `Dt(1:steps)` passed to the integrate methods must be identical: this integrator supports only + !< fixed time steps. private - integer(I_P) :: steps=2 !< Number of time steps. - real(R_P) :: nu=0.01_R_P !< Robert-Asselin filter coefficient. - real(R_P) :: alpha=0.53_R_P !< Robert-Asselin-Williams filter coefficient. + real(R_P) :: nu !< Robert-Asselin filter coefficient. + real(R_P) :: alpha !< Robert-Asselin-Williams filter coefficient. + logical :: is_filtered !< Flag to check if the integration if RAW filtered. + class(integrand_object), allocatable :: filter !< Filter field displacement. contains ! deferred methods procedure, pass(self) :: class_name !< Return the class name of schemes. procedure, pass(self) :: description !< Return pretty-printed object description. procedure, pass(self) :: has_fast_mode !< Return .true. if the integrator class has *fast mode* integrate. procedure, pass(lhs) :: integr_assign_integr !< Operator `=`. - procedure, pass(self) :: is_multistage !< Return .true. for multistage integrator. - procedure, pass(self) :: is_multistep !< Return .true. for multistep integrator. + procedure, pass(self) :: integrate !< Integrate integrand field. + procedure, pass(self) :: integrate_fast !< Integrate integrand field, fast mode. + procedure, pass(self) :: integrate_ub !< Integrate integrand field, unbuffered. + procedure, pass(self) :: integrate_ub_fast !< Integrate integrand field, fast mode, unbuffered. procedure, pass(self) :: is_supported !< Return .true. if the integrator class support the given scheme. - procedure, pass(self) :: stages_number !< Return number of stages used. - procedure, pass(self) :: steps_number !< Return number of steps used. procedure, pass(self) :: supported_schemes !< Return the list of supported schemes. ! public methods - procedure, pass(self) :: destroy !< Destroy the integrator. - procedure, pass(self) :: initialize !< Initialize (create) the integrator. - procedure, pass(self) :: integrate !< Integrate integrand field. - procedure, pass(self) :: integrate_fast !< Integrate integrand field, fast mode. + procedure, pass(self) :: destroy !< Destroy the integrator. + procedure, pass(self) :: initialize !< Initialize (create) the integrator. + ! overridden public methods + procedure, pass(self) :: allocate_integrand_members !< Allocate integrand members. endtype integrator_leapfrog contains @@ -115,30 +117,95 @@ pure subroutine integr_assign_integr(lhs, rhs) class(integrator_leapfrog), intent(inout) :: lhs !< Left hand side. class(integrator_object), intent(in) :: rhs !< Right hand side. - call lhs%assign_abstract(rhs=rhs) + call lhs%assign_multistep(rhs=rhs) select type(rhs) class is(integrator_leapfrog) - lhs%steps = rhs%steps - lhs%nu = rhs%nu - lhs%alpha = rhs%alpha + lhs%nu = rhs%nu + lhs%alpha = rhs%alpha + lhs%is_filtered = rhs%is_filtered + if (allocated(lhs%filter)) deallocate(lhs%filter) + if (allocated(rhs%filter)) then + allocate(lhs%filter, mold=rhs%filter) + lhs%filter = rhs%filter + endif endselect endsubroutine integr_assign_integr - elemental function is_multistage(self) - !< Return .true. for multistage integrator. - class(integrator_leapfrog), intent(in) :: self !< Integrator. - logical :: is_multistage !< Inquire result. - - is_multistage = is_multistage_ - endfunction is_multistage + subroutine integrate(self, U, Dt, t, autoupdate) + !< Integrate field with leapfrog class scheme. + !< + !< @note This method uses integrand previous-steps-buffer stored inside integrator. + class(integrator_leapfrog), intent(inout) :: self !< Integrator. + class(integrand_object), intent(inout) :: U !< Field to be integrated. + real(R_P), intent(in) :: Dt(1:) !< Time step. + real(R_P), intent(in) :: t(1:) !< Time. + logical, optional, intent(in) :: autoupdate !< Perform cyclic autoupdate of previous time steps. + + call self%integrate_ub(U=U, previous=self%previous, Dt=Dt, t=t, autoupdate=autoupdate) + endsubroutine integrate - elemental function is_multistep(self) - !< Return .true. for multistage integrator. - class(integrator_leapfrog), intent(in) :: self !< Integrator. - logical :: is_multistep !< Inquire result. + subroutine integrate_fast(self, U, Dt, t, autoupdate) + !< Integrate field with leapfrog class scheme, fast mode. + !< + !< @note This method uses integrand previous-steps-buffer stored inside integrator. + class(integrator_leapfrog), intent(inout) :: self !< Integrator. + class(integrand_object), intent(inout) :: U !< Field to be integrated. + real(R_P), intent(in) :: Dt(1:) !< Time step. + real(R_P), intent(in) :: t(1:) !< Time. + logical, optional, intent(in) :: autoupdate !< Perform cyclic autoupdate of previous time steps. + + call self%integrate_ub_fast(U=U, previous=self%previous, Dt=Dt, t=t, autoupdate=autoupdate) + endsubroutine integrate_fast - is_multistep = is_multistep_ - endfunction is_multistep + subroutine integrate_ub(self, U, previous, Dt, t, autoupdate) + !< Integrate field with leapfrog class scheme, unbuffered. + class(integrator_leapfrog), intent(inout) :: self !< Integrator. + class(integrand_object), intent(inout) :: U !< Field to be integrated. + class(integrand_object), intent(inout) :: previous(1:) !< Previous time steps solutions of integrand field. + real(R_P), intent(in) :: Dt(1:) !< Time step. + real(R_P), intent(in) :: t(1:) !< Time. + logical, optional, intent(in) :: autoupdate !< Perform cyclic autoupdate of previous time steps. + logical :: autoupdate_ !< Perform cyclic autoupdate of previous time steps, local variable. + + autoupdate_ = .true. ; if (present(autoupdate)) autoupdate_ = autoupdate + U = previous(1) + (previous(2)%t(t=t(2)) * (Dt(2) * 2._R_P)) + if (self%is_filtered) then + self%filter = (previous(1) - (previous(2) * 2._R_P) + U) * self%nu * 0.5_R_P + previous(2) = previous(2) + (self%filter * self%alpha) + U = U + (self%filter * (self%alpha - 1._R_P)) + endif + if (autoupdate_) call self%update_previous(U=U, previous=previous) + endsubroutine integrate_ub + + subroutine integrate_ub_fast(self, U, previous, Dt, t, autoupdate) + !< Integrate field with leapfrog class scheme, unbuffered, fast mode. + class(integrator_leapfrog), intent(inout) :: self !< Integrator. + class(integrand_object), intent(inout) :: U !< Field to be integrated. + class(integrand_object), intent(inout) :: previous(1:) !< Previous time steps solutions of integrand field. + real(R_P), intent(in) :: Dt(1:) !< Time step. + real(R_P), intent(in) :: t(1:) !< Time. + logical, optional, intent(in) :: autoupdate !< Perform cyclic autoupdate of previous time steps. + logical :: autoupdate_ !< Perform cyclic autoupdate of previous time steps, local variable. + + autoupdate_ = .true. ; if (present(autoupdate)) autoupdate_ = autoupdate + self%buffer = previous(2) + call self%buffer%t_fast(t=t(2)) + call self%buffer%multiply_fast(lhs=self%buffer, rhs=Dt(2) * 2._R_P) + call U%add_fast(lhs=previous(1), rhs=self%buffer) + if (self%is_filtered) then + call self%buffer%multiply_fast(lhs=previous(2), rhs=2._R_P) + call self%buffer%subtract_fast(lhs=previous(1), rhs=self%buffer) + call self%buffer%add_fast(lhs=self%buffer, rhs=U) + call self%filter%multiply_fast(lhs=self%buffer, rhs=self%nu * 0.5_R_P) + + call self%buffer%multiply_fast(lhs=self%filter, rhs=self%alpha) + call previous(2)%add_fast(lhs=previous(2), rhs=self%buffer) + + call self%buffer%multiply_fast(lhs=self%filter, rhs=self%alpha - 1._R_P) + call U%add_fast(lhs=U, rhs=self%buffer) + endif + if (autoupdate_) call self%update_previous(U=U, previous=previous) + endsubroutine integrate_ub_fast elemental function is_supported(self, scheme) !< Return .true. if the integrator class support the given scheme. @@ -156,22 +223,6 @@ elemental function is_supported(self, scheme) enddo endfunction is_supported - elemental function stages_number(self) - !< Return number of stages used. - class(integrator_leapfrog), intent(in) :: self !< Integrator. - integer(I_P) :: stages_number !< Number of stages used. - - stages_number = 0 - endfunction stages_number - - elemental function steps_number(self) - !< Return number of steps used. - class(integrator_leapfrog), intent(in) :: self !< Integrator. - integer(I_P) :: steps_number !< Number of steps used. - - steps_number = self%steps - endfunction steps_number - pure function supported_schemes(self) result(schemes) !< Return the list of supported schemes. class(integrator_leapfrog), intent(in) :: self !< Integrator. @@ -186,76 +237,65 @@ elemental subroutine destroy(self) !< Destroy the integrator. class(integrator_leapfrog), intent(INOUT) :: self !< Integrator. - call self%destroy_abstract - self%steps = 2 - self%nu = 0.01_R_P - self%alpha = 0.53_R_P + call self%destroy_multistep + self%nu = 0._R_P + self%alpha = 0._R_P + self%is_filtered = .false. + if (allocated(self%filter)) deallocate(self%filter) endsubroutine destroy - subroutine initialize(self, scheme, nu, alpha) + subroutine initialize(self, scheme, nu, alpha, U, stop_on_fail) !< Create the actual leapfrog integrator: initialize the filter coefficient. - class(integrator_leapfrog), intent(inout) :: self !< Integrator. - character(*), intent(in) :: scheme !< Selected scheme. - real(R_P), intent(in), optional :: nu !< Williams-Robert-Asselin filter coefficient. - real(R_P), intent(in), optional :: alpha !< Robert-Asselin filter coefficient. + class(integrator_leapfrog), intent(inout) :: self !< Integrator. + character(*), intent(in) :: scheme !< Selected scheme. + real(R_P), intent(in), optional :: nu !< Williams-Robert-Asselin filter coefficient. + real(R_P), intent(in), optional :: alpha !< Robert-Asselin filter coefficient. + class(integrand_object), intent(in), optional :: U !< Integrand molding prototype. + logical, intent(in), optional :: stop_on_fail !< Stop execution if initialization fail. if (self%is_supported(scheme=scheme)) then call self%destroy - if (present(nu)) self%nu = nu - if (present(alpha)) self%alpha = alpha + select case(trim(adjustl(scheme))) + case('leapfrog_raw') + self%nu = 0.01_R_P ; if (present(nu)) self%nu = nu + self%alpha = 0.53_R_P ; if (present(alpha)) self%alpha = alpha + self%is_filtered = .true. + endselect + self%steps = 2 + self%registers = self%steps + if (present(U)) call self%allocate_integrand_members(U=U) else call self%trigger_error(error=ERROR_UNSUPPORTED_SCHEME, & error_message='"'//trim(adjustl(scheme))//'" unsupported scheme', & - is_severe=.true.) + is_severe=stop_on_fail) endif endsubroutine initialize - subroutine integrate(self, U, previous, Dt, t, filter) - !< Integrate field with leapfrog class scheme. - class(integrator_leapfrog), intent(in) :: self !< Integrator. - class(integrand_object), intent(inout) :: U !< Field to be integrated. - class(integrand_object), intent(inout) :: previous(1:2) !< Previous time steps solutions of integrand field. - real(R_P), intent(in) :: Dt !< Time step. - real(R_P), intent(in) :: t !< Time. - class(integrand_object), optional, intent(inout) :: filter !< Filter field displacement. - - U = previous(1) + (previous(2)%t(t=t) * (Dt * 2._R_P)) - if (present(filter)) then - filter = (previous(1) - (previous(2) * 2._R_P) + U) * self%nu * 0.5_R_P - previous(2) = previous(2) + (filter * self%alpha) - U = U + (filter * (self%alpha - 1._R_P)) - endif - previous(1) = previous(2) - previous(2) = U - endsubroutine integrate - - subroutine integrate_fast(self, U, previous, buffer, Dt, t, filter) - !< Integrate field with leapfrog class scheme, fast mode. - class(integrator_leapfrog), intent(in) :: self !< Integrator. - class(integrand_object), intent(inout) :: U !< Field to be integrated. - class(integrand_object), intent(inout) :: previous(1:2) !< Previous time steps solutions of integrand field. - class(integrand_object), intent(inout) :: buffer !< Temporary buffer for doing fast operation. - real(R_P), intent(in) :: Dt !< Time step. - real(R_P), intent(in) :: t !< Time. - class(integrand_object), optional, intent(inout) :: filter !< Filter field displacement. - - buffer = previous(2) - call buffer%t_fast(t=t) - call buffer%multiply_fast(lhs=buffer, rhs=Dt * 2._R_P) - call U%add_fast(lhs=previous(1), rhs=buffer) - if (present(filter)) then - call buffer%multiply_fast(lhs=previous(2), rhs=2._R_P) - call buffer%subtract_fast(lhs=previous(1), rhs=buffer) - call buffer%add_fast(lhs=buffer, rhs=U) - call filter%multiply_fast(lhs=buffer, rhs=self%nu * 0.5_R_P) - - call buffer%multiply_fast(lhs=filter, rhs=self%alpha) - call previous(2)%add_fast(lhs=previous(2), rhs=buffer) - - call buffer%multiply_fast(lhs=filter, rhs=self%alpha - 1._R_P) - call U%add_fast(lhs=U, rhs=buffer) - endif - previous(1) = previous(2) - previous(2) = U - endsubroutine integrate_fast + ! overridden public methods + pure subroutine allocate_integrand_members(self, U) + !< Allocate members of interpolator being of [[integrand_object]] class. + !< + !< @note It is assumed that the integrator has been properly initialized before calling this method. + class(integrator_leapfrog), intent(inout) :: self !< Integrator. + class(integrand_object), intent(in) :: U !< Integrand. + integer(I_P) :: s !< Counter. + + if (self%is_multistep() .and. self%registers > 0) then + if (allocated(self%previous)) deallocate(self%previous) + allocate(self%previous(1:self%registers), mold=U) + do s=1, self%registers + self%previous(s) = U + enddo + endif + if (self%has_fast_mode()) then + if (allocated(self%buffer)) deallocate(self%buffer) + allocate(self%buffer, mold=U) + self%buffer = U + endif + if (self%is_filtered) then + if (allocated(self%filter)) deallocate(self%filter) + allocate(self%filter, mold=U) + self%filter = U + endif + endsubroutine allocate_integrand_members endmodule foodie_integrator_leapfrog diff --git a/src/lib/foodie_integrator_lmm_ssp.f90 b/src/lib/foodie_integrator_lmm_ssp.f90 index 70858f12..4a743ddd 100644 --- a/src/lib/foodie_integrator_lmm_ssp.f90 +++ b/src/lib/foodie_integrator_lmm_ssp.f90 @@ -47,7 +47,10 @@ module foodie_integrator_lmm_ssp !< FOODIE integrator: provide an explicit class of Linear Multi-step Methods (LLM) with Strong Stability Preserving property, !< from 2nd to 3rd order accurate. !< - !< @note The integrator must be created or initialized (initialize the *a,b* coefficients) before used. + !< @note The integrator must be initialized before used. + !< + !< @note The time steps `Dt(1:steps)` passed to the integrate methods must be identical: this integrator supports only + !< fixed time steps. private real(R_P), allocatable :: a(:) !< *a* coefficients. real(R_P), allocatable :: b(:) !< *b* coefficients. @@ -123,11 +126,11 @@ subroutine integrate(self, U, Dt, t, autoupdate) !< Integrate field with LMM-SSP class scheme. !< !< @note This method uses integrand previous-steps-buffer stored inside integrator. - class(integrator_lmm_ssp), intent(inout) :: self !< Integrator. - class(integrand_object), intent(inout) :: U !< Field to be integrated. - real(R_P), intent(in) :: Dt !< Time steps. - real(R_P), intent(in) :: t(:) !< Times. - logical, optional, intent(in) :: autoupdate !< Perform cyclic autoupdate of previous time steps. + class(integrator_lmm_ssp), intent(inout) :: self !< Integrator. + class(integrand_object), intent(inout) :: U !< Field to be integrated. + real(R_P), intent(in) :: Dt(1:) !< Time steps. + real(R_P), intent(in) :: t(1:) !< Times. + logical, optional, intent(in) :: autoupdate !< Perform cyclic autoupdate of previous time steps. call self%integrate_ub(U=U, previous=self%previous, Dt=Dt, t=t, autoupdate=autoupdate) endsubroutine integrate @@ -136,24 +139,22 @@ subroutine integrate_fast(self, U, Dt, t, autoupdate) !< Integrate field with LMM-SSP class scheme, fast mode. !< !< @note This method uses integrand previous-steps-buffer stored inside integrator. - class(integrator_lmm_ssp), intent(inout) :: self !< Integrator. - class(integrand_object), intent(inout) :: U !< Field to be integrated. - real(R_P), intent(in) :: Dt !< Time steps. - real(R_P), intent(in) :: t(:) !< Times. - logical, optional, intent(in) :: autoupdate !< Perform cyclic autoupdate of previous time steps. - logical :: autoupdate_ !< Perform cyclic autoupdate of previous time steps, dummy var. - integer(I_P) :: s !< Steps counter. + class(integrator_lmm_ssp), intent(inout) :: self !< Integrator. + class(integrand_object), intent(inout) :: U !< Field to be integrated. + real(R_P), intent(in) :: Dt(1:) !< Time steps. + real(R_P), intent(in) :: t(1:) !< Times. + logical, optional, intent(in) :: autoupdate !< Perform cyclic autoupdate of previous time steps. call self%integrate_ub_fast(U=U, previous=self%previous, Dt=Dt, t=t, autoupdate=autoupdate) endsubroutine integrate_fast subroutine integrate_ub(self, U, previous, Dt, t, autoupdate) !< Integrate field with LMM-SSP class scheme, unbuffered. - class(integrator_lmm_ssp), intent(in) :: self !< Integrator. + class(integrator_lmm_ssp), intent(inout) :: self !< Integrator. class(integrand_object), intent(inout) :: U !< Field to be integrated. class(integrand_object), intent(inout) :: previous(1:) !< Integrand. - real(R_P), intent(in) :: Dt !< Time steps. - real(R_P), intent(in) :: t(:) !< Times. + real(R_P), intent(in) :: Dt(1:) !< Time steps. + real(R_P), intent(in) :: t(1:) !< Times. logical, optional, intent(in) :: autoupdate !< Perform cyclic autoupdate of previous time steps. logical :: autoupdate_ !< Perform cyclic autoupdate of previous time steps, dummy var. integer(I_P) :: s !< Steps counter. @@ -162,7 +163,7 @@ subroutine integrate_ub(self, U, previous, Dt, t, autoupdate) U = U * 0._R_P do s=1, self%steps if (self%a(s) /= 0._R_P) U = U + (previous(s) * self%a(s)) - if (self%b(s) /= 0._R_P) U = U + (previous(s)%t(t=t(s)) * (Dt * self%b(s))) + if (self%b(s) /= 0._R_P) U = U + (previous(s)%t(t=t(s)) * (Dt(s) * self%b(s))) enddo if (autoupdate_) call self%update_previous(U=U, previous=previous) endsubroutine integrate_ub @@ -172,8 +173,8 @@ subroutine integrate_ub_fast(self, U, previous, Dt, t, autoupdate) class(integrator_lmm_ssp), intent(inout) :: self !< Integrator. class(integrand_object), intent(inout) :: U !< Field to be integrated. class(integrand_object), intent(inout) :: previous(1:) !< Integrand. - real(R_P), intent(in) :: Dt !< Time steps. - real(R_P), intent(in) :: t(:) !< Times. + real(R_P), intent(in) :: Dt(1:) !< Time steps. + real(R_P), intent(in) :: t(1:) !< Times. logical, optional, intent(in) :: autoupdate !< Perform cyclic autoupdate of previous time steps. logical :: autoupdate_ !< Perform cyclic autoupdate of previous time steps, dummy var. integer(I_P) :: s !< Steps counter. @@ -188,7 +189,7 @@ subroutine integrate_ub_fast(self, U, previous, Dt, t, autoupdate) if (self%b(s) /= 0._R_P) then self%buffer = previous(s) call self%buffer%t_fast(t=t(s)) - call self%buffer%multiply_fast(lhs=self%buffer, rhs=self%b(s)) + call self%buffer%multiply_fast(lhs=self%buffer, rhs=Dt(s) * self%b(s)) call U%add_fast(lhs=U, rhs=self%buffer) endif enddo diff --git a/src/lib/foodie_integrator_lmm_ssp_vss.f90 b/src/lib/foodie_integrator_lmm_ssp_vss.f90 index 63a064e0..e43592c3 100644 --- a/src/lib/foodie_integrator_lmm_ssp_vss.f90 +++ b/src/lib/foodie_integrator_lmm_ssp_vss.f90 @@ -39,6 +39,7 @@ module foodie_integrator_lmm_ssp_vss use foodie_error_codes, only : ERROR_UNSUPPORTED_SCHEME use foodie_integrand_object, only : integrand_object +use foodie_integrator_multistep_explicit_object, only : integrator_multistep_explicit_object use foodie_integrator_object, only : integrator_object use penf, only : I_P, R_P @@ -54,16 +55,13 @@ module foodie_integrator_lmm_ssp_vss trim(class_name_)//'_steps_5_order_3'] !< List of supported schemes. logical, parameter :: has_fast_mode_=.true. !< Flag to check if integrator provides *fast mode* integrate. -logical, parameter :: is_multistage_=.false. !< Flag to check if integrator is multistage. -logical, parameter :: is_multistep_=.true. !< Flag to check if integrator is multistep. -type, extends(integrator_object) :: integrator_lmm_ssp_vss +type, extends(integrator_multistep_explicit_object) :: integrator_lmm_ssp_vss !< FOODIE integrator: provide an explicit class of Linear Multi-step Methods (LLM) with Strong Stability Preserving property and !< variable stepsize (VSS), from 2nd to 3rd order accurate. !< !< @note The integrator must be created or initialized before used. private - integer(I_P) :: steps=0 !< Number of time steps. procedure(integrate_interface), pointer :: integrate_ => integrate_order_2 !< Integrate integrand field. procedure(integrate_fast_interface), pointer :: integrate_fast_ => integrate_order_2_fast !< Integrate integrand field, fast. contains @@ -72,18 +70,15 @@ module foodie_integrator_lmm_ssp_vss procedure, pass(self) :: description !< Return pretty-printed object description. procedure, pass(self) :: has_fast_mode !< Return .true. if the integrator class has *fast mode* integrate. procedure, pass(lhs) :: integr_assign_integr !< Operator `=`. - procedure, pass(self) :: is_multistage !< Return .true. for multistage integrator. - procedure, pass(self) :: is_multistep !< Return .true. for multistep integrator. + procedure, pass(self) :: integrate !< Integrate integrand field. + procedure, pass(self) :: integrate_fast !< Integrate integrand field, fast mode. + procedure, pass(self) :: integrate_ub !< Integrate integrand field, unbuffered. + procedure, pass(self) :: integrate_ub_fast !< Integrate integrand field, unbuffered, fast mode. procedure, pass(self) :: is_supported !< Return .true. if the integrator class support the given scheme. - procedure, pass(self) :: stages_number !< Return number of stages used. - procedure, pass(self) :: steps_number !< Return number of steps used. procedure, pass(self) :: supported_schemes !< Return the list of supported schemes. ! public methods - procedure, pass(self) :: destroy !< Destroy the integrator. - procedure, pass(self) :: initialize !< Initialize (create) the integrator. - procedure, pass(self) :: integrate !< Integrate integrand field. - procedure, pass(self) :: integrate_fast !< Integrate integrand field, fast mode. - procedure, pass(self) :: update_previous !< Cyclic update previous time steps. + procedure, pass(self) :: destroy !< Destroy the integrator. + procedure, pass(self) :: initialize !< Initialize (create) the integrator. ! private methods procedure, pass(self), private :: integrate_order_2 !< Integrate integrand field by 2nd order formula. procedure, pass(self), private :: integrate_order_3 !< Integrate integrand field by 3rd order formula. @@ -96,23 +91,25 @@ module foodie_integrator_lmm_ssp_vss subroutine integrate_interface(self, U, previous, Dt, t, autoupdate) !< Integrate field with LMM-SSP class scheme. import :: integrand_object, integrator_lmm_ssp_vss, R_P - class(integrator_lmm_ssp_vss), intent(in) :: self !< Integrator. + class(integrator_lmm_ssp_vss), intent(inout) :: self !< Integrator. class(integrand_object), intent(inout) :: U !< Field to be integrated. class(integrand_object), intent(inout) :: previous(1:) !< Previous time steps solutions of integrand field. - real(R_P), intent(inout) :: Dt(:) !< Time steps. - real(R_P), intent(in) :: t(:) !< Times. + ! real(R_P), intent(inout) :: Dt(1:) !< Time steps. + real(R_P), intent(in) :: Dt(1:) !< Time steps. + real(R_P), intent(in) :: t(1:) !< Times. logical, optional, intent(in) :: autoupdate !< Perform cyclic autoupdate of previous time steps. endsubroutine integrate_interface subroutine integrate_fast_interface(self, U, previous, buffer, Dt, t, autoupdate) !< Integrate field with LMM-SSP class scheme. import :: integrand_object, integrator_lmm_ssp_vss, R_P - class(integrator_lmm_ssp_vss), intent(in) :: self !< Integrator. + class(integrator_lmm_ssp_vss), intent(inout) :: self !< Integrator. class(integrand_object), intent(inout) :: U !< Field to be integrated. class(integrand_object), intent(inout) :: previous(1:) !< Previous time steps solutions of integrand field. class(integrand_object), intent(inout) :: buffer !< Temporary buffer for doing fast operation. - real(R_P), intent(inout) :: Dt(:) !< Time steps. - real(R_P), intent(in) :: t(:) !< Times. + ! real(R_P), intent(inout) :: Dt(1:) !< Time steps. + real(R_P), intent(in) :: Dt(1:) !< Time steps. + real(R_P), intent(in) :: t(1:) !< Times. logical, optional, intent(in) :: autoupdate !< Perform cyclic autoupdate of previous time steps. endsubroutine integrate_fast_interface endinterface @@ -159,29 +156,62 @@ pure subroutine integr_assign_integr(lhs, rhs) class(integrator_lmm_ssp_vss), intent(inout) :: lhs !< Left hand side. class(integrator_object), intent(in) :: rhs !< Right hand side. - call lhs%assign_abstract(rhs=rhs) + call lhs%assign_multistep(rhs=rhs) select type(rhs) class is (integrator_lmm_ssp_vss) - lhs%steps = rhs%steps if (associated(rhs%integrate_)) lhs%integrate_ => rhs%integrate_ endselect endsubroutine integr_assign_integr - elemental function is_multistage(self) - !< Return .true. for multistage integrator. - class(integrator_lmm_ssp_vss), intent(in) :: self !< Integrator. - logical :: is_multistage !< Inquire result. + subroutine integrate(self, U, Dt, t, autoupdate) + !< Integrate field with LMM-SSP class scheme. + class(integrator_lmm_ssp_vss), intent(inout) :: self !< Integrator. + class(integrand_object), intent(inout) :: U !< Field to be integrated. + ! real(R_P), intent(inout) :: Dt(1:) !< Time steps. + real(R_P), intent(in) :: Dt(1:) !< Time steps. + real(R_P), intent(in) :: t(1:) !< Times. + logical, optional, intent(in) :: autoupdate !< Perform cyclic autoupdate of previous time steps. + + call self%integrate_(U=U, previous=self%previous, Dt=Dt, t=t, autoupdate=autoupdate) + endsubroutine integrate - is_multistage = is_multistage_ - endfunction is_multistage + subroutine integrate_fast(self, U, Dt, t, autoupdate) + !< Integrate field with LMM-SSP class scheme, fast mode. + class(integrator_lmm_ssp_vss), intent(inout) :: self !< Integrator. + class(integrand_object), intent(inout) :: U !< Field to be integrated. + ! real(R_P), intent(inout) :: Dt(1:) !< Time steps. + real(R_P), intent(in) :: Dt(1:) !< Time steps. + real(R_P), intent(in) :: t(1:) !< Times. + logical, optional, intent(in) :: autoupdate !< Perform cyclic autoupdate of previous time steps. - elemental function is_multistep(self) - !< Return .true. for multistage integrator. - class(integrator_lmm_ssp_vss), intent(in) :: self !< Integrator. - logical :: is_multistep !< Inquire result. + call self%integrate_fast_(U=U, previous=self%previous, buffer=self%buffer, Dt=Dt, t=t, autoupdate=autoupdate) + endsubroutine integrate_fast + + subroutine integrate_ub(self, U, previous, Dt, t, autoupdate) + !< Integrate field with LMM-SSP class scheme, unbuffered. + class(integrator_lmm_ssp_vss), intent(inout) :: self !< Integrator. + class(integrand_object), intent(inout) :: U !< Field to be integrated. + class(integrand_object), intent(inout) :: previous(1:) !< Previous time steps solutions of integrand field. + ! real(R_P), intent(inout) :: Dt(1:) !< Time steps. + real(R_P), intent(in) :: Dt(1:) !< Time steps. + real(R_P), intent(in) :: t(1:) !< Times. + logical, optional, intent(in) :: autoupdate !< Perform cyclic autoupdate of previous time steps. + + call self%integrate_(U=U, previous=previous, Dt=Dt, t=t, autoupdate=autoupdate) + endsubroutine integrate_ub + + subroutine integrate_ub_fast(self, U, previous, Dt, t, autoupdate) + !< Integrate field with LMM-SSP class scheme, unbuffered, fast mode. + class(integrator_lmm_ssp_vss), intent(inout) :: self !< Integrator. + class(integrand_object), intent(inout) :: U !< Field to be integrated. + class(integrand_object), intent(inout) :: previous(1:) !< Previous time steps solutions of integrand field. + ! real(R_P), intent(inout) :: Dt(1:) !< Time steps. + real(R_P), intent(in) :: Dt(1:) !< Time steps. + real(R_P), intent(in) :: t(1:) !< Times. + logical, optional, intent(in) :: autoupdate !< Perform cyclic autoupdate of previous time steps. - is_multistep = is_multistep_ - endfunction is_multistep + call self%integrate_fast_(U=U, previous=previous, buffer=self%buffer, Dt=Dt, t=t, autoupdate=autoupdate) + endsubroutine integrate_ub_fast elemental function is_supported(self, scheme) !< Return .true. if the integrator class support the given scheme. @@ -199,22 +229,6 @@ elemental function is_supported(self, scheme) enddo endfunction is_supported - elemental function stages_number(self) - !< Return number of stages used. - class(integrator_lmm_ssp_vss), intent(in) :: self !< Integrator. - integer(I_P) :: stages_number !< Number of stages used. - - stages_number = 0 - endfunction stages_number - - elemental function steps_number(self) - !< Return number of steps used. - class(integrator_lmm_ssp_vss), intent(in) :: self !< Integrator. - integer(I_P) :: steps_number !< Number of steps used. - - steps_number = self%steps - endfunction steps_number - pure function supported_schemes(self) result(schemes) !< Return the list of supported schemes. class(integrator_lmm_ssp_vss), intent(in) :: self !< Integrator. @@ -229,18 +243,18 @@ elemental subroutine destroy(self) !< Destroy the integrator. class(integrator_lmm_ssp_vss), intent(inout) :: self !< Integrator. - call self%destroy_abstract - self%steps = 0 + call self%destroy_multistep self%integrate_ => integrate_order_2 endsubroutine destroy - subroutine initialize(self, scheme, stop_on_fail) + subroutine initialize(self, scheme, U, stop_on_fail) !< Create the actual LMM-SSP-VSS integrator. !< !< @note If the integrator is initialized with a bad (unsupported) number of required time steps the initialization fails and !< the integrator error status is updated consistently for external-provided errors handling. class(integrator_lmm_ssp_vss), intent(inout) :: self !< Integrator. character(*), intent(in) :: scheme !< Selected scheme. + class(integrand_object), intent(in), optional :: U !< Integrand molding prototype. logical, intent(in), optional :: stop_on_fail !< Stop execution if initialization fail. if (self%is_supported(scheme=scheme)) then @@ -267,6 +281,8 @@ subroutine initialize(self, scheme, stop_on_fail) self%integrate_ => integrate_order_3 self%integrate_fast_ => integrate_order_3_fast endselect + self%registers = self%steps + if (present(U)) call self%allocate_integrand_members(U=U) else call self%trigger_error(error=ERROR_UNSUPPORTED_SCHEME, & error_message='"'//trim(adjustl(scheme))//'" unsupported scheme', & @@ -274,77 +290,40 @@ subroutine initialize(self, scheme, stop_on_fail) endif endsubroutine initialize - subroutine integrate(self, U, previous, Dt, t, autoupdate) - !< Integrate field with LMM-SSP class scheme. - class(integrator_lmm_ssp_vss), intent(in) :: self !< Integrator. - class(integrand_object), intent(inout) :: U !< Field to be integrated. - class(integrand_object), intent(inout) :: previous(1:) !< Previous time steps solutions of integrand field. - real(R_P), intent(inout) :: Dt(:) !< Time steps. - real(R_P), intent(in) :: t(:) !< Times. - logical, optional, intent(in) :: autoupdate !< Perform cyclic autoupdate of previous time steps. - - call self%integrate_(U=U, previous=previous, Dt=Dt, t=t, autoupdate=autoupdate) - endsubroutine integrate - - subroutine integrate_fast(self, U, previous, buffer, Dt, t, autoupdate) - !< Integrate field with LMM-SSP class scheme. - class(integrator_lmm_ssp_vss), intent(in) :: self !< Integrator. - class(integrand_object), intent(inout) :: U !< Field to be integrated. - class(integrand_object), intent(inout) :: previous(1:) !< Previous time steps solutions of integrand field. - class(integrand_object), intent(inout) :: buffer !< Temporary buffer for doing fast operation. - real(R_P), intent(inout) :: Dt(:) !< Time steps. - real(R_P), intent(in) :: t(:) !< Times. - logical, optional, intent(in) :: autoupdate !< Perform cyclic autoupdate of previous time steps. - - call self%integrate_fast_(U=U, previous=previous, buffer=buffer, Dt=Dt, t=t, autoupdate=autoupdate) - endsubroutine integrate_fast - - subroutine update_previous(self, U, previous, Dt) - !< Cyclic update previous time steps. - class(integrator_lmm_ssp_vss), intent(in) :: self !< Integrator. - class(integrand_object), intent(in) :: U !< Field to be integrated. - class(integrand_object), intent(inout) :: previous(1:) !< Previous time steps solutions of integrand field. - real(R_P), intent(inout) :: Dt(:) !< Time steps. - integer(I_P) :: s !< Steps counter. - - do s=1, self%steps - 1 - previous(s) = previous(s + 1) - Dt(s) = Dt(s + 1) - enddo - previous(self%steps) = U - endsubroutine update_previous - ! private methods subroutine integrate_order_2(self, U, previous, Dt, t, autoupdate) !< Integrate field with LMM-SSP-VSS 2nd order class scheme. - class(integrator_lmm_ssp_vss), intent(in) :: self !< Integrator. - class(integrand_object), intent(inout) :: U !< Field to be integrated. - class(integrand_object), intent(inout) :: previous(1:) !< Previous time steps solutions of integrand field. - real(R_P), intent(inout) :: Dt(:) !< Time steps. - real(R_P), intent(in) :: t(:) !< Times. - logical, optional, intent(in) :: autoupdate !< Perform cyclic autoupdate of previous time steps. - logical :: autoupdate_ !< Perform cyclic autoupdate of previous time steps, dummy var. - real(R_P) :: omega_ !< Omega coefficient. - real(R_P) :: omega_sq !< Square of omega coefficient. + class(integrator_lmm_ssp_vss), intent(inout) :: self !< Integrator. + class(integrand_object), intent(inout) :: U !< Field to be integrated. + class(integrand_object), intent(inout) :: previous(1:) !< Previous time steps solutions of integrand field. + ! real(R_P), intent(inout) :: Dt(1:) !< Time steps. + real(R_P), intent(in) :: Dt(1:) !< Time steps. + real(R_P), intent(in) :: t(1:) !< Times. + logical, optional, intent(in) :: autoupdate !< Perform cyclic autoupdate of previous time steps. + logical :: autoupdate_ !< Perform cyclic autoupdate of previous time steps, dummy var. + real(R_P) :: omega_ !< Omega coefficient. + real(R_P) :: omega_sq !< Square of omega coefficient. autoupdate_ = .true. ; if (present(autoupdate)) autoupdate_ = autoupdate omega_ = omega(Dt=Dt, s=self%steps-1) omega_sq = omega_ * omega_ U = (previous(1) * (1._R_P / omega_sq)) + (previous(self%steps) * ((omega_sq - 1._R_P) / omega_sq)) + & (previous(self%steps)%t(t=t(self%steps)) * (Dt(self%steps) * (omega_ + 1._R_P) / omega_)) - if (autoupdate_) call self%update_previous(U=U, previous=previous, Dt=Dt) + ! if (autoupdate_) call self%update_previous(U=U, previous=previous, Dt=Dt) + if (autoupdate_) call self%update_previous(U=U, previous=previous) endsubroutine integrate_order_2 subroutine integrate_order_3(self, U, previous, Dt, t, autoupdate) !< Integrate field with LMM-SSP-VSS 3rd order class scheme. - class(integrator_lmm_ssp_vss), intent(in) :: self !< Integrator. - class(integrand_object), intent(inout) :: U !< Field to be integrated. - class(integrand_object), intent(inout) :: previous(1:) !< Previous time steps solutions of integrand field. - real(R_P), intent(inout) :: Dt(:) !< Time steps. - real(R_P), intent(in) :: t(:) !< Times. - logical, optional, intent(in) :: autoupdate !< Perform cyclic autoupdate of previous time steps. - logical :: autoupdate_ !< Perform cyclic autoupdate of previous time steps, dummy var. - real(R_P) :: omega_ !< Omega coefficient. + class(integrator_lmm_ssp_vss), intent(inout) :: self !< Integrator. + class(integrand_object), intent(inout) :: U !< Field to be integrated. + class(integrand_object), intent(inout) :: previous(1:) !< Previous time steps solutions of integrand field. + ! real(R_P), intent(inout) :: Dt(1:) !< Time steps. + real(R_P), intent(in) :: Dt(1:) !< Time steps. + real(R_P), intent(in) :: t(1:) !< Times. + logical, optional, intent(in) :: autoupdate !< Perform cyclic autoupdate of previous time steps. + logical :: autoupdate_ !< Perform cyclic autoupdate of previous time steps, dummy var. + real(R_P) :: omega_ !< Omega coefficient. autoupdate_ = .true. ; if (present(autoupdate)) autoupdate_ = autoupdate omega_= omega(Dt=Dt, s=self%steps-1) @@ -352,17 +331,19 @@ subroutine integrate_order_3(self, U, previous, Dt, t, autoupdate) (previous(self%steps) * (((omega_ + 1._R_P) ** 2) * (omega_ - 2._R_P) / omega_ ** 3)) + & (previous(1)%t(t=t(1)) * (Dt(self%steps) * (omega_ + 1._R_P) / omega_ ** 2)) + & (previous(self%steps)%t(t=t(self%steps)) * (Dt(self%steps) * (omega_ + 1._R_P) ** 2 / omega_ ** 2)) - if (autoupdate_) call self%update_previous(U=U, previous=previous, Dt=Dt) + ! if (autoupdate_) call self%update_previous(U=U, previous=previous, Dt=Dt) + if (autoupdate_) call self%update_previous(U=U, previous=previous) endsubroutine integrate_order_3 subroutine integrate_order_2_fast(self, U, previous, buffer, Dt, t, autoupdate) !< Integrate field with LMM-SSP-VSS 2nd order class scheme. - class(integrator_lmm_ssp_vss), intent(in) :: self !< Integrator. + class(integrator_lmm_ssp_vss), intent(inout) :: self !< Integrator. class(integrand_object), intent(inout) :: U !< Field to be integrated. class(integrand_object), intent(inout) :: previous(1:) !< Previous time steps solutions of integrand field. class(integrand_object), intent(inout) :: buffer !< Temporary buffer for doing fast operation. - real(R_P), intent(inout) :: Dt(:) !< Time steps. - real(R_P), intent(in) :: t(:) !< Times. + ! real(R_P), intent(inout) :: Dt(1:) !< Time steps. + real(R_P), intent(in) :: Dt(1:) !< Time steps. + real(R_P), intent(in) :: t(1:) !< Times. logical, optional, intent(in) :: autoupdate !< Perform cyclic autoupdate of previous time steps. logical :: autoupdate_ !< Perform cyclic autoupdate of previous time steps, dummy var. real(R_P) :: omega_ !< Omega coefficient. @@ -378,17 +359,19 @@ subroutine integrate_order_2_fast(self, U, previous, buffer, Dt, t, autoupdate) call buffer%t_fast(t=t(self%steps)) call buffer%multiply_fast(lhs=buffer, rhs=Dt(self%steps) * (omega_ + 1._R_P) / omega_) call U%add_fast(lhs=U, rhs=buffer) - if (autoupdate_) call self%update_previous(U=U, previous=previous, Dt=Dt) + ! if (autoupdate_) call self%update_previous(U=U, previous=previous, Dt=Dt) + if (autoupdate_) call self%update_previous(U=U, previous=previous) endsubroutine integrate_order_2_fast subroutine integrate_order_3_fast(self, U, previous, buffer, Dt, t, autoupdate) !< Integrate field with LMM-SSP-VSS 3rd order class scheme, fast mode. - class(integrator_lmm_ssp_vss), intent(in) :: self !< Integrator. + class(integrator_lmm_ssp_vss), intent(inout) :: self !< Integrator. class(integrand_object), intent(inout) :: U !< Field to be integrated. class(integrand_object), intent(inout) :: previous(1:) !< Previous time steps solutions of integrand field. class(integrand_object), intent(inout) :: buffer !< Temporary buffer for doing fast operation. - real(R_P), intent(inout) :: Dt(:) !< Time steps. - real(R_P), intent(in) :: t(:) !< Times. + ! real(R_P), intent(inout) :: Dt(1:) !< Time steps. + real(R_P), intent(in) :: Dt(1:) !< Time steps. + real(R_P), intent(in) :: t(1:) !< Times. logical, optional, intent(in) :: autoupdate !< Perform cyclic autoupdate of previous time steps. logical :: autoupdate_ !< Perform cyclic autoupdate of previous time steps, dummy var. real(R_P) :: omega_ !< Omega coefficient. @@ -407,7 +390,8 @@ subroutine integrate_order_3_fast(self, U, previous, buffer, Dt, t, autoupdate) call buffer%t_fast(t=t(self%steps)) call buffer%multiply_fast(lhs=buffer, rhs=(Dt(self%steps) * (omega_ + 1._R_P) ** 2 / (omega_ ** 2))) call U%add_fast(lhs=U, rhs=buffer) - if (autoupdate_) call self%update_previous(U=U, previous=previous, Dt=Dt) + ! if (autoupdate_) call self%update_previous(U=U, previous=previous, Dt=Dt) + if (autoupdate_) call self%update_previous(U=U, previous=previous) endsubroutine integrate_order_3_fast ! private non TBP diff --git a/src/lib/foodie_integrator_multistage_explicit_object.f90 b/src/lib/foodie_integrator_multistage_explicit_object.f90 index 35a082f2..a44d6582 100644 --- a/src/lib/foodie_integrator_multistage_explicit_object.f90 +++ b/src/lib/foodie_integrator_multistage_explicit_object.f90 @@ -29,20 +29,12 @@ module foodie_integrator_multistage_explicit_object procedure, pass(self) :: steps_number !< Return number of steps used. ! public methods procedure, pass(self) :: allocate_integrand_members !< Allocate integrand members. + procedure, pass(lhs) :: assign_multistage !< Assign members of [[integrator_multistage_explicit_object]] and parents. procedure, pass(self) :: destroy_multistage !< Destroy the integrator. endtype integrator_multistage_explicit_object abstract interface !< Abstract interfaces of deferred methods of [[integrator_multistage_explicit_object]]. - pure subroutine allocate_integrands_interface(self, U) - !< Allocate members of interpolator being of [[integrand_object]] class. - !< - !< @note It is assumed that the integrator has been properly initialized before calling this method. - import :: integrand_object, integrator_multistage_explicit_object - class(integrator_multistage_explicit_object), intent(inout) :: self !< Integrator. - class(integrand_object), intent(in) :: U !< Integrand. - endsubroutine allocate_integrands_interface - subroutine integrate_interface(self, U, Dt, t, new_Dt) !< Integrate integrand field. import :: integrand_object, integrator_multistage_explicit_object, R_P @@ -121,6 +113,32 @@ pure subroutine allocate_integrand_members(self, U) endif endsubroutine allocate_integrand_members + pure subroutine assign_multistage(lhs, rhs) + !< Assign members of [[integrator_multistage_explicit_object]] and parents. + class(integrator_multistage_explicit_object), intent(inout) :: lhs !< Left hand side. + class(integrator_object), intent(in) :: rhs !< Right hand side. + integer(I_P) :: s !< Counter. + + call lhs%assign_abstract(rhs=rhs) + select type(rhs) + class is (integrator_multistage_explicit_object) + lhs%registers = rhs%registers + lhs%stages = rhs%stages + if (allocated(lhs%stage)) deallocate(lhs%stage) + if (allocated(rhs%stage)) then + allocate(lhs%stage(1:lhs%registers), mold=rhs%stage) + do s=1, lhs%registers + lhs%stage(s) = rhs%stage(s) + enddo + endif + if (allocated(lhs%buffer)) deallocate(lhs%buffer) + if (allocated(rhs%buffer)) then + allocate(lhs%buffer, mold=rhs%buffer) + lhs%buffer = rhs%buffer + endif + endselect + endsubroutine assign_multistage + elemental subroutine destroy_multistage(self) !< Destroy the integrator. class(integrator_multistage_explicit_object), intent(inout) :: self !< Integrator. diff --git a/src/lib/foodie_integrator_multistep_explicit_object.f90 b/src/lib/foodie_integrator_multistep_explicit_object.f90 index 1dbf182c..eb9aa84a 100644 --- a/src/lib/foodie_integrator_multistep_explicit_object.f90 +++ b/src/lib/foodie_integrator_multistep_explicit_object.f90 @@ -32,6 +32,7 @@ module foodie_integrator_multistep_explicit_object procedure, pass(self) :: steps_number !< Return number of steps used. ! public methods procedure, pass(self) :: allocate_integrand_members !< Allocate integrand members. + procedure, pass(lhs) :: assign_multistep !< Assign members of [[integrator_multistep_explicit_object]] and parents. procedure, pass(self) :: destroy_multistep !< Destroy the integrator. procedure, pass(self) :: update_previous !< Cyclic update previous time steps. endtype integrator_multistep_explicit_object @@ -45,8 +46,8 @@ subroutine integrate_interface(self, U, Dt, t, autoupdate) import :: integrand_object, integrator_multistep_explicit_object, R_P class(integrator_multistep_explicit_object), intent(inout) :: self !< Integrator. class(integrand_object), intent(inout) :: U !< Integrand. - real(R_P), intent(in) :: Dt !< Time steps. - real(R_P), intent(in) :: t(:) !< Times. + real(R_P), intent(in) :: Dt(1:) !< Time steps. + real(R_P), intent(in) :: t(1:) !< Times. logical, optional, intent(in) :: autoupdate !< Perform cyclic autoupdate of previous time steps. endsubroutine integrate_interface @@ -57,19 +58,19 @@ subroutine integrate_fast_interface(self, U, Dt, t, autoupdate) import :: integrand_object, integrator_multistep_explicit_object, R_P class(integrator_multistep_explicit_object), intent(inout) :: self !< Integrator. class(integrand_object), intent(inout) :: U !< Field to be integrated. - real(R_P), intent(in) :: Dt !< Time steps. - real(R_P), intent(in) :: t(:) !< Times. + real(R_P), intent(in) :: Dt(1:) !< Time steps. + real(R_P), intent(in) :: t(1:) !< Times. logical, optional, intent(in) :: autoupdate !< Perform cyclic autoupdate of previous time steps. endsubroutine integrate_fast_interface subroutine integrate_ub_interface(self, U, previous, Dt, t, autoupdate) !< Integrate integrand field, unbuffered. import :: integrand_object, integrator_multistep_explicit_object, R_P - class(integrator_multistep_explicit_object), intent(in) :: self !< Integrator. + class(integrator_multistep_explicit_object), intent(inout) :: self !< Integrator. class(integrand_object), intent(inout) :: U !< Integrand. class(integrand_object), intent(inout) :: previous(1:) !< Integrand. - real(R_P), intent(in) :: Dt !< Time steps. - real(R_P), intent(in) :: t(:) !< Times. + real(R_P), intent(in) :: Dt(1:) !< Time steps. + real(R_P), intent(in) :: t(1:) !< Times. logical, optional, intent(in) :: autoupdate !< Perform cyclic autoupdate of previous time steps. endsubroutine integrate_ub_interface @@ -79,8 +80,8 @@ subroutine integrate_ub_fast_interface(self, U, previous, Dt, t, autoupdate) class(integrator_multistep_explicit_object), intent(inout) :: self !< Integrator. class(integrand_object), intent(inout) :: U !< Field to be integrated. class(integrand_object), intent(inout) :: previous(1:) !< Integrand. - real(R_P), intent(in) :: Dt !< Time steps. - real(R_P), intent(in) :: t(:) !< Times. + real(R_P), intent(in) :: Dt(1:) !< Time steps. + real(R_P), intent(in) :: t(1:) !< Times. logical, optional, intent(in) :: autoupdate !< Perform cyclic autoupdate of previous time steps. endsubroutine integrate_ub_fast_interface endinterface @@ -142,6 +143,32 @@ pure subroutine allocate_integrand_members(self, U) endif endsubroutine allocate_integrand_members + pure subroutine assign_multistep(lhs, rhs) + !< Assign members of [[integrator_multistep_explicit_object]] and parents. + class(integrator_multistep_explicit_object), intent(inout) :: lhs !< Left hand side. + class(integrator_object), intent(in) :: rhs !< Right hand side. + integer(I_P) :: s !< Counter. + + call lhs%assign_abstract(rhs=rhs) + select type(rhs) + class is (integrator_multistep_explicit_object) + lhs%registers = rhs%registers + lhs%steps = rhs%steps + if (allocated(lhs%previous)) deallocate(lhs%previous) + if (allocated(rhs%previous)) then + allocate(lhs%previous(1:lhs%registers), mold=rhs%previous) + do s=1, lhs%registers + lhs%previous(s) = rhs%previous(s) + enddo + endif + if (allocated(lhs%buffer)) deallocate(lhs%buffer) + if (allocated(rhs%buffer)) then + allocate(lhs%buffer, mold=rhs%buffer) + lhs%buffer = rhs%buffer + endif + endselect + endsubroutine assign_multistep + elemental subroutine destroy_multistep(self) !< Destroy the integrator. class(integrator_multistep_explicit_object), intent(inout) :: self !< Integrator. @@ -162,6 +189,7 @@ subroutine update_previous(self, U, previous) do s=1, self%steps - 1 previous(s) = previous(s + 1) + ! Dt(s) = Dt(s + 1) enddo previous(self%steps) = U endsubroutine update_previous diff --git a/src/lib/foodie_integrator_multistep_implicit_object.f90 b/src/lib/foodie_integrator_multistep_implicit_object.f90 index c4eff5a3..e10a2304 100644 --- a/src/lib/foodie_integrator_multistep_implicit_object.f90 +++ b/src/lib/foodie_integrator_multistep_implicit_object.f90 @@ -45,8 +45,8 @@ subroutine integrate_interface(self, U, Dt, t, iterations, autoupdate) import :: integrand_object, integrator_multistep_implicit_object, I_P, R_P class(integrator_multistep_implicit_object), intent(inout) :: self !< Integrator. class(integrand_object), intent(inout) :: U !< Integrand. - real(R_P), intent(in) :: Dt !< Time steps. - real(R_P), intent(in) :: t(:) !< Times. + real(R_P), intent(in) :: Dt(1:) !< Time steps. + real(R_P), intent(in) :: t(1:) !< Times. integer(I_P), optional, intent(in) :: iterations !< Fixed point iterations. logical, optional, intent(in) :: autoupdate !< Perform cyclic autoupdate of previous time steps. endsubroutine integrate_interface @@ -58,8 +58,8 @@ subroutine integrate_fast_interface(self, U, Dt, t, iterations, autoupdate) import :: integrand_object, integrator_multistep_implicit_object, I_P, R_P class(integrator_multistep_implicit_object), intent(inout) :: self !< Integrator. class(integrand_object), intent(inout) :: U !< Field to be integrated. - real(R_P), intent(in) :: Dt !< Time steps. - real(R_P), intent(in) :: t(:) !< Times. + real(R_P), intent(in) :: Dt(1:) !< Time steps. + real(R_P), intent(in) :: t(1:) !< Times. integer(I_P), optional, intent(in) :: iterations !< Fixed point iterations. logical, optional, intent(in) :: autoupdate !< Perform cyclic autoupdate of previous time steps. endsubroutine integrate_fast_interface @@ -67,11 +67,11 @@ subroutine integrate_fast_interface(self, U, Dt, t, iterations, autoupdate) subroutine integrate_ub_interface(self, U, previous, Dt, t, iterations, autoupdate) !< Integrate integrand field, unbuffered. import :: integrand_object, integrator_multistep_implicit_object, I_P, R_P - class(integrator_multistep_implicit_object), intent(in) :: self !< Integrator. + class(integrator_multistep_implicit_object), intent(inout) :: self !< Integrator. class(integrand_object), intent(inout) :: U !< Integrand. class(integrand_object), intent(inout) :: previous(1:) !< Integrand. - real(R_P), intent(in) :: Dt !< Time steps. - real(R_P), intent(in) :: t(:) !< Times. + real(R_P), intent(in) :: Dt(1:) !< Time steps. + real(R_P), intent(in) :: t(1:) !< Times. integer(I_P), optional, intent(in) :: iterations !< Fixed point iterations. logical, optional, intent(in) :: autoupdate !< Perform cyclic autoupdate of previous time steps. endsubroutine integrate_ub_interface @@ -82,8 +82,8 @@ subroutine integrate_ub_fast_interface(self, U, previous, Dt, t, iterations, aut class(integrator_multistep_implicit_object), intent(inout) :: self !< Integrator. class(integrand_object), intent(inout) :: U !< Field to be integrated. class(integrand_object), intent(inout) :: previous(1:) !< Integrand. - real(R_P), intent(in) :: Dt !< Time steps. - real(R_P), intent(in) :: t(:) !< Times. + real(R_P), intent(in) :: Dt(1:) !< Time steps. + real(R_P), intent(in) :: t(1:) !< Times. integer(I_P), optional, intent(in) :: iterations !< Fixed point iterations. logical, optional, intent(in) :: autoupdate !< Perform cyclic autoupdate of previous time steps. endsubroutine integrate_ub_fast_interface diff --git a/src/lib/foodie_integrator_runge_kutta_ssp.f90 b/src/lib/foodie_integrator_runge_kutta_ssp.f90 index c40a44b9..76e370ea 100644 --- a/src/lib/foodie_integrator_runge_kutta_ssp.f90 +++ b/src/lib/foodie_integrator_runge_kutta_ssp.f90 @@ -137,8 +137,8 @@ module foodie_integrator_runge_kutta_ssp procedure, pass(self) :: is_supported !< Return .true. if the integrator class support the given scheme. procedure, pass(self) :: supported_schemes !< Return the list of supported schemes. ! public methods - procedure, pass(self) :: destroy !< Destroy the integrator. - procedure, pass(self) :: initialize !< Initialize (create) the integrator. + procedure, pass(self) :: destroy !< Destroy the integrator. + procedure, pass(self) :: initialize !< Initialize (create) the integrator. endtype integrator_runge_kutta_ssp contains diff --git a/src/tests/tester/foodie_tester.f90 b/src/tests/tester/foodie_tester.f90 index a2b7f775..dcc8fb9d 100644 --- a/src/tests/tester/foodie_tester.f90 +++ b/src/tests/tester/foodie_tester.f90 @@ -256,12 +256,10 @@ subroutine integrate(scheme, integrand_0, Dt, final_time, iterations, stages, is class(integrator_object), allocatable :: integrator !< The integrator. type(integrator_runge_kutta_ssp) :: integrator_start !< The (auto) start integrator. class(integrand_object), allocatable :: integrand !< Integrand. - ! class(integrand_object), allocatable :: filter !< Filter displacement. real(R_P), allocatable :: time(:) !< Time. real(R_P), allocatable :: Dts(:) !< Time steps. integer(I_P) :: step !< Time steps counter. integer(I_P) :: step_offset !< Time steps counter offset for slicing previous data array. - integer(I_P) :: s !< Counter. allocate(integrand, mold=integrand_0) ; integrand = integrand_0 @@ -275,6 +273,7 @@ subroutine integrate(scheme, integrand_0, Dt, final_time, iterations, stages, is else step_offset = integrator%steps_number() ! for >0 step-solver offset is steps endif + allocate(Dts(1:step_offset)) else step_offset = 1 ! for 0 step-(a convention)-solver offset is 1 endif @@ -312,9 +311,9 @@ subroutine integrate(scheme, integrand_0, Dt, final_time, iterations, stages, is time(step) = time(step-1) + Dt else if (is_fast) then - call integrator%integrate_fast(U=integrand, Dt=Dt, t=time) + call integrator%integrate_fast(U=integrand, Dt=Dts, t=time) else - call integrator%integrate(U=integrand, Dt=Dt, t=time) + call integrator%integrate(U=integrand, Dt=Dts, t=time) endif call update_previous_times endif @@ -332,15 +331,15 @@ subroutine integrate(scheme, integrand_0, Dt, final_time, iterations, stages, is else if (is_fast) then if (iterations>1) then - call integrator%integrate_fast(U=integrand, Dt=Dt, t=time, iterations=iterations) + call integrator%integrate_fast(U=integrand, Dt=Dts, t=time, iterations=iterations) else - call integrator%integrate_fast(U=integrand, Dt=Dt, t=time) + call integrator%integrate_fast(U=integrand, Dt=Dts, t=time) endif else if (iterations>1) then - call integrator%integrate(U=integrand, Dt=Dt, t=time, iterations=iterations) + call integrator%integrate(U=integrand, Dt=Dts, t=time, iterations=iterations) else - call integrator%integrate(U=integrand, Dt=Dt, t=time) + call integrator%integrate(U=integrand, Dt=Dts, t=time) endif endif call update_previous_times @@ -349,68 +348,6 @@ subroutine integrate(scheme, integrand_0, Dt, final_time, iterations, stages, is call integrand_export_tecplot enddo - ! type is(integrator_euler_explicit) - ! do - ! step = step + 1 - ! if (is_fast) then - ! call integrator%integrate_fast(U=integrand, buffer=buffer, Dt=Dt, t=time(step_offset)) - ! else - ! call integrator%integrate(U=integrand, Dt=Dt, t=time(step_offset)) - ! endif - ! call update_previous_times - ! if ((time(step_offset) >= final_time)) exit - ! call integrand_export_tecplot - ! enddo - - ! type is(integrator_leapfrog) - ! do - ! step = step + 1 - ! if (integrator%steps_number() >= step) then - ! call integrator_start%integrate(U=integrand, Dt=Dt, t=time(step)) - ! previous(step) = integrand - ! time(step) = time(step-1) + Dt - ! else - ! if (index(scheme, 'raw') > 0 ) then - ! if (is_fast) then - ! call integrator%integrate_fast(U=integrand, previous=previous, buffer=buffer, Dt=Dt, t=time(step_offset), & - ! filter=filter) - ! else - ! call integrator%integrate(U=integrand, previous=previous, Dt=Dt, t=time(step_offset), filter=filter) - ! endif - ! else - ! if (is_fast) then - ! call integrator%integrate_fast(U=integrand, previous=previous, buffer=buffer, Dt=Dt, t=time(step_offset)) - ! else - ! call integrator%integrate(U=integrand, previous=previous, Dt=Dt, t=time(step_offset)) - ! endif - ! endif - ! call update_previous_times - ! endif - ! if ((time(step_offset) >= final_time)) exit - ! call integrand_export_tecplot - ! enddo - - ! type is(integrator_lmm_ssp_vss) - ! allocate(Dts(1:step_offset)) - ! Dts = Dt - ! do - ! step = step + 1 - ! if (integrator%steps_number() >= step) then - ! call integrator_start%integrate(U=integrand, Dt=Dt, t=time(step)) - ! previous(step) = integrand - ! time(step) = time(step-1) + Dt - ! else - ! if (is_fast) then - ! call integrator%integrate_fast(U=integrand, previous=previous, buffer=buffer, Dt=Dts, t=time) - ! else - ! call integrator%integrate(U=integrand, previous=previous, Dt=Dts, t=time) - ! endif - ! call update_previous_times - ! endif - ! if ((time(step) >= final_time)) exit - ! call integrand_export_tecplot - ! enddo - ! type is(integrator_ms_runge_kutta_ssp) ! do ! step = step + 1 From b61911a1c27f7690cd6112ada4c31c7faf72ec0c Mon Sep 17 00:00:00 2001 From: Stefano Zaghi Date: Wed, 24 May 2017 21:20:45 +0200 Subject: [PATCH 17/25] fix tester issue on Dts --- src/tests/tester/foodie_tester.f90 | 1 + 1 file changed, 1 insertion(+) diff --git a/src/tests/tester/foodie_tester.f90 b/src/tests/tester/foodie_tester.f90 index dcc8fb9d..a7b72d8e 100644 --- a/src/tests/tester/foodie_tester.f90 +++ b/src/tests/tester/foodie_tester.f90 @@ -274,6 +274,7 @@ subroutine integrate(scheme, integrand_0, Dt, final_time, iterations, stages, is step_offset = integrator%steps_number() ! for >0 step-solver offset is steps endif allocate(Dts(1:step_offset)) + Dts = Dt else step_offset = 1 ! for 0 step-(a convention)-solver offset is 1 endif From ebb76352a314985e8a4b1592949fdb6c7fdddff6 Mon Sep 17 00:00:00 2001 From: Stefano Zaghi Date: Thu, 25 May 2017 18:24:36 +0200 Subject: [PATCH 18/25] good cleanup --- fobos | 16 +- src/lib/foodie.f90 | 18 ++- src/lib/foodie_integrator_adams_bashforth.f90 | 58 +++---- ...die_integrator_adams_bashforth_moulton.f90 | 102 ++++++------ src/lib/foodie_integrator_adams_moulton.f90 | 120 +++++++------- ...rator_backward_differentiation_formula.f90 | 74 ++++----- src/lib/foodie_integrator_leapfrog.f90 | 62 ++++---- src/lib/foodie_integrator_lmm_ssp.f90 | 58 +++---- src/lib/foodie_integrator_lmm_ssp_vss.f90 | 150 +++++++----------- ...e_integrator_multistep_explicit_object.f90 | 79 +++++---- ...e_integrator_multistep_implicit_object.f90 | 136 ++++++++++------ src/tests/tester/foodie_tester.f90 | 23 ++- 12 files changed, 441 insertions(+), 455 deletions(-) diff --git a/fobos b/fobos index 49a1f246..3902fbbc 100644 --- a/fobos +++ b/fobos @@ -218,17 +218,17 @@ rule = tar --xform="s%^%FOODIE/%" -czf FOODIE.tar.gz * [rule-makecoverage] help = Rule for performing coverage analysis -rule_1 = FoBiS.py build -f src/tests/accuracy/oscillation/fobos -mode gnu-coverage -rule_2 = ./build/tests/accuracy/oscillation/oscillation -s all -rule_3 = rm -f build/tests/accuracy/oscillation/obj/penf* build/tests/accuracy/oscillation/obj/face* build/tests/accuracy/oscillation/obj/flap* build/tests/accuracy/oscillation/obj/wenoof* -rule_4 = gcov -o build/tests/accuracy/oscillation/obj/ src/lib/foodie* +rule_1 = FoBiS.py build -f src/tests/tester/fobos -mode gnu-coverage +rule_2 = ./build/tests/tester/foodie_tester +rule_3 = rm -f build/tests/tester/obj/penf* build/tests/tester/obj/face* build/tests/tester/obj/flap* build/tests/tester/obj/wenoof* +rule_4 = gcov -o build/tests/tester/obj/ src/lib/foodie* rule_5 = rm -f *.gcov [rule-coverage-analysis] help = Rule for performing coverage analysis and saving reports in markdown -rule_1 = FoBiS.py build -f src/tests/accuracy/oscillation/fobos -mode gnu-coverage -rule_2 = ./build/tests/accuracy/oscillation/oscillation -s all -rule_3 = rm -f build/tests/accuracy/oscillation/obj/penf* build/tests/accuracy/oscillation/obj/face* build/tests/accuracy/oscillation/obj/flap* build/tests/accuracy/oscillation/obj/wenoof* -rule_4 = gcov -o build/tests/accuracy/oscillation/obj/ src/lib/foodie* +rule_1 = FoBiS.py build -f src/tests/tester/fobos -mode gnu-coverage +rule_2 = ./build/tests/tester/foodie_tester +rule_3 = rm -f build/tests/tester/obj/penf* build/tests/tester/obj/face* build/tests/tester/obj/flap* build/tests/tester/obj/wenoof* +rule_4 = gcov -o build/tests/tester/obj/ src/lib/foodie* rule_5 = FoBiS.py rule -gcov_analyzer wiki/ Coverage-Analysis rule_6 = rm -f *.gcov diff --git a/src/lib/foodie.f90 b/src/lib/foodie.f90 index 83c76efa..bcfae015 100644 --- a/src/lib/foodie.f90 +++ b/src/lib/foodie.f90 @@ -146,7 +146,7 @@ pure function foodie_integrator_class_names() result(names) names = [names, int_runge_kutta_ssp % class_name()] endfunction foodie_integrator_class_names - subroutine foodie_integrator_factory(scheme, integrator, stages, tolerance, nu, alpha, U) + subroutine foodie_integrator_factory(scheme, integrator, stages, tolerance, nu, alpha, iterations, autoupdate, U) !< Return a concrete instance of [[integrator_object]] given a scheme selection. !< !< This is the FOODIE integrators factory. @@ -158,6 +158,8 @@ subroutine foodie_integrator_factory(scheme, integrator, stages, tolerance, nu, real(R_P), optional, intent(in) :: tolerance !< Tolerance on the local truncation error. real(R_P), optional, intent(in) :: nu !< Williams-Robert-Asselin filter coefficient. real(R_P), optional, intent(in) :: alpha !< Robert-Asselin filter coefficient. + integer(I_P), optional, intent(in) :: iterations !< Implicit iterations. + logical, optional, intent(in) :: autoupdate !< Enable cyclic autoupdate for multistep. class(integrand_object), optional, intent(in) :: U !< Integrand molding prototype. type(integrator_adams_bashforth) :: int_adams_bashforth !< Integrator Adams Bashforth. type(integrator_adams_bashforth_moulton) :: int_adams_bashforth_moulton !< Integrator Adams Bashforth Moulton. @@ -177,25 +179,25 @@ subroutine foodie_integrator_factory(scheme, integrator, stages, tolerance, nu, allocate(integrator_adams_bashforth_moulton :: integrator) select type(integrator) type is(integrator_adams_bashforth_moulton) - call integrator%initialize(scheme=scheme, U=U) + call integrator%initialize(scheme=scheme, iterations=iterations, autoupdate=autoupdate, U=U) endselect elseif (index(trim(adjustl(scheme)), trim(int_adams_bashforth%class_name())) > 0) then allocate(integrator_adams_bashforth :: integrator) select type(integrator) type is(integrator_adams_bashforth) - call integrator%initialize(scheme=scheme, U=U) + call integrator%initialize(scheme=scheme, autoupdate=autoupdate, U=U) endselect elseif (index(trim(adjustl(scheme)), trim(int_adams_moulton%class_name())) > 0) then allocate(integrator_adams_moulton :: integrator) select type(integrator) type is(integrator_adams_moulton) - call integrator%initialize(scheme=scheme, U=U) + call integrator%initialize(scheme=scheme, iterations=iterations, autoupdate=autoupdate, U=U) endselect elseif (index(trim(adjustl(scheme)), trim(int_back_df%class_name())) > 0) then allocate(integrator_back_df :: integrator) select type(integrator) type is(integrator_back_df) - call integrator%initialize(scheme=scheme, U=U) + call integrator%initialize(scheme=scheme, iterations=iterations, autoupdate=autoupdate, U=U) endselect elseif (index(trim(adjustl(scheme)), trim(int_euler_explicit%class_name())) > 0) then allocate(integrator_euler_explicit :: integrator) @@ -207,19 +209,19 @@ subroutine foodie_integrator_factory(scheme, integrator, stages, tolerance, nu, allocate(integrator_leapfrog :: integrator) select type(integrator) type is(integrator_leapfrog) - call integrator%initialize(scheme=scheme, nu=nu, alpha=alpha, U=U) + call integrator%initialize(scheme=scheme, nu=nu, alpha=alpha, autoupdate=autoupdate, U=U) endselect elseif (index(trim(adjustl(scheme)), trim(int_lmm_ssp_vss%class_name())) > 0) then allocate(integrator_lmm_ssp_vss :: integrator) select type(integrator) type is(integrator_lmm_ssp_vss) - call integrator%initialize(scheme=scheme, U=U) + call integrator%initialize(scheme=scheme, autoupdate=autoupdate, U=U) endselect elseif (index(trim(adjustl(scheme)), trim(int_lmm_ssp%class_name())) > 0) then allocate(integrator_lmm_ssp :: integrator) select type(integrator) type is(integrator_lmm_ssp) - call integrator%initialize(scheme=scheme, U=U) + call integrator%initialize(scheme=scheme, autoupdate=autoupdate, U=U) endselect elseif (index(trim(adjustl(scheme)), trim(int_ms_runge_kutta_ssp%class_name())) > 0) then allocate(integrator_ms_runge_kutta_ssp :: integrator) diff --git a/src/lib/foodie_integrator_adams_bashforth.f90 b/src/lib/foodie_integrator_adams_bashforth.f90 index 52430d2e..d28397d0 100644 --- a/src/lib/foodie_integrator_adams_bashforth.f90 +++ b/src/lib/foodie_integrator_adams_bashforth.f90 @@ -131,69 +131,61 @@ pure subroutine integr_assign_integr(lhs, rhs) endselect endsubroutine integr_assign_integr - subroutine integrate(self, U, Dt, t, autoupdate) + subroutine integrate(self, U, Dt, t) !< Integrate field with Adams-Bashforth class scheme. !< !< @note This method uses integrand previous-steps-buffer stored inside integrator. - class(integrator_adams_bashforth), intent(inout) :: self !< Integrator. - class(integrand_object), intent(inout) :: U !< Field to be integrated. - real(R_P), intent(in) :: Dt(1:) !< Time steps. - real(R_P), intent(in) :: t(1:) !< Times. - logical, optional, intent(in) :: autoupdate !< Perform cyclic autoupdate of previous time steps. + class(integrator_adams_bashforth), intent(inout) :: self !< Integrator. + class(integrand_object), intent(inout) :: U !< Field to be integrated. + real(R_P), intent(in) :: Dt !< Time step. + real(R_P), intent(in) :: t !< Time. - call self%integrate_ub(U=U, previous=self%previous, Dt=Dt, t=t, autoupdate=autoupdate) + call self%integrate_ub(U=U, previous=self%previous, Dt=Dt, t=t) endsubroutine integrate - subroutine integrate_fast(self, U, Dt, t, autoupdate) + subroutine integrate_fast(self, U, Dt, t) !< Integrate field with Adams-Bashforth class scheme, fast mode. !< !< @note This method uses integrand previous-steps-buffer stored inside integrator. - class(integrator_adams_bashforth), intent(inout) :: self !< Integrator. - class(integrand_object), intent(inout) :: U !< Field to be integrated. - real(R_P), intent(in) :: Dt(1:) !< Time steps. - real(R_P), intent(in) :: t(1:) !< Times. - logical, optional, intent(in) :: autoupdate !< Perform cyclic autoupdate of previous time steps. + class(integrator_adams_bashforth), intent(inout) :: self !< Integrator. + class(integrand_object), intent(inout) :: U !< Field to be integrated. + real(R_P), intent(in) :: Dt !< Time step. + real(R_P), intent(in) :: t !< Time. - call self%integrate_ub_fast(U=U, previous=self%previous, Dt=Dt, t=t, autoupdate=autoupdate) + call self%integrate_ub_fast(U=U, previous=self%previous, Dt=Dt, t=t) endsubroutine integrate_fast - subroutine integrate_ub(self, U, previous, Dt, t, autoupdate) + subroutine integrate_ub(self, U, previous, Dt, t) !< Integrate field with Adams-Bashforth class scheme, unbuffered. class(integrator_adams_bashforth), intent(inout) :: self !< Integrator. class(integrand_object), intent(inout) :: U !< Field to be integrated. class(integrand_object), intent(inout) :: previous(1:) !< Integrand. - real(R_P), intent(in) :: Dt(1:) !< Time steps. - real(R_P), intent(in) :: t(1:) !< Times. - logical, optional, intent(in) :: autoupdate !< Perform cyclic autoupdate of previous time steps. - logical :: autoupdate_ !< Perform cyclic autoupdate of previous time steps, dummy var. + real(R_P), intent(in) :: Dt !< Time step. + real(R_P), intent(in) :: t !< Time. integer(I_P) :: s !< Steps counter. - autoupdate_ = .true. ; if (present(autoupdate)) autoupdate_ = autoupdate do s=1, self%steps - U = U + (previous(s)%t(t=t(s)) * (Dt(s) * self%b(s))) + U = U + (previous(s)%t(t=self%t(s)) * (Dt * self%b(s))) enddo - if (autoupdate_) call self%update_previous(U=U, previous=previous) + if (self%autoupdate) call self%update_previous(U=U, previous=previous, Dt=Dt, t=t, previous_t=self%t) endsubroutine integrate_ub - subroutine integrate_ub_fast(self, U, previous, Dt, t, autoupdate) + subroutine integrate_ub_fast(self, U, previous, Dt, t) !< Integrate field with Adams-Bashforth class scheme, unbuffered, fast mode. class(integrator_adams_bashforth), intent(inout) :: self !< Integrator. class(integrand_object), intent(inout) :: U !< Field to be integrated. class(integrand_object), intent(inout) :: previous(1:) !< Integrand. - real(R_P), intent(in) :: Dt(1:) !< Time steps. - real(R_P), intent(in) :: t(1:) !< Times. - logical, optional, intent(in) :: autoupdate !< Perform cyclic autoupdate of previous time steps. - logical :: autoupdate_ !< Perform cyclic autoupdate of previous time steps, dummy var. + real(R_P), intent(in) :: Dt !< Time step. + real(R_P), intent(in) :: t !< Time. integer(I_P) :: s !< Steps counter. - autoupdate_ = .true. ; if (present(autoupdate)) autoupdate_ = autoupdate do s=1, self%steps self%buffer = previous(s) - call self%buffer%t_fast(t=t(s)) - call self%buffer%multiply_fast(lhs=self%buffer, rhs=Dt(s) * self%b(s)) + call self%buffer%t_fast(t=self%t(s)) + call self%buffer%multiply_fast(lhs=self%buffer, rhs=Dt * self%b(s)) call U%add_fast(lhs=U, rhs=self%buffer) enddo - if (autoupdate_) call self%update_previous(U=U, previous=previous) + if (self%autoupdate) call self%update_previous(U=U, previous=previous, Dt=Dt, t=t, previous_t=self%t) endsubroutine integrate_ub_fast elemental function is_supported(self, scheme) @@ -230,13 +222,14 @@ elemental subroutine destroy(self) if (allocated(self%b)) deallocate(self%b) endsubroutine destroy - subroutine initialize(self, scheme, U, stop_on_fail) + subroutine initialize(self, scheme, autoupdate, U, stop_on_fail) !< Create the actual Adams-Bashforth integrator: initialize the *b* coefficients. !< !< @note If the integrator is initialized with a bad (unsupported) number of required time steps the initialization fails and !< the integrator error status is updated consistently for external-provided errors handling. class(integrator_adams_bashforth), intent(inout) :: self !< Integrator. character(*), intent(in) :: scheme !< Selected scheme. + logical, intent(in), optional :: autoupdate !< Enable cyclic autoupdate of previous time steps. class(integrand_object), intent(in), optional :: U !< Integrand molding prototype. logical, intent(in), optional :: stop_on_fail !< Stop execution if initialization fail. @@ -412,6 +405,7 @@ subroutine initialize(self, scheme, U, stop_on_fail) self%b(15) = -2161567671248849.0_R_P/62768369664000.0_R_P self%b(16) = 362555126427073.0_R_P/62768369664000.0_R_P endselect + self%autoupdate = .true. ; if (present(autoupdate)) self%autoupdate = autoupdate self%registers = self%steps if (present(U)) call self%allocate_integrand_members(U=U) else diff --git a/src/lib/foodie_integrator_adams_bashforth_moulton.f90 b/src/lib/foodie_integrator_adams_bashforth_moulton.f90 index 5d2624da..9f01df77 100644 --- a/src/lib/foodie_integrator_adams_bashforth_moulton.f90 +++ b/src/lib/foodie_integrator_adams_bashforth_moulton.f90 @@ -178,7 +178,7 @@ pure subroutine integr_assign_integr(lhs, rhs) class(integrator_adams_bashforth_moulton), intent(inout) :: lhs !< Left hand side. class(integrator_object), intent(in) :: rhs !< Right hand side. - call lhs%assign_abstract(rhs=rhs) + call lhs%assign_multistep(rhs=rhs) select type(rhs) class is (integrator_adams_bashforth_moulton) lhs%steps = rhs%steps @@ -187,68 +187,62 @@ pure subroutine integr_assign_integr(lhs, rhs) endselect endsubroutine integr_assign_integr - subroutine integrate(self, U, Dt, t, iterations, autoupdate) + subroutine integrate(self, U, Dt, t) !< Integrate field with Adams-Bashforth-Moulton class scheme. !< !< @note This method uses integrand previous-steps-buffer stored inside integrator. - class(integrator_adams_bashforth_moulton), intent(inout) :: self !< Integrator. - class(integrand_object), intent(inout) :: U !< Field to be integrated. - real(R_P), intent(in) :: Dt(1:) !< Time steps. - real(R_P), intent(in) :: t(1:) !< Times. - integer(I_P), intent(in), optional :: iterations !< Fixed point iterations of AM scheme. - logical, intent(in), optional :: autoupdate !< Cyclic autoupdate of previous time steps flag. - - call self%integrate_ub(U=U, previous=self%previous, Dt=Dt, t=t, iterations=iterations, autoupdate=autoupdate) + class(integrator_adams_bashforth_moulton), intent(inout) :: self !< Integrator. + class(integrand_object), intent(inout) :: U !< Field to be integrated. + real(R_P), intent(in) :: Dt !< Time steps. + real(R_P), intent(in) :: t !< Times. + + call self%integrate_ub(U=U, previous=self%previous, Dt=Dt, t=t) endsubroutine integrate - subroutine integrate_fast(self, U, Dt, t, iterations, autoupdate) + subroutine integrate_fast(self, U, Dt, t) !< Integrate field with Adams-Bashforth-Moulton class scheme, fast mode. !< !< @note This method uses integrand previous-steps-buffer stored inside integrator. - class(integrator_adams_bashforth_moulton), intent(inout) :: self !< Integrator. - class(integrand_object), intent(inout) :: U !< Field to be integrated. - real(R_P), intent(in) :: Dt(1:) !< Time steps. - real(R_P), intent(in) :: t(1:) !< Times. - integer(I_P), intent(in), optional :: iterations !< Fixed point iterations of AM scheme. - logical, intent(in), optional :: autoupdate !< Cyclic autoupdate of previous time steps flag. - - call self%integrate_ub_fast(U=U, previous=self%previous, Dt=Dt, t=t, iterations=iterations, autoupdate=autoupdate) + class(integrator_adams_bashforth_moulton), intent(inout) :: self !< Integrator. + class(integrand_object), intent(inout) :: U !< Field to be integrated. + real(R_P), intent(in) :: Dt !< Time steps. + real(R_P), intent(in) :: t !< Times. + + call self%integrate_ub_fast(U=U, previous=self%previous, Dt=Dt, t=t) endsubroutine integrate_fast - subroutine integrate_ub(self, U, previous, Dt, t, iterations, autoupdate) + subroutine integrate_ub(self, U, previous, Dt, t) !< Integrate field with Adams-Bashforth-Moulton class scheme, unbuffered. - class(integrator_adams_bashforth_moulton), intent(inout) :: self !< Integrator. - class(integrand_object), intent(inout) :: U !< Field to be integrated. - class(integrand_object), intent(inout) :: previous(1:) !< Integrand. - real(R_P), intent(in) :: Dt(1:) !< Time steps. - real(R_P), intent(in) :: t(1:) !< Times. - integer(I_P), intent(in), optional :: iterations !< Fixed point iterations of AM scheme. - logical, intent(in), optional :: autoupdate !< Cyclic autoupdate of previous time steps flag. - logical :: autoupdate_ !< Cyclic autoupdate of previous time steps flag, - !< local variable. - - autoupdate_ = .true. ; if (present(autoupdate)) autoupdate_ = autoupdate - call self%predictor%integrate_ub(U=U, previous=previous, Dt=Dt, t=t, autoupdate=.false.) - call self%corrector%integrate_ub(U=U, previous=previous(2:), Dt=Dt, t=t, iterations=iterations, autoupdate=.false.) - if (autoupdate_) call self%predictor%update_previous(U=U, previous=previous) + class(integrator_adams_bashforth_moulton), intent(inout) :: self !< Integrator. + class(integrand_object), intent(inout) :: U !< Field to be integrated. + class(integrand_object), intent(inout) :: previous(1:) !< Integrand. + real(R_P), intent(in) :: Dt !< Time steps. + real(R_P), intent(in) :: t !< Times. + + self%predictor%t = self%t(1:self%steps) + self%predictor%Dt = self%Dt(1:self%steps) + self%corrector%t = self%t(1:self%steps) + self%corrector%Dt = self%Dt(1:self%steps) + call self%predictor%integrate_ub(U=U, previous=previous, Dt=Dt, t=t) + call self%corrector%integrate_ub(U=U, previous=previous(2:), Dt=Dt, t=t) + if (self%autoupdate) call self%update_previous(U=U, previous=previous(1:self%steps), Dt=Dt, t=t, previous_t=self%t(1:self%steps)) endsubroutine integrate_ub - subroutine integrate_ub_fast(self, U, previous, Dt, t, iterations, autoupdate) + subroutine integrate_ub_fast(self, U, previous, Dt, t) !< Integrate field with Adams-Bashforth-Moulton class scheme, unbuffered, fast mode. - class(integrator_adams_bashforth_moulton), intent(inout) :: self !< Integrator. - class(integrand_object), intent(inout) :: U !< Field to be integrated. - class(integrand_object), intent(inout) :: previous(1:) !< Integrand. - real(R_P), intent(in) :: Dt(1:) !< Time steps. - real(R_P), intent(in) :: t(1:) !< Times. - integer(I_P), intent(in), optional :: iterations !< Fixed point iterations of AM scheme. - logical, intent(in), optional :: autoupdate !< Cyclic autoupdate of previous time steps flag. - logical :: autoupdate_ !< Cyclic autoupdate of previous time steps flag, - !< local variable. - - autoupdate_ = .true. ; if (present(autoupdate)) autoupdate_ = autoupdate - call self%predictor%integrate_ub_fast(U=U, previous=previous, Dt=Dt, t=t, autoupdate=.false.) - call self%corrector%integrate_ub_fast(U=U, previous=previous(2:), Dt=Dt, t=t, iterations=iterations, autoupdate=.false.) - if (autoupdate_) call self%predictor%update_previous(U=U, previous=previous) + class(integrator_adams_bashforth_moulton), intent(inout) :: self !< Integrator. + class(integrand_object), intent(inout) :: U !< Field to be integrated. + class(integrand_object), intent(inout) :: previous(1:) !< Integrand. + real(R_P), intent(in) :: Dt !< Time steps. + real(R_P), intent(in) :: t !< Times. + + self%predictor%t = self%t + self%predictor%Dt = self%Dt + self%corrector%t = self%t + self%corrector%Dt = self%Dt + call self%predictor%integrate_ub_fast(U=U, previous=previous, Dt=Dt, t=t) + call self%corrector%integrate_ub_fast(U=U, previous=previous(2:), Dt=Dt, t=t) + if (self%autoupdate) call self%update_previous(U=U, previous=previous(1:self%steps), Dt=Dt, t=t, previous_t=self%t(1:self%steps)) endsubroutine integrate_ub_fast elemental function is_supported(self, scheme) @@ -286,10 +280,12 @@ elemental subroutine destroy(self) call self%corrector%destroy endsubroutine destroy - subroutine initialize(self, scheme, U, stop_on_fail) + subroutine initialize(self, scheme, iterations, autoupdate, U, stop_on_fail) !< Create the actual Adams-Bashforth-Moulton integrator: initialize the *b* coefficients. class(integrator_adams_bashforth_moulton), intent(inout) :: self !< Integrator. character(*), intent(in) :: scheme !< Selected scheme. + integer(I_P), intent(in), optional :: iterations !< Implicit iterations. + logical, intent(in), optional :: autoupdate !< Enable cyclic autoupdate of previous time steps. class(integrand_object), intent(in), optional :: U !< Integrand molding prototype. logical, intent(in), optional :: stop_on_fail !< Stop execution if initialization fail. character(len=99), allocatable :: schemes_ab(:) !< Adams-Bashforth schemes. @@ -301,8 +297,10 @@ subroutine initialize(self, scheme, U, stop_on_fail) scheme_number_ = self%scheme_number(scheme=scheme) schemes_ab = self%predictor%supported_schemes() schemes_am = self%corrector%supported_schemes() - call self%predictor%initialize(scheme=schemes_ab(scheme_number_)) - call self%corrector%initialize(scheme=schemes_am(scheme_number_)) + self%autoupdate = .true. ; if (present(autoupdate)) self%autoupdate = autoupdate + self%iterations = 1 ; if (present(iterations)) self%iterations = iterations + call self%predictor%initialize(scheme=schemes_ab(scheme_number_), autoupdate=.false.) + call self%corrector%initialize(scheme=schemes_am(scheme_number_), iterations=self%iterations, autoupdate=.false.) self%steps = self%predictor%steps_number() self%registers = self%steps + 1 if (present(U)) call self%allocate_integrand_members(U=U) diff --git a/src/lib/foodie_integrator_adams_moulton.f90 b/src/lib/foodie_integrator_adams_moulton.f90 index 61724ed4..8f87f9d7 100644 --- a/src/lib/foodie_integrator_adams_moulton.f90 +++ b/src/lib/foodie_integrator_adams_moulton.f90 @@ -125,7 +125,7 @@ pure subroutine integr_assign_integr(lhs, rhs) class(integrator_adams_moulton), intent(inout) :: lhs !< Left hand side. class(integrator_object), intent(in) :: rhs !< Right hand side. - call lhs%assign_abstract(rhs=rhs) + call lhs%assign_multistep(rhs=rhs) select type(rhs) class is (integrator_adams_moulton) lhs%steps = rhs%steps @@ -133,117 +133,105 @@ pure subroutine integr_assign_integr(lhs, rhs) endselect endsubroutine integr_assign_integr - subroutine integrate(self, U, Dt, t, iterations, autoupdate) + subroutine integrate(self, U, Dt, t) !< Integrate field with Adams-Moulton class scheme. !< !< @note This method uses integrand previous-steps-buffer stored inside integrator. - class(integrator_adams_moulton), intent(inout) :: self !< Integrator. - class(integrand_object), intent(inout) :: U !< Field to be integrated. - real(R_P), intent(in) :: Dt(1:) !< Time steps. - real(R_P), intent(in) :: t(1:) !< Times. - integer(I_P), intent(in), optional :: iterations !< Fixed point iterations. - logical, intent(in), optional :: autoupdate !< Cyclic autoupdate of previous time steps flag. + class(integrator_adams_moulton), intent(inout) :: self !< Integrator. + class(integrand_object), intent(inout) :: U !< Field to be integrated. + real(R_P), intent(in) :: Dt !< Time step. + real(R_P), intent(in) :: t !< Time. - call self%integrate_ub(U=U, previous=self%previous, Dt=Dt, t=t, iterations=iterations, autoupdate=autoupdate) + call self%integrate_ub(U=U, previous=self%previous, Dt=Dt, t=t) endsubroutine integrate - subroutine integrate_fast(self, U, Dt, t, iterations, autoupdate) + subroutine integrate_fast(self, U, Dt, t) !< Integrate field with Adams-Moulton class scheme, fast mode. !< !< @note This method uses integrand previous-steps-buffer stored inside integrator. - class(integrator_adams_moulton), intent(inout) :: self !< Integrator. - class(integrand_object), intent(inout) :: U !< Field to be integrated. - real(R_P), intent(in) :: Dt(1:) !< Time steps. - real(R_P), intent(in) :: t(1:) !< Times. - integer(I_P), intent(in), optional :: iterations !< Fixed point iterations. - logical, intent(in), optional :: autoupdate !< Cyclic autoupdate of previous time steps flag. + class(integrator_adams_moulton), intent(inout) :: self !< Integrator. + class(integrand_object), intent(inout) :: U !< Field to be integrated. + real(R_P), intent(in) :: Dt !< Time step. + real(R_P), intent(in) :: t !< Time. - call self%integrate_ub_fast(U=U, previous=self%previous, Dt=Dt, t=t, iterations=iterations, autoupdate=autoupdate) + call self%integrate_ub_fast(U=U, previous=self%previous, Dt=Dt, t=t) endsubroutine integrate_fast - subroutine integrate_ub(self, U, previous, Dt, t, iterations, autoupdate) + subroutine integrate_ub(self, U, previous, Dt, t) !< Integrate field with Adams-Moulton class scheme. - class(integrator_adams_moulton), intent(inout) :: self !< Integrator. - class(integrand_object), intent(inout) :: U !< Field to be integrated. - class(integrand_object), intent(inout) :: previous(1:) !< Integrand. - real(R_P), intent(in) :: Dt(1:) !< Time steps. - real(R_P), intent(in) :: t(1:) !< Times. - integer(I_P), intent(in), optional :: iterations !< Fixed point iterations. - logical, intent(in), optional :: autoupdate !< Cyclic autoupdate of previous time steps flag. - logical :: autoupdate_ !< Cyclic autoupdate of previous time steps flag, dummy var. - class(integrand_object), allocatable :: delta !< Delta RHS for fixed point iterations. - integer(I_P) :: s !< Steps counter. + class(integrator_adams_moulton), intent(inout) :: self !< Integrator. + class(integrand_object), intent(inout) :: U !< Field to be integrated. + class(integrand_object), intent(inout) :: previous(1:) !< Integrand. + real(R_P), intent(in) :: Dt !< Time step. + real(R_P), intent(in) :: t !< Time. + class(integrand_object), allocatable :: delta !< Delta RHS for fixed point iterations. + integer(I_P) :: s !< Steps counter. - autoupdate_ = .true. ; if (present(autoupdate)) autoupdate_ = autoupdate - if (self%steps>0) then - if (present(iterations)) then ! perform fixed point iterations + if ( self%steps>0 ) then + if (self%iterations > 0) then ! perform fixed point iterations allocate(delta, mold=U) delta = previous(self%steps) do s=0, self%steps - 1 - delta = delta + (previous(s+1)%t(t=t(s+1)) * (Dt(s+1) * self%b(s))) + delta = delta + (previous(s+1)%t(t=self%t(s+1)) * (Dt * self%b(s))) enddo - do s=1, iterations - U = delta + (U%t(t=t(self%steps) + Dt(self%steps)) * (Dt(self%steps) * self%b(self%steps))) + do s=1, self%iterations + U = delta + (U%t(t=self%t(self%steps) + Dt) * (Dt * self%b(self%steps))) enddo else - U = previous(self%steps) + (U%t(t=t(self%steps) + Dt(self%steps)) * (Dt(self%steps) * self%b(self%steps))) + U = previous(self%steps) + (U%t(t=self%t(self%steps) + Dt) * (Dt * self%b(self%steps))) do s=0, self%steps - 1 - U = U + (previous(s+1)%t(t=t(s+1)) * (Dt(s+1) * self%b(s))) + U = U + (previous(s+1)%t(t=self%t(s+1)) * (Dt * self%b(s))) enddo endif - if (autoupdate_) call self%update_previous(U=U, previous=previous) + if (self%autoupdate) call self%update_previous(U=U, previous=previous, Dt=Dt, t=t, previous_t=self%t) else - U = U + (U%t(t=t(1)) * (Dt(1) * self%b(0))) + U = U + (U%t(t=t) * (Dt * self%b(0))) endif endsubroutine integrate_ub - subroutine integrate_ub_fast(self, U, previous, Dt, t, iterations, autoupdate) + subroutine integrate_ub_fast(self, U, previous, Dt, t) !< Integrate field with Adams-Moulton class scheme, fast mode. - class(integrator_adams_moulton), intent(inout) :: self !< Integrator. - class(integrand_object), intent(inout) :: U !< Field to be integrated. - class(integrand_object), intent(inout) :: previous(1:) !< Integrand. - real(R_P), intent(in) :: Dt(1:) !< Time steps. - real(R_P), intent(in) :: t(1:) !< Times. - integer(I_P), intent(in), optional :: iterations !< Fixed point iterations. - logical, intent(in), optional :: autoupdate !< Cyclic autoupdate of previous time steps flag. - logical :: autoupdate_ !< Cyclic autoupdate of previous time steps flag, dummy var. - class(integrand_object), allocatable :: delta !< Delta RHS for fixed point iterations. - integer(I_P) :: s !< Steps counter. + class(integrator_adams_moulton), intent(inout) :: self !< Integrator. + class(integrand_object), intent(inout) :: U !< Field to be integrated. + class(integrand_object), intent(inout) :: previous(1:) !< Integrand. + real(R_P), intent(in) :: Dt !< Time step. + real(R_P), intent(in) :: t !< Time. + class(integrand_object), allocatable :: delta !< Delta RHS for fixed point iterations. + integer(I_P) :: s !< Steps counter. - autoupdate_ = .true. ; if (present(autoupdate)) autoupdate_ = autoupdate if (self%steps>0) then - if (present(iterations)) then ! perform fixed point iterations + if (self%iterations > 0) then ! perform fixed point iterations allocate(delta, mold=U) delta = previous(self%steps) do s=0, self%steps - 1 self%buffer = previous(s+1) - call self%buffer%t_fast(t=t(s+1)) - call self%buffer%multiply_fast(lhs=self%buffer, rhs=Dt(s+1) * self%b(s)) + call self%buffer%t_fast(t=self%t(s+1)) + call self%buffer%multiply_fast(lhs=self%buffer, rhs=Dt * self%b(s)) call delta%add_fast(lhs=delta, rhs=self%buffer) enddo - do s=1, iterations + do s=1, self%iterations self%buffer = U - call self%buffer%t_fast(t=t(self%steps) + Dt(self%steps)) - call self%buffer%multiply_fast(lhs=self%buffer, rhs=Dt(self%steps) * self%b(self%steps)) + call self%buffer%t_fast(t=self%t(self%steps) + Dt) + call self%buffer%multiply_fast(lhs=self%buffer, rhs=Dt * self%b(self%steps)) call U%add_fast(lhs=delta, rhs=self%buffer) enddo else self%buffer = U - call self%buffer%t_fast(t=t(self%steps) + Dt(self%steps)) - call self%buffer%multiply_fast(lhs=self%buffer, rhs=Dt(self%steps) * self%b(self%steps)) + call self%buffer%t_fast(t=self%t(self%steps) + Dt) + call self%buffer%multiply_fast(lhs=self%buffer, rhs=Dt * self%b(self%steps)) call U%add_fast(lhs=previous(self%steps), rhs=self%buffer) do s=0, self%steps - 1 self%buffer = previous(s+1) - call self%buffer%t_fast(t=t(s+1)) - call self%buffer%multiply_fast(lhs=self%buffer, rhs=Dt(s+1) * self%b(s)) + call self%buffer%t_fast(t=self%t(s+1)) + call self%buffer%multiply_fast(lhs=self%buffer, rhs=Dt * self%b(s)) call U%add_fast(lhs=U, rhs=self%buffer) enddo endif - if (autoupdate_) call self%update_previous(U=U, previous=previous) + if (self%autoupdate) call self%update_previous(U=U, previous=previous, Dt=Dt, t=t, previous_t=self%t) else self%buffer = U - call self%buffer%t_fast(t=t(1)) - call self%buffer%multiply_fast(lhs=self%buffer, rhs=Dt(1) * self%b(0)) + call self%buffer%t_fast(t=t) + call self%buffer%multiply_fast(lhs=self%buffer, rhs=Dt * self%b(0)) call U%add_fast(lhs=U, rhs=self%buffer) endif endsubroutine integrate_ub_fast @@ -282,10 +270,12 @@ elemental subroutine destroy(self) if (allocated(self%b)) deallocate(self%b) endsubroutine destroy - subroutine initialize(self, scheme, U, stop_on_fail) + subroutine initialize(self, scheme, iterations, autoupdate, U, stop_on_fail) !< Create the actual Adams-Moulton integrator: initialize the *b* coefficients. class(integrator_adams_moulton), intent(inout) :: self !< Integrator. character(*), intent(in) :: scheme !< Selected scheme. + integer(I_P), intent(in), optional :: iterations !< Implicit iterations. + logical, intent(in), optional :: autoupdate !< Enable cyclic autoupdate of previous time steps. class(integrand_object), intent(in), optional :: U !< Integrand molding prototype. logical, intent(in), optional :: stop_on_fail !< Stop execution if initialization fail. @@ -461,6 +451,8 @@ subroutine initialize(self, scheme, U, stop_on_fail) self%b(14) = 105145058757073.0_R_P/62768369664000.0_R_P self%b(15) = 16088129229375.0_R_P/62768369664000.0_R_P endselect + self%autoupdate = .true. ; if (present(autoupdate)) self%autoupdate = autoupdate + self%iterations = 1 ; if (present(iterations)) self%iterations = iterations self%registers = self%steps if (present(U)) call self%allocate_integrand_members(U=U) else diff --git a/src/lib/foodie_integrator_backward_differentiation_formula.f90 b/src/lib/foodie_integrator_backward_differentiation_formula.f90 index 91d8a4c1..025e9c67 100644 --- a/src/lib/foodie_integrator_backward_differentiation_formula.f90 +++ b/src/lib/foodie_integrator_backward_differentiation_formula.f90 @@ -123,7 +123,7 @@ pure subroutine integr_assign_integr(lhs, rhs) class(integrator_back_df), intent(inout) :: lhs !< Left hand side. class(integrator_object), intent(in) :: rhs !< Right hand side. - call lhs%assign_abstract(rhs=rhs) + call lhs%assign_multistep(rhs=rhs) select type(rhs) class is (integrator_back_df) lhs%steps = rhs%steps @@ -132,90 +132,74 @@ pure subroutine integr_assign_integr(lhs, rhs) endselect endsubroutine integr_assign_integr - subroutine integrate(self, U, Dt, t, iterations, autoupdate) + subroutine integrate(self, U, Dt, t) !< Integrate field with BDF class scheme. !< !< @note This method uses integrand previous-steps-buffer stored inside integrator. - class(integrator_back_df), intent(inout) :: self !< Integrator. - class(integrand_object), intent(inout) :: U !< Field to be integrated. - real(R_P), intent(in) :: Dt(1:) !< Time steps. - real(R_P), intent(in) :: t(1:) !< Times. - integer(I_P), optional, intent(in) :: iterations !< Fixed point iterations. - logical, optional, intent(in) :: autoupdate !< Perform cyclic autoupdate of previous time steps. + class(integrator_back_df), intent(inout) :: self !< Integrator. + class(integrand_object), intent(inout) :: U !< Field to be integrated. + real(R_P), intent(in) :: Dt !< Time step. + real(R_P), intent(in) :: t !< Time. - call self%integrate_ub(U=U, previous=self%previous, Dt=Dt, t=t, iterations=iterations, autoupdate=autoupdate) + call self%integrate_ub(U=U, previous=self%previous, Dt=Dt, t=t) endsubroutine integrate - subroutine integrate_fast(self, U, Dt, t, iterations, autoupdate) + subroutine integrate_fast(self, U, Dt, t) !< Integrate field with BDF class scheme. !< !< @note This method uses integrand previous-steps-buffer stored inside integrator. - class(integrator_back_df), intent(inout) :: self !< Integrator. - class(integrand_object), intent(inout) :: U !< Field to be integrated. - real(R_P), intent(in) :: Dt(1:) !< Time steps. - real(R_P), intent(in) :: t(1:) !< Times. - integer(I_P), optional, intent(in) :: iterations !< Fixed point iterations. - logical, optional, intent(in) :: autoupdate !< Perform cyclic autoupdate of previous time steps. + class(integrator_back_df), intent(inout) :: self !< Integrator. + class(integrand_object), intent(inout) :: U !< Field to be integrated. + real(R_P), intent(in) :: Dt !< Time step. + real(R_P), intent(in) :: t !< Time. - call self%integrate_ub_fast(U=U, previous=self%previous, Dt=Dt, t=t, iterations=iterations, autoupdate=autoupdate) + call self%integrate_ub_fast(U=U, previous=self%previous, Dt=Dt, t=t) endsubroutine integrate_fast - subroutine integrate_ub(self, U, previous, Dt, t, iterations, autoupdate) + subroutine integrate_ub(self, U, previous, Dt, t) !< Integrate field with BDF class scheme. class(integrator_back_df), intent(inout) :: self !< Integrator. class(integrand_object), intent(inout) :: U !< Field to be integrated. class(integrand_object), intent(inout) :: previous(1:) !< Integrand. - real(R_P), intent(in) :: Dt(1:) !< Time steps. - real(R_P), intent(in) :: t(1:) !< Times. - integer(I_P), optional, intent(in) :: iterations !< Fixed point iterations. - logical, optional, intent(in) :: autoupdate !< Perform cyclic autoupdate of previous time steps. - integer(I_P) :: iterations_ !< Fixed point iterations. - logical :: autoupdate_ !< Perform cyclic autoupdate of previous time steps, dummy var. + real(R_P), intent(in) :: Dt !< Time step. + real(R_P), intent(in) :: t !< Time. class(integrand_object), allocatable :: delta !< Delta RHS for fixed point iterations. integer(I_P) :: s !< Steps counter. - autoupdate_ = .true. ; if (present(autoupdate)) autoupdate_ = autoupdate - iterations_ = 1 ; if (present(iterations)) iterations_ = iterations allocate(delta, mold=U) delta = previous(self%steps) * (-self%a(self%steps)) do s=1, self%steps - 1 delta = delta + (previous(s) * (-self%a(s))) enddo - do s=1, iterations_ - U = delta + (U%t(t=t(self%steps) + Dt(self%steps)) * (Dt(self%steps) * self%b)) + do s=1, self%iterations + U = delta + (U%t(t=self%t(self%steps) + Dt) * (Dt * self%b)) enddo - if (autoupdate_) call self%update_previous(U=U, previous=previous, is_like_explicit=.true.) + if (self%autoupdate) call self%update_previous(U=U, previous=previous, Dt=Dt, t=t, previous_t=self%t) endsubroutine integrate_ub - subroutine integrate_ub_fast(self, U, previous, Dt, t, iterations, autoupdate) + subroutine integrate_ub_fast(self, U, previous, Dt, t) !< Integrate field with BDF class scheme. class(integrator_back_df), intent(inout) :: self !< Integrator. class(integrand_object), intent(inout) :: U !< Field to be integrated. class(integrand_object), intent(inout) :: previous(1:) !< Integrand. - real(R_P), intent(in) :: Dt(1:) !< Time steps. - real(R_P), intent(in) :: t(1:) !< Times. - integer(I_P), optional, intent(in) :: iterations !< Fixed point iterations. - logical, optional, intent(in) :: autoupdate !< Perform cyclic autoupdate of previous time steps. - integer(I_P) :: iterations_ !< Fixed point iterations. - logical :: autoupdate_ !< Perform cyclic autoupdate of previous time steps, dummy var. + real(R_P), intent(in) :: Dt !< Time steps. + real(R_P), intent(in) :: t !< Times. class(integrand_object), allocatable :: delta !< Delta RHS for fixed point iterations. integer(I_P) :: s !< Steps counter. - autoupdate_ = .true. ; if (present(autoupdate)) autoupdate_ = autoupdate - iterations_ = 1 ; if (present(iterations)) iterations_ = iterations allocate(delta, mold=U) call delta%multiply_fast(lhs=previous(self%steps), rhs=-self%a(self%steps)) do s=1, self%steps - 1 call self%buffer%multiply_fast(lhs=previous(s), rhs=-self%a(s)) call delta%add_fast(lhs=delta, rhs=self%buffer) enddo - do s=1, iterations + do s=1, self%iterations self%buffer = U - call self%buffer%t_fast(t=t(self%steps) + Dt(self%steps)) - call self%buffer%multiply_fast(lhs=self%buffer, rhs=Dt(self%steps) * self%b) + call self%buffer%t_fast(t=self%t(self%steps) + Dt) + call self%buffer%multiply_fast(lhs=self%buffer, rhs=Dt * self%b) call U%add_fast(lhs=delta, rhs=self%buffer) enddo - if (autoupdate_) call self%update_previous(U=U, previous=previous, is_like_explicit=.true.) + if (self%autoupdate) call self%update_previous(U=U, previous=previous, Dt=Dt, t=t, previous_t=self%t) endsubroutine integrate_ub_fast elemental function is_supported(self, scheme) @@ -253,10 +237,12 @@ elemental subroutine destroy(self) self%b = 0.0_R_P endsubroutine destroy - subroutine initialize(self, scheme, U, stop_on_fail) + subroutine initialize(self, scheme, iterations, autoupdate, U, stop_on_fail) !< Create the actual BDF integrator: initialize the *alpha* and *beta* coefficients. class(integrator_back_df), intent(inout) :: self !< Integrator. character(*), intent(in) :: scheme !< Selected scheme. + integer(I_P), intent(in), optional :: iterations !< Implicit iterations. + logical, intent(in), optional :: autoupdate !< Enable cyclic autoupdate of previous time steps. class(integrand_object), intent(in), optional :: U !< Integrand molding prototype. logical, intent(in), optional :: stop_on_fail !< Stop execution if initialization fail. @@ -304,6 +290,8 @@ subroutine initialize(self, scheme, U, stop_on_fail) self%b = 60.0_R_P/147.0_R_P case default endselect + self%autoupdate = .true. ; if (present(autoupdate)) self%autoupdate = autoupdate + self%iterations = 1 ; if (present(iterations)) self%iterations = iterations self%registers = self%steps if (present(U)) call self%allocate_integrand_members(U=U) else diff --git a/src/lib/foodie_integrator_leapfrog.f90 b/src/lib/foodie_integrator_leapfrog.f90 index f582d0ae..b5544ed3 100644 --- a/src/lib/foodie_integrator_leapfrog.f90 +++ b/src/lib/foodie_integrator_leapfrog.f90 @@ -131,66 +131,58 @@ pure subroutine integr_assign_integr(lhs, rhs) endselect endsubroutine integr_assign_integr - subroutine integrate(self, U, Dt, t, autoupdate) + subroutine integrate(self, U, Dt, t) !< Integrate field with leapfrog class scheme. !< !< @note This method uses integrand previous-steps-buffer stored inside integrator. - class(integrator_leapfrog), intent(inout) :: self !< Integrator. - class(integrand_object), intent(inout) :: U !< Field to be integrated. - real(R_P), intent(in) :: Dt(1:) !< Time step. - real(R_P), intent(in) :: t(1:) !< Time. - logical, optional, intent(in) :: autoupdate !< Perform cyclic autoupdate of previous time steps. + class(integrator_leapfrog), intent(inout) :: self !< Integrator. + class(integrand_object), intent(inout) :: U !< Field to be integrated. + real(R_P), intent(in) :: Dt !< Time step. + real(R_P), intent(in) :: t !< Time. - call self%integrate_ub(U=U, previous=self%previous, Dt=Dt, t=t, autoupdate=autoupdate) + call self%integrate_ub(U=U, previous=self%previous, Dt=Dt, t=t) endsubroutine integrate - subroutine integrate_fast(self, U, Dt, t, autoupdate) + subroutine integrate_fast(self, U, Dt, t) !< Integrate field with leapfrog class scheme, fast mode. !< !< @note This method uses integrand previous-steps-buffer stored inside integrator. - class(integrator_leapfrog), intent(inout) :: self !< Integrator. - class(integrand_object), intent(inout) :: U !< Field to be integrated. - real(R_P), intent(in) :: Dt(1:) !< Time step. - real(R_P), intent(in) :: t(1:) !< Time. - logical, optional, intent(in) :: autoupdate !< Perform cyclic autoupdate of previous time steps. + class(integrator_leapfrog), intent(inout) :: self !< Integrator. + class(integrand_object), intent(inout) :: U !< Field to be integrated. + real(R_P), intent(in) :: Dt !< Time step. + real(R_P), intent(in) :: t !< Time. - call self%integrate_ub_fast(U=U, previous=self%previous, Dt=Dt, t=t, autoupdate=autoupdate) + call self%integrate_ub_fast(U=U, previous=self%previous, Dt=Dt, t=t) endsubroutine integrate_fast - subroutine integrate_ub(self, U, previous, Dt, t, autoupdate) + subroutine integrate_ub(self, U, previous, Dt, t) !< Integrate field with leapfrog class scheme, unbuffered. class(integrator_leapfrog), intent(inout) :: self !< Integrator. class(integrand_object), intent(inout) :: U !< Field to be integrated. class(integrand_object), intent(inout) :: previous(1:) !< Previous time steps solutions of integrand field. - real(R_P), intent(in) :: Dt(1:) !< Time step. - real(R_P), intent(in) :: t(1:) !< Time. - logical, optional, intent(in) :: autoupdate !< Perform cyclic autoupdate of previous time steps. - logical :: autoupdate_ !< Perform cyclic autoupdate of previous time steps, local variable. + real(R_P), intent(in) :: Dt !< Time step. + real(R_P), intent(in) :: t !< Time. - autoupdate_ = .true. ; if (present(autoupdate)) autoupdate_ = autoupdate - U = previous(1) + (previous(2)%t(t=t(2)) * (Dt(2) * 2._R_P)) + U = previous(1) + (previous(2)%t(t=t) * (Dt * 2._R_P)) if (self%is_filtered) then self%filter = (previous(1) - (previous(2) * 2._R_P) + U) * self%nu * 0.5_R_P previous(2) = previous(2) + (self%filter * self%alpha) U = U + (self%filter * (self%alpha - 1._R_P)) endif - if (autoupdate_) call self%update_previous(U=U, previous=previous) + if (self%autoupdate) call self%update_previous(U=U, previous=previous) endsubroutine integrate_ub - subroutine integrate_ub_fast(self, U, previous, Dt, t, autoupdate) + subroutine integrate_ub_fast(self, U, previous, Dt, t) !< Integrate field with leapfrog class scheme, unbuffered, fast mode. class(integrator_leapfrog), intent(inout) :: self !< Integrator. class(integrand_object), intent(inout) :: U !< Field to be integrated. class(integrand_object), intent(inout) :: previous(1:) !< Previous time steps solutions of integrand field. - real(R_P), intent(in) :: Dt(1:) !< Time step. - real(R_P), intent(in) :: t(1:) !< Time. - logical, optional, intent(in) :: autoupdate !< Perform cyclic autoupdate of previous time steps. - logical :: autoupdate_ !< Perform cyclic autoupdate of previous time steps, local variable. + real(R_P), intent(in) :: Dt !< Time step. + real(R_P), intent(in) :: t !< Time. - autoupdate_ = .true. ; if (present(autoupdate)) autoupdate_ = autoupdate self%buffer = previous(2) - call self%buffer%t_fast(t=t(2)) - call self%buffer%multiply_fast(lhs=self%buffer, rhs=Dt(2) * 2._R_P) + call self%buffer%t_fast(t=t) + call self%buffer%multiply_fast(lhs=self%buffer, rhs=Dt * 2._R_P) call U%add_fast(lhs=previous(1), rhs=self%buffer) if (self%is_filtered) then call self%buffer%multiply_fast(lhs=previous(2), rhs=2._R_P) @@ -204,7 +196,7 @@ subroutine integrate_ub_fast(self, U, previous, Dt, t, autoupdate) call self%buffer%multiply_fast(lhs=self%filter, rhs=self%alpha - 1._R_P) call U%add_fast(lhs=U, rhs=self%buffer) endif - if (autoupdate_) call self%update_previous(U=U, previous=previous) + if (self%autoupdate) call self%update_previous(U=U, previous=previous) endsubroutine integrate_ub_fast elemental function is_supported(self, scheme) @@ -244,12 +236,13 @@ elemental subroutine destroy(self) if (allocated(self%filter)) deallocate(self%filter) endsubroutine destroy - subroutine initialize(self, scheme, nu, alpha, U, stop_on_fail) + subroutine initialize(self, scheme, nu, alpha, autoupdate, U, stop_on_fail) !< Create the actual leapfrog integrator: initialize the filter coefficient. class(integrator_leapfrog), intent(inout) :: self !< Integrator. character(*), intent(in) :: scheme !< Selected scheme. real(R_P), intent(in), optional :: nu !< Williams-Robert-Asselin filter coefficient. real(R_P), intent(in), optional :: alpha !< Robert-Asselin filter coefficient. + logical, intent(in), optional :: autoupdate !< Enable cyclic autoupdate of previous time steps. class(integrand_object), intent(in), optional :: U !< Integrand molding prototype. logical, intent(in), optional :: stop_on_fail !< Stop execution if initialization fail. @@ -261,6 +254,7 @@ subroutine initialize(self, scheme, nu, alpha, U, stop_on_fail) self%alpha = 0.53_R_P ; if (present(alpha)) self%alpha = alpha self%is_filtered = .true. endselect + self%autoupdate = .true. ; if (present(autoupdate)) self%autoupdate = autoupdate self%steps = 2 self%registers = self%steps if (present(U)) call self%allocate_integrand_members(U=U) @@ -281,6 +275,10 @@ pure subroutine allocate_integrand_members(self, U) integer(I_P) :: s !< Counter. if (self%is_multistep() .and. self%registers > 0) then + if (allocated(self%Dt)) deallocate(self%Dt) + allocate(self%Dt(1:self%registers)) ; self%Dt = 0._R_P + if (allocated(self%t)) deallocate(self%t) + allocate(self%t(1:self%registers)) ; self%t = 0._R_P if (allocated(self%previous)) deallocate(self%previous) allocate(self%previous(1:self%registers), mold=U) do s=1, self%registers diff --git a/src/lib/foodie_integrator_lmm_ssp.f90 b/src/lib/foodie_integrator_lmm_ssp.f90 index 4a743ddd..606d9118 100644 --- a/src/lib/foodie_integrator_lmm_ssp.f90 +++ b/src/lib/foodie_integrator_lmm_ssp.f90 @@ -122,64 +122,56 @@ pure subroutine integr_assign_integr(lhs, rhs) endselect endsubroutine integr_assign_integr - subroutine integrate(self, U, Dt, t, autoupdate) + subroutine integrate(self, U, Dt, t) !< Integrate field with LMM-SSP class scheme. !< !< @note This method uses integrand previous-steps-buffer stored inside integrator. - class(integrator_lmm_ssp), intent(inout) :: self !< Integrator. - class(integrand_object), intent(inout) :: U !< Field to be integrated. - real(R_P), intent(in) :: Dt(1:) !< Time steps. - real(R_P), intent(in) :: t(1:) !< Times. - logical, optional, intent(in) :: autoupdate !< Perform cyclic autoupdate of previous time steps. + class(integrator_lmm_ssp), intent(inout) :: self !< Integrator. + class(integrand_object), intent(inout) :: U !< Field to be integrated. + real(R_P), intent(in) :: Dt !< Time step. + real(R_P), intent(in) :: t !< Time. - call self%integrate_ub(U=U, previous=self%previous, Dt=Dt, t=t, autoupdate=autoupdate) + call self%integrate_ub(U=U, previous=self%previous, Dt=Dt, t=t) endsubroutine integrate - subroutine integrate_fast(self, U, Dt, t, autoupdate) + subroutine integrate_fast(self, U, Dt, t) !< Integrate field with LMM-SSP class scheme, fast mode. !< !< @note This method uses integrand previous-steps-buffer stored inside integrator. - class(integrator_lmm_ssp), intent(inout) :: self !< Integrator. - class(integrand_object), intent(inout) :: U !< Field to be integrated. - real(R_P), intent(in) :: Dt(1:) !< Time steps. - real(R_P), intent(in) :: t(1:) !< Times. - logical, optional, intent(in) :: autoupdate !< Perform cyclic autoupdate of previous time steps. + class(integrator_lmm_ssp), intent(inout) :: self !< Integrator. + class(integrand_object), intent(inout) :: U !< Field to be integrated. + real(R_P), intent(in) :: Dt !< Time step. + real(R_P), intent(in) :: t !< Time. - call self%integrate_ub_fast(U=U, previous=self%previous, Dt=Dt, t=t, autoupdate=autoupdate) + call self%integrate_ub_fast(U=U, previous=self%previous, Dt=Dt, t=t) endsubroutine integrate_fast - subroutine integrate_ub(self, U, previous, Dt, t, autoupdate) + subroutine integrate_ub(self, U, previous, Dt, t) !< Integrate field with LMM-SSP class scheme, unbuffered. class(integrator_lmm_ssp), intent(inout) :: self !< Integrator. class(integrand_object), intent(inout) :: U !< Field to be integrated. class(integrand_object), intent(inout) :: previous(1:) !< Integrand. - real(R_P), intent(in) :: Dt(1:) !< Time steps. - real(R_P), intent(in) :: t(1:) !< Times. - logical, optional, intent(in) :: autoupdate !< Perform cyclic autoupdate of previous time steps. - logical :: autoupdate_ !< Perform cyclic autoupdate of previous time steps, dummy var. + real(R_P), intent(in) :: Dt !< Time step. + real(R_P), intent(in) :: t !< Time. integer(I_P) :: s !< Steps counter. - autoupdate_ = .true. ; if (present(autoupdate)) autoupdate_ = autoupdate U = U * 0._R_P do s=1, self%steps if (self%a(s) /= 0._R_P) U = U + (previous(s) * self%a(s)) - if (self%b(s) /= 0._R_P) U = U + (previous(s)%t(t=t(s)) * (Dt(s) * self%b(s))) + if (self%b(s) /= 0._R_P) U = U + (previous(s)%t(t=self%t(s)) * (Dt * self%b(s))) enddo - if (autoupdate_) call self%update_previous(U=U, previous=previous) + if (self%autoupdate) call self%update_previous(U=U, previous=previous, Dt=Dt, t=t, previous_t=self%t) endsubroutine integrate_ub - subroutine integrate_ub_fast(self, U, previous, Dt, t, autoupdate) + subroutine integrate_ub_fast(self, U, previous, Dt, t) !< Integrate field with LMM-SSP class scheme, unbuffered, fast mode. class(integrator_lmm_ssp), intent(inout) :: self !< Integrator. class(integrand_object), intent(inout) :: U !< Field to be integrated. class(integrand_object), intent(inout) :: previous(1:) !< Integrand. - real(R_P), intent(in) :: Dt(1:) !< Time steps. - real(R_P), intent(in) :: t(1:) !< Times. - logical, optional, intent(in) :: autoupdate !< Perform cyclic autoupdate of previous time steps. - logical :: autoupdate_ !< Perform cyclic autoupdate of previous time steps, dummy var. + real(R_P), intent(in) :: Dt !< Time step. + real(R_P), intent(in) :: t !< Time. integer(I_P) :: s !< Steps counter. - autoupdate_ = .true. ; if (present(autoupdate)) autoupdate_ = autoupdate call U%multiply_fast(lhs=U, rhs=0._R_P) do s=1, self%steps if (self%a(s) /= 0._R_P) then @@ -188,12 +180,12 @@ subroutine integrate_ub_fast(self, U, previous, Dt, t, autoupdate) endif if (self%b(s) /= 0._R_P) then self%buffer = previous(s) - call self%buffer%t_fast(t=t(s)) - call self%buffer%multiply_fast(lhs=self%buffer, rhs=Dt(s) * self%b(s)) + call self%buffer%t_fast(t=self%t(s)) + call self%buffer%multiply_fast(lhs=self%buffer, rhs=Dt * self%b(s)) call U%add_fast(lhs=U, rhs=self%buffer) endif enddo - if (autoupdate_) call self%update_previous(U=U, previous=previous) + if (self%autoupdate) call self%update_previous(U=U, previous=previous, Dt=Dt, t=t, previous_t=self%t) endsubroutine integrate_ub_fast elemental function is_supported(self, scheme) @@ -231,13 +223,14 @@ elemental subroutine destroy(self) if (allocated(self%b)) deallocate(self%b) endsubroutine destroy - subroutine initialize(self, scheme, U, stop_on_fail) + subroutine initialize(self, scheme, autoupdate, U, stop_on_fail) !< Create the actual LMM-SSP integrator: initialize the *a,b* coefficients. !< !< @note If the integrator is initialized with a bad (unsupported) number of required time steps the initialization fails and !< the integrator error status is updated consistently for external-provided errors handling. class(integrator_lmm_ssp), intent(inout) :: self !< Integrator. character(*), intent(in) :: scheme !< Selected scheme. + logical, intent(in), optional :: autoupdate !< Enable cyclic autoupdate of previous time steps. class(integrand_object), intent(in), optional :: U !< Integrand molding prototype. logical, intent(in), optional :: stop_on_fail !< Stop execution if initialization fail. @@ -284,6 +277,7 @@ subroutine initialize(self, scheme, U, stop_on_fail) self%b(4) = 0._R_P self%b(5) = 25._R_P/16._R_P endselect + self%autoupdate = .true. ; if (present(autoupdate)) self%autoupdate = autoupdate self%registers = self%steps if (present(U)) call self%allocate_integrand_members(U=U) else diff --git a/src/lib/foodie_integrator_lmm_ssp_vss.f90 b/src/lib/foodie_integrator_lmm_ssp_vss.f90 index e43592c3..684447b1 100644 --- a/src/lib/foodie_integrator_lmm_ssp_vss.f90 +++ b/src/lib/foodie_integrator_lmm_ssp_vss.f90 @@ -88,29 +88,25 @@ module foodie_integrator_lmm_ssp_vss abstract interface !< Abstract interfaces of [[integrator_lmm_ssp_vss]] methods. - subroutine integrate_interface(self, U, previous, Dt, t, autoupdate) + subroutine integrate_interface(self, U, previous, Dt, t) !< Integrate field with LMM-SSP class scheme. import :: integrand_object, integrator_lmm_ssp_vss, R_P class(integrator_lmm_ssp_vss), intent(inout) :: self !< Integrator. class(integrand_object), intent(inout) :: U !< Field to be integrated. class(integrand_object), intent(inout) :: previous(1:) !< Previous time steps solutions of integrand field. - ! real(R_P), intent(inout) :: Dt(1:) !< Time steps. - real(R_P), intent(in) :: Dt(1:) !< Time steps. - real(R_P), intent(in) :: t(1:) !< Times. - logical, optional, intent(in) :: autoupdate !< Perform cyclic autoupdate of previous time steps. + real(R_P), intent(in) :: Dt !< Time step. + real(R_P), intent(in) :: t !< Time. endsubroutine integrate_interface - subroutine integrate_fast_interface(self, U, previous, buffer, Dt, t, autoupdate) + subroutine integrate_fast_interface(self, U, previous, buffer, Dt, t) !< Integrate field with LMM-SSP class scheme. import :: integrand_object, integrator_lmm_ssp_vss, R_P class(integrator_lmm_ssp_vss), intent(inout) :: self !< Integrator. class(integrand_object), intent(inout) :: U !< Field to be integrated. class(integrand_object), intent(inout) :: previous(1:) !< Previous time steps solutions of integrand field. class(integrand_object), intent(inout) :: buffer !< Temporary buffer for doing fast operation. - ! real(R_P), intent(inout) :: Dt(1:) !< Time steps. - real(R_P), intent(in) :: Dt(1:) !< Time steps. - real(R_P), intent(in) :: t(1:) !< Times. - logical, optional, intent(in) :: autoupdate !< Perform cyclic autoupdate of previous time steps. + real(R_P), intent(in) :: Dt !< Time step. + real(R_P), intent(in) :: t !< Time. endsubroutine integrate_fast_interface endinterface @@ -163,54 +159,46 @@ pure subroutine integr_assign_integr(lhs, rhs) endselect endsubroutine integr_assign_integr - subroutine integrate(self, U, Dt, t, autoupdate) + subroutine integrate(self, U, Dt, t) !< Integrate field with LMM-SSP class scheme. - class(integrator_lmm_ssp_vss), intent(inout) :: self !< Integrator. - class(integrand_object), intent(inout) :: U !< Field to be integrated. - ! real(R_P), intent(inout) :: Dt(1:) !< Time steps. - real(R_P), intent(in) :: Dt(1:) !< Time steps. - real(R_P), intent(in) :: t(1:) !< Times. - logical, optional, intent(in) :: autoupdate !< Perform cyclic autoupdate of previous time steps. - - call self%integrate_(U=U, previous=self%previous, Dt=Dt, t=t, autoupdate=autoupdate) + class(integrator_lmm_ssp_vss), intent(inout) :: self !< Integrator. + class(integrand_object), intent(inout) :: U !< Field to be integrated. + real(R_P), intent(in) :: Dt !< Time step. + real(R_P), intent(in) :: t !< Time. + + call self%integrate_(U=U, previous=self%previous, Dt=Dt, t=t) endsubroutine integrate - subroutine integrate_fast(self, U, Dt, t, autoupdate) + subroutine integrate_fast(self, U, Dt, t) !< Integrate field with LMM-SSP class scheme, fast mode. - class(integrator_lmm_ssp_vss), intent(inout) :: self !< Integrator. - class(integrand_object), intent(inout) :: U !< Field to be integrated. - ! real(R_P), intent(inout) :: Dt(1:) !< Time steps. - real(R_P), intent(in) :: Dt(1:) !< Time steps. - real(R_P), intent(in) :: t(1:) !< Times. - logical, optional, intent(in) :: autoupdate !< Perform cyclic autoupdate of previous time steps. - - call self%integrate_fast_(U=U, previous=self%previous, buffer=self%buffer, Dt=Dt, t=t, autoupdate=autoupdate) + class(integrator_lmm_ssp_vss), intent(inout) :: self !< Integrator. + class(integrand_object), intent(inout) :: U !< Field to be integrated. + real(R_P), intent(in) :: Dt !< Time step. + real(R_P), intent(in) :: t !< Time. + + call self%integrate_fast_(U=U, previous=self%previous, buffer=self%buffer, Dt=Dt, t=t) endsubroutine integrate_fast - subroutine integrate_ub(self, U, previous, Dt, t, autoupdate) + subroutine integrate_ub(self, U, previous, Dt, t) !< Integrate field with LMM-SSP class scheme, unbuffered. class(integrator_lmm_ssp_vss), intent(inout) :: self !< Integrator. class(integrand_object), intent(inout) :: U !< Field to be integrated. class(integrand_object), intent(inout) :: previous(1:) !< Previous time steps solutions of integrand field. - ! real(R_P), intent(inout) :: Dt(1:) !< Time steps. - real(R_P), intent(in) :: Dt(1:) !< Time steps. - real(R_P), intent(in) :: t(1:) !< Times. - logical, optional, intent(in) :: autoupdate !< Perform cyclic autoupdate of previous time steps. + real(R_P), intent(in) :: Dt !< Time step. + real(R_P), intent(in) :: t !< Time. - call self%integrate_(U=U, previous=previous, Dt=Dt, t=t, autoupdate=autoupdate) + call self%integrate_(U=U, previous=previous, Dt=Dt, t=t) endsubroutine integrate_ub - subroutine integrate_ub_fast(self, U, previous, Dt, t, autoupdate) + subroutine integrate_ub_fast(self, U, previous, Dt, t) !< Integrate field with LMM-SSP class scheme, unbuffered, fast mode. class(integrator_lmm_ssp_vss), intent(inout) :: self !< Integrator. class(integrand_object), intent(inout) :: U !< Field to be integrated. class(integrand_object), intent(inout) :: previous(1:) !< Previous time steps solutions of integrand field. - ! real(R_P), intent(inout) :: Dt(1:) !< Time steps. - real(R_P), intent(in) :: Dt(1:) !< Time steps. - real(R_P), intent(in) :: t(1:) !< Times. - logical, optional, intent(in) :: autoupdate !< Perform cyclic autoupdate of previous time steps. + real(R_P), intent(in) :: Dt !< Time step. + real(R_P), intent(in) :: t !< Time. - call self%integrate_fast_(U=U, previous=previous, buffer=self%buffer, Dt=Dt, t=t, autoupdate=autoupdate) + call self%integrate_fast_(U=U, previous=previous, buffer=self%buffer, Dt=Dt, t=t) endsubroutine integrate_ub_fast elemental function is_supported(self, scheme) @@ -247,13 +235,14 @@ elemental subroutine destroy(self) self%integrate_ => integrate_order_2 endsubroutine destroy - subroutine initialize(self, scheme, U, stop_on_fail) + subroutine initialize(self, scheme, autoupdate, U, stop_on_fail) !< Create the actual LMM-SSP-VSS integrator. !< !< @note If the integrator is initialized with a bad (unsupported) number of required time steps the initialization fails and !< the integrator error status is updated consistently for external-provided errors handling. class(integrator_lmm_ssp_vss), intent(inout) :: self !< Integrator. character(*), intent(in) :: scheme !< Selected scheme. + logical, intent(in), optional :: autoupdate !< Enable cyclic autoupdate of previous time steps. class(integrand_object), intent(in), optional :: U !< Integrand molding prototype. logical, intent(in), optional :: stop_on_fail !< Stop execution if initialization fail. @@ -281,6 +270,7 @@ subroutine initialize(self, scheme, U, stop_on_fail) self%integrate_ => integrate_order_3 self%integrate_fast_ => integrate_order_3_fast endselect + self%autoupdate = .true. ; if (present(autoupdate)) self%autoupdate = autoupdate self%registers = self%steps if (present(U)) call self%allocate_integrand_members(U=U) else @@ -291,107 +281,87 @@ subroutine initialize(self, scheme, U, stop_on_fail) endsubroutine initialize ! private methods - subroutine integrate_order_2(self, U, previous, Dt, t, autoupdate) + subroutine integrate_order_2(self, U, previous, Dt, t) !< Integrate field with LMM-SSP-VSS 2nd order class scheme. class(integrator_lmm_ssp_vss), intent(inout) :: self !< Integrator. class(integrand_object), intent(inout) :: U !< Field to be integrated. class(integrand_object), intent(inout) :: previous(1:) !< Previous time steps solutions of integrand field. - ! real(R_P), intent(inout) :: Dt(1:) !< Time steps. - real(R_P), intent(in) :: Dt(1:) !< Time steps. - real(R_P), intent(in) :: t(1:) !< Times. - logical, optional, intent(in) :: autoupdate !< Perform cyclic autoupdate of previous time steps. - logical :: autoupdate_ !< Perform cyclic autoupdate of previous time steps, dummy var. + real(R_P), intent(in) :: Dt !< Time step. + real(R_P), intent(in) :: t !< Time. real(R_P) :: omega_ !< Omega coefficient. real(R_P) :: omega_sq !< Square of omega coefficient. - autoupdate_ = .true. ; if (present(autoupdate)) autoupdate_ = autoupdate - omega_ = omega(Dt=Dt, s=self%steps-1) + omega_ = omega(Dt=self%Dt, s=self%steps-1) omega_sq = omega_ * omega_ U = (previous(1) * (1._R_P / omega_sq)) + (previous(self%steps) * ((omega_sq - 1._R_P) / omega_sq)) + & - (previous(self%steps)%t(t=t(self%steps)) * (Dt(self%steps) * (omega_ + 1._R_P) / omega_)) - ! if (autoupdate_) call self%update_previous(U=U, previous=previous, Dt=Dt) - if (autoupdate_) call self%update_previous(U=U, previous=previous) + (previous(self%steps)%t(t=self%t(self%steps)) * (self%Dt(self%steps) * (omega_ + 1._R_P) / omega_)) + if (self%autoupdate) call self%update_previous(U=U, previous=previous, Dt=Dt, t=t, previous_Dt=self%Dt, previous_t=self%t) endsubroutine integrate_order_2 - subroutine integrate_order_3(self, U, previous, Dt, t, autoupdate) + subroutine integrate_order_3(self, U, previous, Dt, t) !< Integrate field with LMM-SSP-VSS 3rd order class scheme. class(integrator_lmm_ssp_vss), intent(inout) :: self !< Integrator. class(integrand_object), intent(inout) :: U !< Field to be integrated. class(integrand_object), intent(inout) :: previous(1:) !< Previous time steps solutions of integrand field. - ! real(R_P), intent(inout) :: Dt(1:) !< Time steps. - real(R_P), intent(in) :: Dt(1:) !< Time steps. - real(R_P), intent(in) :: t(1:) !< Times. - logical, optional, intent(in) :: autoupdate !< Perform cyclic autoupdate of previous time steps. - logical :: autoupdate_ !< Perform cyclic autoupdate of previous time steps, dummy var. + real(R_P), intent(in) :: Dt !< Time step. + real(R_P), intent(in) :: t !< Time. real(R_P) :: omega_ !< Omega coefficient. - autoupdate_ = .true. ; if (present(autoupdate)) autoupdate_ = autoupdate - omega_= omega(Dt=Dt, s=self%steps-1) + omega_= omega(Dt=self%Dt, s=self%steps-1) U = (previous(1) * ((3._R_P * omega_ + 2._R_P) / omega_ ** 3 )) + & (previous(self%steps) * (((omega_ + 1._R_P) ** 2) * (omega_ - 2._R_P) / omega_ ** 3)) + & - (previous(1)%t(t=t(1)) * (Dt(self%steps) * (omega_ + 1._R_P) / omega_ ** 2)) + & - (previous(self%steps)%t(t=t(self%steps)) * (Dt(self%steps) * (omega_ + 1._R_P) ** 2 / omega_ ** 2)) - ! if (autoupdate_) call self%update_previous(U=U, previous=previous, Dt=Dt) - if (autoupdate_) call self%update_previous(U=U, previous=previous) + (previous(1)%t(t=self%t(1)) * (self%Dt(self%steps) * (omega_ + 1._R_P) / omega_ ** 2)) + & + (previous(self%steps)%t(t=self%t(self%steps)) * (self%Dt(self%steps) * (omega_ + 1._R_P) ** 2 / omega_ ** 2)) + if (self%autoupdate) call self%update_previous(U=U, previous=previous, Dt=Dt, t=t, previous_Dt=self%Dt, previous_t=self%t) endsubroutine integrate_order_3 - subroutine integrate_order_2_fast(self, U, previous, buffer, Dt, t, autoupdate) + subroutine integrate_order_2_fast(self, U, previous, buffer, Dt, t) !< Integrate field with LMM-SSP-VSS 2nd order class scheme. class(integrator_lmm_ssp_vss), intent(inout) :: self !< Integrator. class(integrand_object), intent(inout) :: U !< Field to be integrated. class(integrand_object), intent(inout) :: previous(1:) !< Previous time steps solutions of integrand field. class(integrand_object), intent(inout) :: buffer !< Temporary buffer for doing fast operation. - ! real(R_P), intent(inout) :: Dt(1:) !< Time steps. - real(R_P), intent(in) :: Dt(1:) !< Time steps. - real(R_P), intent(in) :: t(1:) !< Times. - logical, optional, intent(in) :: autoupdate !< Perform cyclic autoupdate of previous time steps. - logical :: autoupdate_ !< Perform cyclic autoupdate of previous time steps, dummy var. + real(R_P), intent(in) :: Dt !< Time step. + real(R_P), intent(in) :: t !< Time. real(R_P) :: omega_ !< Omega coefficient. real(R_P) :: omega_sq !< Square of omega coefficient. - autoupdate_ = .true. ; if (present(autoupdate)) autoupdate_ = autoupdate - omega_ = omega(Dt=Dt, s=self%steps-1) + omega_ = omega(Dt=self%Dt, s=self%steps-1) omega_sq = omega_ * omega_ call U%multiply_fast(lhs=previous(1), rhs=1._R_P / omega_sq) call buffer%multiply_fast(lhs=previous(self%steps), rhs=(omega_sq - 1._R_P) / omega_sq) call U%add_fast(lhs=U, rhs=buffer) buffer = previous(self%steps) - call buffer%t_fast(t=t(self%steps)) - call buffer%multiply_fast(lhs=buffer, rhs=Dt(self%steps) * (omega_ + 1._R_P) / omega_) + call buffer%t_fast(t=self%t(self%steps)) + call buffer%multiply_fast(lhs=buffer, rhs=self%Dt(self%steps) * (omega_ + 1._R_P) / omega_) call U%add_fast(lhs=U, rhs=buffer) - ! if (autoupdate_) call self%update_previous(U=U, previous=previous, Dt=Dt) - if (autoupdate_) call self%update_previous(U=U, previous=previous) + if (self%autoupdate) call self%update_previous(U=U, previous=previous, Dt=Dt, t=t, previous_Dt=self%Dt, previous_t=self%t) endsubroutine integrate_order_2_fast - subroutine integrate_order_3_fast(self, U, previous, buffer, Dt, t, autoupdate) + subroutine integrate_order_3_fast(self, U, previous, buffer, Dt, t) !< Integrate field with LMM-SSP-VSS 3rd order class scheme, fast mode. class(integrator_lmm_ssp_vss), intent(inout) :: self !< Integrator. class(integrand_object), intent(inout) :: U !< Field to be integrated. class(integrand_object), intent(inout) :: previous(1:) !< Previous time steps solutions of integrand field. class(integrand_object), intent(inout) :: buffer !< Temporary buffer for doing fast operation. - ! real(R_P), intent(inout) :: Dt(1:) !< Time steps. - real(R_P), intent(in) :: Dt(1:) !< Time steps. - real(R_P), intent(in) :: t(1:) !< Times. - logical, optional, intent(in) :: autoupdate !< Perform cyclic autoupdate of previous time steps. - logical :: autoupdate_ !< Perform cyclic autoupdate of previous time steps, dummy var. + real(R_P), intent(in) :: Dt !< Time step. + real(R_P), intent(in) :: t !< Time. real(R_P) :: omega_ !< Omega coefficient. - autoupdate_ = .true. ; if (present(autoupdate)) autoupdate_ = autoupdate - omega_= omega(Dt=Dt, s=self%steps-1) + omega_= omega(Dt=self%Dt, s=self%steps-1) call U%multiply_fast(lhs=previous(1), rhs=(3._R_P * omega_ + 2._R_P) / (omega_ ** 3)) call buffer%multiply_fast(lhs=previous(self%steps), rhs=(((omega_ + 1._R_P) ** 2) * (omega_ - 2._R_P) / (omega_ ** 3))) call U%add_fast(lhs=U, rhs=buffer) buffer = previous(1) - call buffer%t_fast(t=t(1)) - call buffer%multiply_fast(lhs=buffer, rhs=Dt(self%steps) * (omega_ + 1._R_P) / (omega_ ** 2)) + call buffer%t_fast(t=self%t(1)) + call buffer%multiply_fast(lhs=buffer, rhs=self%Dt(self%steps) * (omega_ + 1._R_P) / (omega_ ** 2)) call U%add_fast(lhs=U, rhs=buffer) buffer = previous(self%steps) - call buffer%t_fast(t=t(self%steps)) - call buffer%multiply_fast(lhs=buffer, rhs=(Dt(self%steps) * (omega_ + 1._R_P) ** 2 / (omega_ ** 2))) + call buffer%t_fast(t=self%t(self%steps)) + call buffer%multiply_fast(lhs=buffer, rhs=(self%Dt(self%steps) * (omega_ + 1._R_P) ** 2 / (omega_ ** 2))) call U%add_fast(lhs=U, rhs=buffer) - ! if (autoupdate_) call self%update_previous(U=U, previous=previous, Dt=Dt) - if (autoupdate_) call self%update_previous(U=U, previous=previous) + if (self%autoupdate) call self%update_previous(U=U, previous=previous, Dt=Dt, t=t, previous_Dt=self%Dt, previous_t=self%t) endsubroutine integrate_order_3_fast ! private non TBP diff --git a/src/lib/foodie_integrator_multistep_explicit_object.f90 b/src/lib/foodie_integrator_multistep_explicit_object.f90 index eb9aa84a..d11bea4c 100644 --- a/src/lib/foodie_integrator_multistep_explicit_object.f90 +++ b/src/lib/foodie_integrator_multistep_explicit_object.f90 @@ -16,6 +16,9 @@ module foodie_integrator_multistep_explicit_object !< Abstract type of FOODIE ODE integrators of the multistep family. integer(I_P) :: registers !< Number of registers used for stages. integer(I_P) :: steps !< Number of time steps. + logical :: autoupdate !< Perform cyclic autoupdate of previous time steps buffers. + real(R_P), allocatable :: Dt(:) !< Previous time steps. + real(R_P), allocatable :: t(:) !< Previous times. class(integrand_object), allocatable :: previous(:) !< Previous steps. class(integrand_object), allocatable :: buffer !< Buffer used for fast integration. contains @@ -34,55 +37,51 @@ module foodie_integrator_multistep_explicit_object procedure, pass(self) :: allocate_integrand_members !< Allocate integrand members. procedure, pass(lhs) :: assign_multistep !< Assign members of [[integrator_multistep_explicit_object]] and parents. procedure, pass(self) :: destroy_multistep !< Destroy the integrator. - procedure, pass(self) :: update_previous !< Cyclic update previous time steps. + procedure, nopass :: update_previous !< Cyclic update previous time steps. endtype integrator_multistep_explicit_object abstract interface !< Abstract interfaces of deferred methods of [[integrator_multistep_explicit_object]]. - subroutine integrate_interface(self, U, Dt, t, autoupdate) + subroutine integrate_interface(self, U, Dt, t) !< Integrate integrand field. !< !< @note This method uses integrand previous-steps-buffer stored inside integrator. import :: integrand_object, integrator_multistep_explicit_object, R_P - class(integrator_multistep_explicit_object), intent(inout) :: self !< Integrator. - class(integrand_object), intent(inout) :: U !< Integrand. - real(R_P), intent(in) :: Dt(1:) !< Time steps. - real(R_P), intent(in) :: t(1:) !< Times. - logical, optional, intent(in) :: autoupdate !< Perform cyclic autoupdate of previous time steps. + class(integrator_multistep_explicit_object), intent(inout) :: self !< Integrator. + class(integrand_object), intent(inout) :: U !< Integrand. + real(R_P), intent(in) :: Dt !< Time step. + real(R_P), intent(in) :: t !< Time. endsubroutine integrate_interface - subroutine integrate_fast_interface(self, U, Dt, t, autoupdate) + subroutine integrate_fast_interface(self, U, Dt, t) !< Integrate integrand field, fast mode. !< !< @note This method uses integrand previous-steps-buffer stored inside integrator. import :: integrand_object, integrator_multistep_explicit_object, R_P - class(integrator_multistep_explicit_object), intent(inout) :: self !< Integrator. - class(integrand_object), intent(inout) :: U !< Field to be integrated. - real(R_P), intent(in) :: Dt(1:) !< Time steps. - real(R_P), intent(in) :: t(1:) !< Times. - logical, optional, intent(in) :: autoupdate !< Perform cyclic autoupdate of previous time steps. + class(integrator_multistep_explicit_object), intent(inout) :: self !< Integrator. + class(integrand_object), intent(inout) :: U !< Field to be integrated. + real(R_P), intent(in) :: Dt !< Time steps. + real(R_P), intent(in) :: t !< Times. endsubroutine integrate_fast_interface - subroutine integrate_ub_interface(self, U, previous, Dt, t, autoupdate) + subroutine integrate_ub_interface(self, U, previous, Dt, t) !< Integrate integrand field, unbuffered. import :: integrand_object, integrator_multistep_explicit_object, R_P class(integrator_multistep_explicit_object), intent(inout) :: self !< Integrator. class(integrand_object), intent(inout) :: U !< Integrand. class(integrand_object), intent(inout) :: previous(1:) !< Integrand. - real(R_P), intent(in) :: Dt(1:) !< Time steps. - real(R_P), intent(in) :: t(1:) !< Times. - logical, optional, intent(in) :: autoupdate !< Perform cyclic autoupdate of previous time steps. + real(R_P), intent(in) :: Dt !< Time steps. + real(R_P), intent(in) :: t !< Times. endsubroutine integrate_ub_interface - subroutine integrate_ub_fast_interface(self, U, previous, Dt, t, autoupdate) + subroutine integrate_ub_fast_interface(self, U, previous, Dt, t) !< Integrate integrand field, unbuffered, fast mode. import :: integrand_object, integrator_multistep_explicit_object, R_P class(integrator_multistep_explicit_object), intent(inout) :: self !< Integrator. class(integrand_object), intent(inout) :: U !< Field to be integrated. class(integrand_object), intent(inout) :: previous(1:) !< Integrand. - real(R_P), intent(in) :: Dt(1:) !< Time steps. - real(R_P), intent(in) :: t(1:) !< Times. - logical, optional, intent(in) :: autoupdate !< Perform cyclic autoupdate of previous time steps. + real(R_P), intent(in) :: Dt !< Time steps. + real(R_P), intent(in) :: t !< Times. endsubroutine integrate_ub_fast_interface endinterface @@ -130,6 +129,10 @@ pure subroutine allocate_integrand_members(self, U) integer(I_P) :: s !< Counter. if (self%is_multistep() .and. self%registers > 0) then + if (allocated(self%Dt)) deallocate(self%Dt) + allocate(self%Dt(1:self%registers)) ; self%Dt = 0._R_P + if (allocated(self%t)) deallocate(self%t) + allocate(self%t(1:self%registers)) ; self%t = 0._R_P if (allocated(self%previous)) deallocate(self%previous) allocate(self%previous(1:self%registers), mold=U) do s=1, self%registers @@ -154,6 +157,11 @@ pure subroutine assign_multistep(lhs, rhs) class is (integrator_multistep_explicit_object) lhs%registers = rhs%registers lhs%steps = rhs%steps + lhs%autoupdate = rhs%autoupdate + if (allocated(lhs%Dt)) deallocate(lhs%Dt) + if (allocated(rhs%Dt)) lhs%Dt = rhs%Dt + if (allocated(lhs%t)) deallocate(lhs%t) + if (allocated(rhs%t)) lhs%t = rhs%t if (allocated(lhs%previous)) deallocate(lhs%previous) if (allocated(rhs%previous)) then allocate(lhs%previous(1:lhs%registers), mold=rhs%previous) @@ -176,21 +184,32 @@ elemental subroutine destroy_multistep(self) call self%destroy_abstract self%registers = 0 self%steps = 0 + self%autoupdate = .false. + if (allocated(self%Dt)) deallocate(self%Dt) + if (allocated(self%t)) deallocate(self%t) if (allocated(self%previous)) deallocate(self%previous) if (allocated(self%buffer)) deallocate(self%buffer) endsubroutine destroy_multistep - subroutine update_previous(self, U, previous) + subroutine update_previous(U, previous, Dt, t, previous_Dt, previous_t) !< Cyclic update previous time steps. - class(integrator_multistep_explicit_object), intent(in) :: self !< Integrator. - class(integrand_object), intent(in) :: U !< Field to be integrated. - class(integrand_object), intent(inout) :: previous(1:) !< Previous time steps solutions of integrand field. - integer(I_P) :: s !< Steps counter. - - do s=1, self%steps - 1 + class(integrand_object), intent(in) :: U !< Field to be integrated. + class(integrand_object), intent(inout) :: previous(1:) !< Previous time steps of integrand. + real(R_P), intent(in), optional :: Dt !< Time step. + real(R_P), intent(in), optional :: t !< Time. + real(R_P), intent(inout), optional :: previous_Dt(1:) !< Time step. + real(R_P), intent(inout), optional :: previous_t(1:) !< Time. + integer(I_P) :: last_step !< Last step. + integer(I_P) :: s !< Steps counter. + + last_step = size(previous, dim=1) + do s=1, last_step - 1 previous(s) = previous(s + 1) - ! Dt(s) = Dt(s + 1) + if (present(previous_Dt)) previous_Dt(s) = previous_Dt(s + 1) + if (present(previous_t)) previous_t(s) = previous_t(s + 1) enddo - previous(self%steps) = U + previous(last_step) = U + if (present(previous_Dt)) previous_Dt(last_step) = Dt + if (present(previous_t)) previous_t(last_step) = t + Dt endsubroutine update_previous endmodule foodie_integrator_multistep_explicit_object diff --git a/src/lib/foodie_integrator_multistep_implicit_object.f90 b/src/lib/foodie_integrator_multistep_implicit_object.f90 index e10a2304..60e997c3 100644 --- a/src/lib/foodie_integrator_multistep_implicit_object.f90 +++ b/src/lib/foodie_integrator_multistep_implicit_object.f90 @@ -16,6 +16,10 @@ module foodie_integrator_multistep_implicit_object !< Abstract type of FOODIE ODE integrators of the multistep-implicit family. integer(I_P) :: registers !< Number of registers used for stages. integer(I_P) :: steps !< Number of time steps. + logical :: autoupdate !< Perform cyclic autoupdate of previous time steps buffers. + integer(I_P) :: iterations !< Implicit iterations. + real(R_P), allocatable :: Dt(:) !< Previous time steps. + real(R_P), allocatable :: t(:) !< Previous times. class(integrand_object), allocatable :: previous(:) !< Previous steps. class(integrand_object), allocatable :: buffer !< Buffer used for fast integration. contains @@ -32,60 +36,53 @@ module foodie_integrator_multistep_implicit_object procedure, pass(self) :: steps_number !< Return number of steps used. ! public methods procedure, pass(self) :: allocate_integrand_members !< Allocate integrand members. + procedure, pass(lhs) :: assign_multistep !< Assign members of [[integrator_multistep_implicit_object]] and parents. procedure, pass(self) :: destroy_multistep !< Destroy the integrator. - procedure, pass(self) :: update_previous !< Cyclic update previous time steps. + procedure, nopass :: update_previous !< Cyclic update previous time steps. endtype integrator_multistep_implicit_object abstract interface !< Abstract interfaces of deferred methods of [[integrator_multistep_implicit_object]]. - subroutine integrate_interface(self, U, Dt, t, iterations, autoupdate) + subroutine integrate_interface(self, U, Dt, t) !< Integrate integrand field. !< !< @note This method uses integrand previous-steps-buffer stored inside integrator. - import :: integrand_object, integrator_multistep_implicit_object, I_P, R_P - class(integrator_multistep_implicit_object), intent(inout) :: self !< Integrator. - class(integrand_object), intent(inout) :: U !< Integrand. - real(R_P), intent(in) :: Dt(1:) !< Time steps. - real(R_P), intent(in) :: t(1:) !< Times. - integer(I_P), optional, intent(in) :: iterations !< Fixed point iterations. - logical, optional, intent(in) :: autoupdate !< Perform cyclic autoupdate of previous time steps. + import :: integrand_object, integrator_multistep_implicit_object, R_P + class(integrator_multistep_implicit_object), intent(inout) :: self !< Integrator. + class(integrand_object), intent(inout) :: U !< Integrand. + real(R_P), intent(in) :: Dt !< Time steps. + real(R_P), intent(in) :: t !< Times. endsubroutine integrate_interface - subroutine integrate_fast_interface(self, U, Dt, t, iterations, autoupdate) + subroutine integrate_fast_interface(self, U, Dt, t) !< Integrate integrand field, fast mode. !< !< @note This method uses integrand previous-steps-buffer stored inside integrator. - import :: integrand_object, integrator_multistep_implicit_object, I_P, R_P - class(integrator_multistep_implicit_object), intent(inout) :: self !< Integrator. - class(integrand_object), intent(inout) :: U !< Field to be integrated. - real(R_P), intent(in) :: Dt(1:) !< Time steps. - real(R_P), intent(in) :: t(1:) !< Times. - integer(I_P), optional, intent(in) :: iterations !< Fixed point iterations. - logical, optional, intent(in) :: autoupdate !< Perform cyclic autoupdate of previous time steps. + import :: integrand_object, integrator_multistep_implicit_object, R_P + class(integrator_multistep_implicit_object), intent(inout) :: self !< Integrator. + class(integrand_object), intent(inout) :: U !< Field to be integrated. + real(R_P), intent(in) :: Dt !< Time steps. + real(R_P), intent(in) :: t !< Times. endsubroutine integrate_fast_interface - subroutine integrate_ub_interface(self, U, previous, Dt, t, iterations, autoupdate) + subroutine integrate_ub_interface(self, U, previous, Dt, t) !< Integrate integrand field, unbuffered. - import :: integrand_object, integrator_multistep_implicit_object, I_P, R_P + import :: integrand_object, integrator_multistep_implicit_object, R_P class(integrator_multistep_implicit_object), intent(inout) :: self !< Integrator. class(integrand_object), intent(inout) :: U !< Integrand. class(integrand_object), intent(inout) :: previous(1:) !< Integrand. - real(R_P), intent(in) :: Dt(1:) !< Time steps. - real(R_P), intent(in) :: t(1:) !< Times. - integer(I_P), optional, intent(in) :: iterations !< Fixed point iterations. - logical, optional, intent(in) :: autoupdate !< Perform cyclic autoupdate of previous time steps. + real(R_P), intent(in) :: Dt !< Time steps. + real(R_P), intent(in) :: t !< Times. endsubroutine integrate_ub_interface - subroutine integrate_ub_fast_interface(self, U, previous, Dt, t, iterations, autoupdate) + subroutine integrate_ub_fast_interface(self, U, previous, Dt, t) !< Integrate integrand field, unbuffered, fast mode. - import :: integrand_object, integrator_multistep_implicit_object, I_P, R_P + import :: integrand_object, integrator_multistep_implicit_object, R_P class(integrator_multistep_implicit_object), intent(inout) :: self !< Integrator. class(integrand_object), intent(inout) :: U !< Field to be integrated. class(integrand_object), intent(inout) :: previous(1:) !< Integrand. - real(R_P), intent(in) :: Dt(1:) !< Time steps. - real(R_P), intent(in) :: t(1:) !< Times. - integer(I_P), optional, intent(in) :: iterations !< Fixed point iterations. - logical, optional, intent(in) :: autoupdate !< Perform cyclic autoupdate of previous time steps. + real(R_P), intent(in) :: Dt !< Time steps. + real(R_P), intent(in) :: t !< Times. endsubroutine integrate_ub_fast_interface endinterface @@ -133,6 +130,10 @@ pure subroutine allocate_integrand_members(self, U) integer(I_P) :: s !< Counter. if (self%is_multistep() .and. self%registers > 0) then + if (allocated(self%Dt)) deallocate(self%Dt) + allocate(self%Dt(1:self%registers)) ; self%Dt = 0._R_P + if (allocated(self%t)) deallocate(self%t) + allocate(self%t(1:self%registers)) ; self%t = 0._R_P if (allocated(self%previous)) deallocate(self%previous) allocate(self%previous(1:self%registers), mold=U) do s=1, self%registers @@ -146,6 +147,38 @@ pure subroutine allocate_integrand_members(self, U) endif endsubroutine allocate_integrand_members + pure subroutine assign_multistep(lhs, rhs) + !< Assign members of [[integrator_multistep_implicit_object]] and parents. + class(integrator_multistep_implicit_object), intent(inout) :: lhs !< Left hand side. + class(integrator_object), intent(in) :: rhs !< Right hand side. + integer(I_P) :: s !< Counter. + + call lhs%assign_abstract(rhs=rhs) + select type(rhs) + class is (integrator_multistep_implicit_object) + lhs%registers = rhs%registers + lhs%steps = rhs%steps + lhs%autoupdate = rhs%autoupdate + lhs%iterations = rhs%iterations + if (allocated(lhs%Dt)) deallocate(lhs%Dt) + if (allocated(rhs%Dt)) lhs%Dt = rhs%Dt + if (allocated(lhs%t)) deallocate(lhs%t) + if (allocated(rhs%t)) lhs%t = rhs%t + if (allocated(lhs%previous)) deallocate(lhs%previous) + if (allocated(rhs%previous)) then + allocate(lhs%previous(1:lhs%registers), mold=rhs%previous) + do s=1, lhs%registers + lhs%previous(s) = rhs%previous(s) + enddo + endif + if (allocated(lhs%buffer)) deallocate(lhs%buffer) + if (allocated(rhs%buffer)) then + allocate(lhs%buffer, mold=rhs%buffer) + lhs%buffer = rhs%buffer + endif + endselect + endsubroutine assign_multistep + elemental subroutine destroy_multistep(self) !< Destroy the integrator. class(integrator_multistep_implicit_object), intent(inout) :: self !< Integrator. @@ -153,32 +186,33 @@ elemental subroutine destroy_multistep(self) call self%destroy_abstract self%registers = 0 self%steps = -1 + self%autoupdate = .false. + self%iterations = 0 + if (allocated(self%Dt)) deallocate(self%Dt) + if (allocated(self%t)) deallocate(self%t) if (allocated(self%previous)) deallocate(self%previous) if (allocated(self%buffer)) deallocate(self%buffer) endsubroutine destroy_multistep - subroutine update_previous(self, U, previous, is_like_explicit) + subroutine update_previous(U, previous, Dt, t, previous_Dt, previous_t) !< Cyclic update previous time steps. - class(integrator_multistep_implicit_object), intent(in) :: self !< Integrator. - class(integrand_object), intent(in) :: U !< Field to be integrated. - class(integrand_object), intent(inout) :: previous(1:) !< Previous time steps solutions of integrand. - logical, optional, intent(in) :: is_like_explicit !< Use explicit-like update. - logical :: is_like_explicit_ !< Use explicit-like update, local variable. - integer(I_P) :: s !< Steps counter. - - is_like_explicit_ = .false. ; if (present(is_like_explicit)) is_like_explicit_ = is_like_explicit - if (is_like_explicit_) then - do s=1, self%steps - 1 - previous(s) = previous(s + 1) - enddo - previous(self%steps) = U - else - if (self%steps > 0) then - do s=0, self%steps - 2 - previous(s + 1) = previous(s + 2) - enddo - previous(self%steps) = U - endif - endif + class(integrand_object), intent(in) :: U !< Field to be integrated. + class(integrand_object), intent(inout) :: previous(1:) !< Previous time steps solutions of integrand. + real(R_P), intent(in), optional :: Dt !< Time step. + real(R_P), intent(in), optional :: t !< Time. + real(R_P), intent(inout), optional :: previous_Dt(1:) !< Time step. + real(R_P), intent(inout), optional :: previous_t(1:) !< Time. + integer(I_P) :: last_step !< Last step. + integer(I_P) :: s !< Steps counter. + + last_step = size(previous, dim=1) + do s=1, last_step - 1 + previous(s) = previous(s + 1) + if (present(previous_Dt)) previous_Dt(s) = previous_Dt(s + 1) + if (present(previous_t)) previous_t(s) = previous_t(s + 1) + enddo + previous(last_step) = U + if (present(previous_Dt)) previous_Dt(last_step) = Dt + if (present(previous_t)) previous_t(last_step) = t + Dt endsubroutine update_previous endmodule foodie_integrator_multistep_implicit_object diff --git a/src/tests/tester/foodie_tester.f90 b/src/tests/tester/foodie_tester.f90 index a7b72d8e..c0f92d69 100644 --- a/src/tests/tester/foodie_tester.f90 +++ b/src/tests/tester/foodie_tester.f90 @@ -263,7 +263,8 @@ subroutine integrate(scheme, integrand_0, Dt, final_time, iterations, stages, is allocate(integrand, mold=integrand_0) ; integrand = integrand_0 - call foodie_integrator_factory(scheme=scheme, integrator=integrator, stages=stages, tolerance=1e2_R_P, U=integrand_0) + call foodie_integrator_factory(scheme=scheme, integrator=integrator, stages=stages, & + tolerance=1e2_R_P, iterations=iterations, autoupdate=.true., U=integrand_0) if (is_fast) call check_scheme_has_fast_mode(scheme=trim(adjustl(scheme)), integrator=integrator) if (integrator%is_multistep()) then @@ -310,11 +311,13 @@ subroutine integrate(scheme, integrand_0, Dt, final_time, iterations, stages, is call integrator_start%integrate(U=integrand, Dt=Dt, t=time(step)) integrator%previous(step) = integrand time(step) = time(step-1) + Dt + integrator%Dt(step) = Dt + integrator%t(step) = time(step) else if (is_fast) then - call integrator%integrate_fast(U=integrand, Dt=Dts, t=time) + call integrator%integrate_fast(U=integrand, Dt=Dt, t=time(step_offset)) else - call integrator%integrate(U=integrand, Dt=Dts, t=time) + call integrator%integrate(U=integrand, Dt=Dt, t=time(step_offset)) endif call update_previous_times endif @@ -329,19 +332,13 @@ subroutine integrate(scheme, integrand_0, Dt, final_time, iterations, stages, is call integrator_start%integrate(U=integrand, Dt=Dt, t=time(step)) integrator%previous(step) = integrand time(step) = time(step-1) + Dt + integrator%Dt(step) = Dt + integrator%t(step) = time(step) else if (is_fast) then - if (iterations>1) then - call integrator%integrate_fast(U=integrand, Dt=Dts, t=time, iterations=iterations) - else - call integrator%integrate_fast(U=integrand, Dt=Dts, t=time) - endif + call integrator%integrate_fast(U=integrand, Dt=Dt, t=time(step_offset)) else - if (iterations>1) then - call integrator%integrate(U=integrand, Dt=Dts, t=time, iterations=iterations) - else - call integrator%integrate(U=integrand, Dt=Dts, t=time) - endif + call integrator%integrate(U=integrand, Dt=Dt, t=time(step_offset)) endif call update_previous_times endif From e893323aa9bb2a71250cb5ce6b901e155e2ad85e Mon Sep 17 00:00:00 2001 From: Stefano Zaghi Date: Fri, 26 May 2017 11:46:21 +0200 Subject: [PATCH 19/25] clean integrator objects hierarchy --- src/lib/foodie.f90 | 10 +- src/lib/foodie_integrator_adams_bashforth.f90 | 4 +- ...die_integrator_adams_bashforth_moulton.f90 | 4 +- src/lib/foodie_integrator_adams_moulton.f90 | 4 +- ...rator_backward_differentiation_formula.f90 | 4 +- src/lib/foodie_integrator_euler_explicit.f90 | 4 +- src/lib/foodie_integrator_leapfrog.f90 | 4 +- src/lib/foodie_integrator_lmm_ssp.f90 | 4 +- src/lib/foodie_integrator_lmm_ssp_vss.f90 | 4 +- ...> foodie_integrator_multistage_object.f90} | 76 +++---- ...e_integrator_multistep_explicit_object.f90 | 215 ------------------ ...=> foodie_integrator_multistep_object.f90} | 96 ++++---- ...foodie_integrator_runge_kutta_embedded.f90 | 4 +- ...die_integrator_runge_kutta_low_storage.f90 | 4 +- .../foodie_integrator_runge_kutta_lssp.f90 | 4 +- src/lib/foodie_integrator_runge_kutta_ssp.f90 | 4 +- src/tests/tester/foodie_tester.f90 | 66 ++---- 17 files changed, 136 insertions(+), 375 deletions(-) rename src/lib/{foodie_integrator_multistage_explicit_object.f90 => foodie_integrator_multistage_object.f90} (57%) delete mode 100644 src/lib/foodie_integrator_multistep_explicit_object.f90 rename src/lib/{foodie_integrator_multistep_implicit_object.f90 => foodie_integrator_multistep_object.f90} (65%) diff --git a/src/lib/foodie.f90 b/src/lib/foodie.f90 index bcfae015..6c02e5fe 100644 --- a/src/lib/foodie.f90 +++ b/src/lib/foodie.f90 @@ -74,9 +74,8 @@ module foodie use foodie_integrator_lmm_ssp, only : integrator_lmm_ssp use foodie_integrator_lmm_ssp_vss, only : integrator_lmm_ssp_vss use foodie_integrator_ms_runge_kutta_ssp, only : integrator_ms_runge_kutta_ssp -use foodie_integrator_multistage_explicit_object, only : integrator_multistage_explicit_object -use foodie_integrator_multistep_explicit_object, only : integrator_multistep_explicit_object -use foodie_integrator_multistep_implicit_object, only : integrator_multistep_implicit_object +use foodie_integrator_multistage_object, only : integrator_multistage_object +use foodie_integrator_multistep_object, only : integrator_multistep_object use foodie_integrator_runge_kutta_emd, only : integrator_runge_kutta_emd use foodie_integrator_runge_kutta_low_storage, only : integrator_runge_kutta_ls use foodie_integrator_runge_kutta_lssp, only : integrator_runge_kutta_lssp @@ -95,9 +94,8 @@ module foodie ! abstract objects public :: integrand_object public :: integrator_object -public :: integrator_multistage_explicit_object -public :: integrator_multistep_explicit_object -public :: integrator_multistep_implicit_object +public :: integrator_multistage_object +public :: integrator_multistep_object ! concrete objects public :: integrator_adams_bashforth public :: integrator_adams_bashforth_moulton diff --git a/src/lib/foodie_integrator_adams_bashforth.f90 b/src/lib/foodie_integrator_adams_bashforth.f90 index d28397d0..1a665521 100644 --- a/src/lib/foodie_integrator_adams_bashforth.f90 +++ b/src/lib/foodie_integrator_adams_bashforth.f90 @@ -28,7 +28,7 @@ module foodie_integrator_adams_bashforth use foodie_error_codes, only : ERROR_UNSUPPORTED_SCHEME use foodie_integrand_object, only : integrand_object -use foodie_integrator_multistep_explicit_object, only : integrator_multistep_explicit_object +use foodie_integrator_multistep_object, only : integrator_multistep_object use foodie_integrator_object, only : integrator_object use penf, only : I_P, R_P @@ -56,7 +56,7 @@ module foodie_integrator_adams_bashforth logical, parameter :: has_fast_mode_=.true. !< Flag to check if integrator provides *fast mode* integrate. -type, extends(integrator_multistep_explicit_object) :: integrator_adams_bashforth +type, extends(integrator_multistep_object) :: integrator_adams_bashforth !< FOODIE integrator: provide an explicit class of Adams-Bashforth multi-step schemes, from 1st to 16th order accurate. !< !< @note The integrator must be created or initialized (initialize the *b* coefficients) before used. diff --git a/src/lib/foodie_integrator_adams_bashforth_moulton.f90 b/src/lib/foodie_integrator_adams_bashforth_moulton.f90 index 9f01df77..ede0b2e0 100644 --- a/src/lib/foodie_integrator_adams_bashforth_moulton.f90 +++ b/src/lib/foodie_integrator_adams_bashforth_moulton.f90 @@ -80,7 +80,7 @@ module foodie_integrator_adams_bashforth_moulton use foodie_integrand_object, only : integrand_object use foodie_integrator_adams_bashforth, only : integrator_adams_bashforth use foodie_integrator_adams_moulton, only : integrator_adams_moulton -use foodie_integrator_multistep_implicit_object, only : integrator_multistep_implicit_object +use foodie_integrator_multistep_object, only : integrator_multistep_object use foodie_integrator_object, only : integrator_object use penf, only : I_P, R_P @@ -108,7 +108,7 @@ module foodie_integrator_adams_bashforth_moulton logical, parameter :: has_fast_mode_=.true. !< Flag to check if integrator provides *fast mode* integrate. -type, extends(integrator_multistep_implicit_object) :: integrator_adams_bashforth_moulton +type, extends(integrator_multistep_object) :: integrator_adams_bashforth_moulton !< FOODIE integrator: provide an explicit class of Adams-Bashforth-Moulton multi-step schemes, from 1st to 4rd order accurate. !< !< @note The integrator must be created or initialized (predictor and corrector schemes selection) before used. diff --git a/src/lib/foodie_integrator_adams_moulton.f90 b/src/lib/foodie_integrator_adams_moulton.f90 index 8f87f9d7..e34d8754 100644 --- a/src/lib/foodie_integrator_adams_moulton.f90 +++ b/src/lib/foodie_integrator_adams_moulton.f90 @@ -29,7 +29,7 @@ module foodie_integrator_adams_moulton use foodie_error_codes, only : ERROR_UNSUPPORTED_SCHEME use foodie_integrand_object, only : integrand_object -use foodie_integrator_multistep_implicit_object, only : integrator_multistep_implicit_object +use foodie_integrator_multistep_object, only : integrator_multistep_object use foodie_integrator_object, only : integrator_object use penf, only : I_P, R_P @@ -57,7 +57,7 @@ module foodie_integrator_adams_moulton logical, parameter :: has_fast_mode_=.true. !< Flag to check if integrator provides *fast mode* integrate. -type, extends(integrator_multistep_implicit_object) :: integrator_adams_moulton +type, extends(integrator_multistep_object) :: integrator_adams_moulton !< FOODIE integrator: provide an explicit class of Adams-Moulton multi-step schemes, from 1st to 16th order accurate. !< !< @note The integrator must be created or initialized (initialize the *b* coefficients) before used. diff --git a/src/lib/foodie_integrator_backward_differentiation_formula.f90 b/src/lib/foodie_integrator_backward_differentiation_formula.f90 index 025e9c67..c226a2b9 100644 --- a/src/lib/foodie_integrator_backward_differentiation_formula.f90 +++ b/src/lib/foodie_integrator_backward_differentiation_formula.f90 @@ -35,7 +35,7 @@ module foodie_integrator_backward_differentiation_formula use foodie_error_codes, only : ERROR_UNSUPPORTED_SCHEME use foodie_integrand_object, only : integrand_object -use foodie_integrator_multistep_implicit_object, only : integrator_multistep_implicit_object +use foodie_integrator_multistep_object, only : integrator_multistep_object use foodie_integrator_object, only : integrator_object use penf, only : I_P, R_P @@ -53,7 +53,7 @@ module foodie_integrator_backward_differentiation_formula logical, parameter :: has_fast_mode_=.true. !< Flag to check if integrator provides *fast mode* integrate. -type, extends(integrator_multistep_implicit_object) :: integrator_back_df +type, extends(integrator_multistep_object) :: integrator_back_df !< FOODIE integrator: provide an implicit class of Backward-Differentiation-Formula multi-step schemes, from 1st to 6th order !< accurate. !< diff --git a/src/lib/foodie_integrator_euler_explicit.f90 b/src/lib/foodie_integrator_euler_explicit.f90 index d7c5fe86..5dafdb61 100644 --- a/src/lib/foodie_integrator_euler_explicit.f90 +++ b/src/lib/foodie_integrator_euler_explicit.f90 @@ -16,7 +16,7 @@ module foodie_integrator_euler_explicit use foodie_error_codes, only : ERROR_UNSUPPORTED_SCHEME use foodie_integrand_object, only : integrand_object -use foodie_integrator_multistage_explicit_object, only : integrator_multistage_explicit_object +use foodie_integrator_multistage_object, only : integrator_multistage_object use foodie_integrator_object, only : integrator_object use penf, only : I_P, R_P @@ -29,7 +29,7 @@ module foodie_integrator_euler_explicit logical, parameter :: has_fast_mode_=.true. !< Flag to check if integrator provides *fast mode* integrate. -type, extends(integrator_multistage_explicit_object) :: integrator_euler_explicit +type, extends(integrator_multistage_object) :: integrator_euler_explicit !< FOODIE integrator: provide explicit Euler scheme, it being 1st order accurate. contains ! deferred methods diff --git a/src/lib/foodie_integrator_leapfrog.f90 b/src/lib/foodie_integrator_leapfrog.f90 index b5544ed3..69a89436 100644 --- a/src/lib/foodie_integrator_leapfrog.f90 +++ b/src/lib/foodie_integrator_leapfrog.f90 @@ -38,7 +38,7 @@ module foodie_integrator_leapfrog use foodie_error_codes, only : ERROR_UNSUPPORTED_SCHEME use foodie_integrand_object, only : integrand_object -use foodie_integrator_multistep_explicit_object, only : integrator_multistep_explicit_object +use foodie_integrator_multistep_object, only : integrator_multistep_object use foodie_integrator_object, only : integrator_object use penf, only : I_P, R_P @@ -52,7 +52,7 @@ module foodie_integrator_leapfrog logical, parameter :: has_fast_mode_=.true. !< Flag to check if integrator provides *fast mode* integrate. -type, extends(integrator_multistep_explicit_object) :: integrator_leapfrog +type, extends(integrator_multistep_object) :: integrator_leapfrog !< FOODIE integrator: provide an explicit class of leapfrog multi-step schemes, 2nd order accurate. !< !< @note The integrator must be initialized before used. diff --git a/src/lib/foodie_integrator_lmm_ssp.f90 b/src/lib/foodie_integrator_lmm_ssp.f90 index 606d9118..1063d5d4 100644 --- a/src/lib/foodie_integrator_lmm_ssp.f90 +++ b/src/lib/foodie_integrator_lmm_ssp.f90 @@ -28,7 +28,7 @@ module foodie_integrator_lmm_ssp use foodie_error_codes, only : ERROR_UNSUPPORTED_SCHEME use foodie_integrand_object, only : integrand_object -use foodie_integrator_multistep_explicit_object, only : integrator_multistep_explicit_object +use foodie_integrator_multistep_object, only : integrator_multistep_object use foodie_integrator_object, only : integrator_object use penf, only : I_P, R_P @@ -43,7 +43,7 @@ module foodie_integrator_lmm_ssp logical, parameter :: has_fast_mode_=.true. !< Flag to check if integrator provides *fast mode* integrate. -type, extends(integrator_multistep_explicit_object) :: integrator_lmm_ssp +type, extends(integrator_multistep_object) :: integrator_lmm_ssp !< FOODIE integrator: provide an explicit class of Linear Multi-step Methods (LLM) with Strong Stability Preserving property, !< from 2nd to 3rd order accurate. !< diff --git a/src/lib/foodie_integrator_lmm_ssp_vss.f90 b/src/lib/foodie_integrator_lmm_ssp_vss.f90 index 684447b1..d09abe7d 100644 --- a/src/lib/foodie_integrator_lmm_ssp_vss.f90 +++ b/src/lib/foodie_integrator_lmm_ssp_vss.f90 @@ -39,7 +39,7 @@ module foodie_integrator_lmm_ssp_vss use foodie_error_codes, only : ERROR_UNSUPPORTED_SCHEME use foodie_integrand_object, only : integrand_object -use foodie_integrator_multistep_explicit_object, only : integrator_multistep_explicit_object +use foodie_integrator_multistep_object, only : integrator_multistep_object use foodie_integrator_object, only : integrator_object use penf, only : I_P, R_P @@ -56,7 +56,7 @@ module foodie_integrator_lmm_ssp_vss logical, parameter :: has_fast_mode_=.true. !< Flag to check if integrator provides *fast mode* integrate. -type, extends(integrator_multistep_explicit_object) :: integrator_lmm_ssp_vss +type, extends(integrator_multistep_object) :: integrator_lmm_ssp_vss !< FOODIE integrator: provide an explicit class of Linear Multi-step Methods (LLM) with Strong Stability Preserving property and !< variable stepsize (VSS), from 2nd to 3rd order accurate. !< diff --git a/src/lib/foodie_integrator_multistage_explicit_object.f90 b/src/lib/foodie_integrator_multistage_object.f90 similarity index 57% rename from src/lib/foodie_integrator_multistage_explicit_object.f90 rename to src/lib/foodie_integrator_multistage_object.f90 index a44d6582..f633f8ad 100644 --- a/src/lib/foodie_integrator_multistage_explicit_object.f90 +++ b/src/lib/foodie_integrator_multistage_object.f90 @@ -1,7 +1,7 @@ -!< Define the abstract type [[integrator_multistage_explicit_object]] of FOODIE ODE integrators. +!< Define the abstract type [[integrator_multistage_object]] of FOODIE ODE integrators. -module foodie_integrator_multistage_explicit_object -!< Define the abstract type [[integrator_multistage_explicit_object]] of FOODIE ODE integrators. +module foodie_integrator_multistage_object +!< Define the abstract type [[integrator_multistage_object]] of FOODIE ODE integrators. use, intrinsic :: iso_fortran_env, only : stderr=>error_unit use foodie_integrand_object, only : integrand_object @@ -10,9 +10,9 @@ module foodie_integrator_multistage_explicit_object implicit none private -public :: integrator_multistage_explicit_object +public :: integrator_multistage_object -type, extends(integrator_object), abstract :: integrator_multistage_explicit_object +type, extends(integrator_object), abstract :: integrator_multistage_object !< Abstract type of FOODIE ODE integrators of the multistage family. integer(I_P) :: registers !< Number of registers used for stages. integer(I_P) :: stages !< Number of stages. @@ -29,30 +29,30 @@ module foodie_integrator_multistage_explicit_object procedure, pass(self) :: steps_number !< Return number of steps used. ! public methods procedure, pass(self) :: allocate_integrand_members !< Allocate integrand members. - procedure, pass(lhs) :: assign_multistage !< Assign members of [[integrator_multistage_explicit_object]] and parents. + procedure, pass(lhs) :: assign_multistage !< Assign members of [[integrator_multistage_object]] and parents. procedure, pass(self) :: destroy_multistage !< Destroy the integrator. -endtype integrator_multistage_explicit_object +endtype integrator_multistage_object abstract interface - !< Abstract interfaces of deferred methods of [[integrator_multistage_explicit_object]]. + !< Abstract interfaces of deferred methods of [[integrator_multistage_object]]. subroutine integrate_interface(self, U, Dt, t, new_Dt) !< Integrate integrand field. - import :: integrand_object, integrator_multistage_explicit_object, R_P - class(integrator_multistage_explicit_object), intent(inout) :: self !< Integrator. - class(integrand_object), intent(inout) :: U !< Integrand. - real(R_P), intent(in) :: Dt !< Time step. - real(R_P), intent(in) :: t !< Time. - real(R_P), intent(out), optional :: new_Dt !< New adapted time step. + import :: integrand_object, integrator_multistage_object, R_P + class(integrator_multistage_object), intent(inout) :: self !< Integrator. + class(integrand_object), intent(inout) :: U !< Integrand. + real(R_P), intent(in) :: Dt !< Time step. + real(R_P), intent(in) :: t !< Time. + real(R_P), intent(out), optional :: new_Dt !< New adapted time step. endsubroutine integrate_interface subroutine integrate_fast_interface(self, U, Dt, t, new_Dt) !< Integrate integrand field, fast mode. - import :: integrand_object, integrator_multistage_explicit_object, R_P - class(integrator_multistage_explicit_object), intent(inout) :: self !< Integrator. - class(integrand_object), intent(inout) :: U !< Field to be integrated. - real(R_P), intent(in) :: Dt !< Time step. - real(R_P), intent(in) :: t !< Time. - real(R_P), intent(out), optional :: new_Dt !< New adapted time step. + import :: integrand_object, integrator_multistage_object, R_P + class(integrator_multistage_object), intent(inout) :: self !< Integrator. + class(integrand_object), intent(inout) :: U !< Field to be integrated. + real(R_P), intent(in) :: Dt !< Time step. + real(R_P), intent(in) :: t !< Time. + real(R_P), intent(out), optional :: new_Dt !< New adapted time step. endsubroutine integrate_fast_interface endinterface @@ -60,32 +60,32 @@ subroutine integrate_fast_interface(self, U, Dt, t, new_Dt) ! deferred methods elemental function is_multistage(self) !< Return .true. for multistage integrator. - class(integrator_multistage_explicit_object), intent(in) :: self !< Integrator. - logical :: is_multistage !< Inquire result. + class(integrator_multistage_object), intent(in) :: self !< Integrator. + logical :: is_multistage !< Inquire result. is_multistage = .true. endfunction is_multistage elemental function is_multistep(self) !< Return .true. for multistage integrator. - class(integrator_multistage_explicit_object), intent(in) :: self !< Integrator. - logical :: is_multistep !< Inquire result. + class(integrator_multistage_object), intent(in) :: self !< Integrator. + logical :: is_multistep !< Inquire result. is_multistep = .false. endfunction is_multistep elemental function stages_number(self) !< Return number of stages used. - class(integrator_multistage_explicit_object), intent(in) :: self !< Integrator. - integer(I_P) :: stages_number !< Number of stages used. + class(integrator_multistage_object), intent(in) :: self !< Integrator. + integer(I_P) :: stages_number !< Number of stages used. stages_number = self%stages endfunction stages_number elemental function steps_number(self) !< Return number of steps used. - class(integrator_multistage_explicit_object), intent(in) :: self !< Integrator. - integer(I_P) :: steps_number !< Number of steps used. + class(integrator_multistage_object), intent(in) :: self !< Integrator. + integer(I_P) :: steps_number !< Number of steps used. steps_number = 0 endfunction steps_number @@ -95,9 +95,9 @@ pure subroutine allocate_integrand_members(self, U) !< Allocate members of interpolator being of [[integrand_object]] class. !< !< @note It is assumed that the integrator has been properly initialized before calling this method. - class(integrator_multistage_explicit_object), intent(inout) :: self !< Integrator. - class(integrand_object), intent(in) :: U !< Integrand. - integer(I_P) :: s !< Counter. + class(integrator_multistage_object), intent(inout) :: self !< Integrator. + class(integrand_object), intent(in) :: U !< Integrand. + integer(I_P) :: s !< Counter. if (self%is_multistage() .and. self%registers > 0) then if (allocated(self%stage)) deallocate(self%stage) @@ -114,14 +114,14 @@ pure subroutine allocate_integrand_members(self, U) endsubroutine allocate_integrand_members pure subroutine assign_multistage(lhs, rhs) - !< Assign members of [[integrator_multistage_explicit_object]] and parents. - class(integrator_multistage_explicit_object), intent(inout) :: lhs !< Left hand side. - class(integrator_object), intent(in) :: rhs !< Right hand side. - integer(I_P) :: s !< Counter. + !< Assign members of [[integrator_multistage_object]] and parents. + class(integrator_multistage_object), intent(inout) :: lhs !< Left hand side. + class(integrator_object), intent(in) :: rhs !< Right hand side. + integer(I_P) :: s !< Counter. call lhs%assign_abstract(rhs=rhs) select type(rhs) - class is (integrator_multistage_explicit_object) + class is (integrator_multistage_object) lhs%registers = rhs%registers lhs%stages = rhs%stages if (allocated(lhs%stage)) deallocate(lhs%stage) @@ -141,7 +141,7 @@ pure subroutine assign_multistage(lhs, rhs) elemental subroutine destroy_multistage(self) !< Destroy the integrator. - class(integrator_multistage_explicit_object), intent(inout) :: self !< Integrator. + class(integrator_multistage_object), intent(inout) :: self !< Integrator. call self%destroy_abstract self%registers = 0 @@ -149,4 +149,4 @@ elemental subroutine destroy_multistage(self) if (allocated(self%stage)) deallocate(self%stage) if (allocated(self%buffer)) deallocate(self%buffer) endsubroutine destroy_multistage -endmodule foodie_integrator_multistage_explicit_object +endmodule foodie_integrator_multistage_object diff --git a/src/lib/foodie_integrator_multistep_explicit_object.f90 b/src/lib/foodie_integrator_multistep_explicit_object.f90 deleted file mode 100644 index d11bea4c..00000000 --- a/src/lib/foodie_integrator_multistep_explicit_object.f90 +++ /dev/null @@ -1,215 +0,0 @@ -!< Define the abstract type [[integrator_multistep_explicit_object]] of FOODIE ODE integrators. - -module foodie_integrator_multistep_explicit_object -!< Define the abstract type [[integrator_multistep_explicit_object]] of FOODIE ODE integrators. - -use, intrinsic :: iso_fortran_env, only : stderr=>error_unit -use foodie_integrand_object, only : integrand_object -use foodie_integrator_object, only : integrator_object -use penf, only : I_P, R_P - -implicit none -private -public :: integrator_multistep_explicit_object - -type, extends(integrator_object), abstract :: integrator_multistep_explicit_object - !< Abstract type of FOODIE ODE integrators of the multistep family. - integer(I_P) :: registers !< Number of registers used for stages. - integer(I_P) :: steps !< Number of time steps. - logical :: autoupdate !< Perform cyclic autoupdate of previous time steps buffers. - real(R_P), allocatable :: Dt(:) !< Previous time steps. - real(R_P), allocatable :: t(:) !< Previous times. - class(integrand_object), allocatable :: previous(:) !< Previous steps. - class(integrand_object), allocatable :: buffer !< Buffer used for fast integration. - contains - ! deferred methods - procedure(integrate_interface), pass(self), deferred :: integrate !< Integrate integrand field. - procedure(integrate_fast_interface), pass(self), deferred :: integrate_fast !< Integrate integrand field, fast mode. - procedure(integrate_ub_interface), pass(self), deferred :: integrate_ub !< Integrate integrand field, unbuffered. - procedure(integrate_ub_fast_interface), pass(self), deferred :: integrate_ub_fast !< Integrate integrand field, fast mode, - !< unbuffered. - ! implemented deferred methods of parent - procedure, pass(self) :: is_multistage !< Return .true. for multistage integrator. - procedure, pass(self) :: is_multistep !< Return .true. for multistep integrator. - procedure, pass(self) :: stages_number !< Return number of stages used. - procedure, pass(self) :: steps_number !< Return number of steps used. - ! public methods - procedure, pass(self) :: allocate_integrand_members !< Allocate integrand members. - procedure, pass(lhs) :: assign_multistep !< Assign members of [[integrator_multistep_explicit_object]] and parents. - procedure, pass(self) :: destroy_multistep !< Destroy the integrator. - procedure, nopass :: update_previous !< Cyclic update previous time steps. -endtype integrator_multistep_explicit_object - -abstract interface - !< Abstract interfaces of deferred methods of [[integrator_multistep_explicit_object]]. - subroutine integrate_interface(self, U, Dt, t) - !< Integrate integrand field. - !< - !< @note This method uses integrand previous-steps-buffer stored inside integrator. - import :: integrand_object, integrator_multistep_explicit_object, R_P - class(integrator_multistep_explicit_object), intent(inout) :: self !< Integrator. - class(integrand_object), intent(inout) :: U !< Integrand. - real(R_P), intent(in) :: Dt !< Time step. - real(R_P), intent(in) :: t !< Time. - endsubroutine integrate_interface - - subroutine integrate_fast_interface(self, U, Dt, t) - !< Integrate integrand field, fast mode. - !< - !< @note This method uses integrand previous-steps-buffer stored inside integrator. - import :: integrand_object, integrator_multistep_explicit_object, R_P - class(integrator_multistep_explicit_object), intent(inout) :: self !< Integrator. - class(integrand_object), intent(inout) :: U !< Field to be integrated. - real(R_P), intent(in) :: Dt !< Time steps. - real(R_P), intent(in) :: t !< Times. - endsubroutine integrate_fast_interface - - subroutine integrate_ub_interface(self, U, previous, Dt, t) - !< Integrate integrand field, unbuffered. - import :: integrand_object, integrator_multistep_explicit_object, R_P - class(integrator_multistep_explicit_object), intent(inout) :: self !< Integrator. - class(integrand_object), intent(inout) :: U !< Integrand. - class(integrand_object), intent(inout) :: previous(1:) !< Integrand. - real(R_P), intent(in) :: Dt !< Time steps. - real(R_P), intent(in) :: t !< Times. - endsubroutine integrate_ub_interface - - subroutine integrate_ub_fast_interface(self, U, previous, Dt, t) - !< Integrate integrand field, unbuffered, fast mode. - import :: integrand_object, integrator_multistep_explicit_object, R_P - class(integrator_multistep_explicit_object), intent(inout) :: self !< Integrator. - class(integrand_object), intent(inout) :: U !< Field to be integrated. - class(integrand_object), intent(inout) :: previous(1:) !< Integrand. - real(R_P), intent(in) :: Dt !< Time steps. - real(R_P), intent(in) :: t !< Times. - endsubroutine integrate_ub_fast_interface -endinterface - -contains - ! deferred methods - elemental function is_multistage(self) - !< Return .true. for multistage integrator. - class(integrator_multistep_explicit_object), intent(in) :: self !< Integrator. - logical :: is_multistage !< Inquire result. - - is_multistage = .false. - endfunction is_multistage - - elemental function is_multistep(self) - !< Return .true. for multistage integrator. - class(integrator_multistep_explicit_object), intent(in) :: self !< Integrator. - logical :: is_multistep !< Inquire result. - - is_multistep = .true. - endfunction is_multistep - - elemental function stages_number(self) - !< Return number of stages used. - class(integrator_multistep_explicit_object), intent(in) :: self !< Integrator. - integer(I_P) :: stages_number !< Number of stages used. - - stages_number = 0 - endfunction stages_number - - elemental function steps_number(self) - !< Return number of steps used. - class(integrator_multistep_explicit_object), intent(in) :: self !< Integrator. - integer(I_P) :: steps_number !< Number of steps used. - - steps_number = self%steps - endfunction steps_number - - ! public methods - pure subroutine allocate_integrand_members(self, U) - !< Allocate members of interpolator being of [[integrand_object]] class. - !< - !< @note It is assumed that the integrator has been properly initialized before calling this method. - class(integrator_multistep_explicit_object), intent(inout) :: self !< Integrator. - class(integrand_object), intent(in) :: U !< Integrand. - integer(I_P) :: s !< Counter. - - if (self%is_multistep() .and. self%registers > 0) then - if (allocated(self%Dt)) deallocate(self%Dt) - allocate(self%Dt(1:self%registers)) ; self%Dt = 0._R_P - if (allocated(self%t)) deallocate(self%t) - allocate(self%t(1:self%registers)) ; self%t = 0._R_P - if (allocated(self%previous)) deallocate(self%previous) - allocate(self%previous(1:self%registers), mold=U) - do s=1, self%registers - self%previous(s) = U - enddo - endif - if (self%has_fast_mode()) then - if (allocated(self%buffer)) deallocate(self%buffer) - allocate(self%buffer, mold=U) - self%buffer = U - endif - endsubroutine allocate_integrand_members - - pure subroutine assign_multistep(lhs, rhs) - !< Assign members of [[integrator_multistep_explicit_object]] and parents. - class(integrator_multistep_explicit_object), intent(inout) :: lhs !< Left hand side. - class(integrator_object), intent(in) :: rhs !< Right hand side. - integer(I_P) :: s !< Counter. - - call lhs%assign_abstract(rhs=rhs) - select type(rhs) - class is (integrator_multistep_explicit_object) - lhs%registers = rhs%registers - lhs%steps = rhs%steps - lhs%autoupdate = rhs%autoupdate - if (allocated(lhs%Dt)) deallocate(lhs%Dt) - if (allocated(rhs%Dt)) lhs%Dt = rhs%Dt - if (allocated(lhs%t)) deallocate(lhs%t) - if (allocated(rhs%t)) lhs%t = rhs%t - if (allocated(lhs%previous)) deallocate(lhs%previous) - if (allocated(rhs%previous)) then - allocate(lhs%previous(1:lhs%registers), mold=rhs%previous) - do s=1, lhs%registers - lhs%previous(s) = rhs%previous(s) - enddo - endif - if (allocated(lhs%buffer)) deallocate(lhs%buffer) - if (allocated(rhs%buffer)) then - allocate(lhs%buffer, mold=rhs%buffer) - lhs%buffer = rhs%buffer - endif - endselect - endsubroutine assign_multistep - - elemental subroutine destroy_multistep(self) - !< Destroy the integrator. - class(integrator_multistep_explicit_object), intent(inout) :: self !< Integrator. - - call self%destroy_abstract - self%registers = 0 - self%steps = 0 - self%autoupdate = .false. - if (allocated(self%Dt)) deallocate(self%Dt) - if (allocated(self%t)) deallocate(self%t) - if (allocated(self%previous)) deallocate(self%previous) - if (allocated(self%buffer)) deallocate(self%buffer) - endsubroutine destroy_multistep - - subroutine update_previous(U, previous, Dt, t, previous_Dt, previous_t) - !< Cyclic update previous time steps. - class(integrand_object), intent(in) :: U !< Field to be integrated. - class(integrand_object), intent(inout) :: previous(1:) !< Previous time steps of integrand. - real(R_P), intent(in), optional :: Dt !< Time step. - real(R_P), intent(in), optional :: t !< Time. - real(R_P), intent(inout), optional :: previous_Dt(1:) !< Time step. - real(R_P), intent(inout), optional :: previous_t(1:) !< Time. - integer(I_P) :: last_step !< Last step. - integer(I_P) :: s !< Steps counter. - - last_step = size(previous, dim=1) - do s=1, last_step - 1 - previous(s) = previous(s + 1) - if (present(previous_Dt)) previous_Dt(s) = previous_Dt(s + 1) - if (present(previous_t)) previous_t(s) = previous_t(s + 1) - enddo - previous(last_step) = U - if (present(previous_Dt)) previous_Dt(last_step) = Dt - if (present(previous_t)) previous_t(last_step) = t + Dt - endsubroutine update_previous -endmodule foodie_integrator_multistep_explicit_object diff --git a/src/lib/foodie_integrator_multistep_implicit_object.f90 b/src/lib/foodie_integrator_multistep_object.f90 similarity index 65% rename from src/lib/foodie_integrator_multistep_implicit_object.f90 rename to src/lib/foodie_integrator_multistep_object.f90 index 60e997c3..b4e24e50 100644 --- a/src/lib/foodie_integrator_multistep_implicit_object.f90 +++ b/src/lib/foodie_integrator_multistep_object.f90 @@ -1,7 +1,7 @@ -!< Define the abstract type [[integrator_multistep_implicit_object]] of FOODIE ODE integrators. +!< Define the abstract type [[integrator_multistep_object]] of FOODIE ODE integrators. -module foodie_integrator_multistep_implicit_object -!< Define the abstract type [[integrator_multistep_implicit_object]] of FOODIE ODE integrators. +module foodie_integrator_multistep_object +!< Define the abstract type [[integrator_multistep_object]] of FOODIE ODE integrators. use, intrinsic :: iso_fortran_env, only : stderr=>error_unit use foodie_integrand_object, only : integrand_object @@ -10,9 +10,9 @@ module foodie_integrator_multistep_implicit_object implicit none private -public :: integrator_multistep_implicit_object +public :: integrator_multistep_object -type, extends(integrator_object), abstract :: integrator_multistep_implicit_object +type, extends(integrator_object), abstract :: integrator_multistep_object !< Abstract type of FOODIE ODE integrators of the multistep-implicit family. integer(I_P) :: registers !< Number of registers used for stages. integer(I_P) :: steps !< Number of time steps. @@ -36,53 +36,53 @@ module foodie_integrator_multistep_implicit_object procedure, pass(self) :: steps_number !< Return number of steps used. ! public methods procedure, pass(self) :: allocate_integrand_members !< Allocate integrand members. - procedure, pass(lhs) :: assign_multistep !< Assign members of [[integrator_multistep_implicit_object]] and parents. + procedure, pass(lhs) :: assign_multistep !< Assign members of [[integrator_multistep_object]] and parents. procedure, pass(self) :: destroy_multistep !< Destroy the integrator. procedure, nopass :: update_previous !< Cyclic update previous time steps. -endtype integrator_multistep_implicit_object +endtype integrator_multistep_object abstract interface - !< Abstract interfaces of deferred methods of [[integrator_multistep_implicit_object]]. + !< Abstract interfaces of deferred methods of [[integrator_multistep_object]]. subroutine integrate_interface(self, U, Dt, t) !< Integrate integrand field. !< !< @note This method uses integrand previous-steps-buffer stored inside integrator. - import :: integrand_object, integrator_multistep_implicit_object, R_P - class(integrator_multistep_implicit_object), intent(inout) :: self !< Integrator. - class(integrand_object), intent(inout) :: U !< Integrand. - real(R_P), intent(in) :: Dt !< Time steps. - real(R_P), intent(in) :: t !< Times. + import :: integrand_object, integrator_multistep_object, R_P + class(integrator_multistep_object), intent(inout) :: self !< Integrator. + class(integrand_object), intent(inout) :: U !< Integrand. + real(R_P), intent(in) :: Dt !< Time steps. + real(R_P), intent(in) :: t !< Times. endsubroutine integrate_interface subroutine integrate_fast_interface(self, U, Dt, t) !< Integrate integrand field, fast mode. !< !< @note This method uses integrand previous-steps-buffer stored inside integrator. - import :: integrand_object, integrator_multistep_implicit_object, R_P - class(integrator_multistep_implicit_object), intent(inout) :: self !< Integrator. - class(integrand_object), intent(inout) :: U !< Field to be integrated. - real(R_P), intent(in) :: Dt !< Time steps. - real(R_P), intent(in) :: t !< Times. + import :: integrand_object, integrator_multistep_object, R_P + class(integrator_multistep_object), intent(inout) :: self !< Integrator. + class(integrand_object), intent(inout) :: U !< Field to be integrated. + real(R_P), intent(in) :: Dt !< Time steps. + real(R_P), intent(in) :: t !< Times. endsubroutine integrate_fast_interface subroutine integrate_ub_interface(self, U, previous, Dt, t) !< Integrate integrand field, unbuffered. - import :: integrand_object, integrator_multistep_implicit_object, R_P - class(integrator_multistep_implicit_object), intent(inout) :: self !< Integrator. - class(integrand_object), intent(inout) :: U !< Integrand. - class(integrand_object), intent(inout) :: previous(1:) !< Integrand. - real(R_P), intent(in) :: Dt !< Time steps. - real(R_P), intent(in) :: t !< Times. + import :: integrand_object, integrator_multistep_object, R_P + class(integrator_multistep_object), intent(inout) :: self !< Integrator. + class(integrand_object), intent(inout) :: U !< Integrand. + class(integrand_object), intent(inout) :: previous(1:) !< Integrand. + real(R_P), intent(in) :: Dt !< Time steps. + real(R_P), intent(in) :: t !< Times. endsubroutine integrate_ub_interface subroutine integrate_ub_fast_interface(self, U, previous, Dt, t) !< Integrate integrand field, unbuffered, fast mode. - import :: integrand_object, integrator_multistep_implicit_object, R_P - class(integrator_multistep_implicit_object), intent(inout) :: self !< Integrator. - class(integrand_object), intent(inout) :: U !< Field to be integrated. - class(integrand_object), intent(inout) :: previous(1:) !< Integrand. - real(R_P), intent(in) :: Dt !< Time steps. - real(R_P), intent(in) :: t !< Times. + import :: integrand_object, integrator_multistep_object, R_P + class(integrator_multistep_object), intent(inout) :: self !< Integrator. + class(integrand_object), intent(inout) :: U !< Field to be integrated. + class(integrand_object), intent(inout) :: previous(1:) !< Integrand. + real(R_P), intent(in) :: Dt !< Time steps. + real(R_P), intent(in) :: t !< Times. endsubroutine integrate_ub_fast_interface endinterface @@ -90,32 +90,32 @@ subroutine integrate_ub_fast_interface(self, U, previous, Dt, t) ! deferred methods elemental function is_multistage(self) !< Return .true. for multistage integrator. - class(integrator_multistep_implicit_object), intent(in) :: self !< Integrator. - logical :: is_multistage !< Inquire result. + class(integrator_multistep_object), intent(in) :: self !< Integrator. + logical :: is_multistage !< Inquire result. is_multistage = .false. endfunction is_multistage elemental function is_multistep(self) !< Return .true. for multistage integrator. - class(integrator_multistep_implicit_object), intent(in) :: self !< Integrator. - logical :: is_multistep !< Inquire result. + class(integrator_multistep_object), intent(in) :: self !< Integrator. + logical :: is_multistep !< Inquire result. is_multistep = .true. endfunction is_multistep elemental function stages_number(self) !< Return number of stages used. - class(integrator_multistep_implicit_object), intent(in) :: self !< Integrator. - integer(I_P) :: stages_number !< Number of stages used. + class(integrator_multistep_object), intent(in) :: self !< Integrator. + integer(I_P) :: stages_number !< Number of stages used. stages_number = 0 endfunction stages_number elemental function steps_number(self) !< Return number of steps used. - class(integrator_multistep_implicit_object), intent(in) :: self !< Integrator. - integer(I_P) :: steps_number !< Number of steps used. + class(integrator_multistep_object), intent(in) :: self !< Integrator. + integer(I_P) :: steps_number !< Number of steps used. steps_number = self%steps endfunction steps_number @@ -125,9 +125,9 @@ pure subroutine allocate_integrand_members(self, U) !< Allocate members of interpolator being of [[integrand_object]] class. !< !< @note It is assumed that the integrator has been properly initialized before calling this method. - class(integrator_multistep_implicit_object), intent(inout) :: self !< Integrator. - class(integrand_object), intent(in) :: U !< Integrand. - integer(I_P) :: s !< Counter. + class(integrator_multistep_object), intent(inout) :: self !< Integrator. + class(integrand_object), intent(in) :: U !< Integrand. + integer(I_P) :: s !< Counter. if (self%is_multistep() .and. self%registers > 0) then if (allocated(self%Dt)) deallocate(self%Dt) @@ -148,14 +148,14 @@ pure subroutine allocate_integrand_members(self, U) endsubroutine allocate_integrand_members pure subroutine assign_multistep(lhs, rhs) - !< Assign members of [[integrator_multistep_implicit_object]] and parents. - class(integrator_multistep_implicit_object), intent(inout) :: lhs !< Left hand side. - class(integrator_object), intent(in) :: rhs !< Right hand side. - integer(I_P) :: s !< Counter. + !< Assign members of [[integrator_multistep_object]] and parents. + class(integrator_multistep_object), intent(inout) :: lhs !< Left hand side. + class(integrator_object), intent(in) :: rhs !< Right hand side. + integer(I_P) :: s !< Counter. call lhs%assign_abstract(rhs=rhs) select type(rhs) - class is (integrator_multistep_implicit_object) + class is (integrator_multistep_object) lhs%registers = rhs%registers lhs%steps = rhs%steps lhs%autoupdate = rhs%autoupdate @@ -181,7 +181,7 @@ pure subroutine assign_multistep(lhs, rhs) elemental subroutine destroy_multistep(self) !< Destroy the integrator. - class(integrator_multistep_implicit_object), intent(inout) :: self !< Integrator. + class(integrator_multistep_object), intent(inout) :: self !< Integrator. call self%destroy_abstract self%registers = 0 @@ -215,4 +215,4 @@ subroutine update_previous(U, previous, Dt, t, previous_Dt, previous_t) if (present(previous_Dt)) previous_Dt(last_step) = Dt if (present(previous_t)) previous_t(last_step) = t + Dt endsubroutine update_previous -endmodule foodie_integrator_multistep_implicit_object +endmodule foodie_integrator_multistep_object diff --git a/src/lib/foodie_integrator_runge_kutta_embedded.f90 b/src/lib/foodie_integrator_runge_kutta_embedded.f90 index 98f08ff0..0368554c 100644 --- a/src/lib/foodie_integrator_runge_kutta_embedded.f90 +++ b/src/lib/foodie_integrator_runge_kutta_embedded.f90 @@ -268,7 +268,7 @@ module foodie_integrator_runge_kutta_emd use foodie_error_codes, only : ERROR_UNSUPPORTED_SCHEME use foodie_integrand_object, only : integrand_object -use foodie_integrator_multistage_explicit_object, only : integrator_multistage_explicit_object +use foodie_integrator_multistage_object, only : integrator_multistage_object use foodie_integrator_object, only : integrator_object use penf, only : I_P, R_P @@ -286,7 +286,7 @@ module foodie_integrator_runge_kutta_emd logical, parameter :: is_multistage_=.true. !< Flag to check if integrator is multistage. logical, parameter :: is_multistep_=.false. !< Flag to check if integrator is multistep. -type, extends(integrator_multistage_explicit_object) :: integrator_runge_kutta_emd +type, extends(integrator_multistage_object) :: integrator_runge_kutta_emd !< FOODIE integrator: provide an explicit class of embedded Runge-Kutta schemes, from 2nd to 10th order accurate. !< !< @note The integrator must be created or initialized (initialize the RK coefficients) before used. diff --git a/src/lib/foodie_integrator_runge_kutta_low_storage.f90 b/src/lib/foodie_integrator_runge_kutta_low_storage.f90 index 5b11619d..3624e43c 100644 --- a/src/lib/foodie_integrator_runge_kutta_low_storage.f90 +++ b/src/lib/foodie_integrator_runge_kutta_low_storage.f90 @@ -149,7 +149,7 @@ module foodie_integrator_runge_kutta_low_storage use foodie_error_codes, only : ERROR_UNSUPPORTED_SCHEME use foodie_integrand_object, only : integrand_object -use foodie_integrator_multistage_explicit_object, only : integrator_multistage_explicit_object +use foodie_integrator_multistage_object, only : integrator_multistage_object use foodie_integrator_object, only : integrator_object use penf, only : I_P, I8P, R_P @@ -170,7 +170,7 @@ module foodie_integrator_runge_kutta_low_storage logical, parameter :: has_fast_mode_=.true. !< Flag to check if integrator provides *fast mode* integrate. -type, extends(integrator_multistage_explicit_object) :: integrator_runge_kutta_ls +type, extends(integrator_multistage_object) :: integrator_runge_kutta_ls !< FOODIE integrator: provide an explicit class of low storage Runge-Kutta schemes, from 1st to 4th order accurate. !< !< @note The integrator must be created or initialized (initialize the RK coefficients) before used. diff --git a/src/lib/foodie_integrator_runge_kutta_lssp.f90 b/src/lib/foodie_integrator_runge_kutta_lssp.f90 index 1417c95b..4ec0a736 100644 --- a/src/lib/foodie_integrator_runge_kutta_lssp.f90 +++ b/src/lib/foodie_integrator_runge_kutta_lssp.f90 @@ -64,7 +64,7 @@ module foodie_integrator_runge_kutta_lssp use foodie_error_codes, only : ERROR_UNSUPPORTED_SCHEME use foodie_integrand_object, only : integrand_object -use foodie_integrator_multistage_explicit_object, only : integrator_multistage_explicit_object +use foodie_integrator_multistage_object, only : integrator_multistage_object use foodie_integrator_object, only : integrator_object use penf, only : I_P, R_P @@ -78,7 +78,7 @@ module foodie_integrator_runge_kutta_lssp logical, parameter :: has_fast_mode_=.true. !< Flag to check if integrator provides *fast mode* integrate. -type, extends(integrator_multistage_explicit_object) :: integrator_runge_kutta_lssp +type, extends(integrator_multistage_object) :: integrator_runge_kutta_lssp !< FOODIE integrator: provide an explicit class of Linear SSP Runge-Kutta schemes, from 1st to s-th order accurate. !< !< @note The integrator must be created or initialized (initialize the RK coefficients) before used. diff --git a/src/lib/foodie_integrator_runge_kutta_ssp.f90 b/src/lib/foodie_integrator_runge_kutta_ssp.f90 index 76e370ea..d66b4369 100644 --- a/src/lib/foodie_integrator_runge_kutta_ssp.f90 +++ b/src/lib/foodie_integrator_runge_kutta_ssp.f90 @@ -102,7 +102,7 @@ module foodie_integrator_runge_kutta_ssp use foodie_error_codes, only : ERROR_UNSUPPORTED_SCHEME use foodie_integrand_object, only : integrand_object -use foodie_integrator_multistage_explicit_object, only : integrator_multistage_explicit_object +use foodie_integrator_multistage_object, only : integrator_multistage_object use foodie_integrator_object, only : integrator_object use penf, only : I_P, R_P @@ -118,7 +118,7 @@ module foodie_integrator_runge_kutta_ssp logical, parameter :: has_fast_mode_=.true. !< Flag to check if integrator provides *fast mode* integrate. -type, extends(integrator_multistage_explicit_object) :: integrator_runge_kutta_ssp +type, extends(integrator_multistage_object) :: integrator_runge_kutta_ssp !< FOODIE integrator: provide an explicit class of SSP Runge-Kutta schemes, from 1st to 4th order accurate. !< !< @note The integrator must be created or initialized (initialize the RK coefficients) before used. diff --git a/src/tests/tester/foodie_tester.f90 b/src/tests/tester/foodie_tester.f90 index c0f92d69..5a6d3634 100644 --- a/src/tests/tester/foodie_tester.f90 +++ b/src/tests/tester/foodie_tester.f90 @@ -5,27 +5,26 @@ module foodie_test_object use, intrinsic :: iso_fortran_env, only : stderr=>error_unit use flap, only : command_line_interface -use foodie, only : foodie_integrator_class_names, & - foodie_integrator_factory, & - foodie_integrator_schemes, & - integrand_object, & - integrator_adams_bashforth, & - integrator_adams_bashforth_moulton, & - integrator_adams_moulton, & - integrator_back_df, & - integrator_euler_explicit, & - integrator_leapfrog, & - integrator_lmm_ssp, & - integrator_lmm_ssp_vss, & - integrator_ms_runge_kutta_ssp, & - integrator_multistage_explicit_object, & - integrator_multistep_explicit_object, & - integrator_multistep_implicit_object, & - integrator_object, & - integrator_runge_kutta_emd, & - integrator_runge_kutta_ls, & - integrator_runge_kutta_lssp, & - integrator_runge_kutta_ssp, & +use foodie, only : foodie_integrator_class_names, & + foodie_integrator_factory, & + foodie_integrator_schemes, & + integrand_object, & + integrator_adams_bashforth, & + integrator_adams_bashforth_moulton, & + integrator_adams_moulton, & + integrator_back_df, & + integrator_euler_explicit, & + integrator_leapfrog, & + integrator_lmm_ssp, & + integrator_lmm_ssp_vss, & + integrator_ms_runge_kutta_ssp, & + integrator_multistage_object, & + integrator_multistep_object, & + integrator_object, & + integrator_runge_kutta_emd, & + integrator_runge_kutta_ls, & + integrator_runge_kutta_lssp, & + integrator_runge_kutta_ssp, & is_available, is_class_available use foodie_test_integrand_ladvection, only : integrand_ladvection use foodie_test_integrand_oscillation, only : integrand_oscillation @@ -291,7 +290,7 @@ subroutine integrate(scheme, integrand_0, Dt, final_time, iterations, stages, is endselect select type(integrator) - class is(integrator_multistage_explicit_object) + class is(integrator_multistage_object) do step = step + 1 if (is_fast) then @@ -304,28 +303,7 @@ subroutine integrate(scheme, integrand_0, Dt, final_time, iterations, stages, is call integrand_export_tecplot enddo - class is(integrator_multistep_explicit_object) - do - step = step + 1 - if (integrator%steps_number() >= step) then - call integrator_start%integrate(U=integrand, Dt=Dt, t=time(step)) - integrator%previous(step) = integrand - time(step) = time(step-1) + Dt - integrator%Dt(step) = Dt - integrator%t(step) = time(step) - else - if (is_fast) then - call integrator%integrate_fast(U=integrand, Dt=Dt, t=time(step_offset)) - else - call integrator%integrate(U=integrand, Dt=Dt, t=time(step_offset)) - endif - call update_previous_times - endif - if ((time(step_offset) >= final_time)) exit - call integrand_export_tecplot - enddo - - class is(integrator_multistep_implicit_object) + class is(integrator_multistep_object) do step = step + 1 if (integrator%steps_number() >= step) then From 112765ca2d39b35f9181c9d4cf7641f276fdcbe4 Mon Sep 17 00:00:00 2001 From: Stefano Zaghi Date: Fri, 26 May 2017 11:56:06 +0200 Subject: [PATCH 20/25] clean tester --- src/tests/tester/foodie_tester.f90 | 73 ++++++++++-------------------- 1 file changed, 23 insertions(+), 50 deletions(-) diff --git a/src/tests/tester/foodie_tester.f90 b/src/tests/tester/foodie_tester.f90 index 5a6d3634..ea0d7885 100644 --- a/src/tests/tester/foodie_tester.f90 +++ b/src/tests/tester/foodie_tester.f90 @@ -255,10 +255,8 @@ subroutine integrate(scheme, integrand_0, Dt, final_time, iterations, stages, is class(integrator_object), allocatable :: integrator !< The integrator. type(integrator_runge_kutta_ssp) :: integrator_start !< The (auto) start integrator. class(integrand_object), allocatable :: integrand !< Integrand. - real(R_P), allocatable :: time(:) !< Time. - real(R_P), allocatable :: Dts(:) !< Time steps. + real(R_P) :: time !< Time. integer(I_P) :: step !< Time steps counter. - integer(I_P) :: step_offset !< Time steps counter offset for slicing previous data array. allocate(integrand, mold=integrand_0) ; integrand = integrand_0 @@ -266,27 +264,15 @@ subroutine integrate(scheme, integrand_0, Dt, final_time, iterations, stages, is tolerance=1e2_R_P, iterations=iterations, autoupdate=.true., U=integrand_0) if (is_fast) call check_scheme_has_fast_mode(scheme=trim(adjustl(scheme)), integrator=integrator) - if (integrator%is_multistep()) then - call integrator_start%initialize(scheme='runge_kutta_ssp_stages_5_order_4', U=integrand_0) - if (integrator%steps_number()==0) then - step_offset = 1 ! for 0 step-(a convention)-solver offset is 1 - else - step_offset = integrator%steps_number() ! for >0 step-solver offset is steps - endif - allocate(Dts(1:step_offset)) - Dts = Dt - else - step_offset = 1 ! for 0 step-(a convention)-solver offset is 1 - endif - allocate(time(0:step_offset)) + if (integrator%is_multistep()) call integrator_start%initialize(scheme='runge_kutta_ssp_stages_5_order_4', U=integrand_0) step = 0 time = 0._R_P select type(integrand) type is(integrand_ladvection) - if (save_results) call integrand%export_tecplot(file_name=output_file_name, t=time(0), scheme=scheme) + if (save_results) call integrand%export_tecplot(file_name=output_file_name, t=time, scheme=scheme) type is(integrand_oscillation) - if (save_results) call integrand%export_tecplot(file_name=output_file_name, t=time(0), scheme=scheme) + if (save_results) call integrand%export_tecplot(file_name=output_file_name, t=time, scheme=scheme) endselect select type(integrator) @@ -294,12 +280,12 @@ subroutine integrate(scheme, integrand_0, Dt, final_time, iterations, stages, is do step = step + 1 if (is_fast) then - call integrator%integrate_fast(U=integrand, Dt=Dt, t=time(step_offset)) + call integrator%integrate_fast(U=integrand, Dt=Dt, t=time) else - call integrator%integrate(U=integrand, Dt=Dt, t=time(step_offset)) + call integrator%integrate(U=integrand, Dt=Dt, t=time) endif - call update_previous_times - if ((time(step_offset) >= final_time)) exit + time = time + Dt + if ((time >= final_time)) exit call integrand_export_tecplot enddo @@ -307,20 +293,20 @@ subroutine integrate(scheme, integrand_0, Dt, final_time, iterations, stages, is do step = step + 1 if (integrator%steps_number() >= step) then - call integrator_start%integrate(U=integrand, Dt=Dt, t=time(step)) + call integrator_start%integrate(U=integrand, Dt=Dt, t=time) integrator%previous(step) = integrand - time(step) = time(step-1) + Dt + time = time + Dt integrator%Dt(step) = Dt - integrator%t(step) = time(step) + integrator%t(step) = time else if (is_fast) then - call integrator%integrate_fast(U=integrand, Dt=Dt, t=time(step_offset)) + call integrator%integrate_fast(U=integrand, Dt=Dt, t=time) else - call integrator%integrate(U=integrand, Dt=Dt, t=time(step_offset)) + call integrator%integrate(U=integrand, Dt=Dt, t=time) endif - call update_previous_times + time = time + Dt endif - if ((time(step_offset) >= final_time)) exit + if ((time >= final_time)) exit call integrand_export_tecplot enddo @@ -328,28 +314,28 @@ subroutine integrate(scheme, integrand_0, Dt, final_time, iterations, stages, is ! do ! step = step + 1 ! if (integrator%steps_number() >= step) then - ! call integrator_start%integrate(U=integrand, Dt=Dt, t=time(step)) + ! call integrator_start%integrate(U=integrand, Dt=Dt, t=time) ! previous(step) = integrand - ! time(step) = time(step-1) + Dt + ! time = time + Dt ! else ! if (is_fast) then ! call integrator%integrate_fast(U=integrand, previous=previous, stage=stage, buffer=buffer, Dt=Dt,t=time) ! else ! call integrator%integrate(U=integrand, previous=previous, stage=stage, Dt=Dt, t=time) ! endif - ! call update_previous_times + ! time = time + Dt ! endif - ! if ((time(step) >= final_time)) exit + ! if ((time >= final_time)) exit ! call integrand_export_tecplot ! enddo endselect select type(integrand) type is(integrand_ladvection) - if (save_results) call integrand%export_tecplot(t=time(step_offset), scheme=scheme) + if (save_results) call integrand%export_tecplot(t=time, scheme=scheme) if (save_results) call integrand%export_tecplot(close_file=.true.) type is(integrand_oscillation) - if (save_results) call integrand%export_tecplot(t=time(step_offset)) + if (save_results) call integrand%export_tecplot(t=time) if (save_results) call integrand%export_tecplot(close_file=.true.) endselect contains @@ -358,24 +344,11 @@ subroutine integrand_export_tecplot select type(integrand) type is(integrand_ladvection) - if (save_results .and. mod(step, save_frequency)==0) call integrand%export_tecplot(t=time(step_offset), scheme=scheme) + if (save_results .and. mod(step, save_frequency)==0) call integrand%export_tecplot(t=time, scheme=scheme) type is(integrand_oscillation) - if (save_results .and. mod(step, save_frequency)==0) call integrand%export_tecplot(t=time(step_offset)) + if (save_results .and. mod(step, save_frequency)==0) call integrand%export_tecplot(t=time) endselect endsubroutine integrand_export_tecplot - - subroutine update_previous_times - !< Update previous times. - real(R_P) :: temporary !< Temporary buffer. - integer(I_P) :: p !< Counter. - - temporary = time(step_offset) - time(step_offset) = time(step_offset) + Dt - do p=0, step_offset - 2 - time(p) = time(p + 1) - enddo - time(step_offset-1) = temporary - endsubroutine update_previous_times endsubroutine integrate endmodule foodie_test_object From b67b13824f8f0b25bfb16e13665950aa5e693708 Mon Sep 17 00:00:00 2001 From: Stefano Zaghi Date: Fri, 26 May 2017 12:31:46 +0200 Subject: [PATCH 21/25] add intermediate abstract integrand tester --- .../foodie_test_integrand_ladvection.f90 | 45 ++++++----- .../foodie_test_integrand_oscillation.f90 | 58 +++++++------- .../foodie_test_integrand_tester_object.f90 | 51 ++++++++++++ src/tests/tester/foodie_tester.f90 | 80 ++++++++----------- 4 files changed, 140 insertions(+), 94 deletions(-) create mode 100644 src/tests/tester/foodie_test_integrand_tester_object.f90 diff --git a/src/tests/tester/foodie_test_integrand_ladvection.f90 b/src/tests/tester/foodie_test_integrand_ladvection.f90 index 78c9fb11..853d343b 100644 --- a/src/tests/tester/foodie_test_integrand_ladvection.f90 +++ b/src/tests/tester/foodie_test_integrand_ladvection.f90 @@ -8,6 +8,7 @@ module foodie_test_integrand_ladvection use, intrinsic :: iso_fortran_env, only : stderr=>error_unit use flap, only : command_line_interface use foodie, only : integrand_object +use foodie_test_integrand_tester_object, only : integrand_tester_object use penf, only : FR_P, I_P, R_P, str use wenoof, only : interpolator_object, wenoof_create @@ -15,7 +16,7 @@ module foodie_test_integrand_ladvection private public :: integrand_ladvection -type, extends(integrand_object) :: integrand_ladvection +type, extends(integrand_tester_object) :: integrand_ladvection !< 1D linear advection field. !< !< It is a FOODIE integrand class concrete extension. @@ -56,15 +57,15 @@ module foodie_test_integrand_ladvection class(interpolator_object), allocatable :: interpolator !< WENO interpolator. contains ! auxiliary methods - procedure, pass(self), public :: destroy !< Destroy field. - procedure, pass(self), public :: dt => compute_dt !< Compute the current time step, by means of CFL condition. - procedure, pass(self), public :: exact_solution !< Return exact solution. - procedure, pass(self), public :: export_tecplot !< Export integrand to Tecplot file. - procedure, pass(self), public :: output !< Extract integrand state field. - procedure, pass(self), public :: parse_cli !< Initialize from command line interface. - procedure, nopass, public :: set_cli !< Set command line interface. - procedure, pass(self), public :: set_square_wave_initial_state !< Set initial state as a square wave. - ! public deferred methods + procedure, pass(self), public :: destroy !< Destroy field. + procedure, pass(self), public :: dt => compute_dt !< Compute the current time step, by means of CFL condition. + procedure, pass(self), public :: exact_solution !< Return exact solution. + procedure, pass(self), public :: output !< Extract integrand state field. + ! integrand_tester_object deferred methods + procedure, pass(self), public :: export_tecplot !< Export integrand to Tecplot file. + procedure, pass(self), public :: parse_cli !< Initialize from command line interface. + procedure, nopass, public :: set_cli !< Set command line interface. + ! integrand_object deferred methods procedure, pass(self), public :: integrand_dimension !< Return integrand dimension. procedure, pass(self), public :: t => dU_dt !< Time derivative, residuals. ! operators @@ -93,8 +94,9 @@ module foodie_test_integrand_ladvection ! procedure, pass(opr), public :: integrand_multiply_real_scalar_fast !< `* real_scalar` fast operator. ! procedure, pass(opr), public :: integrand_subtract_integrand_fast !< `-` fast operator. ! private methods - procedure, pass(self), private :: impose_boundary_conditions !< Impose boundary conditions. - procedure, pass(self), private :: reconstruct_interfaces !< Reconstruct interface states. + procedure, pass(self), private :: impose_boundary_conditions !< Impose boundary conditions. + procedure, pass(self), private :: reconstruct_interfaces !< Reconstruct interface states. + procedure, pass(self), private :: set_square_wave_initial_state !< Set initial state as a square wave. endtype integrand_ladvection contains @@ -131,6 +133,15 @@ pure function exact_solution(self, u0, t) result(exact) endfunction exact_solution + pure function output(self) result(state) + !< Output the advection field state. + class(integrand_ladvection), intent(in) :: self !< Advection field. + real(R_P), allocatable :: state(:) !< Advection state + + state = self%u(1:self%Ni) + endfunction output + + ! integrand_tester_object deferred methods subroutine export_tecplot(self, file_name, t, scheme, close_file) !< Export integrand to Tecplot file. class(integrand_ladvection), intent(in) :: self !< Advection field. @@ -163,14 +174,6 @@ subroutine export_tecplot(self, file_name, t, scheme, close_file) endif endsubroutine export_tecplot - pure function output(self) result(state) - !< Output the advection field state. - class(integrand_ladvection), intent(in) :: self !< Advection field. - real(R_P), allocatable :: state(:) !< Advection state - - state = self%u(1:self%Ni) - endfunction output - subroutine parse_cli(self, cli) !< Initialize from command line interface. class(integrand_ladvection), intent(inout) :: self !< Advection field. @@ -218,7 +221,7 @@ subroutine set_cli(cli) def='square_wave', choices='square_wave') endsubroutine set_cli - ! ADT integrand deferred methods + ! integrand_object deferred methods function dU_dt(self, t) result(dState_dt) !< Time derivative of advection field, the residuals function. class(integrand_ladvection), intent(in) :: self !< Advection field. diff --git a/src/tests/tester/foodie_test_integrand_oscillation.f90 b/src/tests/tester/foodie_test_integrand_oscillation.f90 index 787c872c..9b7f7d5f 100644 --- a/src/tests/tester/foodie_test_integrand_oscillation.f90 +++ b/src/tests/tester/foodie_test_integrand_oscillation.f90 @@ -5,13 +5,14 @@ module foodie_test_integrand_oscillation use flap, only : command_line_interface use foodie, only : integrand_object +use foodie_test_integrand_tester_object, only : integrand_tester_object use penf, only : FR_P, R_P, I_P, str implicit none private public :: integrand_oscillation -type, extends(integrand_object) :: integrand_oscillation +type, extends(integrand_tester_object) :: integrand_oscillation !< The oscillation equations field. !< !< It is a FOODIE integrand class concrete extension. @@ -50,12 +51,13 @@ module foodie_test_integrand_oscillation ! auxiliary methods procedure, pass(self), public :: amplitude_phase !< Return amplitude and phase of the oscillation. procedure, pass(self), public :: exact_solution !< Return exact solution. - procedure, pass(self), public :: export_tecplot !< Export integrand to Tecplot file. procedure, pass(self), public :: initialize !< Initialize integrand. procedure, pass(self), public :: output !< Extract integrand state field. - procedure, pass(self), public :: parse_cli !< Initialize from command line interface. - procedure, nopass, public :: set_cli !< Set command line interface. - ! public deferred methods + ! integrand_tester_object deferred methods + procedure, pass(self), public :: export_tecplot !< Export integrand to Tecplot file. + procedure, pass(self), public :: parse_cli !< Initialize from command line interface. + procedure, nopass, public :: set_cli !< Set command line interface. + ! integrand_object deferred methods procedure, pass(self), public :: integrand_dimension !< Return integrand dimension. procedure, pass(self), public :: t => dU_dt !< Time derivative, residuals. ! operators @@ -106,6 +108,26 @@ pure function exact_solution(self, t) result(exact) exact(2) = self%U0(1) * sin(self%f * t) + self%U0(2) * cos(self%f * t) endfunction exact_solution + pure subroutine initialize(self, U0, frequency) + !< Initialize integrand. + class(integrand_oscillation), intent(inout) :: self !< Integrand. + real(R_P), intent(in) :: U0(1:2) !< Initial state. + real(R_P), intent(in) :: frequency !< Frequency of oscillation. + + self%U = U0 + self%f = frequency + self%U0 = U0 + endsubroutine initialize + + pure function output(self) result(state) + !< Extract integrand state field. + class(integrand_oscillation), intent(in) :: self !< Integrand. + real(R_P) :: state(1:2) !< State. + + state = self%U + endfunction output + + ! integrand_tester_object deferred methods subroutine export_tecplot(self, file_name, t, scheme, close_file) !< Export integrand to Tecplot file. class(integrand_oscillation), intent(in) :: self !< Advection field. @@ -138,30 +160,10 @@ subroutine export_tecplot(self, file_name, t, scheme, close_file) endif endsubroutine export_tecplot - pure subroutine initialize(self, U0, frequency) - !< Initialize integrand. - class(integrand_oscillation), intent(inout) :: self !< Integrand. - real(R_P), intent(in) :: U0(1:2) !< Initial state. - real(R_P), intent(in) :: frequency !< Frequency of oscillation. - - self%U = U0 - self%f = frequency - self%U0 = U0 - endsubroutine initialize - - pure function output(self) result(state) - !< Extract integrand state field. - class(integrand_oscillation), intent(in) :: self !< Integrand. - real(R_P) :: state(1:2) !< State. - - state = self%U - endfunction output - subroutine parse_cli(self, cli) !< Initialize from command line interface. - class(integrand_oscillation), intent(inout) :: self !< Advection field. - type(command_line_interface), intent(inout) :: cli !< Command line interface handler. - character(99) :: initial_state !< Initial state. + class(integrand_oscillation), intent(inout) :: self !< Advection field. + type(command_line_interface), intent(inout) :: cli !< Command line interface handler. call cli%get(switch='-f', val=self%f, error=cli%error) ; if (cli%error/=0) stop call cli%get(switch='-U0', val=self%U0, error=cli%error) ; if (cli%error/=0) stop @@ -176,7 +178,7 @@ subroutine set_cli(cli) call cli%add(switch='--U0', switch_ab='-U0', nargs='2', help='initial state', required=.false., def='0.0 1.0', act='store') endsubroutine set_cli - ! deferred methods + ! integrand_object deferred methods pure function integrand_dimension(self) !< return integrand dimension. class(integrand_oscillation), intent(in) :: self !< integrand. diff --git a/src/tests/tester/foodie_test_integrand_tester_object.f90 b/src/tests/tester/foodie_test_integrand_tester_object.f90 new file mode 100644 index 00000000..e3d4235c --- /dev/null +++ b/src/tests/tester/foodie_test_integrand_tester_object.f90 @@ -0,0 +1,51 @@ +!< Define [[integrand_tester_object]], the abstract tester integrand. + +module foodie_test_integrand_tester_object +!< Define [[integrand_tester_object]], the abstract tester integrand. + +use flap, only : command_line_interface +use foodie, only : integrand_object +use penf, only : FR_P, R_P, I_P, str + +implicit none +private +public :: integrand_tester_object + +type, abstract, extends(integrand_object) :: integrand_tester_object + !< The abstract tester integrand. + !< + !< This abstract provided some auxiliary methods useful for the tester machinery. + contains + ! auxiliary methods + procedure(export_tecplot_interface), pass(self), deferred :: export_tecplot !< Export integrand to Tecplot file. + procedure(parse_cli_interface), pass(self), deferred :: parse_cli !< Initialize from command line interface. + procedure(set_cli_interface), nopass, deferred :: set_cli !< Set command line interface. +endtype integrand_tester_object + +abstract interface + !< Abstract interfaces of [[integrand_tester_object]] class. + subroutine export_tecplot_interface(self, file_name, t, scheme, close_file) + !< Export integrand to Tecplot file. + import :: integrand_tester_object, R_P + class(integrand_tester_object), intent(in) :: self !< Advection field. + character(*), intent(in), optional :: file_name !< File name. + real(R_P), intent(in), optional :: t !< Time. + character(*), intent(in), optional :: scheme !< Scheme used to integrate integrand. + logical, intent(in), optional :: close_file !< Flag for closing file. + endsubroutine export_tecplot_interface + + subroutine parse_cli_interface(self, cli) + !< Initialize from command line interface. + import :: command_line_interface, integrand_tester_object + class(integrand_tester_object), intent(inout) :: self !< Advection field. + type(command_line_interface), intent(inout) :: cli !< Command line interface handler. + endsubroutine parse_cli_interface + + subroutine set_cli_interface(cli) + !< Set command line interface. + import :: command_line_interface + type(command_line_interface), intent(inout) :: cli !< Command line interface handler. + endsubroutine set_cli_interface +endinterface +endmodule foodie_test_integrand_tester_object + diff --git a/src/tests/tester/foodie_tester.f90 b/src/tests/tester/foodie_tester.f90 index ea0d7885..9c5af73c 100644 --- a/src/tests/tester/foodie_tester.f90 +++ b/src/tests/tester/foodie_tester.f90 @@ -28,6 +28,7 @@ module foodie_test_object is_available, is_class_available use foodie_test_integrand_ladvection, only : integrand_ladvection use foodie_test_integrand_oscillation, only : integrand_oscillation +use foodie_test_integrand_tester_object, only : integrand_tester_object use penf, only : I_P, R_P, FR_P, str, strz implicit none @@ -41,22 +42,22 @@ module foodie_test_object !< !< Test has only 1 public method `execute`: it executes test(s) accordingly to cli options. private - type(command_line_interface) :: cli !< Command line interface handler. - integer(I_P) :: error !< Error handler. - character(99) :: test !< Test executed. - character(99) :: scheme !< Scheme used. - real(R_P), allocatable :: Dt(:) !< Time step(s) exercised. - logical :: is_fast !< Flag for activating fast schemes. - integer(I_P) :: implicit_iterations !< Number of iterations (implicit solvers). - integer(I_P) :: stages !< Number of stages. - real(R_P) :: final_time !< Final integration time. - logical :: save_results !< Flag for activating results saving. - character(99) :: output !< Output files basename. - integer(I_P) :: save_frequency !< Save frequency. - logical :: verbose !< Flag for activating verbose output. - type(integrand_ladvection) :: ladvection_0 !< Initial conditions for linear advection test. - type(integrand_oscillation) :: oscillation_0 !< Initial conditions for oscillation test. - class(integrand_object), allocatable :: integrand_0 !< Initial conditions. + type(command_line_interface) :: cli !< Command line interface handler. + integer(I_P) :: error !< Error handler. + character(99) :: test !< Test executed. + character(99) :: scheme !< Scheme used. + real(R_P), allocatable :: Dt(:) !< Time step(s) exercised. + logical :: is_fast !< Flag for activating fast schemes. + integer(I_P) :: implicit_iterations !< Number of iterations (implicit solvers). + integer(I_P) :: stages !< Number of stages. + real(R_P) :: final_time !< Final integration time. + logical :: save_results !< Flag for activating results saving. + character(99) :: output !< Output files basename. + integer(I_P) :: save_frequency !< Save frequency. + logical :: verbose !< Flag for activating verbose output. + type(integrand_ladvection) :: ladvection_0 !< Initial conditions for linear advection test. + type(integrand_oscillation) :: oscillation_0 !< Initial conditions for oscillation test. + class(integrand_tester_object), allocatable :: integrand_0 !< Initial conditions. contains ! public methods procedure, pass(self) :: execute !< Execute selected test(s). @@ -242,21 +243,21 @@ subroutine check_scheme_has_fast_mode(scheme, integrator) subroutine integrate(scheme, integrand_0, Dt, final_time, iterations, stages, is_fast, save_results, output_file_name, & save_frequency) !< Integrate integrand by means of the given scheme. - character(*), intent(in) :: scheme !< Selected scheme. - class(integrand_object), intent(in) :: integrand_0 !< Initial conditions. - real(R_P), intent(in) :: Dt !< Time step. - real(R_P), intent(in) :: final_time !< Final integration time. - integer(I_P), intent(in) :: iterations !< Number of fixed point iterations. - integer(I_P), intent(in) :: stages !< Number of stages. - logical, intent(in) :: is_fast !< Activate fast mode integration. - logical, intent(in) :: save_results !< Save results. - character(*), intent(in) :: output_file_name !< File name of output results file. - integer(I_P), intent(in) :: save_frequency !< Save frequency. - class(integrator_object), allocatable :: integrator !< The integrator. - type(integrator_runge_kutta_ssp) :: integrator_start !< The (auto) start integrator. - class(integrand_object), allocatable :: integrand !< Integrand. - real(R_P) :: time !< Time. - integer(I_P) :: step !< Time steps counter. + character(*), intent(in) :: scheme !< Selected scheme. + class(integrand_tester_object), intent(in) :: integrand_0 !< Initial conditions. + real(R_P), intent(in) :: Dt !< Time step. + real(R_P), intent(in) :: final_time !< Final integration time. + integer(I_P), intent(in) :: iterations !< Number of fixed point iterations. + integer(I_P), intent(in) :: stages !< Number of stages. + logical, intent(in) :: is_fast !< Activate fast mode integration. + logical, intent(in) :: save_results !< Save results. + character(*), intent(in) :: output_file_name !< File name of output results file. + integer(I_P), intent(in) :: save_frequency !< Save frequency. + class(integrator_object), allocatable :: integrator !< The integrator. + type(integrator_runge_kutta_ssp) :: integrator_start !< The (auto) start integrator. + class(integrand_tester_object), allocatable :: integrand !< Integrand. + real(R_P) :: time !< Time. + integer(I_P) :: step !< Time steps counter. allocate(integrand, mold=integrand_0) ; integrand = integrand_0 @@ -268,12 +269,7 @@ subroutine integrate(scheme, integrand_0, Dt, final_time, iterations, stages, is step = 0 time = 0._R_P - select type(integrand) - type is(integrand_ladvection) - if (save_results) call integrand%export_tecplot(file_name=output_file_name, t=time, scheme=scheme) - type is(integrand_oscillation) - if (save_results) call integrand%export_tecplot(file_name=output_file_name, t=time, scheme=scheme) - endselect + if (save_results) call integrand%export_tecplot(file_name=output_file_name, t=time, scheme=scheme) select type(integrator) class is(integrator_multistage_object) @@ -330,14 +326,8 @@ subroutine integrate(scheme, integrand_0, Dt, final_time, iterations, stages, is ! enddo endselect - select type(integrand) - type is(integrand_ladvection) - if (save_results) call integrand%export_tecplot(t=time, scheme=scheme) - if (save_results) call integrand%export_tecplot(close_file=.true.) - type is(integrand_oscillation) - if (save_results) call integrand%export_tecplot(t=time) - if (save_results) call integrand%export_tecplot(close_file=.true.) - endselect + if (save_results) call integrand%export_tecplot(t=time, scheme=scheme) + if (save_results) call integrand%export_tecplot(close_file=.true.) contains subroutine integrand_export_tecplot !< Export current integrand solution to tecplot file. From ce846c602377d3f4502acbc1f26c90cd8ec044e1 Mon Sep 17 00:00:00 2001 From: Stefano Zaghi Date: Fri, 26 May 2017 13:54:32 +0200 Subject: [PATCH 22/25] trim out unbuffered integrate methods --- src/lib/foodie_integrator_adams_bashforth.f90 | 44 +---- ...die_integrator_adams_bashforth_moulton.f90 | 56 ++---- src/lib/foodie_integrator_adams_moulton.f90 | 78 +++----- ...rator_backward_differentiation_formula.f90 | 70 +++----- src/lib/foodie_integrator_leapfrog.f90 | 56 ++---- src/lib/foodie_integrator_lmm_ssp.f90 | 52 ++---- src/lib/foodie_integrator_lmm_ssp_vss.f90 | 167 +++++++----------- .../foodie_integrator_multistep_object.f90 | 31 +--- src/tests/tester/foodie_tester.f90 | 7 +- 9 files changed, 169 insertions(+), 392 deletions(-) diff --git a/src/lib/foodie_integrator_adams_bashforth.f90 b/src/lib/foodie_integrator_adams_bashforth.f90 index 1a665521..15e25b3c 100644 --- a/src/lib/foodie_integrator_adams_bashforth.f90 +++ b/src/lib/foodie_integrator_adams_bashforth.f90 @@ -73,8 +73,6 @@ module foodie_integrator_adams_bashforth procedure, pass(lhs) :: integr_assign_integr !< Operator `=`. procedure, pass(self) :: integrate !< Integrate integrand field. procedure, pass(self) :: integrate_fast !< Integrate integrand field, fast mode. - procedure, pass(self) :: integrate_ub !< Integrate integrand field, unbuffered. - procedure, pass(self) :: integrate_ub_fast !< Integrate integrand field, fast mode, unbuffered. procedure, pass(self) :: is_supported !< Return .true. if the integrator class support the given scheme. procedure, pass(self) :: supported_schemes !< Return the list of supported schemes. ! public methods @@ -133,60 +131,34 @@ pure subroutine integr_assign_integr(lhs, rhs) subroutine integrate(self, U, Dt, t) !< Integrate field with Adams-Bashforth class scheme. - !< - !< @note This method uses integrand previous-steps-buffer stored inside integrator. class(integrator_adams_bashforth), intent(inout) :: self !< Integrator. class(integrand_object), intent(inout) :: U !< Field to be integrated. real(R_P), intent(in) :: Dt !< Time step. real(R_P), intent(in) :: t !< Time. + integer(I_P) :: s !< Steps counter. - call self%integrate_ub(U=U, previous=self%previous, Dt=Dt, t=t) + do s=1, self%steps + U = U + (self%previous(s)%t(t=self%t(s)) * (Dt * self%b(s))) + enddo + if (self%autoupdate) call self%update_previous(U=U, previous=self%previous, Dt=Dt, t=t, previous_t=self%t) endsubroutine integrate subroutine integrate_fast(self, U, Dt, t) !< Integrate field with Adams-Bashforth class scheme, fast mode. - !< - !< @note This method uses integrand previous-steps-buffer stored inside integrator. class(integrator_adams_bashforth), intent(inout) :: self !< Integrator. class(integrand_object), intent(inout) :: U !< Field to be integrated. real(R_P), intent(in) :: Dt !< Time step. real(R_P), intent(in) :: t !< Time. - - call self%integrate_ub_fast(U=U, previous=self%previous, Dt=Dt, t=t) - endsubroutine integrate_fast - - subroutine integrate_ub(self, U, previous, Dt, t) - !< Integrate field with Adams-Bashforth class scheme, unbuffered. - class(integrator_adams_bashforth), intent(inout) :: self !< Integrator. - class(integrand_object), intent(inout) :: U !< Field to be integrated. - class(integrand_object), intent(inout) :: previous(1:) !< Integrand. - real(R_P), intent(in) :: Dt !< Time step. - real(R_P), intent(in) :: t !< Time. integer(I_P) :: s !< Steps counter. do s=1, self%steps - U = U + (previous(s)%t(t=self%t(s)) * (Dt * self%b(s))) - enddo - if (self%autoupdate) call self%update_previous(U=U, previous=previous, Dt=Dt, t=t, previous_t=self%t) - endsubroutine integrate_ub - - subroutine integrate_ub_fast(self, U, previous, Dt, t) - !< Integrate field with Adams-Bashforth class scheme, unbuffered, fast mode. - class(integrator_adams_bashforth), intent(inout) :: self !< Integrator. - class(integrand_object), intent(inout) :: U !< Field to be integrated. - class(integrand_object), intent(inout) :: previous(1:) !< Integrand. - real(R_P), intent(in) :: Dt !< Time step. - real(R_P), intent(in) :: t !< Time. - integer(I_P) :: s !< Steps counter. - - do s=1, self%steps - self%buffer = previous(s) + self%buffer = self%previous(s) call self%buffer%t_fast(t=self%t(s)) call self%buffer%multiply_fast(lhs=self%buffer, rhs=Dt * self%b(s)) call U%add_fast(lhs=U, rhs=self%buffer) enddo - if (self%autoupdate) call self%update_previous(U=U, previous=previous, Dt=Dt, t=t, previous_t=self%t) - endsubroutine integrate_ub_fast + if (self%autoupdate) call self%update_previous(U=U, previous=self%previous, Dt=Dt, t=t, previous_t=self%t) + endsubroutine integrate_fast elemental function is_supported(self, scheme) !< Return .true. if the integrator class support the given scheme. diff --git a/src/lib/foodie_integrator_adams_bashforth_moulton.f90 b/src/lib/foodie_integrator_adams_bashforth_moulton.f90 index ede0b2e0..bdeea5c6 100644 --- a/src/lib/foodie_integrator_adams_bashforth_moulton.f90 +++ b/src/lib/foodie_integrator_adams_bashforth_moulton.f90 @@ -126,8 +126,6 @@ module foodie_integrator_adams_bashforth_moulton procedure, pass(lhs) :: integr_assign_integr !< Operator `=`. procedure, pass(self) :: integrate !< Integrate integrand field. procedure, pass(self) :: integrate_fast !< Integrate integrand field. - procedure, pass(self) :: integrate_ub !< Integrate integrand field, unbuffered. - procedure, pass(self) :: integrate_ub_fast !< Integrate integrand field, unbuffered, fast mode. procedure, pass(self) :: is_supported !< Return .true. if the integrator class support the given scheme. procedure, pass(self) :: supported_schemes !< Return the list of supported schemes. ! public methods @@ -189,62 +187,36 @@ pure subroutine integr_assign_integr(lhs, rhs) subroutine integrate(self, U, Dt, t) !< Integrate field with Adams-Bashforth-Moulton class scheme. - !< - !< @note This method uses integrand previous-steps-buffer stored inside integrator. class(integrator_adams_bashforth_moulton), intent(inout) :: self !< Integrator. class(integrand_object), intent(inout) :: U !< Field to be integrated. real(R_P), intent(in) :: Dt !< Time steps. real(R_P), intent(in) :: t !< Times. - call self%integrate_ub(U=U, previous=self%previous, Dt=Dt, t=t) + ! self%predictor%t = self%t(1:self%steps) + ! self%predictor%Dt = self%Dt(1:self%steps) + ! self%corrector%t = self%t(1:self%steps) + ! self%corrector%Dt = self%Dt(1:self%steps) + ! call self%predictor%integrate_ub(U=U, previous=previous, Dt=Dt, t=t) + ! call self%corrector%integrate_ub(U=U, previous=previous(2:), Dt=Dt, t=t) + ! if (self%autoupdate) call self%update_previous(U=U, previous=previous(1:self%steps), Dt=Dt, t=t, previous_t=self%t(1:self%steps)) endsubroutine integrate subroutine integrate_fast(self, U, Dt, t) !< Integrate field with Adams-Bashforth-Moulton class scheme, fast mode. - !< - !< @note This method uses integrand previous-steps-buffer stored inside integrator. class(integrator_adams_bashforth_moulton), intent(inout) :: self !< Integrator. class(integrand_object), intent(inout) :: U !< Field to be integrated. real(R_P), intent(in) :: Dt !< Time steps. real(R_P), intent(in) :: t !< Times. - call self%integrate_ub_fast(U=U, previous=self%previous, Dt=Dt, t=t) + ! self%predictor%t = self%t + ! self%predictor%Dt = self%Dt + ! self%corrector%t = self%t + ! self%corrector%Dt = self%Dt + ! call self%predictor%integrate_ub_fast(U=U, previous=previous, Dt=Dt, t=t) + ! call self%corrector%integrate_ub_fast(U=U, previous=previous(2:), Dt=Dt, t=t) + ! if (self%autoupdate) call self%update_previous(U=U, previous=previous(1:self%steps), Dt=Dt, t=t, previous_t=self%t(1:self%steps)) endsubroutine integrate_fast - subroutine integrate_ub(self, U, previous, Dt, t) - !< Integrate field with Adams-Bashforth-Moulton class scheme, unbuffered. - class(integrator_adams_bashforth_moulton), intent(inout) :: self !< Integrator. - class(integrand_object), intent(inout) :: U !< Field to be integrated. - class(integrand_object), intent(inout) :: previous(1:) !< Integrand. - real(R_P), intent(in) :: Dt !< Time steps. - real(R_P), intent(in) :: t !< Times. - - self%predictor%t = self%t(1:self%steps) - self%predictor%Dt = self%Dt(1:self%steps) - self%corrector%t = self%t(1:self%steps) - self%corrector%Dt = self%Dt(1:self%steps) - call self%predictor%integrate_ub(U=U, previous=previous, Dt=Dt, t=t) - call self%corrector%integrate_ub(U=U, previous=previous(2:), Dt=Dt, t=t) - if (self%autoupdate) call self%update_previous(U=U, previous=previous(1:self%steps), Dt=Dt, t=t, previous_t=self%t(1:self%steps)) - endsubroutine integrate_ub - - subroutine integrate_ub_fast(self, U, previous, Dt, t) - !< Integrate field with Adams-Bashforth-Moulton class scheme, unbuffered, fast mode. - class(integrator_adams_bashforth_moulton), intent(inout) :: self !< Integrator. - class(integrand_object), intent(inout) :: U !< Field to be integrated. - class(integrand_object), intent(inout) :: previous(1:) !< Integrand. - real(R_P), intent(in) :: Dt !< Time steps. - real(R_P), intent(in) :: t !< Times. - - self%predictor%t = self%t - self%predictor%Dt = self%Dt - self%corrector%t = self%t - self%corrector%Dt = self%Dt - call self%predictor%integrate_ub_fast(U=U, previous=previous, Dt=Dt, t=t) - call self%corrector%integrate_ub_fast(U=U, previous=previous(2:), Dt=Dt, t=t) - if (self%autoupdate) call self%update_previous(U=U, previous=previous(1:self%steps), Dt=Dt, t=t, previous_t=self%t(1:self%steps)) - endsubroutine integrate_ub_fast - elemental function is_supported(self, scheme) !< Return .true. if the integrator class support the given scheme. class(integrator_adams_bashforth_moulton), intent(in) :: self !< Integrator. diff --git a/src/lib/foodie_integrator_adams_moulton.f90 b/src/lib/foodie_integrator_adams_moulton.f90 index e34d8754..9f54c321 100644 --- a/src/lib/foodie_integrator_adams_moulton.f90 +++ b/src/lib/foodie_integrator_adams_moulton.f90 @@ -74,8 +74,6 @@ module foodie_integrator_adams_moulton procedure, pass(self) :: has_fast_mode !< Return .true. if the integrator class has *fast mode* integrate. procedure, pass(self) :: integrate !< Integrate integrand field. procedure, pass(self) :: integrate_fast !< Integrate integrand field, fast mode. - procedure, pass(self) :: integrate_ub !< Integrate integrand field, unbuffered. - procedure, pass(self) :: integrate_ub_fast !< Integrate integrand field, unbuffered, fast mode. procedure, pass(self) :: is_supported !< Return .true. if the integrator class support the given scheme. procedure, pass(self) :: supported_schemes !< Return the list of supported schemes. ! public methods @@ -135,76 +133,50 @@ pure subroutine integr_assign_integr(lhs, rhs) subroutine integrate(self, U, Dt, t) !< Integrate field with Adams-Moulton class scheme. - !< - !< @note This method uses integrand previous-steps-buffer stored inside integrator. - class(integrator_adams_moulton), intent(inout) :: self !< Integrator. - class(integrand_object), intent(inout) :: U !< Field to be integrated. - real(R_P), intent(in) :: Dt !< Time step. - real(R_P), intent(in) :: t !< Time. - - call self%integrate_ub(U=U, previous=self%previous, Dt=Dt, t=t) - endsubroutine integrate - - subroutine integrate_fast(self, U, Dt, t) - !< Integrate field with Adams-Moulton class scheme, fast mode. - !< - !< @note This method uses integrand previous-steps-buffer stored inside integrator. - class(integrator_adams_moulton), intent(inout) :: self !< Integrator. - class(integrand_object), intent(inout) :: U !< Field to be integrated. - real(R_P), intent(in) :: Dt !< Time step. - real(R_P), intent(in) :: t !< Time. - - call self%integrate_ub_fast(U=U, previous=self%previous, Dt=Dt, t=t) - endsubroutine integrate_fast - - subroutine integrate_ub(self, U, previous, Dt, t) - !< Integrate field with Adams-Moulton class scheme. - class(integrator_adams_moulton), intent(inout) :: self !< Integrator. - class(integrand_object), intent(inout) :: U !< Field to be integrated. - class(integrand_object), intent(inout) :: previous(1:) !< Integrand. - real(R_P), intent(in) :: Dt !< Time step. - real(R_P), intent(in) :: t !< Time. - class(integrand_object), allocatable :: delta !< Delta RHS for fixed point iterations. - integer(I_P) :: s !< Steps counter. + class(integrator_adams_moulton), intent(inout) :: self !< Integrator. + class(integrand_object), intent(inout) :: U !< Field to be integrated. + real(R_P), intent(in) :: Dt !< Time step. + real(R_P), intent(in) :: t !< Time. + class(integrand_object), allocatable :: delta !< Delta RHS for fixed point iterations. + integer(I_P) :: s !< Steps counter. if ( self%steps>0 ) then if (self%iterations > 0) then ! perform fixed point iterations allocate(delta, mold=U) - delta = previous(self%steps) + delta = self%previous(self%steps) do s=0, self%steps - 1 - delta = delta + (previous(s+1)%t(t=self%t(s+1)) * (Dt * self%b(s))) + delta = delta + (self%previous(s+1)%t(t=self%t(s+1)) * (Dt * self%b(s))) enddo do s=1, self%iterations U = delta + (U%t(t=self%t(self%steps) + Dt) * (Dt * self%b(self%steps))) enddo else - U = previous(self%steps) + (U%t(t=self%t(self%steps) + Dt) * (Dt * self%b(self%steps))) + U = self%previous(self%steps) + (U%t(t=self%t(self%steps) + Dt) * (Dt * self%b(self%steps))) do s=0, self%steps - 1 - U = U + (previous(s+1)%t(t=self%t(s+1)) * (Dt * self%b(s))) + U = U + (self%previous(s+1)%t(t=self%t(s+1)) * (Dt * self%b(s))) enddo endif - if (self%autoupdate) call self%update_previous(U=U, previous=previous, Dt=Dt, t=t, previous_t=self%t) + if (self%autoupdate) call self%update_previous(U=U, previous=self%previous, Dt=Dt, t=t, previous_t=self%t) else U = U + (U%t(t=t) * (Dt * self%b(0))) endif - endsubroutine integrate_ub + endsubroutine integrate - subroutine integrate_ub_fast(self, U, previous, Dt, t) + subroutine integrate_fast(self, U, Dt, t) !< Integrate field with Adams-Moulton class scheme, fast mode. - class(integrator_adams_moulton), intent(inout) :: self !< Integrator. - class(integrand_object), intent(inout) :: U !< Field to be integrated. - class(integrand_object), intent(inout) :: previous(1:) !< Integrand. - real(R_P), intent(in) :: Dt !< Time step. - real(R_P), intent(in) :: t !< Time. - class(integrand_object), allocatable :: delta !< Delta RHS for fixed point iterations. - integer(I_P) :: s !< Steps counter. + class(integrator_adams_moulton), intent(inout) :: self !< Integrator. + class(integrand_object), intent(inout) :: U !< Field to be integrated. + real(R_P), intent(in) :: Dt !< Time step. + real(R_P), intent(in) :: t !< Time. + class(integrand_object), allocatable :: delta !< Delta RHS for fixed point iterations. + integer(I_P) :: s !< Steps counter. if (self%steps>0) then if (self%iterations > 0) then ! perform fixed point iterations allocate(delta, mold=U) - delta = previous(self%steps) + delta = self%previous(self%steps) do s=0, self%steps - 1 - self%buffer = previous(s+1) + self%buffer = self%previous(s+1) call self%buffer%t_fast(t=self%t(s+1)) call self%buffer%multiply_fast(lhs=self%buffer, rhs=Dt * self%b(s)) call delta%add_fast(lhs=delta, rhs=self%buffer) @@ -219,22 +191,22 @@ subroutine integrate_ub_fast(self, U, previous, Dt, t) self%buffer = U call self%buffer%t_fast(t=self%t(self%steps) + Dt) call self%buffer%multiply_fast(lhs=self%buffer, rhs=Dt * self%b(self%steps)) - call U%add_fast(lhs=previous(self%steps), rhs=self%buffer) + call U%add_fast(lhs=self%previous(self%steps), rhs=self%buffer) do s=0, self%steps - 1 - self%buffer = previous(s+1) + self%buffer = self%previous(s+1) call self%buffer%t_fast(t=self%t(s+1)) call self%buffer%multiply_fast(lhs=self%buffer, rhs=Dt * self%b(s)) call U%add_fast(lhs=U, rhs=self%buffer) enddo endif - if (self%autoupdate) call self%update_previous(U=U, previous=previous, Dt=Dt, t=t, previous_t=self%t) + if (self%autoupdate) call self%update_previous(U=U, previous=self%previous, Dt=Dt, t=t, previous_t=self%t) else self%buffer = U call self%buffer%t_fast(t=t) call self%buffer%multiply_fast(lhs=self%buffer, rhs=Dt * self%b(0)) call U%add_fast(lhs=U, rhs=self%buffer) endif - endsubroutine integrate_ub_fast + endsubroutine integrate_fast elemental function is_supported(self, scheme) !< Return .true. if the integrator class support the given scheme. diff --git a/src/lib/foodie_integrator_backward_differentiation_formula.f90 b/src/lib/foodie_integrator_backward_differentiation_formula.f90 index c226a2b9..af6c85f6 100644 --- a/src/lib/foodie_integrator_backward_differentiation_formula.f90 +++ b/src/lib/foodie_integrator_backward_differentiation_formula.f90 @@ -72,8 +72,6 @@ module foodie_integrator_backward_differentiation_formula procedure, pass(lhs) :: integr_assign_integr !< Operator `=`. procedure, pass(self) :: integrate !< Integrate integrand field. procedure, pass(self) :: integrate_fast !< Integrate integrand field, fast mode. - procedure, pass(self) :: integrate_ub !< Integrate integrand field, unbuffered. - procedure, pass(self) :: integrate_ub_fast !< Integrate integrand field, unbuffered, fast mode. procedure, pass(self) :: is_supported !< Return .true. if the integrator class support the given scheme. procedure, pass(self) :: supported_schemes !< Return the list of supported schemes. ! public methods @@ -134,63 +132,37 @@ pure subroutine integr_assign_integr(lhs, rhs) subroutine integrate(self, U, Dt, t) !< Integrate field with BDF class scheme. - !< - !< @note This method uses integrand previous-steps-buffer stored inside integrator. - class(integrator_back_df), intent(inout) :: self !< Integrator. - class(integrand_object), intent(inout) :: U !< Field to be integrated. - real(R_P), intent(in) :: Dt !< Time step. - real(R_P), intent(in) :: t !< Time. - - call self%integrate_ub(U=U, previous=self%previous, Dt=Dt, t=t) - endsubroutine integrate - - subroutine integrate_fast(self, U, Dt, t) - !< Integrate field with BDF class scheme. - !< - !< @note This method uses integrand previous-steps-buffer stored inside integrator. - class(integrator_back_df), intent(inout) :: self !< Integrator. - class(integrand_object), intent(inout) :: U !< Field to be integrated. - real(R_P), intent(in) :: Dt !< Time step. - real(R_P), intent(in) :: t !< Time. - - call self%integrate_ub_fast(U=U, previous=self%previous, Dt=Dt, t=t) - endsubroutine integrate_fast - - subroutine integrate_ub(self, U, previous, Dt, t) - !< Integrate field with BDF class scheme. - class(integrator_back_df), intent(inout) :: self !< Integrator. - class(integrand_object), intent(inout) :: U !< Field to be integrated. - class(integrand_object), intent(inout) :: previous(1:) !< Integrand. - real(R_P), intent(in) :: Dt !< Time step. - real(R_P), intent(in) :: t !< Time. - class(integrand_object), allocatable :: delta !< Delta RHS for fixed point iterations. - integer(I_P) :: s !< Steps counter. + class(integrator_back_df), intent(inout) :: self !< Integrator. + class(integrand_object), intent(inout) :: U !< Field to be integrated. + real(R_P), intent(in) :: Dt !< Time step. + real(R_P), intent(in) :: t !< Time. + class(integrand_object), allocatable :: delta !< Delta RHS for fixed point iterations. + integer(I_P) :: s !< Steps counter. allocate(delta, mold=U) - delta = previous(self%steps) * (-self%a(self%steps)) + delta = self%previous(self%steps) * (-self%a(self%steps)) do s=1, self%steps - 1 - delta = delta + (previous(s) * (-self%a(s))) + delta = delta + (self%previous(s) * (-self%a(s))) enddo do s=1, self%iterations U = delta + (U%t(t=self%t(self%steps) + Dt) * (Dt * self%b)) enddo - if (self%autoupdate) call self%update_previous(U=U, previous=previous, Dt=Dt, t=t, previous_t=self%t) - endsubroutine integrate_ub + if (self%autoupdate) call self%update_previous(U=U, previous=self%previous, Dt=Dt, t=t, previous_t=self%t) + endsubroutine integrate - subroutine integrate_ub_fast(self, U, previous, Dt, t) + subroutine integrate_fast(self, U, Dt, t) !< Integrate field with BDF class scheme. - class(integrator_back_df), intent(inout) :: self !< Integrator. - class(integrand_object), intent(inout) :: U !< Field to be integrated. - class(integrand_object), intent(inout) :: previous(1:) !< Integrand. - real(R_P), intent(in) :: Dt !< Time steps. - real(R_P), intent(in) :: t !< Times. - class(integrand_object), allocatable :: delta !< Delta RHS for fixed point iterations. - integer(I_P) :: s !< Steps counter. + class(integrator_back_df), intent(inout) :: self !< Integrator. + class(integrand_object), intent(inout) :: U !< Field to be integrated. + real(R_P), intent(in) :: Dt !< Time step. + real(R_P), intent(in) :: t !< Time. + class(integrand_object), allocatable :: delta !< Delta RHS for fixed point iterations. + integer(I_P) :: s !< Steps counter. allocate(delta, mold=U) - call delta%multiply_fast(lhs=previous(self%steps), rhs=-self%a(self%steps)) + call delta%multiply_fast(lhs=self%previous(self%steps), rhs=-self%a(self%steps)) do s=1, self%steps - 1 - call self%buffer%multiply_fast(lhs=previous(s), rhs=-self%a(s)) + call self%buffer%multiply_fast(lhs=self%previous(s), rhs=-self%a(s)) call delta%add_fast(lhs=delta, rhs=self%buffer) enddo do s=1, self%iterations @@ -199,8 +171,8 @@ subroutine integrate_ub_fast(self, U, previous, Dt, t) call self%buffer%multiply_fast(lhs=self%buffer, rhs=Dt * self%b) call U%add_fast(lhs=delta, rhs=self%buffer) enddo - if (self%autoupdate) call self%update_previous(U=U, previous=previous, Dt=Dt, t=t, previous_t=self%t) - endsubroutine integrate_ub_fast + if (self%autoupdate) call self%update_previous(U=U, previous=self%previous, Dt=Dt, t=t, previous_t=self%t) + endsubroutine integrate_fast elemental function is_supported(self, scheme) !< Return .true. if the integrator class support the given scheme. diff --git a/src/lib/foodie_integrator_leapfrog.f90 b/src/lib/foodie_integrator_leapfrog.f90 index 69a89436..8c266070 100644 --- a/src/lib/foodie_integrator_leapfrog.f90 +++ b/src/lib/foodie_integrator_leapfrog.f90 @@ -72,8 +72,6 @@ module foodie_integrator_leapfrog procedure, pass(lhs) :: integr_assign_integr !< Operator `=`. procedure, pass(self) :: integrate !< Integrate integrand field. procedure, pass(self) :: integrate_fast !< Integrate integrand field, fast mode. - procedure, pass(self) :: integrate_ub !< Integrate integrand field, unbuffered. - procedure, pass(self) :: integrate_ub_fast !< Integrate integrand field, fast mode, unbuffered. procedure, pass(self) :: is_supported !< Return .true. if the integrator class support the given scheme. procedure, pass(self) :: supported_schemes !< Return the list of supported schemes. ! public methods @@ -133,71 +131,45 @@ pure subroutine integr_assign_integr(lhs, rhs) subroutine integrate(self, U, Dt, t) !< Integrate field with leapfrog class scheme. - !< - !< @note This method uses integrand previous-steps-buffer stored inside integrator. class(integrator_leapfrog), intent(inout) :: self !< Integrator. class(integrand_object), intent(inout) :: U !< Field to be integrated. real(R_P), intent(in) :: Dt !< Time step. real(R_P), intent(in) :: t !< Time. - call self%integrate_ub(U=U, previous=self%previous, Dt=Dt, t=t) + U = self%previous(1) + (self%previous(2)%t(t=t) * (Dt * 2._R_P)) + if (self%is_filtered) then + self%filter = (self%previous(1) - (self%previous(2) * 2._R_P) + U) * self%nu * 0.5_R_P + self%previous(2) = self%previous(2) + (self%filter * self%alpha) + U = U + (self%filter * (self%alpha - 1._R_P)) + endif + if (self%autoupdate) call self%update_previous(U=U, previous=self%previous) endsubroutine integrate subroutine integrate_fast(self, U, Dt, t) !< Integrate field with leapfrog class scheme, fast mode. - !< - !< @note This method uses integrand previous-steps-buffer stored inside integrator. class(integrator_leapfrog), intent(inout) :: self !< Integrator. class(integrand_object), intent(inout) :: U !< Field to be integrated. real(R_P), intent(in) :: Dt !< Time step. real(R_P), intent(in) :: t !< Time. - call self%integrate_ub_fast(U=U, previous=self%previous, Dt=Dt, t=t) - endsubroutine integrate_fast - - subroutine integrate_ub(self, U, previous, Dt, t) - !< Integrate field with leapfrog class scheme, unbuffered. - class(integrator_leapfrog), intent(inout) :: self !< Integrator. - class(integrand_object), intent(inout) :: U !< Field to be integrated. - class(integrand_object), intent(inout) :: previous(1:) !< Previous time steps solutions of integrand field. - real(R_P), intent(in) :: Dt !< Time step. - real(R_P), intent(in) :: t !< Time. - - U = previous(1) + (previous(2)%t(t=t) * (Dt * 2._R_P)) - if (self%is_filtered) then - self%filter = (previous(1) - (previous(2) * 2._R_P) + U) * self%nu * 0.5_R_P - previous(2) = previous(2) + (self%filter * self%alpha) - U = U + (self%filter * (self%alpha - 1._R_P)) - endif - if (self%autoupdate) call self%update_previous(U=U, previous=previous) - endsubroutine integrate_ub - - subroutine integrate_ub_fast(self, U, previous, Dt, t) - !< Integrate field with leapfrog class scheme, unbuffered, fast mode. - class(integrator_leapfrog), intent(inout) :: self !< Integrator. - class(integrand_object), intent(inout) :: U !< Field to be integrated. - class(integrand_object), intent(inout) :: previous(1:) !< Previous time steps solutions of integrand field. - real(R_P), intent(in) :: Dt !< Time step. - real(R_P), intent(in) :: t !< Time. - - self%buffer = previous(2) + self%buffer = self%previous(2) call self%buffer%t_fast(t=t) call self%buffer%multiply_fast(lhs=self%buffer, rhs=Dt * 2._R_P) - call U%add_fast(lhs=previous(1), rhs=self%buffer) + call U%add_fast(lhs=self%previous(1), rhs=self%buffer) if (self%is_filtered) then - call self%buffer%multiply_fast(lhs=previous(2), rhs=2._R_P) - call self%buffer%subtract_fast(lhs=previous(1), rhs=self%buffer) + call self%buffer%multiply_fast(lhs=self%previous(2), rhs=2._R_P) + call self%buffer%subtract_fast(lhs=self%previous(1), rhs=self%buffer) call self%buffer%add_fast(lhs=self%buffer, rhs=U) call self%filter%multiply_fast(lhs=self%buffer, rhs=self%nu * 0.5_R_P) call self%buffer%multiply_fast(lhs=self%filter, rhs=self%alpha) - call previous(2)%add_fast(lhs=previous(2), rhs=self%buffer) + call self%previous(2)%add_fast(lhs=self%previous(2), rhs=self%buffer) call self%buffer%multiply_fast(lhs=self%filter, rhs=self%alpha - 1._R_P) call U%add_fast(lhs=U, rhs=self%buffer) endif - if (self%autoupdate) call self%update_previous(U=U, previous=previous) - endsubroutine integrate_ub_fast + if (self%autoupdate) call self%update_previous(U=U, previous=self%previous) + endsubroutine integrate_fast elemental function is_supported(self, scheme) !< Return .true. if the integrator class support the given scheme. diff --git a/src/lib/foodie_integrator_lmm_ssp.f90 b/src/lib/foodie_integrator_lmm_ssp.f90 index 1063d5d4..4545d4ff 100644 --- a/src/lib/foodie_integrator_lmm_ssp.f90 +++ b/src/lib/foodie_integrator_lmm_ssp.f90 @@ -62,8 +62,6 @@ module foodie_integrator_lmm_ssp procedure, pass(lhs) :: integr_assign_integr !< Operator `=`. procedure, pass(self) :: integrate !< Integrate integrand field. procedure, pass(self) :: integrate_fast !< Integrate integrand field, fast mode. - procedure, pass(self) :: integrate_ub !< Integrate integrand field, unbuffered. - procedure, pass(self) :: integrate_ub_fast !< Integrate integrand field, fast mode, unbuffered. procedure, pass(self) :: is_supported !< Return .true. if the integrator class support the given scheme. procedure, pass(self) :: supported_schemes !< Return the list of supported schemes. ! public methods @@ -124,69 +122,43 @@ pure subroutine integr_assign_integr(lhs, rhs) subroutine integrate(self, U, Dt, t) !< Integrate field with LMM-SSP class scheme. - !< - !< @note This method uses integrand previous-steps-buffer stored inside integrator. class(integrator_lmm_ssp), intent(inout) :: self !< Integrator. class(integrand_object), intent(inout) :: U !< Field to be integrated. real(R_P), intent(in) :: Dt !< Time step. real(R_P), intent(in) :: t !< Time. + integer(I_P) :: s !< Steps counter. - call self%integrate_ub(U=U, previous=self%previous, Dt=Dt, t=t) + U = U * 0._R_P + do s=1, self%steps + if (self%a(s) /= 0._R_P) U = U + (self%previous(s) * self%a(s)) + if (self%b(s) /= 0._R_P) U = U + (self%previous(s)%t(t=self%t(s)) * (Dt * self%b(s))) + enddo + if (self%autoupdate) call self%update_previous(U=U, previous=self%previous, Dt=Dt, t=t, previous_t=self%t) endsubroutine integrate subroutine integrate_fast(self, U, Dt, t) !< Integrate field with LMM-SSP class scheme, fast mode. - !< - !< @note This method uses integrand previous-steps-buffer stored inside integrator. class(integrator_lmm_ssp), intent(inout) :: self !< Integrator. class(integrand_object), intent(inout) :: U !< Field to be integrated. real(R_P), intent(in) :: Dt !< Time step. real(R_P), intent(in) :: t !< Time. - - call self%integrate_ub_fast(U=U, previous=self%previous, Dt=Dt, t=t) - endsubroutine integrate_fast - - subroutine integrate_ub(self, U, previous, Dt, t) - !< Integrate field with LMM-SSP class scheme, unbuffered. - class(integrator_lmm_ssp), intent(inout) :: self !< Integrator. - class(integrand_object), intent(inout) :: U !< Field to be integrated. - class(integrand_object), intent(inout) :: previous(1:) !< Integrand. - real(R_P), intent(in) :: Dt !< Time step. - real(R_P), intent(in) :: t !< Time. - integer(I_P) :: s !< Steps counter. - - U = U * 0._R_P - do s=1, self%steps - if (self%a(s) /= 0._R_P) U = U + (previous(s) * self%a(s)) - if (self%b(s) /= 0._R_P) U = U + (previous(s)%t(t=self%t(s)) * (Dt * self%b(s))) - enddo - if (self%autoupdate) call self%update_previous(U=U, previous=previous, Dt=Dt, t=t, previous_t=self%t) - endsubroutine integrate_ub - - subroutine integrate_ub_fast(self, U, previous, Dt, t) - !< Integrate field with LMM-SSP class scheme, unbuffered, fast mode. - class(integrator_lmm_ssp), intent(inout) :: self !< Integrator. - class(integrand_object), intent(inout) :: U !< Field to be integrated. - class(integrand_object), intent(inout) :: previous(1:) !< Integrand. - real(R_P), intent(in) :: Dt !< Time step. - real(R_P), intent(in) :: t !< Time. - integer(I_P) :: s !< Steps counter. + integer(I_P) :: s !< Steps counter. call U%multiply_fast(lhs=U, rhs=0._R_P) do s=1, self%steps if (self%a(s) /= 0._R_P) then - call self%buffer%multiply_fast(lhs=previous(s), rhs=self%a(s)) + call self%buffer%multiply_fast(lhs=self%previous(s), rhs=self%a(s)) call U%add_fast(lhs=U, rhs=self%buffer) endif if (self%b(s) /= 0._R_P) then - self%buffer = previous(s) + self%buffer = self%previous(s) call self%buffer%t_fast(t=self%t(s)) call self%buffer%multiply_fast(lhs=self%buffer, rhs=Dt * self%b(s)) call U%add_fast(lhs=U, rhs=self%buffer) endif enddo - if (self%autoupdate) call self%update_previous(U=U, previous=previous, Dt=Dt, t=t, previous_t=self%t) - endsubroutine integrate_ub_fast + if (self%autoupdate) call self%update_previous(U=U, previous=self%previous, Dt=Dt, t=t, previous_t=self%t) + endsubroutine integrate_fast elemental function is_supported(self, scheme) !< Return .true. if the integrator class support the given scheme. diff --git a/src/lib/foodie_integrator_lmm_ssp_vss.f90 b/src/lib/foodie_integrator_lmm_ssp_vss.f90 index d09abe7d..25f86221 100644 --- a/src/lib/foodie_integrator_lmm_ssp_vss.f90 +++ b/src/lib/foodie_integrator_lmm_ssp_vss.f90 @@ -72,8 +72,6 @@ module foodie_integrator_lmm_ssp_vss procedure, pass(lhs) :: integr_assign_integr !< Operator `=`. procedure, pass(self) :: integrate !< Integrate integrand field. procedure, pass(self) :: integrate_fast !< Integrate integrand field, fast mode. - procedure, pass(self) :: integrate_ub !< Integrate integrand field, unbuffered. - procedure, pass(self) :: integrate_ub_fast !< Integrate integrand field, unbuffered, fast mode. procedure, pass(self) :: is_supported !< Return .true. if the integrator class support the given scheme. procedure, pass(self) :: supported_schemes !< Return the list of supported schemes. ! public methods @@ -88,25 +86,22 @@ module foodie_integrator_lmm_ssp_vss abstract interface !< Abstract interfaces of [[integrator_lmm_ssp_vss]] methods. - subroutine integrate_interface(self, U, previous, Dt, t) + subroutine integrate_interface(self, U, Dt, t) !< Integrate field with LMM-SSP class scheme. import :: integrand_object, integrator_lmm_ssp_vss, R_P - class(integrator_lmm_ssp_vss), intent(inout) :: self !< Integrator. - class(integrand_object), intent(inout) :: U !< Field to be integrated. - class(integrand_object), intent(inout) :: previous(1:) !< Previous time steps solutions of integrand field. - real(R_P), intent(in) :: Dt !< Time step. - real(R_P), intent(in) :: t !< Time. + class(integrator_lmm_ssp_vss), intent(inout) :: self !< Integrator. + class(integrand_object), intent(inout) :: U !< Field to be integrated. + real(R_P), intent(in) :: Dt !< Time step. + real(R_P), intent(in) :: t !< Time. endsubroutine integrate_interface - subroutine integrate_fast_interface(self, U, previous, buffer, Dt, t) + subroutine integrate_fast_interface(self, U, Dt, t) !< Integrate field with LMM-SSP class scheme. import :: integrand_object, integrator_lmm_ssp_vss, R_P - class(integrator_lmm_ssp_vss), intent(inout) :: self !< Integrator. - class(integrand_object), intent(inout) :: U !< Field to be integrated. - class(integrand_object), intent(inout) :: previous(1:) !< Previous time steps solutions of integrand field. - class(integrand_object), intent(inout) :: buffer !< Temporary buffer for doing fast operation. - real(R_P), intent(in) :: Dt !< Time step. - real(R_P), intent(in) :: t !< Time. + class(integrator_lmm_ssp_vss), intent(inout) :: self !< Integrator. + class(integrand_object), intent(inout) :: U !< Field to be integrated. + real(R_P), intent(in) :: Dt !< Time step. + real(R_P), intent(in) :: t !< Time. endsubroutine integrate_fast_interface endinterface @@ -166,7 +161,7 @@ subroutine integrate(self, U, Dt, t) real(R_P), intent(in) :: Dt !< Time step. real(R_P), intent(in) :: t !< Time. - call self%integrate_(U=U, previous=self%previous, Dt=Dt, t=t) + call self%integrate_(U=U, Dt=Dt, t=t) endsubroutine integrate subroutine integrate_fast(self, U, Dt, t) @@ -176,31 +171,9 @@ subroutine integrate_fast(self, U, Dt, t) real(R_P), intent(in) :: Dt !< Time step. real(R_P), intent(in) :: t !< Time. - call self%integrate_fast_(U=U, previous=self%previous, buffer=self%buffer, Dt=Dt, t=t) + call self%integrate_fast_(U=U, Dt=Dt, t=t) endsubroutine integrate_fast - subroutine integrate_ub(self, U, previous, Dt, t) - !< Integrate field with LMM-SSP class scheme, unbuffered. - class(integrator_lmm_ssp_vss), intent(inout) :: self !< Integrator. - class(integrand_object), intent(inout) :: U !< Field to be integrated. - class(integrand_object), intent(inout) :: previous(1:) !< Previous time steps solutions of integrand field. - real(R_P), intent(in) :: Dt !< Time step. - real(R_P), intent(in) :: t !< Time. - - call self%integrate_(U=U, previous=previous, Dt=Dt, t=t) - endsubroutine integrate_ub - - subroutine integrate_ub_fast(self, U, previous, Dt, t) - !< Integrate field with LMM-SSP class scheme, unbuffered, fast mode. - class(integrator_lmm_ssp_vss), intent(inout) :: self !< Integrator. - class(integrand_object), intent(inout) :: U !< Field to be integrated. - class(integrand_object), intent(inout) :: previous(1:) !< Previous time steps solutions of integrand field. - real(R_P), intent(in) :: Dt !< Time step. - real(R_P), intent(in) :: t !< Time. - - call self%integrate_fast_(U=U, previous=previous, buffer=self%buffer, Dt=Dt, t=t) - endsubroutine integrate_ub_fast - elemental function is_supported(self, scheme) !< Return .true. if the integrator class support the given scheme. class(integrator_lmm_ssp_vss), intent(in) :: self !< Integrator. @@ -281,87 +254,81 @@ subroutine initialize(self, scheme, autoupdate, U, stop_on_fail) endsubroutine initialize ! private methods - subroutine integrate_order_2(self, U, previous, Dt, t) + subroutine integrate_order_2(self, U, Dt, t) !< Integrate field with LMM-SSP-VSS 2nd order class scheme. - class(integrator_lmm_ssp_vss), intent(inout) :: self !< Integrator. - class(integrand_object), intent(inout) :: U !< Field to be integrated. - class(integrand_object), intent(inout) :: previous(1:) !< Previous time steps solutions of integrand field. - real(R_P), intent(in) :: Dt !< Time step. - real(R_P), intent(in) :: t !< Time. - real(R_P) :: omega_ !< Omega coefficient. - real(R_P) :: omega_sq !< Square of omega coefficient. + class(integrator_lmm_ssp_vss), intent(inout) :: self !< Integrator. + class(integrand_object), intent(inout) :: U !< Field to be integrated. + real(R_P), intent(in) :: Dt !< Time step. + real(R_P), intent(in) :: t !< Time. + real(R_P) :: omega_ !< Omega coefficient. + real(R_P) :: omega_sq !< Square of omega coefficient. omega_ = omega(Dt=self%Dt, s=self%steps-1) omega_sq = omega_ * omega_ - U = (previous(1) * (1._R_P / omega_sq)) + (previous(self%steps) * ((omega_sq - 1._R_P) / omega_sq)) + & - (previous(self%steps)%t(t=self%t(self%steps)) * (self%Dt(self%steps) * (omega_ + 1._R_P) / omega_)) - if (self%autoupdate) call self%update_previous(U=U, previous=previous, Dt=Dt, t=t, previous_Dt=self%Dt, previous_t=self%t) + U = (self%previous(1) * (1._R_P / omega_sq)) + (self%previous(self%steps) * ((omega_sq - 1._R_P) / omega_sq)) + & + (self%previous(self%steps)%t(t=self%t(self%steps)) * (self%Dt(self%steps) * (omega_ + 1._R_P) / omega_)) + if (self%autoupdate) call self%update_previous(U=U, previous=self%previous, Dt=Dt, t=t, previous_Dt=self%Dt, previous_t=self%t) endsubroutine integrate_order_2 - subroutine integrate_order_3(self, U, previous, Dt, t) + subroutine integrate_order_3(self, U, Dt, t) !< Integrate field with LMM-SSP-VSS 3rd order class scheme. - class(integrator_lmm_ssp_vss), intent(inout) :: self !< Integrator. - class(integrand_object), intent(inout) :: U !< Field to be integrated. - class(integrand_object), intent(inout) :: previous(1:) !< Previous time steps solutions of integrand field. - real(R_P), intent(in) :: Dt !< Time step. - real(R_P), intent(in) :: t !< Time. - real(R_P) :: omega_ !< Omega coefficient. + class(integrator_lmm_ssp_vss), intent(inout) :: self !< Integrator. + class(integrand_object), intent(inout) :: U !< Field to be integrated. + real(R_P), intent(in) :: Dt !< Time step. + real(R_P), intent(in) :: t !< Time. + real(R_P) :: omega_ !< Omega coefficient. omega_= omega(Dt=self%Dt, s=self%steps-1) - U = (previous(1) * ((3._R_P * omega_ + 2._R_P) / omega_ ** 3 )) + & - (previous(self%steps) * (((omega_ + 1._R_P) ** 2) * (omega_ - 2._R_P) / omega_ ** 3)) + & - (previous(1)%t(t=self%t(1)) * (self%Dt(self%steps) * (omega_ + 1._R_P) / omega_ ** 2)) + & - (previous(self%steps)%t(t=self%t(self%steps)) * (self%Dt(self%steps) * (omega_ + 1._R_P) ** 2 / omega_ ** 2)) - if (self%autoupdate) call self%update_previous(U=U, previous=previous, Dt=Dt, t=t, previous_Dt=self%Dt, previous_t=self%t) + U = (self%previous(1) * ((3._R_P * omega_ + 2._R_P) / omega_ ** 3 )) + & + (self%previous(self%steps) * (((omega_ + 1._R_P) ** 2) * (omega_ - 2._R_P) / omega_ ** 3)) + & + (self%previous(1)%t(t=self%t(1)) * (self%Dt(self%steps) * (omega_ + 1._R_P) / omega_ ** 2)) + & + (self%previous(self%steps)%t(t=self%t(self%steps)) * (self%Dt(self%steps) * (omega_ + 1._R_P) ** 2 / omega_ ** 2)) + if (self%autoupdate) call self%update_previous(U=U, previous=self%previous, Dt=Dt, t=t, previous_Dt=self%Dt, previous_t=self%t) endsubroutine integrate_order_3 - subroutine integrate_order_2_fast(self, U, previous, buffer, Dt, t) - !< Integrate field with LMM-SSP-VSS 2nd order class scheme. - class(integrator_lmm_ssp_vss), intent(inout) :: self !< Integrator. - class(integrand_object), intent(inout) :: U !< Field to be integrated. - class(integrand_object), intent(inout) :: previous(1:) !< Previous time steps solutions of integrand field. - class(integrand_object), intent(inout) :: buffer !< Temporary buffer for doing fast operation. - real(R_P), intent(in) :: Dt !< Time step. - real(R_P), intent(in) :: t !< Time. - real(R_P) :: omega_ !< Omega coefficient. - real(R_P) :: omega_sq !< Square of omega coefficient. + subroutine integrate_order_2_fast(self, U, Dt, t) + !< Integrate field with LMM-SSP-VSS 2nd order class scheme, fast mode. + class(integrator_lmm_ssp_vss), intent(inout) :: self !< Integrator. + class(integrand_object), intent(inout) :: U !< Field to be integrated. + real(R_P), intent(in) :: Dt !< Time step. + real(R_P), intent(in) :: t !< Time. + real(R_P) :: omega_ !< Omega coefficient. + real(R_P) :: omega_sq !< Square of omega coefficient. omega_ = omega(Dt=self%Dt, s=self%steps-1) omega_sq = omega_ * omega_ - call U%multiply_fast(lhs=previous(1), rhs=1._R_P / omega_sq) - call buffer%multiply_fast(lhs=previous(self%steps), rhs=(omega_sq - 1._R_P) / omega_sq) - call U%add_fast(lhs=U, rhs=buffer) - buffer = previous(self%steps) - call buffer%t_fast(t=self%t(self%steps)) - call buffer%multiply_fast(lhs=buffer, rhs=self%Dt(self%steps) * (omega_ + 1._R_P) / omega_) - call U%add_fast(lhs=U, rhs=buffer) - if (self%autoupdate) call self%update_previous(U=U, previous=previous, Dt=Dt, t=t, previous_Dt=self%Dt, previous_t=self%t) + call U%multiply_fast(lhs=self%previous(1), rhs=1._R_P / omega_sq) + call self%buffer%multiply_fast(lhs=self%previous(self%steps), rhs=(omega_sq - 1._R_P) / omega_sq) + call U%add_fast(lhs=U, rhs=self%buffer) + self%buffer = self%previous(self%steps) + call self%buffer%t_fast(t=self%t(self%steps)) + call self%buffer%multiply_fast(lhs=self%buffer, rhs=self%Dt(self%steps) * (omega_ + 1._R_P) / omega_) + call U%add_fast(lhs=U, rhs=self%buffer) + if (self%autoupdate) call self%update_previous(U=U, previous=self%previous, Dt=Dt, t=t, previous_Dt=self%Dt, previous_t=self%t) endsubroutine integrate_order_2_fast - subroutine integrate_order_3_fast(self, U, previous, buffer, Dt, t) + subroutine integrate_order_3_fast(self, U, Dt, t) !< Integrate field with LMM-SSP-VSS 3rd order class scheme, fast mode. - class(integrator_lmm_ssp_vss), intent(inout) :: self !< Integrator. - class(integrand_object), intent(inout) :: U !< Field to be integrated. - class(integrand_object), intent(inout) :: previous(1:) !< Previous time steps solutions of integrand field. - class(integrand_object), intent(inout) :: buffer !< Temporary buffer for doing fast operation. - real(R_P), intent(in) :: Dt !< Time step. - real(R_P), intent(in) :: t !< Time. - real(R_P) :: omega_ !< Omega coefficient. + class(integrator_lmm_ssp_vss), intent(inout) :: self !< Integrator. + class(integrand_object), intent(inout) :: U !< Field to be integrated. + real(R_P), intent(in) :: Dt !< Time step. + real(R_P), intent(in) :: t !< Time. + real(R_P) :: omega_ !< Omega coefficient. omega_= omega(Dt=self%Dt, s=self%steps-1) - call U%multiply_fast(lhs=previous(1), rhs=(3._R_P * omega_ + 2._R_P) / (omega_ ** 3)) - call buffer%multiply_fast(lhs=previous(self%steps), rhs=(((omega_ + 1._R_P) ** 2) * (omega_ - 2._R_P) / (omega_ ** 3))) - call U%add_fast(lhs=U, rhs=buffer) - buffer = previous(1) - call buffer%t_fast(t=self%t(1)) - call buffer%multiply_fast(lhs=buffer, rhs=self%Dt(self%steps) * (omega_ + 1._R_P) / (omega_ ** 2)) - call U%add_fast(lhs=U, rhs=buffer) - buffer = previous(self%steps) - call buffer%t_fast(t=self%t(self%steps)) - call buffer%multiply_fast(lhs=buffer, rhs=(self%Dt(self%steps) * (omega_ + 1._R_P) ** 2 / (omega_ ** 2))) - call U%add_fast(lhs=U, rhs=buffer) - if (self%autoupdate) call self%update_previous(U=U, previous=previous, Dt=Dt, t=t, previous_Dt=self%Dt, previous_t=self%t) + call U%multiply_fast(lhs=self%previous(1), rhs=(3._R_P * omega_ + 2._R_P) / (omega_ ** 3)) + call self%buffer%multiply_fast(lhs=self%previous(self%steps), rhs=(((omega_ + 1._R_P) ** 2) * (omega_ - 2._R_P) / (omega_ ** 3))) + call U%add_fast(lhs=U, rhs=self%buffer) + self%buffer = self%previous(1) + call self%buffer%t_fast(t=self%t(1)) + call self%buffer%multiply_fast(lhs=self%buffer, rhs=self%Dt(self%steps) * (omega_ + 1._R_P) / (omega_ ** 2)) + call U%add_fast(lhs=U, rhs=self%buffer) + self%buffer = self%previous(self%steps) + call self%buffer%t_fast(t=self%t(self%steps)) + call self%buffer%multiply_fast(lhs=self%buffer, rhs=(self%Dt(self%steps) * (omega_ + 1._R_P) ** 2 / (omega_ ** 2))) + call U%add_fast(lhs=U, rhs=self%buffer) + if (self%autoupdate) call self%update_previous(U=U, previous=self%previous, Dt=Dt, t=t, previous_Dt=self%Dt, previous_t=self%t) endsubroutine integrate_order_3_fast ! private non TBP diff --git a/src/lib/foodie_integrator_multistep_object.f90 b/src/lib/foodie_integrator_multistep_object.f90 index b4e24e50..58312603 100644 --- a/src/lib/foodie_integrator_multistep_object.f90 +++ b/src/lib/foodie_integrator_multistep_object.f90 @@ -24,11 +24,8 @@ module foodie_integrator_multistep_object class(integrand_object), allocatable :: buffer !< Buffer used for fast integration. contains ! deferred methods - procedure(integrate_interface), pass(self), deferred :: integrate !< Integrate integrand field. - procedure(integrate_fast_interface), pass(self), deferred :: integrate_fast !< Integrate integrand field, fast mode. - procedure(integrate_ub_interface), pass(self), deferred :: integrate_ub !< Integrate integrand field, unbuffered. - procedure(integrate_ub_fast_interface), pass(self), deferred :: integrate_ub_fast !< Integrate integrand field, fast mode, - !< unbuffered. + procedure(integrate_interface), pass(self), deferred :: integrate !< Integrate integrand field. + procedure(integrate_fast_interface), pass(self), deferred :: integrate_fast !< Integrate integrand field, fast mode. ! implemented deferred methods of parent procedure, pass(self) :: is_multistage !< Return .true. for multistage integrator. procedure, pass(self) :: is_multistep !< Return .true. for multistep integrator. @@ -45,8 +42,6 @@ module foodie_integrator_multistep_object !< Abstract interfaces of deferred methods of [[integrator_multistep_object]]. subroutine integrate_interface(self, U, Dt, t) !< Integrate integrand field. - !< - !< @note This method uses integrand previous-steps-buffer stored inside integrator. import :: integrand_object, integrator_multistep_object, R_P class(integrator_multistep_object), intent(inout) :: self !< Integrator. class(integrand_object), intent(inout) :: U !< Integrand. @@ -56,34 +51,12 @@ subroutine integrate_interface(self, U, Dt, t) subroutine integrate_fast_interface(self, U, Dt, t) !< Integrate integrand field, fast mode. - !< - !< @note This method uses integrand previous-steps-buffer stored inside integrator. import :: integrand_object, integrator_multistep_object, R_P class(integrator_multistep_object), intent(inout) :: self !< Integrator. class(integrand_object), intent(inout) :: U !< Field to be integrated. real(R_P), intent(in) :: Dt !< Time steps. real(R_P), intent(in) :: t !< Times. endsubroutine integrate_fast_interface - - subroutine integrate_ub_interface(self, U, previous, Dt, t) - !< Integrate integrand field, unbuffered. - import :: integrand_object, integrator_multistep_object, R_P - class(integrator_multistep_object), intent(inout) :: self !< Integrator. - class(integrand_object), intent(inout) :: U !< Integrand. - class(integrand_object), intent(inout) :: previous(1:) !< Integrand. - real(R_P), intent(in) :: Dt !< Time steps. - real(R_P), intent(in) :: t !< Times. - endsubroutine integrate_ub_interface - - subroutine integrate_ub_fast_interface(self, U, previous, Dt, t) - !< Integrate integrand field, unbuffered, fast mode. - import :: integrand_object, integrator_multistep_object, R_P - class(integrator_multistep_object), intent(inout) :: self !< Integrator. - class(integrand_object), intent(inout) :: U !< Field to be integrated. - class(integrand_object), intent(inout) :: previous(1:) !< Integrand. - real(R_P), intent(in) :: Dt !< Time steps. - real(R_P), intent(in) :: t !< Times. - endsubroutine integrate_ub_fast_interface endinterface contains diff --git a/src/tests/tester/foodie_tester.f90 b/src/tests/tester/foodie_tester.f90 index 9c5af73c..90836012 100644 --- a/src/tests/tester/foodie_tester.f90 +++ b/src/tests/tester/foodie_tester.f90 @@ -326,7 +326,12 @@ subroutine integrate(scheme, integrand_0, Dt, final_time, iterations, stages, is ! enddo endselect - if (save_results) call integrand%export_tecplot(t=time, scheme=scheme) + select type(integrand) + type is(integrand_ladvection) + if (save_results .and. mod(step, save_frequency)==0) call integrand%export_tecplot(t=time, scheme=scheme) + type is(integrand_oscillation) + if (save_results .and. mod(step, save_frequency)==0) call integrand%export_tecplot(t=time) + endselect if (save_results) call integrand%export_tecplot(close_file=.true.) contains subroutine integrand_export_tecplot From c50c848d6a9f8c0df4a630e5ad5bf107df821337 Mon Sep 17 00:00:00 2001 From: Stefano Zaghi Date: Fri, 26 May 2017 14:23:24 +0200 Subject: [PATCH 23/25] restore adams bashforth moulton --- ...die_integrator_adams_bashforth_moulton.f90 | 48 ++++++++++++------- 1 file changed, 32 insertions(+), 16 deletions(-) diff --git a/src/lib/foodie_integrator_adams_bashforth_moulton.f90 b/src/lib/foodie_integrator_adams_bashforth_moulton.f90 index bdeea5c6..caaaac6d 100644 --- a/src/lib/foodie_integrator_adams_bashforth_moulton.f90 +++ b/src/lib/foodie_integrator_adams_bashforth_moulton.f90 @@ -191,14 +191,22 @@ subroutine integrate(self, U, Dt, t) class(integrand_object), intent(inout) :: U !< Field to be integrated. real(R_P), intent(in) :: Dt !< Time steps. real(R_P), intent(in) :: t !< Times. + integer(I_P) :: s !< Step counter. - ! self%predictor%t = self%t(1:self%steps) - ! self%predictor%Dt = self%Dt(1:self%steps) - ! self%corrector%t = self%t(1:self%steps) - ! self%corrector%Dt = self%Dt(1:self%steps) - ! call self%predictor%integrate_ub(U=U, previous=previous, Dt=Dt, t=t) - ! call self%corrector%integrate_ub(U=U, previous=previous(2:), Dt=Dt, t=t) - ! if (self%autoupdate) call self%update_previous(U=U, previous=previous(1:self%steps), Dt=Dt, t=t, previous_t=self%t(1:self%steps)) + do s=1, self%steps + self%predictor%previous(s) = self%previous(s) + enddo + self%predictor%t(:) = self%t(1:self%steps) + self%predictor%Dt(:) = self%Dt(1:self%steps) + do s=1, self%steps - 1 + self%corrector%previous(s) = self%previous(s+1) + enddo + self%corrector%t(:) = self%t(2:self%steps) + self%corrector%Dt(:) = self%Dt(2:self%steps) + call self%predictor%integrate(U=U, Dt=Dt, t=t) + call self%corrector%integrate(U=U, Dt=Dt, t=t) + if (self%autoupdate) & + call self%update_previous(U=U, previous=self%previous(1:self%steps), Dt=Dt, t=t, previous_t=self%t(1:self%steps)) endsubroutine integrate subroutine integrate_fast(self, U, Dt, t) @@ -207,14 +215,22 @@ subroutine integrate_fast(self, U, Dt, t) class(integrand_object), intent(inout) :: U !< Field to be integrated. real(R_P), intent(in) :: Dt !< Time steps. real(R_P), intent(in) :: t !< Times. + integer(I_P) :: s !< Step counter. - ! self%predictor%t = self%t - ! self%predictor%Dt = self%Dt - ! self%corrector%t = self%t - ! self%corrector%Dt = self%Dt - ! call self%predictor%integrate_ub_fast(U=U, previous=previous, Dt=Dt, t=t) - ! call self%corrector%integrate_ub_fast(U=U, previous=previous(2:), Dt=Dt, t=t) - ! if (self%autoupdate) call self%update_previous(U=U, previous=previous(1:self%steps), Dt=Dt, t=t, previous_t=self%t(1:self%steps)) + do s=1, self%steps + self%predictor%previous(s) = self%previous(s) + enddo + self%predictor%t(:) = self%t(1:self%steps) + self%predictor%Dt(:) = self%Dt(1:self%steps) + do s=1, self%steps - 1 + self%corrector%previous(s) = self%previous(s+1) + enddo + self%corrector%t(:) = self%t(2:self%steps) + self%corrector%Dt(:) = self%Dt(2:self%steps) + call self%predictor%integrate_fast(U=U, Dt=Dt, t=t) + call self%corrector%integrate_fast(U=U, Dt=Dt, t=t) + if (self%autoupdate) & + call self%update_previous(U=U, previous=self%previous(1:self%steps), Dt=Dt, t=t, previous_t=self%t(1:self%steps)) endsubroutine integrate_fast elemental function is_supported(self, scheme) @@ -271,8 +287,8 @@ subroutine initialize(self, scheme, iterations, autoupdate, U, stop_on_fail) schemes_am = self%corrector%supported_schemes() self%autoupdate = .true. ; if (present(autoupdate)) self%autoupdate = autoupdate self%iterations = 1 ; if (present(iterations)) self%iterations = iterations - call self%predictor%initialize(scheme=schemes_ab(scheme_number_), autoupdate=.false.) - call self%corrector%initialize(scheme=schemes_am(scheme_number_), iterations=self%iterations, autoupdate=.false.) + call self%predictor%initialize(scheme=schemes_ab(scheme_number_), U=U, autoupdate=.false.) + call self%corrector%initialize(scheme=schemes_am(scheme_number_), U=U, iterations=self%iterations, autoupdate=.false.) self%steps = self%predictor%steps_number() self%registers = self%steps + 1 if (present(U)) call self%allocate_integrand_members(U=U) From f806e9d48ff4169427498301ae8ea6a8c24d9ba9 Mon Sep 17 00:00:00 2001 From: Stefano Zaghi Date: Fri, 26 May 2017 16:12:38 +0200 Subject: [PATCH 24/25] restore all integrators, work on oscillation --- src/lib/foodie.f90 | 4 +- ...die_integrator_adams_bashforth_moulton.f90 | 14 +- .../foodie_integrator_ms_runge_kutta_ssp.f90 | 330 +++++++----------- ...integrator_multistage_multistep_object.f90 | 213 +++++++++++ .../foodie_integrator_multistep_object.f90 | 2 +- ...die_integrator_runge_kutta_low_storage.f90 | 1 - src/tests/tester/foodie_tester.f90 | 83 ++--- 7 files changed, 401 insertions(+), 246 deletions(-) create mode 100644 src/lib/foodie_integrator_multistage_multistep_object.f90 diff --git a/src/lib/foodie.f90 b/src/lib/foodie.f90 index 6c02e5fe..c32c7b91 100644 --- a/src/lib/foodie.f90 +++ b/src/lib/foodie.f90 @@ -75,6 +75,7 @@ module foodie use foodie_integrator_lmm_ssp_vss, only : integrator_lmm_ssp_vss use foodie_integrator_ms_runge_kutta_ssp, only : integrator_ms_runge_kutta_ssp use foodie_integrator_multistage_object, only : integrator_multistage_object +use foodie_integrator_multistage_multistep_object, only : integrator_multistage_multistep_object use foodie_integrator_multistep_object, only : integrator_multistep_object use foodie_integrator_runge_kutta_emd, only : integrator_runge_kutta_emd use foodie_integrator_runge_kutta_low_storage, only : integrator_runge_kutta_ls @@ -95,6 +96,7 @@ module foodie public :: integrand_object public :: integrator_object public :: integrator_multistage_object +public :: integrator_multistage_multistep_object public :: integrator_multistep_object ! concrete objects public :: integrator_adams_bashforth @@ -225,7 +227,7 @@ subroutine foodie_integrator_factory(scheme, integrator, stages, tolerance, nu, allocate(integrator_ms_runge_kutta_ssp :: integrator) select type(integrator) type is(integrator_ms_runge_kutta_ssp) - call integrator%initialize(scheme=scheme) + call integrator%initialize(scheme=scheme, iterations=iterations, autoupdate=autoupdate, U=U) endselect elseif (index(trim(adjustl(scheme)), trim(int_runge_kutta_emd%class_name())) > 0) then allocate(integrator_runge_kutta_emd :: integrator) diff --git a/src/lib/foodie_integrator_adams_bashforth_moulton.f90 b/src/lib/foodie_integrator_adams_bashforth_moulton.f90 index caaaac6d..367c37d1 100644 --- a/src/lib/foodie_integrator_adams_bashforth_moulton.f90 +++ b/src/lib/foodie_integrator_adams_bashforth_moulton.f90 @@ -195,18 +195,18 @@ subroutine integrate(self, U, Dt, t) do s=1, self%steps self%predictor%previous(s) = self%previous(s) + self%predictor%t(s) = self%t(s) + self%predictor%Dt(s) = self%Dt(s) enddo - self%predictor%t(:) = self%t(1:self%steps) - self%predictor%Dt(:) = self%Dt(1:self%steps) do s=1, self%steps - 1 - self%corrector%previous(s) = self%previous(s+1) + self%corrector%previous(s) = self%predictor%previous(s+1) + self%corrector%t(s) = self%predictor%t(s+1) + self%corrector%Dt(s) = self%predictor%Dt(s+1) enddo - self%corrector%t(:) = self%t(2:self%steps) - self%corrector%Dt(:) = self%Dt(2:self%steps) call self%predictor%integrate(U=U, Dt=Dt, t=t) call self%corrector%integrate(U=U, Dt=Dt, t=t) if (self%autoupdate) & - call self%update_previous(U=U, previous=self%previous(1:self%steps), Dt=Dt, t=t, previous_t=self%t(1:self%steps)) + call self%update_previous(U=U, previous=self%previous, Dt=Dt, t=t, previous_t=self%t) endsubroutine integrate subroutine integrate_fast(self, U, Dt, t) @@ -290,7 +290,7 @@ subroutine initialize(self, scheme, iterations, autoupdate, U, stop_on_fail) call self%predictor%initialize(scheme=schemes_ab(scheme_number_), U=U, autoupdate=.false.) call self%corrector%initialize(scheme=schemes_am(scheme_number_), U=U, iterations=self%iterations, autoupdate=.false.) self%steps = self%predictor%steps_number() - self%registers = self%steps + 1 + self%registers = self%steps if (present(U)) call self%allocate_integrand_members(U=U) else call self%trigger_error(error=ERROR_UNSUPPORTED_SCHEME, & diff --git a/src/lib/foodie_integrator_ms_runge_kutta_ssp.f90 b/src/lib/foodie_integrator_ms_runge_kutta_ssp.f90 index 9b649398..ab505c74 100644 --- a/src/lib/foodie_integrator_ms_runge_kutta_ssp.f90 +++ b/src/lib/foodie_integrator_ms_runge_kutta_ssp.f90 @@ -36,6 +36,7 @@ module foodie_integrator_ms_runge_kutta_ssp use foodie_error_codes, only : ERROR_UNSUPPORTED_SCHEME use foodie_integrand_object, only : integrand_object +use foodie_integrator_multistage_multistep_object, only : integrator_multistage_multistep_object use foodie_integrator_object, only : integrator_object use penf, only : I_P, R_P @@ -50,41 +51,32 @@ module foodie_integrator_ms_runge_kutta_ssp !< schemes. logical, parameter :: has_fast_mode_=.true. !< Flag to check if integrator provides *fast mode* integrate. -logical, parameter :: is_multistage_=.true. !< Flag to check if integrator is multistage. -logical, parameter :: is_multistep_=.true. !< Flag to check if integrator is multistep. -type, extends(integrator_object) :: integrator_ms_runge_kutta_ssp +type, extends(integrator_multistage_multistep_object) :: integrator_ms_runge_kutta_ssp !< FOODIE integrator: provide an explicit class of Multi-step Runge-Kutta Methods with Strong Stability Preserving property, !< from 3rd to 8th order accurate. !< !< @note The integrator must be created or initialized (initialize the *A,Ahat,B,Bhat,D,T* coefficients) before used. private - integer(I_P) :: steps=0 !< Number of time steps. - integer(I_P) :: stages=0 !< Number of stages. real(R_P), allocatable :: A(:,:) !< *A* coefficients. real(R_P), allocatable :: Ahat(:,:) !< *Ahat* coefficients. real(R_P), allocatable :: B(:) !< *B* coefficients. real(R_P), allocatable :: Bhat(:) !< *Bhat* coefficients. real(R_P), allocatable :: D(:,:) !< *D* coefficients. - real(R_P), allocatable :: T(:) !< *T* coefficients. + real(R_P), allocatable :: Q(:) !< *T* coefficients. contains ! deferred methods procedure, pass(self) :: class_name !< Return the class name of schemes. procedure, pass(self) :: description !< Return pretty-printed object description. procedure, pass(self) :: has_fast_mode !< Return .true. if the integrator class has *fast mode* integrate. procedure, pass(lhs) :: integr_assign_integr !< Operator `=`. - procedure, pass(self) :: is_multistage !< Return .true. for multistage integrator. - procedure, pass(self) :: is_multistep !< Return .true. for multistep integrator. + procedure, pass(self) :: integrate !< Integrate integrand field. + procedure, pass(self) :: integrate_fast !< Integrate integrand field, fast mode. procedure, pass(self) :: is_supported !< Return .true. if the integrator class support the given scheme. - procedure, pass(self) :: stages_number !< Return number of stages used. - procedure, pass(self) :: steps_number !< Return number of steps used. procedure, pass(self) :: supported_schemes !< Return the list of supported schemes. ! public methods - procedure, pass(self) :: destroy !< Destroy the integrator. - procedure, pass(self) :: initialize !< Initialize (create) the integrator. - procedure, pass(self) :: integrate !< Integrate integrand field. - procedure, pass(self) :: integrate_fast !< Integrate integrand field, fast mode. - procedure, pass(self) :: update_previous !< Cyclic update previous time steps. + procedure, pass(self) :: destroy !< Destroy the integrator. + procedure, pass(self) :: initialize !< Initialize (create) the integrator. endtype integrator_ms_runge_kutta_ssp contains @@ -129,35 +121,118 @@ pure subroutine integr_assign_integr(lhs, rhs) class(integrator_ms_runge_kutta_ssp), intent(inout) :: lhs !< Left hand side. class(integrator_object), intent(in) :: rhs !< Right hand side. - call lhs%assign_abstract(rhs=rhs) + call lhs%assign_multistage_multistep(rhs=rhs) select type(rhs) class is (integrator_ms_runge_kutta_ssp) - lhs%steps = rhs%steps - lhs%stages = rhs%stages - if (allocated(rhs%A )) lhs%A = rhs%A - if (allocated(rhs%Ahat)) lhs%Ahat = rhs%Ahat - if (allocated(rhs%B )) lhs%B = rhs%B - if (allocated(rhs%Bhat)) lhs%Bhat = rhs%Bhat - if (allocated(rhs%D )) lhs%D = rhs%D - if (allocated(rhs%T )) lhs%T = rhs%T + if (allocated(rhs%A )) lhs%A = rhs%A + if (allocated(rhs%Ahat)) lhs%Ahat = rhs%Ahat + if (allocated(rhs%B )) lhs%B = rhs%B + if (allocated(rhs%Bhat)) lhs%Bhat = rhs%Bhat + if (allocated(rhs%D )) lhs%D = rhs%D + if (allocated(rhs%Q )) lhs%Q = rhs%Q endselect endsubroutine integr_assign_integr - elemental function is_multistage(self) - !< Return .true. for multistage integrator. - class(integrator_ms_runge_kutta_ssp), intent(in) :: self !< Integrator. - logical :: is_multistage !< Inquire result. + subroutine integrate(self, U, Dt, t) + !< Integrate field with LMM-SSP class scheme. + class(integrator_ms_runge_kutta_ssp), intent(inout) :: self !< Integrator. + class(integrand_object), intent(inout) :: U !< Field to be integrated. + real(R_P), intent(in) :: Dt !< Time step. + real(R_P), intent(in) :: t !< Time. + integer(I_P) :: k, kk !< Stages counters. + integer(I_P) :: s !< Steps counter. - is_multistage = is_multistage_ - endfunction is_multistage + ! computing stages + self%stage(1) = U + do k=2, self%stages + self%stage(k) = U * 0._R_P + do s=1, self%steps + if (self%D(k, s) /= 0._R_P) self%stage(k) = self%stage(k) + (self%previous(s) * self%D(k, s)) + enddo + do s=1, self%steps - 1 + if (self%Ahat(k, s) /= 0._R_P) self%stage(k) = self%stage(k) + (self%previous(s)%t(t=self%t(s)) * (Dt * self%Ahat(k, s))) + enddo + do kk=1, k - 1 + if (self%A(k, kk) /= 0._R_P) self%stage(k) = self%stage(k) + (self%stage(kk)%t(t=t) * (Dt * self%A(k, kk))) + enddo + enddo + ! computing new time step + U = U * 0._R_P + do s=1, self%steps + if (self%Q(s) /= 0._R_P) U = U + (self%previous(s) * self%Q(s)) + enddo + do s=1, self%steps - 1 + if (self%Bhat(s) /= 0._R_P) U = U + (self%previous(s)%t(t=self%t(s)) * (Dt * self%Bhat(s))) + enddo + do k=1, self%stages + if (self%B(k) /= 0._R_P) U = U + (self%stage(k)%t(t=t) * (Dt * self%B(k))) + enddo + if (self%autoupdate) call self%update_previous(U=U, previous=self%previous, Dt=Dt, t=t, previous_t=self%t) + endsubroutine integrate - elemental function is_multistep(self) - !< Return .true. for multistage integrator. - class(integrator_ms_runge_kutta_ssp), intent(in) :: self !< Integrator. - logical :: is_multistep !< Inquire result. + subroutine integrate_fast(self, U, Dt, t) + !< Integrate field with LMM-SSP class scheme, fast mode. + class(integrator_ms_runge_kutta_ssp), intent(inout) :: self !< Integrator. + class(integrand_object), intent(inout) :: U !< Field to be integrated. + real(R_P), intent(in) :: Dt !< Time step. + real(R_P), intent(in) :: t !< Time. + integer(I_P) :: k, kk !< Stages counters. + integer(I_P) :: s !< Steps counter. - is_multistep = is_multistep_ - endfunction is_multistep + ! computing stages + self%stage(1) = U + do k=2, self%stages + call self%stage(k)%multiply_fast(lhs=U, rhs=0._R_P) + do s=1, self%steps + if (self%D(k, s) /= 0._R_P) then + call self%buffer%multiply_fast(lhs=self%previous(s), rhs=self%D(k, s)) + call self%stage(k)%add_fast(lhs=self%stage(k), rhs=self%buffer) + endif + enddo + do s=1, self%steps - 1 + if (self%Ahat(k, s) /= 0._R_P) then + self%buffer = self%previous(s) + call self%buffer%t_fast(t=self%t(s)) + call self%buffer%multiply_fast(lhs=self%buffer, rhs=Dt * self%Ahat(k, s)) + call self%stage(k)%add_fast(lhs=self%stage(k), rhs=self%buffer) + endif + enddo + do kk=1, k - 1 + if (self%A(k, kk) /= 0._R_P) then + self%buffer = self%stage(kk) + call self%buffer%t_fast(t=t) + call self%buffer%multiply_fast(lhs=self%buffer, rhs=Dt * self%A(k, kk)) + call self%stage(k)%add_fast(lhs=self%stage(k), rhs=self%buffer) + endif + enddo + enddo + ! computing new time step + U = U * 0._R_P + do s=1, self%steps + if (self%Q(s) /= 0._R_P) then + call self%buffer%multiply_fast(lhs=self%previous(s), rhs=self%Q(s)) + call U%add_fast(lhs=U, rhs=self%buffer) + endif + enddo + do s=1, self%steps - 1 + if (self%Bhat(s) /= 0._R_P) then + self%buffer = self%previous(s) + call self%buffer%t_fast(t=self%t(s)) + call self%buffer%multiply_fast(lhs=self%buffer, rhs=Dt * self%Bhat(s)) + call U%add_fast(lhs=U, rhs=self%buffer) + endif + enddo + do k=1, self%stages + if (self%B(k) /= 0._R_P) U = U + (self%stage(k)%t(t=t) * (Dt * self%B(k))) + if (self%B(k) /= 0._R_P) then + self%buffer = self%stage(k) + call self%buffer%t_fast(t=t) + call self%buffer%multiply_fast(lhs=self%buffer, rhs=Dt * self%B(k)) + call U%add_fast(lhs=U, rhs=self%buffer) + endif + enddo + if (self%autoupdate) call self%update_previous(U=U, previous=self%previous, Dt=Dt, t=t, previous_t=self%t) + endsubroutine integrate_fast elemental function is_supported(self, scheme) !< Return .true. if the integrator class support the given scheme. @@ -175,22 +250,6 @@ elemental function is_supported(self, scheme) enddo endfunction is_supported - elemental function stages_number(self) - !< Return number of stages used. - class(integrator_ms_runge_kutta_ssp), intent(in) :: self !< Integrator. - integer(I_P) :: stages_number !< Number of stages used. - - stages_number = self%stages - endfunction stages_number - - elemental function steps_number(self) - !< Return number of steps used. - class(integrator_ms_runge_kutta_ssp), intent(in) :: self !< Integrator. - integer(I_P) :: steps_number !< Number of steps used. - - steps_number = self%steps - endfunction steps_number - pure function supported_schemes(self) result(schemes) !< Return the list of supported schemes. class(integrator_ms_runge_kutta_ssp), intent(in) :: self !< Integrator. @@ -205,21 +264,22 @@ elemental subroutine destroy(self) !< Destroy the integrator. class(integrator_ms_runge_kutta_ssp), intent(inout) :: self !< Integrator. - call self%destroy_abstract - self%steps = 0 - self%stages = 0 + call self%destroy_multistage_multistep if (allocated(self%A )) deallocate(self%A ) if (allocated(self%Ahat)) deallocate(self%Ahat) if (allocated(self%B )) deallocate(self%B ) if (allocated(self%Bhat)) deallocate(self%Bhat) if (allocated(self%D )) deallocate(self%D ) - if (allocated(self%T )) deallocate(self%T ) + if (allocated(self%Q )) deallocate(self%Q ) endsubroutine destroy - subroutine initialize(self, scheme, stop_on_fail) + subroutine initialize(self, scheme, iterations, autoupdate, U, stop_on_fail) !< Create the actual MS-RK-SSP integrator: initialize the *A,Ahat,B,Bhat,D,T* coefficients. class(integrator_ms_runge_kutta_ssp), intent(inout) :: self !< Integrator. character(*), intent(in) :: scheme !< Selected scheme. + integer(I_P), intent(in), optional :: iterations !< Implicit iterations. + logical, intent(in), optional :: autoupdate !< Enable cyclic autoupdate of previous time steps. + class(integrand_object), intent(in), optional :: U !< Integrand molding prototype. logical, intent(in), optional :: stop_on_fail !< Stop execution if initialization fail. if (self%is_supported(scheme=scheme)) then @@ -246,9 +306,9 @@ subroutine initialize(self, scheme, stop_on_fail) self%D(2, 1) = 1._R_P / 3._R_P self%D(2, 2) = 2._R_P / 3._R_P - allocate(self%T(1:self%steps)) ; self%T = 0._R_P - self%T(1) = 0.607695154586736_R_P - self%T(2) = 0.392304845413264_R_P + allocate(self%Q(1:self%steps)) ; self%Q = 0._R_P + self%Q(1) = 0.607695154586736_R_P + self%Q(2) = 0.392304845413264_R_P case('ms_runge_kutta_ssp_steps_3_stages_2_order_3') self%steps = 3 @@ -272,10 +332,10 @@ subroutine initialize(self, scheme, stop_on_fail) self%D(2, 2) = 1.80945758995975e-24_R_P self%D(2, 3) = 0.813566151883148_R_P - allocate(self%T(1:self%steps)) ; self%T = 0._R_P - self%T(1) = 0.312198313277933_R_P - self%T(2) = 2.58493941422821e-24_R_P - self%T(3) = 0.687801686722067_R_P + allocate(self%Q(1:self%steps)) ; self%Q = 0._R_P + self%Q(1) = 0.312198313277933_R_P + self%Q(2) = 2.58493941422821e-24_R_P + self%Q(3) = 0.687801686722067_R_P case('ms_runge_kutta_ssp_steps_4_stages_5_order_8') self%steps = 4 @@ -344,143 +404,21 @@ subroutine initialize(self, scheme, stop_on_fail) self%D(4, 4) = 0.0749075156298171_R_P self%D(5, 4) = 0.353491551483958_R_P - allocate(self%T(1:self%steps)) ; self%T = 0._R_P - self%T(1) = 0.0273988434707855_R_P - self%T(2) = 0.286296288278021_R_P - self%T(3) = 0.484893800452111_R_P - self%T(4) = 0.201411067799082_R_P + allocate(self%Q(1:self%steps)) ; self%Q = 0._R_P + self%Q(1) = 0.0273988434707855_R_P + self%Q(2) = 0.286296288278021_R_P + self%Q(3) = 0.484893800452111_R_P + self%Q(4) = 0.201411067799082_R_P endselect + self%autoupdate = .true. ; if (present(autoupdate)) self%autoupdate = autoupdate + self%iterations = 1 ; if (present(iterations)) self%iterations = iterations + self%registers_stages = self%stages + self%registers_steps = self%steps + if (present(U)) call self%allocate_integrand_members(U=U) else call self%trigger_error(error=ERROR_UNSUPPORTED_SCHEME, & error_message='"'//trim(adjustl(scheme))//'" unsupported scheme', & is_severe=stop_on_fail) endif endsubroutine initialize - - subroutine integrate(self, U, previous, stage, Dt, t, autoupdate) - !< Integrate field with LMM-SSP class scheme. - class(integrator_ms_runge_kutta_ssp), intent(in) :: self !< Integrator. - class(integrand_object), intent(inout) :: U !< Field to be integrated. - class(integrand_object), intent(inout) :: previous(1:) !< Previous time steps solutions of integrand. - class(integrand_object), intent(inout) :: stage(1:) !< Runge-Kutta stages [1:stages]. - real(R_P), intent(in) :: Dt !< Time steps. - real(R_P), intent(in) :: t(:) !< Times. - logical, intent(in), optional :: autoupdate !< Perform cyclic autoupdate of previous steps. - logical :: autoupdate_ !< Perform cyclic autoupdate of previous steps, - !< local variable. - integer(I_P) :: k, kk !< Stages counters. - integer(I_P) :: s !< Steps counter. - - autoupdate_ = .true. ; if (present(autoupdate)) autoupdate_ = autoupdate - ! computing stages - stage(1) = U - do k=2, self%stages - stage(k) = U * 0._R_P - do s=1, self%steps - if (self%D(k, s) /= 0._R_P) stage(k) = stage(k) + (previous(s) * self%D(k, s)) - enddo - do s=1, self%steps - 1 - if (self%Ahat(k, s) /= 0._R_P) stage(k) = stage(k) + (previous(s)%t(t=t(s)) * (Dt * self%Ahat(k, s))) - enddo - do kk=1, k - 1 - if (self%A(k, kk) /= 0._R_P) stage(k) = stage(k) + (stage(kk)%t(t=t(self%steps)) * (Dt * self%A(k, kk))) - enddo - enddo - ! computing new time step - U = U * 0._R_P - do s=1, self%steps - if (self%T(s) /= 0._R_P) U = U + (previous(s) * self%T(s)) - enddo - do s=1, self%steps - 1 - if (self%Bhat(s) /= 0._R_P) U = U + (previous(s)%t(t=t(s)) * (Dt * self%Bhat(s))) - enddo - do k=1, self%stages - if (self%B(k) /= 0._R_P) U = U + (stage(k)%t(t=t(self%steps)) * (Dt * self%B(k))) - enddo - if (autoupdate_) call self%update_previous(U=U, previous=previous) - endsubroutine integrate - - subroutine integrate_fast(self, U, previous, stage, buffer, Dt, t, autoupdate) - !< Integrate field with LMM-SSP class scheme, fast mode. - class(integrator_ms_runge_kutta_ssp), intent(in) :: self !< Integrator. - class(integrand_object), intent(inout) :: U !< Field to be integrated. - class(integrand_object), intent(inout) :: previous(1:) !< Previous time steps solutions of integrand. - class(integrand_object), intent(inout) :: stage(1:) !< Runge-Kutta stages [1:stages]. - class(integrand_object), intent(inout) :: buffer !< Temporary buffer for doing fast operation. - real(R_P), intent(in) :: Dt !< Time steps. - real(R_P), intent(in) :: t(:) !< Times. - logical, intent(in), optional :: autoupdate !< Perform cyclic autoupdate of previous steps. - logical :: autoupdate_ !< Perform cyclic autoupdate of previous steps, - !< local variable. - integer(I_P) :: k, kk !< Stages counters. - integer(I_P) :: s !< Steps counter. - - autoupdate_ = .true. ; if (present(autoupdate)) autoupdate_ = autoupdate - ! computing stages - stage(1) = U - do k=2, self%stages - call stage(k)%multiply_fast(lhs=U, rhs=0._R_P) - do s=1, self%steps - if (self%D(k, s) /= 0._R_P) then - call buffer%multiply_fast(lhs=previous(s), rhs=self%D(k, s)) - call stage(k)%add_fast(lhs=stage(k), rhs=buffer) - endif - enddo - do s=1, self%steps - 1 - if (self%Ahat(k, s) /= 0._R_P) then - buffer = previous(s) - call buffer%t_fast(t=t(s)) - call buffer%multiply_fast(lhs=buffer, rhs=Dt * self%Ahat(k, s)) - call stage(k)%add_fast(lhs=stage(k), rhs=buffer) - endif - enddo - do kk=1, k - 1 - if (self%A(k, kk) /= 0._R_P) then - buffer = stage(kk) - call buffer%t_fast(t=t(self%steps)) - call buffer%multiply_fast(lhs=buffer, rhs=Dt * self%A(k, kk)) - call stage(k)%add_fast(lhs=stage(k), rhs=buffer) - endif - enddo - enddo - ! computing new time step - U = U * 0._R_P - do s=1, self%steps - if (self%T(s) /= 0._R_P) then - call buffer%multiply_fast(lhs=previous(s), rhs=self%T(s)) - call U%add_fast(lhs=U, rhs=buffer) - endif - enddo - do s=1, self%steps - 1 - if (self%Bhat(s) /= 0._R_P) then - buffer = previous(s) - call buffer%t_fast(t=t(s)) - call buffer%multiply_fast(lhs=buffer, rhs=Dt * self%Bhat(s)) - call U%add_fast(lhs=U, rhs=buffer) - endif - enddo - do k=1, self%stages - if (self%B(k) /= 0._R_P) U = U + (stage(k)%t(t=t(self%steps)) * (Dt * self%B(k))) - if (self%B(k) /= 0._R_P) then - buffer = stage(k) - call buffer%t_fast(t=t(self%steps)) - call buffer%multiply_fast(lhs=buffer, rhs=Dt * self%B(k)) - call U%add_fast(lhs=U, rhs=buffer) - endif - enddo - if (autoupdate_) call self%update_previous(U=U, previous=previous) - endsubroutine integrate_fast - - subroutine update_previous(self, U, previous) - !< Cyclic update previous time steps. - class(integrator_ms_runge_kutta_ssp), intent(in) :: self !< Integrator. - class(integrand_object), intent(in) :: U !< Field to be integrated. - class(integrand_object), intent(inout) :: previous(1:) !< Previous time steps solutions of integrand field. - integer(I_P) :: s !< Steps counter. - - do s=1, self%steps - 1 - previous(s) = previous(s + 1) - enddo - previous(self%steps) = U - endsubroutine update_previous endmodule foodie_integrator_ms_runge_kutta_ssp diff --git a/src/lib/foodie_integrator_multistage_multistep_object.f90 b/src/lib/foodie_integrator_multistage_multistep_object.f90 new file mode 100644 index 00000000..e73d7bcd --- /dev/null +++ b/src/lib/foodie_integrator_multistage_multistep_object.f90 @@ -0,0 +1,213 @@ +!< Define the abstract type [[integrator_multistage_multistep_object]] of FOODIE ODE integrators. + +module foodie_integrator_multistage_multistep_object +!< Define the abstract type [[integrator_multistage_multistep_object]] of FOODIE ODE integrators. + +use, intrinsic :: iso_fortran_env, only : stderr=>error_unit +use foodie_integrand_object, only : integrand_object +use foodie_integrator_object, only : integrator_object +use penf, only : I_P, R_P + +implicit none +private +public :: integrator_multistage_multistep_object + +type, extends(integrator_object), abstract :: integrator_multistage_multistep_object + !< Abstract type of FOODIE ODE integrators of the multistage/multistep family. + integer(I_P) :: registers_stages !< Number of registers used for stages. + integer(I_P) :: registers_steps !< Number of registers used for steps. + integer(I_P) :: stages !< Number of stages. + integer(I_P) :: steps !< Number of time steps. + logical :: autoupdate !< Perform cyclic autoupdate of previous time steps buffers. + integer(I_P) :: iterations !< Implicit iterations. + real(R_P), allocatable :: Dt(:) !< Previous time steps. + real(R_P), allocatable :: t(:) !< Previous times. + class(integrand_object), allocatable :: previous(:) !< Previous steps. + class(integrand_object), allocatable :: stage(:) !< Stages. + class(integrand_object), allocatable :: buffer !< Buffer used for fast integration. + contains + ! deferred methods + procedure(integrate_interface), pass(self), deferred :: integrate !< Integrate integrand field. + procedure(integrate_fast_interface), pass(self), deferred :: integrate_fast !< Integrate integrand field, fast mode. + ! implemented deferred methods of parent + procedure, pass(self) :: is_multistage !< Return .true. for multistage integrator. + procedure, pass(self) :: is_multistep !< Return .true. for multistep integrator. + procedure, pass(self) :: stages_number !< Return number of stages used. + procedure, pass(self) :: steps_number !< Return number of steps used. + ! public methods + procedure, pass(self) :: allocate_integrand_members !< Allocate integrand members. + procedure, pass(lhs) :: assign_multistage_multistep !< Assign members of [[integrator_multistage_multistep_object]]. + procedure, pass(self) :: destroy_multistage_multistep !< Destroy the integrator. + procedure, nopass :: update_previous !< Cyclic update previous time steps. +endtype integrator_multistage_multistep_object + +abstract interface + !< Abstract interfaces of deferred methods of [[integrator_multistage_multistep_object]]. + subroutine integrate_interface(self, U, Dt, t) + !< Integrate integrand field. + import :: integrand_object, integrator_multistage_multistep_object, R_P + class(integrator_multistage_multistep_object), intent(inout) :: self !< Integrator. + class(integrand_object), intent(inout) :: U !< Integrand. + real(R_P), intent(in) :: Dt !< Time step. + real(R_P), intent(in) :: t !< Time. + endsubroutine integrate_interface + + subroutine integrate_fast_interface(self, U, Dt, t) + !< Integrate integrand field, fast mode. + import :: integrand_object, integrator_multistage_multistep_object, R_P + class(integrator_multistage_multistep_object), intent(inout) :: self !< Integrator. + class(integrand_object), intent(inout) :: U !< Field to be integrated. + real(R_P), intent(in) :: Dt !< Time step. + real(R_P), intent(in) :: t !< Time. + endsubroutine integrate_fast_interface +endinterface + +contains + ! deferred methods + elemental function is_multistage(self) + !< Return .true. for multistage integrator. + class(integrator_multistage_multistep_object), intent(in) :: self !< Integrator. + logical :: is_multistage !< Inquire result. + + is_multistage = .true. + endfunction is_multistage + + elemental function is_multistep(self) + !< Return .true. for multistage integrator. + class(integrator_multistage_multistep_object), intent(in) :: self !< Integrator. + logical :: is_multistep !< Inquire result. + + is_multistep = .true. + endfunction is_multistep + + elemental function stages_number(self) + !< Return number of stages used. + class(integrator_multistage_multistep_object), intent(in) :: self !< Integrator. + integer(I_P) :: stages_number !< Number of stages used. + + stages_number = self%stages + endfunction stages_number + + elemental function steps_number(self) + !< Return number of steps used. + class(integrator_multistage_multistep_object), intent(in) :: self !< Integrator. + integer(I_P) :: steps_number !< Number of steps used. + + steps_number = self%steps + endfunction steps_number + + ! public methods + pure subroutine allocate_integrand_members(self, U) + !< Allocate members of interpolator being of [[integrand_object]] class. + !< + !< @note It is assumed that the integrator has been properly initialized before calling this method. + class(integrator_multistage_multistep_object), intent(inout) :: self !< Integrator. + class(integrand_object), intent(in) :: U !< Integrand. + integer(I_P) :: s !< Counter. + + if (self%is_multistage() .and. self%registers_stages > 0) then + if (allocated(self%stage)) deallocate(self%stage) + allocate(self%stage(1:self%registers_stages), mold=U) + do s=1, self%registers_stages + self%stage(s) = U + enddo + endif + if (self%is_multistep() .and. self%registers_steps > 0) then + if (allocated(self%Dt)) deallocate(self%Dt) + allocate(self%Dt(1:self%registers_steps)) ; self%Dt = 0._R_P + if (allocated(self%t)) deallocate(self%t) + allocate(self%t(1:self%registers_steps)) ; self%t = 0._R_P + if (allocated(self%previous)) deallocate(self%previous) + allocate(self%previous(1:self%registers_steps), mold=U) + do s=1, self%registers_steps + self%previous(s) = U + enddo + endif + if (self%has_fast_mode()) then + if (allocated(self%buffer)) deallocate(self%buffer) + allocate(self%buffer, mold=U) + self%buffer = U + endif + endsubroutine allocate_integrand_members + + pure subroutine assign_multistage_multistep(lhs, rhs) + !< Assign members of [[integrator_multistage_multistep_object]] and parents. + class(integrator_multistage_multistep_object), intent(inout) :: lhs !< Left hand side. + class(integrator_object), intent(in) :: rhs !< Right hand side. + integer(I_P) :: s !< Counter. + + call lhs%assign_abstract(rhs=rhs) + select type(rhs) + class is (integrator_multistage_multistep_object) + lhs%registers_stages = rhs%registers_stages + lhs%registers_steps = rhs%registers_steps + lhs%stages = rhs%stages + lhs%steps = rhs%steps + lhs%autoupdate = rhs%autoupdate + lhs%iterations = rhs%iterations + if (allocated(lhs%Dt)) deallocate(lhs%Dt) + if (allocated(rhs%Dt)) lhs%Dt = rhs%Dt + if (allocated(lhs%t)) deallocate(lhs%t) + if (allocated(rhs%t)) lhs%t = rhs%t + if (allocated(lhs%previous)) deallocate(lhs%previous) + if (allocated(rhs%previous)) then + allocate(lhs%previous(1:lhs%registers_steps), mold=rhs%previous) + do s=1, lhs%registers_steps + lhs%previous(s) = rhs%previous(s) + enddo + endif + if (allocated(lhs%stage)) deallocate(lhs%stage) + if (allocated(rhs%stage)) then + allocate(lhs%stage(1:lhs%registers_stages), mold=rhs%stage) + do s=1, lhs%registers_stages + lhs%stage(s) = rhs%stage(s) + enddo + endif + if (allocated(lhs%buffer)) deallocate(lhs%buffer) + if (allocated(rhs%buffer)) then + allocate(lhs%buffer, mold=rhs%buffer) + lhs%buffer = rhs%buffer + endif + endselect + endsubroutine assign_multistage_multistep + + elemental subroutine destroy_multistage_multistep(self) + !< Destroy the integrator. + class(integrator_multistage_multistep_object), intent(inout) :: self !< Integrator. + + call self%destroy_abstract + self%registers_stages = 0 + self%registers_steps = 0 + self%stages = 0 + self%steps = -1 + self%autoupdate = .false. + self%iterations = 0 + if (allocated(self%Dt)) deallocate(self%Dt) + if (allocated(self%t)) deallocate(self%t) + if (allocated(self%previous)) deallocate(self%previous) + if (allocated(self%stage)) deallocate(self%stage) + if (allocated(self%buffer)) deallocate(self%buffer) + endsubroutine destroy_multistage_multistep + + subroutine update_previous(U, previous, Dt, t, previous_Dt, previous_t) + !< Cyclic update previous time steps. + class(integrand_object), intent(in) :: U !< Field to be integrated. + class(integrand_object), intent(inout) :: previous(1:) !< Previous time steps solutions of integrand. + real(R_P), intent(in), optional :: Dt !< Time step. + real(R_P), intent(in), optional :: t !< Time. + real(R_P), intent(inout), optional :: previous_Dt(1:) !< Time step. + real(R_P), intent(inout), optional :: previous_t(1:) !< Time. + integer(I_P) :: last_step !< Last step. + integer(I_P) :: s !< Steps counter. + + last_step = size(previous, dim=1) + do s=1, last_step - 1 + previous(s) = previous(s + 1) + if (present(previous_Dt)) previous_Dt(s) = previous_Dt(s + 1) + if (present(previous_t)) previous_t(s) = previous_t(s + 1) + enddo + previous(last_step) = U + if (present(previous_Dt)) previous_Dt(last_step) = Dt + if (present(previous_t)) previous_t(last_step) = t + Dt + endsubroutine update_previous +endmodule foodie_integrator_multistage_multistep_object diff --git a/src/lib/foodie_integrator_multistep_object.f90 b/src/lib/foodie_integrator_multistep_object.f90 index 58312603..87dfca5e 100644 --- a/src/lib/foodie_integrator_multistep_object.f90 +++ b/src/lib/foodie_integrator_multistep_object.f90 @@ -14,7 +14,7 @@ module foodie_integrator_multistep_object type, extends(integrator_object), abstract :: integrator_multistep_object !< Abstract type of FOODIE ODE integrators of the multistep-implicit family. - integer(I_P) :: registers !< Number of registers used for stages. + integer(I_P) :: registers !< Number of registers used for steps. integer(I_P) :: steps !< Number of time steps. logical :: autoupdate !< Perform cyclic autoupdate of previous time steps buffers. integer(I_P) :: iterations !< Implicit iterations. diff --git a/src/lib/foodie_integrator_runge_kutta_low_storage.f90 b/src/lib/foodie_integrator_runge_kutta_low_storage.f90 index 3624e43c..92022343 100644 --- a/src/lib/foodie_integrator_runge_kutta_low_storage.f90 +++ b/src/lib/foodie_integrator_runge_kutta_low_storage.f90 @@ -451,7 +451,6 @@ subroutine initialize(self, scheme, U, stop_on_fail) self%A(14) = -7.1151571693922548_R_P ; self%B(14) = 5.5059777270269628_R_P ; self%C(14) = 0.8734213127600976_R_P endselect self%registers = 2 - self%registers = self%stages if (present(U)) call self%allocate_integrand_members(U=U) else call self%trigger_error(error=ERROR_UNSUPPORTED_SCHEME, & diff --git a/src/tests/tester/foodie_tester.f90 b/src/tests/tester/foodie_tester.f90 index 90836012..adb40167 100644 --- a/src/tests/tester/foodie_tester.f90 +++ b/src/tests/tester/foodie_tester.f90 @@ -5,26 +5,27 @@ module foodie_test_object use, intrinsic :: iso_fortran_env, only : stderr=>error_unit use flap, only : command_line_interface -use foodie, only : foodie_integrator_class_names, & - foodie_integrator_factory, & - foodie_integrator_schemes, & - integrand_object, & - integrator_adams_bashforth, & - integrator_adams_bashforth_moulton, & - integrator_adams_moulton, & - integrator_back_df, & - integrator_euler_explicit, & - integrator_leapfrog, & - integrator_lmm_ssp, & - integrator_lmm_ssp_vss, & - integrator_ms_runge_kutta_ssp, & - integrator_multistage_object, & - integrator_multistep_object, & - integrator_object, & - integrator_runge_kutta_emd, & - integrator_runge_kutta_ls, & - integrator_runge_kutta_lssp, & - integrator_runge_kutta_ssp, & +use foodie, only : foodie_integrator_class_names, & + foodie_integrator_factory, & + foodie_integrator_schemes, & + integrand_object, & + integrator_adams_bashforth, & + integrator_adams_bashforth_moulton, & + integrator_adams_moulton, & + integrator_back_df, & + integrator_euler_explicit, & + integrator_leapfrog, & + integrator_lmm_ssp, & + integrator_lmm_ssp_vss, & + integrator_ms_runge_kutta_ssp, & + integrator_multistage_object, & + integrator_multistage_multistep_object, & + integrator_multistep_object, & + integrator_object, & + integrator_runge_kutta_emd, & + integrator_runge_kutta_ls, & + integrator_runge_kutta_lssp, & + integrator_runge_kutta_ssp, & is_available, is_class_available use foodie_test_integrand_ladvection, only : integrand_ladvection use foodie_test_integrand_oscillation, only : integrand_oscillation @@ -132,14 +133,14 @@ subroutine set_cli() description = 'Tester factory of FOODIE integrators', & examples = ["foodie_tester --scheme euler_explicit --save_results ", & "foodie_tester --scheme all -r "]) - call cli%add(switch='--test', switch_ab='-t', help='test executed', required=.false., def='linear_advection', & + call cli%add(switch='--test', switch_ab='-t', help='test executed', required=.false., def='oscillation', & act='store', choices='linear_advection,oscillation') call cli%add(switch='--scheme', switch_ab='-s', help='integrator scheme used', required=.false., def='all', act='store') call cli%add(switch='--time_step', switch_ab='-Dt', nargs='+', help='time step', required=.false., def='1e2', act='store') call cli%add(switch='--fast', help='activate fast solvers', required=.false., act='store_true', def='.false.') call cli%add(switch='--iterations', help='iterations number for implicit schemes', required=.false., act='store', def='5') call cli%add(switch='--stages', help='stages number', required=.false., def='2', act='store') - call cli%add(switch='--final_time', switch_ab='-ft', help='integration time', required=.false., def='1', act='store') + call cli%add(switch='--final_time', switch_ab='-ft', help='integration time', required=.false., def='1e6', act='store') call cli%add(switch='--save_results', switch_ab='-r',help='save result', required=.false., act='store_true', def='.false.') call cli%add(switch='--output', help='output file basename', required=.false., act='store', def='foodie_test') call cli%add(switch='--save_frequency', help='save frequency', required=.false., act='store', def='1') @@ -306,24 +307,26 @@ subroutine integrate(scheme, integrand_0, Dt, final_time, iterations, stages, is call integrand_export_tecplot enddo - ! type is(integrator_ms_runge_kutta_ssp) - ! do - ! step = step + 1 - ! if (integrator%steps_number() >= step) then - ! call integrator_start%integrate(U=integrand, Dt=Dt, t=time) - ! previous(step) = integrand - ! time = time + Dt - ! else - ! if (is_fast) then - ! call integrator%integrate_fast(U=integrand, previous=previous, stage=stage, buffer=buffer, Dt=Dt,t=time) - ! else - ! call integrator%integrate(U=integrand, previous=previous, stage=stage, Dt=Dt, t=time) - ! endif - ! time = time + Dt - ! endif - ! if ((time >= final_time)) exit - ! call integrand_export_tecplot - ! enddo + class is(integrator_multistage_multistep_object) + do + step = step + 1 + if (integrator%steps_number() >= step) then + call integrator_start%integrate(U=integrand, Dt=Dt, t=time) + integrator%previous(step) = integrand + time = time + Dt + integrator%Dt(step) = Dt + integrator%t(step) = time + else + if (is_fast) then + call integrator%integrate_fast(U=integrand, Dt=Dt,t=time) + else + call integrator%integrate(U=integrand, Dt=Dt, t=time) + endif + time = time + Dt + endif + if ((time >= final_time)) exit + call integrand_export_tecplot + enddo endselect select type(integrand) From 1812d6e2cbb0e3060ec2db3af834ff21335dd9dd Mon Sep 17 00:00:00 2001 From: Stefano Zaghi Date: Fri, 26 May 2017 17:32:16 +0200 Subject: [PATCH 25/25] dehydrate tester --- src/lib/foodie_integrator_adams_bashforth.f90 | 21 +-- ...die_integrator_adams_bashforth_moulton.f90 | 21 +-- src/lib/foodie_integrator_adams_moulton.f90 | 23 +-- ...rator_backward_differentiation_formula.f90 | 23 +-- src/lib/foodie_integrator_euler_explicit.f90 | 49 +++--- src/lib/foodie_integrator_leapfrog.f90 | 41 ++--- src/lib/foodie_integrator_lmm_ssp.f90 | 147 ++++++++---------- src/lib/foodie_integrator_lmm_ssp_vss.f90 | 79 ++++------ .../foodie_integrator_ms_runge_kutta_ssp.f90 | 21 +-- src/lib/foodie_integrator_object.f90 | 20 ++- ...foodie_integrator_runge_kutta_embedded.f90 | 29 +--- ...die_integrator_runge_kutta_low_storage.f90 | 21 +-- .../foodie_integrator_runge_kutta_lssp.f90 | 23 +-- src/lib/foodie_integrator_runge_kutta_ssp.f90 | 21 +-- .../foodie_test_integrand_ladvection.f90 | 14 +- .../foodie_test_integrand_oscillation.f90 | 12 ++ .../foodie_test_integrand_tester_object.f90 | 17 +- src/tests/tester/foodie_tester.f90 | 42 ++--- 18 files changed, 213 insertions(+), 411 deletions(-) diff --git a/src/lib/foodie_integrator_adams_bashforth.f90 b/src/lib/foodie_integrator_adams_bashforth.f90 index 15e25b3c..eee8348d 100644 --- a/src/lib/foodie_integrator_adams_bashforth.f90 +++ b/src/lib/foodie_integrator_adams_bashforth.f90 @@ -68,7 +68,6 @@ module foodie_integrator_adams_bashforth contains ! deferred methods procedure, pass(self) :: class_name !< Return the class name of schemes. - procedure, pass(self) :: description !< Return pretty-printed object description. procedure, pass(self) :: has_fast_mode !< Return .true. if the integrator class has *fast mode* integrate. procedure, pass(lhs) :: integr_assign_integr !< Operator `=`. procedure, pass(self) :: integrate !< Integrate integrand field. @@ -90,25 +89,6 @@ pure function class_name(self) class_name = trim(adjustl(class_name_)) endfunction class_name - pure function description(self, prefix) result(desc) - !< Return a pretty-formatted object description. - class(integrator_adams_bashforth), intent(in) :: self !< Integrator. - character(*), intent(in), optional :: prefix !< Prefixing string. - character(len=:), allocatable :: desc !< Description. - character(len=:), allocatable :: prefix_ !< Prefixing string, local variable. - character(len=1), parameter :: NL=new_line('a') !< New line character. - integer(I_P) :: s !< Counter. - - prefix_ = '' ; if (present(prefix)) prefix_ = prefix - desc = '' - desc = desc//prefix_//'Adams-Bashforth multi-step schemes class'//NL - desc = desc//prefix_//' Supported schemes:'//NL - do s=lbound(supported_schemes_, dim=1), ubound(supported_schemes_, dim=1) - 1 - desc = desc//prefix_//' + '//supported_schemes_(s)//NL - enddo - desc = desc//prefix_//' + '//supported_schemes_(ubound(supported_schemes_, dim=1)) - endfunction description - elemental function has_fast_mode(self) !< Return .true. if the integrator class has *fast mode* integrate. class(integrator_adams_bashforth), intent(in) :: self !< Integrator. @@ -207,6 +187,7 @@ subroutine initialize(self, scheme, autoupdate, U, stop_on_fail) if (self%is_supported(scheme=scheme)) then call self%destroy + self%description_ = trim(adjustl(scheme)) select case(trim(adjustl(scheme))) case('adams_bashforth_1') self%steps = 1 ; allocate(self%b(1:self%steps)) ; self%b = 0.0_R_P diff --git a/src/lib/foodie_integrator_adams_bashforth_moulton.f90 b/src/lib/foodie_integrator_adams_bashforth_moulton.f90 index 367c37d1..297ba49c 100644 --- a/src/lib/foodie_integrator_adams_bashforth_moulton.f90 +++ b/src/lib/foodie_integrator_adams_bashforth_moulton.f90 @@ -121,7 +121,6 @@ module foodie_integrator_adams_bashforth_moulton contains ! deferred methods procedure, pass(self) :: class_name !< Return the class name of schemes. - procedure, pass(self) :: description !< Return pretty-printed object description. procedure, pass(self) :: has_fast_mode !< Return .true. if the integrator class has *fast mode* integrate. procedure, pass(lhs) :: integr_assign_integr !< Operator `=`. procedure, pass(self) :: integrate !< Integrate integrand field. @@ -144,25 +143,6 @@ pure function class_name(self) class_name = trim(adjustl(class_name_)) endfunction class_name - pure function description(self, prefix) result(desc) - !< Return a pretty-formatted object description. - class(integrator_adams_bashforth_moulton), intent(in) :: self !< Integrator. - character(*), intent(in), optional :: prefix !< Prefixing string. - character(len=:), allocatable :: desc !< Description. - character(len=:), allocatable :: prefix_ !< Prefixing string, local variable. - character(len=1), parameter :: NL=new_line('a') !< New line character. - integer(I_P) :: s !< Counter. - - prefix_ = '' ; if (present(prefix)) prefix_ = prefix - desc = '' - desc = desc//prefix_//'Adams-Bashforth-Moulton multi-step (predictor-corrector) schemes class'//NL - desc = desc//prefix_//' Supported schemes:'//NL - do s=lbound(supported_schemes_, dim=1), ubound(supported_schemes_, dim=1) - 1 - desc = desc//prefix_//' + '//supported_schemes_(s)//NL - enddo - desc = desc//prefix_//' + '//supported_schemes_(ubound(supported_schemes_, dim=1)) - endfunction description - elemental function has_fast_mode(self) !< Return .true. if the integrator class has *fast mode* integrate. class(integrator_adams_bashforth_moulton), intent(in) :: self !< Integrator. @@ -282,6 +262,7 @@ subroutine initialize(self, scheme, iterations, autoupdate, U, stop_on_fail) if (self%is_supported(scheme=scheme)) then call self%destroy + self%description_ = trim(adjustl(scheme)) scheme_number_ = self%scheme_number(scheme=scheme) schemes_ab = self%predictor%supported_schemes() schemes_am = self%corrector%supported_schemes() diff --git a/src/lib/foodie_integrator_adams_moulton.f90 b/src/lib/foodie_integrator_adams_moulton.f90 index 9f54c321..62b0e73c 100644 --- a/src/lib/foodie_integrator_adams_moulton.f90 +++ b/src/lib/foodie_integrator_adams_moulton.f90 @@ -69,7 +69,6 @@ module foodie_integrator_adams_moulton contains ! deferred methods procedure, pass(self) :: class_name !< Return the class name of schemes. - procedure, pass(self) :: description !< Return pretty-printed object description. procedure, pass(lhs) :: integr_assign_integr !< Operator `=`. procedure, pass(self) :: has_fast_mode !< Return .true. if the integrator class has *fast mode* integrate. procedure, pass(self) :: integrate !< Integrate integrand field. @@ -91,25 +90,6 @@ pure function class_name(self) class_name = trim(adjustl(class_name_)) endfunction class_name - pure function description(self, prefix) result(desc) - !< Return a pretty-formatted object description. - class(integrator_adams_moulton), intent(in) :: self !< Integrator. - character(*), intent(in), optional :: prefix !< Prefixing string. - character(len=:), allocatable :: desc !< Description. - character(len=:), allocatable :: prefix_ !< Prefixing string, local variable. - character(len=1), parameter :: NL=new_line('a') !< New line character. - integer(I_P) :: s !< Counter. - - prefix_ = '' ; if (present(prefix)) prefix_ = prefix - desc = '' - desc = desc//prefix_//'Adams-Moulton multi-step schemes class'//NL - desc = desc//prefix_//' Supported schemes:'//NL - do s=lbound(supported_schemes_, dim=1), ubound(supported_schemes_, dim=1) - 1 - desc = desc//prefix_//' + '//supported_schemes_(s)//NL - enddo - desc = desc//prefix_//' + '//supported_schemes_(ubound(supported_schemes_, dim=1)) - endfunction description - elemental function has_fast_mode(self) !< Return .true. if the integrator class has *fast mode* integrate. class(integrator_adams_moulton), intent(in) :: self !< Integrator. @@ -252,7 +232,8 @@ subroutine initialize(self, scheme, iterations, autoupdate, U, stop_on_fail) logical, intent(in), optional :: stop_on_fail !< Stop execution if initialization fail. if (self%is_supported(scheme=scheme)) then - call self%destroy + call self%destroy + self%description_ = trim(adjustl(scheme)) select case(trim(adjustl(scheme))) case('adams_moulton_0') self%steps = 0 ; allocate(self%b(0:self%steps)) ; self%b = 0.0_R_P diff --git a/src/lib/foodie_integrator_backward_differentiation_formula.f90 b/src/lib/foodie_integrator_backward_differentiation_formula.f90 index af6c85f6..52f7eb13 100644 --- a/src/lib/foodie_integrator_backward_differentiation_formula.f90 +++ b/src/lib/foodie_integrator_backward_differentiation_formula.f90 @@ -67,7 +67,6 @@ module foodie_integrator_backward_differentiation_formula contains ! deferred methods procedure, pass(self) :: class_name !< Return the class name of schemes. - procedure, pass(self) :: description !< Return pretty-printed object description. procedure, pass(self) :: has_fast_mode !< Return .true. if the integrator class has *fast mode* integrate. procedure, pass(lhs) :: integr_assign_integr !< Operator `=`. procedure, pass(self) :: integrate !< Integrate integrand field. @@ -89,25 +88,6 @@ pure function class_name(self) class_name = trim(adjustl(class_name_)) endfunction class_name - pure function description(self, prefix) result(desc) - !< Return a pretty-formatted object description. - class(integrator_back_df), intent(in) :: self !< Integrator. - character(*), intent(in), optional :: prefix !< Prefixing string. - character(len=:), allocatable :: desc !< Description. - character(len=:), allocatable :: prefix_ !< Prefixing string, local variable. - character(len=1), parameter :: NL=new_line('a') !< New line character. - integer(I_P) :: s !< Counter. - - prefix_ = '' ; if (present(prefix)) prefix_ = prefix - desc = '' - desc = desc//prefix_//'Backward-Differentiation-Formula multi-step schemes class'//NL - desc = desc//prefix_//' Supported schemes:'//NL - do s=lbound(supported_schemes_, dim=1), ubound(supported_schemes_, dim=1) - 1 - desc = desc//prefix_//' + '//supported_schemes_(s)//NL - enddo - desc = desc//prefix_//' + '//supported_schemes_(ubound(supported_schemes_, dim=1)) - endfunction description - elemental function has_fast_mode(self) !< Return .true. if the integrator class has *fast mode* integrate. class(integrator_back_df), intent(in) :: self !< Integrator. @@ -219,7 +199,8 @@ subroutine initialize(self, scheme, iterations, autoupdate, U, stop_on_fail) logical, intent(in), optional :: stop_on_fail !< Stop execution if initialization fail. if (self%is_supported(scheme=scheme)) then - call self%destroy + call self%destroy + self%description_ = trim(adjustl(scheme)) select case(trim(adjustl(scheme))) case('back_df_1') self%steps = 1 ; allocate(self%a(1:self%steps)) ; self%a = 0.0_R_P diff --git a/src/lib/foodie_integrator_euler_explicit.f90 b/src/lib/foodie_integrator_euler_explicit.f90 index 5dafdb61..90b1f030 100644 --- a/src/lib/foodie_integrator_euler_explicit.f90 +++ b/src/lib/foodie_integrator_euler_explicit.f90 @@ -34,7 +34,6 @@ module foodie_integrator_euler_explicit contains ! deferred methods procedure, pass(self) :: class_name !< Return the class name of schemes. - procedure, pass(self) :: description !< Return pretty-printed object description. procedure, pass(self) :: has_fast_mode !< Return .true. if the integrator class has *fast mode* integrate. procedure, pass(lhs) :: integr_assign_integr !< Operator `=`. procedure, pass(self) :: integrate !< Integrate integrand field. @@ -55,17 +54,6 @@ pure function class_name(self) class_name = trim(adjustl(class_name_)) endfunction class_name - pure function description(self, prefix) result(desc) - !< Return a pretty-formatted object description. - class(integrator_euler_explicit), intent(in) :: self !< Integrator. - character(*), intent(in), optional :: prefix !< Prefixing string. - character(len=:), allocatable :: desc !< Description. - character(len=:), allocatable :: prefix_ !< Prefixing string, local variable. - - prefix_ = '' ; if (present(prefix)) prefix_ = prefix - desc = prefix_//'Euler, Explicit (1 step/stage) 1st order scheme' - endfunction description - elemental function has_fast_mode(self) !< Return .true. if the integrator class has *fast mode* integrate. class(integrator_euler_explicit), intent(in) :: self !< Integrator. @@ -142,22 +130,23 @@ elemental subroutine destroy(self) call self%destroy_multistage endsubroutine destroy - subroutine initialize(self, scheme, U, stop_on_fail) - !< Create the actual RK integrator: initialize the Butcher' table coefficients. - class(integrator_euler_explicit), intent(inout) :: self !< Integrator. - character(*), intent(in) :: scheme !< Selected scheme. - class(integrand_object), intent(in), optional :: U !< Integrand molding prototype. - logical, intent(in), optional :: stop_on_fail !< Stop execution if initialization fail. - - if (self%is_supported(scheme=scheme)) then - call self%destroy - self%stages = 0 - self%registers = self%stages - if (present(U)) call self%allocate_integrand_members(U=U) - else - call self%trigger_error(error=ERROR_UNSUPPORTED_SCHEME, & - error_message='"'//trim(adjustl(scheme))//'" unsupported scheme', & - is_severe=stop_on_fail) - endif - endsubroutine initialize + subroutine initialize(self, scheme, U, stop_on_fail) + !< Create the actual RK integrator: initialize the Butcher' table coefficients. + class(integrator_euler_explicit), intent(inout) :: self !< Integrator. + character(*), intent(in) :: scheme !< Selected scheme. + class(integrand_object), intent(in), optional :: U !< Integrand molding prototype. + logical, intent(in), optional :: stop_on_fail !< Stop execution if initialization fail. + + if (self%is_supported(scheme=scheme)) then + call self%destroy + self%description_ = trim(adjustl(scheme)) + self%stages = 0 + self%registers = self%stages + if (present(U)) call self%allocate_integrand_members(U=U) + else + call self%trigger_error(error=ERROR_UNSUPPORTED_SCHEME, & + error_message='"'//trim(adjustl(scheme))//'" unsupported scheme', & + is_severe=stop_on_fail) + endif + endsubroutine initialize endmodule foodie_integrator_euler_explicit diff --git a/src/lib/foodie_integrator_leapfrog.f90 b/src/lib/foodie_integrator_leapfrog.f90 index 8c266070..697af33c 100644 --- a/src/lib/foodie_integrator_leapfrog.f90 +++ b/src/lib/foodie_integrator_leapfrog.f90 @@ -67,7 +67,6 @@ module foodie_integrator_leapfrog contains ! deferred methods procedure, pass(self) :: class_name !< Return the class name of schemes. - procedure, pass(self) :: description !< Return pretty-printed object description. procedure, pass(self) :: has_fast_mode !< Return .true. if the integrator class has *fast mode* integrate. procedure, pass(lhs) :: integr_assign_integr !< Operator `=`. procedure, pass(self) :: integrate !< Integrate integrand field. @@ -91,17 +90,6 @@ pure function class_name(self) class_name = trim(adjustl(class_name_)) endfunction class_name - pure function description(self, prefix) result(desc) - !< Return a pretty-formatted object description. - class(integrator_leapfrog), intent(in) :: self !< Integrator. - character(*), intent(in), optional :: prefix !< Prefixing string. - character(len=:), allocatable :: desc !< Description. - character(len=:), allocatable :: prefix_ !< Prefixing string, local variable. - - prefix_ = '' ; if (present(prefix)) prefix_ = prefix - desc = desc//prefix_//'Explicit leapfrog multi-step 2nd order scheme' - endfunction description - elemental function has_fast_mode(self) !< Return .true. if the integrator class has *fast mode* integrate. class(integrator_leapfrog), intent(in) :: self !< Integrator. @@ -219,21 +207,22 @@ subroutine initialize(self, scheme, nu, alpha, autoupdate, U, stop_on_fail) logical, intent(in), optional :: stop_on_fail !< Stop execution if initialization fail. if (self%is_supported(scheme=scheme)) then - call self%destroy - select case(trim(adjustl(scheme))) - case('leapfrog_raw') - self%nu = 0.01_R_P ; if (present(nu)) self%nu = nu - self%alpha = 0.53_R_P ; if (present(alpha)) self%alpha = alpha - self%is_filtered = .true. - endselect - self%autoupdate = .true. ; if (present(autoupdate)) self%autoupdate = autoupdate - self%steps = 2 - self%registers = self%steps - if (present(U)) call self%allocate_integrand_members(U=U) + call self%destroy + self%description_ = trim(adjustl(scheme)) + select case(trim(adjustl(scheme))) + case('leapfrog_raw') + self%nu = 0.01_R_P ; if (present(nu)) self%nu = nu + self%alpha = 0.53_R_P ; if (present(alpha)) self%alpha = alpha + self%is_filtered = .true. + endselect + self%autoupdate = .true. ; if (present(autoupdate)) self%autoupdate = autoupdate + self%steps = 2 + self%registers = self%steps + if (present(U)) call self%allocate_integrand_members(U=U) else - call self%trigger_error(error=ERROR_UNSUPPORTED_SCHEME, & - error_message='"'//trim(adjustl(scheme))//'" unsupported scheme', & - is_severe=stop_on_fail) + call self%trigger_error(error=ERROR_UNSUPPORTED_SCHEME, & + error_message='"'//trim(adjustl(scheme))//'" unsupported scheme', & + is_severe=stop_on_fail) endif endsubroutine initialize diff --git a/src/lib/foodie_integrator_lmm_ssp.f90 b/src/lib/foodie_integrator_lmm_ssp.f90 index 4545d4ff..6916cd9d 100644 --- a/src/lib/foodie_integrator_lmm_ssp.f90 +++ b/src/lib/foodie_integrator_lmm_ssp.f90 @@ -57,7 +57,6 @@ module foodie_integrator_lmm_ssp contains ! deferred methods procedure, pass(self) :: class_name !< Return the class name of schemes. - procedure, pass(self) :: description !< Return pretty-printed object description. procedure, pass(self) :: has_fast_mode !< Return .true. if the integrator class has *fast mode* integrate. procedure, pass(lhs) :: integr_assign_integr !< Operator `=`. procedure, pass(self) :: integrate !< Integrate integrand field. @@ -79,25 +78,6 @@ pure function class_name(self) class_name = trim(adjustl(class_name_)) endfunction class_name - pure function description(self, prefix) result(desc) - !< Return a pretty-formatted object description. - class(integrator_lmm_ssp), intent(in) :: self !< Integrator. - character(*), intent(in), optional :: prefix !< Prefixing string. - character(len=:), allocatable :: desc !< Description. - character(len=:), allocatable :: prefix_ !< Prefixing string, local variable. - character(len=1), parameter :: NL=new_line('a') !< New line character. - integer(I_P) :: s !< Counter. - - prefix_ = '' ; if (present(prefix)) prefix_ = prefix - desc = '' - desc = desc//prefix_//'Strong Stability preserving Linear-Multistep-Methods class'//NL - desc = desc//prefix_//' Supported schemes:'//NL - do s=lbound(supported_schemes_, dim=1), ubound(supported_schemes_, dim=1) - 1 - desc = desc//prefix_//' + '//supported_schemes_(s)//NL - enddo - desc = desc//prefix_//' + '//supported_schemes_(ubound(supported_schemes_, dim=1)) - endfunction description - elemental function has_fast_mode(self) !< Return .true. if the integrator class has *fast mode* integrate. class(integrator_lmm_ssp), intent(in) :: self !< Integrator. @@ -195,67 +175,68 @@ elemental subroutine destroy(self) if (allocated(self%b)) deallocate(self%b) endsubroutine destroy - subroutine initialize(self, scheme, autoupdate, U, stop_on_fail) - !< Create the actual LMM-SSP integrator: initialize the *a,b* coefficients. - !< - !< @note If the integrator is initialized with a bad (unsupported) number of required time steps the initialization fails and - !< the integrator error status is updated consistently for external-provided errors handling. - class(integrator_lmm_ssp), intent(inout) :: self !< Integrator. - character(*), intent(in) :: scheme !< Selected scheme. - logical, intent(in), optional :: autoupdate !< Enable cyclic autoupdate of previous time steps. - class(integrand_object), intent(in), optional :: U !< Integrand molding prototype. - logical, intent(in), optional :: stop_on_fail !< Stop execution if initialization fail. - - if (self%is_supported(scheme=scheme)) then - call self%destroy - select case(trim(adjustl(scheme))) - case('lmm_ssp_steps_3_order_2') - self%steps = 3 - allocate(self%a(1:self%steps)) ; self%a = 0.0_R_P - allocate(self%b(1:self%steps)) ; self%b = 0.0_R_P - self%a(1) = 1._R_P/4._R_P - self%a(2) = 0._R_P - self%a(3) = 3._R_P/4._R_P - - self%b(1) = 0._R_P - self%b(2) = 0._R_P - self%b(3) = 3._R_P/2._R_P - case('lmm_ssp_steps_4_order_3') - self%steps = 4 - allocate(self%a(1:self%steps)) ; self%a = 0.0_R_P - allocate(self%b(1:self%steps)) ; self%b = 0.0_R_P - self%a(1) = 11._R_P/27._R_P - self%a(2) = 0._R_P - self%a(3) = 0._R_P - self%a(4) = 16._R_P/27._R_P - - self%b(1) = 12._R_P/27._R_P - self%b(2) = 0._R_P - self%b(3) = 0._R_P - self%b(4) = 16._R_P/9._R_P - case('lmm_ssp_steps_5_order_3') - self%steps = 5 - allocate(self%a(1:self%steps)) ; self%a = 0.0_R_P - allocate(self%b(1:self%steps)) ; self%b = 0.0_R_P - self%a(1) = 7._R_P/32._R_P - self%a(2) = 0._R_P - self%a(3) = 0._R_P - self%a(4) = 0._R_P - self%a(5) = 25._R_P/32._R_P - - self%b(1) = 5._R_P/16._R_P - self%b(2) = 0._R_P - self%b(3) = 0._R_P - self%b(4) = 0._R_P - self%b(5) = 25._R_P/16._R_P - endselect - self%autoupdate = .true. ; if (present(autoupdate)) self%autoupdate = autoupdate - self%registers = self%steps - if (present(U)) call self%allocate_integrand_members(U=U) - else - call self%trigger_error(error=ERROR_UNSUPPORTED_SCHEME, & - error_message='"'//trim(adjustl(scheme))//'" unsupported scheme', & - is_severe=stop_on_fail) - endif - endsubroutine initialize + subroutine initialize(self, scheme, autoupdate, U, stop_on_fail) + !< Create the actual LMM-SSP integrator: initialize the *a,b* coefficients. + !< + !< @note If the integrator is initialized with a bad (unsupported) number of required time steps the initialization fails and + !< the integrator error status is updated consistently for external-provided errors handling. + class(integrator_lmm_ssp), intent(inout) :: self !< Integrator. + character(*), intent(in) :: scheme !< Selected scheme. + logical, intent(in), optional :: autoupdate !< Enable cyclic autoupdate of previous time steps. + class(integrand_object), intent(in), optional :: U !< Integrand molding prototype. + logical, intent(in), optional :: stop_on_fail !< Stop execution if initialization fail. + + if (self%is_supported(scheme=scheme)) then + call self%destroy + self%description_ = trim(adjustl(scheme)) + select case(trim(adjustl(scheme))) + case('lmm_ssp_steps_3_order_2') + self%steps = 3 + allocate(self%a(1:self%steps)) ; self%a = 0.0_R_P + allocate(self%b(1:self%steps)) ; self%b = 0.0_R_P + self%a(1) = 1._R_P/4._R_P + self%a(2) = 0._R_P + self%a(3) = 3._R_P/4._R_P + + self%b(1) = 0._R_P + self%b(2) = 0._R_P + self%b(3) = 3._R_P/2._R_P + case('lmm_ssp_steps_4_order_3') + self%steps = 4 + allocate(self%a(1:self%steps)) ; self%a = 0.0_R_P + allocate(self%b(1:self%steps)) ; self%b = 0.0_R_P + self%a(1) = 11._R_P/27._R_P + self%a(2) = 0._R_P + self%a(3) = 0._R_P + self%a(4) = 16._R_P/27._R_P + + self%b(1) = 12._R_P/27._R_P + self%b(2) = 0._R_P + self%b(3) = 0._R_P + self%b(4) = 16._R_P/9._R_P + case('lmm_ssp_steps_5_order_3') + self%steps = 5 + allocate(self%a(1:self%steps)) ; self%a = 0.0_R_P + allocate(self%b(1:self%steps)) ; self%b = 0.0_R_P + self%a(1) = 7._R_P/32._R_P + self%a(2) = 0._R_P + self%a(3) = 0._R_P + self%a(4) = 0._R_P + self%a(5) = 25._R_P/32._R_P + + self%b(1) = 5._R_P/16._R_P + self%b(2) = 0._R_P + self%b(3) = 0._R_P + self%b(4) = 0._R_P + self%b(5) = 25._R_P/16._R_P + endselect + self%autoupdate = .true. ; if (present(autoupdate)) self%autoupdate = autoupdate + self%registers = self%steps + if (present(U)) call self%allocate_integrand_members(U=U) + else + call self%trigger_error(error=ERROR_UNSUPPORTED_SCHEME, & + error_message='"'//trim(adjustl(scheme))//'" unsupported scheme', & + is_severe=stop_on_fail) + endif + endsubroutine initialize endmodule foodie_integrator_lmm_ssp diff --git a/src/lib/foodie_integrator_lmm_ssp_vss.f90 b/src/lib/foodie_integrator_lmm_ssp_vss.f90 index 25f86221..2f1d3680 100644 --- a/src/lib/foodie_integrator_lmm_ssp_vss.f90 +++ b/src/lib/foodie_integrator_lmm_ssp_vss.f90 @@ -67,7 +67,6 @@ module foodie_integrator_lmm_ssp_vss contains ! deferred methods procedure, pass(self) :: class_name !< Return the class name of schemes. - procedure, pass(self) :: description !< Return pretty-printed object description. procedure, pass(self) :: has_fast_mode !< Return .true. if the integrator class has *fast mode* integrate. procedure, pass(lhs) :: integr_assign_integr !< Operator `=`. procedure, pass(self) :: integrate !< Integrate integrand field. @@ -115,25 +114,6 @@ pure function class_name(self) class_name = trim(adjustl(class_name_)) endfunction class_name - pure function description(self, prefix) result(desc) - !< Return a pretty-formatted object description. - class(integrator_lmm_ssp_vss), intent(in) :: self !< Integrator. - character(*), intent(in), optional :: prefix !< Prefixing string. - character(len=:), allocatable :: desc !< Description. - character(len=:), allocatable :: prefix_ !< Prefixing string, local variable. - character(len=1), parameter :: NL=new_line('a') !< New line character. - integer(I_P) :: s !< Counter. - - prefix_ = '' ; if (present(prefix)) prefix_ = prefix - desc = '' - desc = desc//prefix_//'Strong Stability preserving Linear-Multistep-Methods Variable Stepsize class'//NL - desc = desc//prefix_//' Supported schemes:'//NL - do s=lbound(supported_schemes_, dim=1), ubound(supported_schemes_, dim=1) - 1 - desc = desc//prefix_//' + '//supported_schemes_(s)//NL - enddo - desc = desc//prefix_//' + '//supported_schemes_(ubound(supported_schemes_, dim=1)) - endfunction description - elemental function has_fast_mode(self) !< Return .true. if the integrator class has *fast mode* integrate. class(integrator_lmm_ssp_vss), intent(in) :: self !< Integrator. @@ -220,36 +200,37 @@ subroutine initialize(self, scheme, autoupdate, U, stop_on_fail) logical, intent(in), optional :: stop_on_fail !< Stop execution if initialization fail. if (self%is_supported(scheme=scheme)) then - call self%destroy - select case(trim(adjustl(scheme))) - case('lmm_ssp_vss_steps_2_order_2') - self%steps = 2 - self%integrate_ => integrate_order_2 - self%integrate_fast_ => integrate_order_2_fast - case('lmm_ssp_vss_steps_3_order_2') - self%steps = 3 - self%integrate_ => integrate_order_2 - self%integrate_fast_ => integrate_order_2_fast - case('lmm_ssp_vss_steps_3_order_3') - self%steps = 3 - self%integrate_ => integrate_order_3 - self%integrate_fast_ => integrate_order_3_fast - case('lmm_ssp_vss_steps_4_order_3') - self%steps = 4 - self%integrate_ => integrate_order_3 - self%integrate_fast_ => integrate_order_3_fast - case('lmm_ssp_vss_steps_5_order_3') - self%steps = 5 - self%integrate_ => integrate_order_3 - self%integrate_fast_ => integrate_order_3_fast - endselect - self%autoupdate = .true. ; if (present(autoupdate)) self%autoupdate = autoupdate - self%registers = self%steps - if (present(U)) call self%allocate_integrand_members(U=U) + call self%destroy + self%description_ = trim(adjustl(scheme)) + select case(trim(adjustl(scheme))) + case('lmm_ssp_vss_steps_2_order_2') + self%steps = 2 + self%integrate_ => integrate_order_2 + self%integrate_fast_ => integrate_order_2_fast + case('lmm_ssp_vss_steps_3_order_2') + self%steps = 3 + self%integrate_ => integrate_order_2 + self%integrate_fast_ => integrate_order_2_fast + case('lmm_ssp_vss_steps_3_order_3') + self%steps = 3 + self%integrate_ => integrate_order_3 + self%integrate_fast_ => integrate_order_3_fast + case('lmm_ssp_vss_steps_4_order_3') + self%steps = 4 + self%integrate_ => integrate_order_3 + self%integrate_fast_ => integrate_order_3_fast + case('lmm_ssp_vss_steps_5_order_3') + self%steps = 5 + self%integrate_ => integrate_order_3 + self%integrate_fast_ => integrate_order_3_fast + endselect + self%autoupdate = .true. ; if (present(autoupdate)) self%autoupdate = autoupdate + self%registers = self%steps + if (present(U)) call self%allocate_integrand_members(U=U) else - call self%trigger_error(error=ERROR_UNSUPPORTED_SCHEME, & - error_message='"'//trim(adjustl(scheme))//'" unsupported scheme', & - is_severe=stop_on_fail) + call self%trigger_error(error=ERROR_UNSUPPORTED_SCHEME, & + error_message='"'//trim(adjustl(scheme))//'" unsupported scheme', & + is_severe=stop_on_fail) endif endsubroutine initialize diff --git a/src/lib/foodie_integrator_ms_runge_kutta_ssp.f90 b/src/lib/foodie_integrator_ms_runge_kutta_ssp.f90 index ab505c74..02a376a8 100644 --- a/src/lib/foodie_integrator_ms_runge_kutta_ssp.f90 +++ b/src/lib/foodie_integrator_ms_runge_kutta_ssp.f90 @@ -67,7 +67,6 @@ module foodie_integrator_ms_runge_kutta_ssp contains ! deferred methods procedure, pass(self) :: class_name !< Return the class name of schemes. - procedure, pass(self) :: description !< Return pretty-printed object description. procedure, pass(self) :: has_fast_mode !< Return .true. if the integrator class has *fast mode* integrate. procedure, pass(lhs) :: integr_assign_integr !< Operator `=`. procedure, pass(self) :: integrate !< Integrate integrand field. @@ -89,25 +88,6 @@ pure function class_name(self) class_name = trim(adjustl(class_name_)) endfunction class_name - pure function description(self, prefix) result(desc) - !< Return a pretty-formatted object description. - class(integrator_ms_runge_kutta_ssp), intent(in) :: self !< Integrator. - character(*), intent(in), optional :: prefix !< Prefixing string. - character(len=:), allocatable :: desc !< Description. - character(len=:), allocatable :: prefix_ !< Prefixing string, local variable. - character(len=1), parameter :: NL=new_line('a') !< New line character. - integer(I_P) :: s !< Counter. - - prefix_ = '' ; if (present(prefix)) prefix_ = prefix - desc = '' - desc = desc//prefix_//'Multi-step Strong Stability preserving Runge-Kutta schemes class'//NL - desc = desc//prefix_//' Supported schemes:'//NL - do s=lbound(supported_schemes_, dim=1), ubound(supported_schemes_, dim=1) - 1 - desc = desc//prefix_//' + '//supported_schemes_(s)//NL - enddo - desc = desc//prefix_//' + '//supported_schemes_(ubound(supported_schemes_, dim=1)) - endfunction description - elemental function has_fast_mode(self) !< Return .true. if the integrator class has *fast mode* integrate. class(integrator_ms_runge_kutta_ssp), intent(in) :: self !< Integrator. @@ -284,6 +264,7 @@ subroutine initialize(self, scheme, iterations, autoupdate, U, stop_on_fail) if (self%is_supported(scheme=scheme)) then call self%destroy + self%description_ = trim(adjustl(scheme)) select case(trim(adjustl(scheme))) case('ms_runge_kutta_ssp_steps_2_stages_2_order_3') self%steps = 2 diff --git a/src/lib/foodie_integrator_object.f90 b/src/lib/foodie_integrator_object.f90 index 19559243..d74d36d4 100644 --- a/src/lib/foodie_integrator_object.f90 +++ b/src/lib/foodie_integrator_object.f90 @@ -12,17 +12,18 @@ module foodie_integrator_object type, abstract :: integrator_object !< Abstract type of FOODIE ODE integrators. + character(len=:), allocatable :: description_ !< Informative description of the integrator. integer(I_P) :: error=0 !< Error status code. character(len=:), allocatable :: error_message !< Error message, hopefully meaningful. contains ! public methods procedure, pass(lhs) :: assign_abstract !< Assign ony members of abstract [[integrator_object]] type. procedure, pass(self) :: check_error !< Check for error occurrencies. + procedure, pass(self) :: description !< Return informative integrator description. procedure, pass(self) :: destroy_abstract !< Destroy only members of abstract [[integrator_object]] type. procedure, pass(self) :: trigger_error !< Trigger an error. ! deferred methods procedure(class_name_interface), pass(self), deferred :: class_name !< Return the class name of schemes. - procedure(description_interface), pass(self), deferred :: description !< Return pretty-printed obj. description. procedure(has_fast_mode_interface), pass(self), deferred :: has_fast_mode !< Return .true. if the integrator class !< has *fast mode* integrate. procedure(assignment_interface), pass(lhs), deferred :: integr_assign_integr !< Operator `=`. @@ -105,6 +106,7 @@ pure subroutine assign_abstract(lhs, rhs) class(integrator_object), intent(inout) :: lhs !< Left hand side. class(integrator_object), intent(in) :: rhs !< Right hand side. + if (allocated(rhs%description_ )) lhs%description_ = rhs%description_ lhs%error = rhs%error if (allocated(rhs%error_message)) lhs%error_message = rhs%error_message endsubroutine assign_abstract @@ -129,10 +131,26 @@ subroutine check_error(self, is_severe) endif endsubroutine check_error + pure function description(self, prefix) result(desc) + !< Return informative integrator description. + class(integrator_object), intent(in) :: self !< Integrator. + character(*), intent(in), optional :: prefix !< Prefixing string. + character(len=:), allocatable :: desc !< Description. + character(len=:), allocatable :: prefix_ !< Prefixing string, local variable. + + prefix_ = '' ; if (present(prefix)) prefix_ = prefix + if (allocated(self%description_)) then + desc = prefix//self%description_ + else + desc = prefix//self%class_name() + endif + endfunction description + elemental subroutine destroy_abstract(self) !< Destroy only members of abstract [[integrator_object]] type. class(integrator_object), intent(inout) :: self !< Integrator. + if (allocated(self%description_)) deallocate(self%description_) self%error = 0 if (allocated(self%error_message)) deallocate(self%error_message) endsubroutine destroy_abstract diff --git a/src/lib/foodie_integrator_runge_kutta_embedded.f90 b/src/lib/foodie_integrator_runge_kutta_embedded.f90 index 0368554c..7e1d84a7 100644 --- a/src/lib/foodie_integrator_runge_kutta_embedded.f90 +++ b/src/lib/foodie_integrator_runge_kutta_embedded.f90 @@ -283,8 +283,6 @@ module foodie_integrator_runge_kutta_emd trim(class_name_)//'_stages_17_order_10'] !< List of supported schemes. logical, parameter :: has_fast_mode_=.true. !< Flag to check if integrator provides *fast mode* integrate. -logical, parameter :: is_multistage_=.true. !< Flag to check if integrator is multistage. -logical, parameter :: is_multistep_=.false. !< Flag to check if integrator is multistep. type, extends(integrator_multistage_object) :: integrator_runge_kutta_emd !< FOODIE integrator: provide an explicit class of embedded Runge-Kutta schemes, from 2nd to 10th order accurate. @@ -301,7 +299,6 @@ module foodie_integrator_runge_kutta_emd contains ! deferred methods procedure, pass(self) :: class_name !< Return the class name of schemes. - procedure, pass(self) :: description !< Return pretty-printed object description. procedure, pass(self) :: has_fast_mode !< Return .true. if the integrator class has *fast mode* integrate. procedure, pass(lhs) :: integr_assign_integr !< Operator `=`. procedure, pass(self) :: integrate !< Integrate integrand field. @@ -326,25 +323,6 @@ pure function class_name(self) class_name = trim(adjustl(class_name_)) endfunction class_name - pure function description(self, prefix) result(desc) - !< Return a pretty-formatted object description. - class(integrator_runge_kutta_emd), intent(in) :: self !< Integrator. - character(*), intent(in), optional :: prefix !< Prefixing string. - character(len=:), allocatable :: desc !< Description. - character(len=:), allocatable :: prefix_ !< Prefixing string, local variable. - character(len=1), parameter :: NL=new_line('a') !< New line character. - integer(I_P) :: s !< Counter. - - prefix_ = '' ; if (present(prefix)) prefix_ = prefix - desc = '' - desc = desc//prefix_//'Embedded Runge-Kutta multi-stage schemes class'//NL - desc = desc//prefix_//' Supported schemes:'//NL - do s=lbound(supported_schemes_, dim=1), ubound(supported_schemes_, dim=1) - 1 - desc = desc//prefix_//' + '//supported_schemes_(s)//NL - enddo - desc = desc//prefix_//' + '//supported_schemes_(ubound(supported_schemes_, dim=1)) - endfunction description - elemental function has_fast_mode(self) !< Return .true. if the integrator class has *fast mode* integrate. class(integrator_runge_kutta_emd), intent(in) :: self !< Integrator. @@ -499,11 +477,8 @@ subroutine initialize(self, scheme, U, tolerance, stop_on_fail) if (self%is_supported(scheme=scheme)) then call self%destroy - if (present(tolerance)) then - self%tolerance = tolerance - else - self%tolerance = 0.01_R_P - endif + self%description_ = trim(adjustl(scheme)) + self%tolerance = 0.01_R_P ; if (present(tolerance)) self%tolerance = tolerance select case(trim(adjustl(scheme))) case('runge_kutta_emd_stages_2_order_2') ! do not use, seems to not work! self%stages = 2 diff --git a/src/lib/foodie_integrator_runge_kutta_low_storage.f90 b/src/lib/foodie_integrator_runge_kutta_low_storage.f90 index 92022343..4803239a 100644 --- a/src/lib/foodie_integrator_runge_kutta_low_storage.f90 +++ b/src/lib/foodie_integrator_runge_kutta_low_storage.f90 @@ -181,7 +181,6 @@ module foodie_integrator_runge_kutta_low_storage contains ! deferred methods procedure, pass(self) :: class_name !< Return the class name of schemes. - procedure, pass(self) :: description !< Return pretty-printed object description. procedure, pass(self) :: has_fast_mode !< Return .true. if the integrator class has *fast mode* integrate. procedure, pass(lhs) :: integr_assign_integr !< Operator `=`. procedure, pass(self) :: integrate !< Integrate integrand field. @@ -204,25 +203,6 @@ pure function class_name(self) class_name = trim(adjustl(class_name_)) endfunction class_name - pure function description(self, prefix) result(desc) - !< Return a pretty-formatted object description. - class(integrator_runge_kutta_ls), intent(in) :: self !< Integrator. - character(*), intent(in), optional :: prefix !< Prefixing string. - character(len=:), allocatable :: desc !< Description. - character(len=:), allocatable :: prefix_ !< Prefixing string, local variable. - character(len=1), parameter :: NL=new_line('a') !< New line character. - integer(I_P) :: s !< Counter. - - prefix_ = '' ; if (present(prefix)) prefix_ = prefix - desc = '' - desc = desc//prefix_//'Low storage (2-registers) Runge-Kutta multi-stage schemes class'//NL - desc = desc//prefix_//' Supported schemes:'//NL - do s=lbound(supported_schemes_, dim=1), ubound(supported_schemes_, dim=1) - 1 - desc = desc//prefix_//' + '//supported_schemes_(s)//NL - enddo - desc = desc//prefix_//' + '//supported_schemes_(ubound(supported_schemes_, dim=1)) - endfunction description - elemental function has_fast_mode(self) !< Return .true. if the integrator class has *fast mode* integrate. class(integrator_runge_kutta_ls), intent(in) :: self !< Integrator. @@ -336,6 +316,7 @@ subroutine initialize(self, scheme, U, stop_on_fail) if (self%is_supported(scheme=scheme)) then call self%destroy + self%description_ = trim(adjustl(scheme)) select case(trim(adjustl(scheme))) case('runge_kutta_ls_stages_1_order_1') self%stages = 1 diff --git a/src/lib/foodie_integrator_runge_kutta_lssp.f90 b/src/lib/foodie_integrator_runge_kutta_lssp.f90 index 4ec0a736..d062c470 100644 --- a/src/lib/foodie_integrator_runge_kutta_lssp.f90 +++ b/src/lib/foodie_integrator_runge_kutta_lssp.f90 @@ -66,7 +66,7 @@ module foodie_integrator_runge_kutta_lssp use foodie_integrand_object, only : integrand_object use foodie_integrator_multistage_object, only : integrator_multistage_object use foodie_integrator_object, only : integrator_object -use penf, only : I_P, R_P +use penf, only : I_P, R_P, str implicit none private @@ -89,7 +89,6 @@ module foodie_integrator_runge_kutta_lssp contains ! deferred methods procedure, pass(self) :: class_name !< Return the class name of schemes. - procedure, pass(self) :: description !< Return pretty-printed object description. procedure, pass(self) :: has_fast_mode !< Return .true. if the integrator class has *fast mode* integrate. procedure, pass(lhs) :: integr_assign_integr !< Operator `=`. procedure, pass(self) :: integrate !< Integrate integrand field. @@ -137,25 +136,6 @@ pure function class_name(self) class_name = trim(adjustl(class_name_)) endfunction class_name - pure function description(self, prefix) result(desc) - !< Return a pretty-formatted object description. - class(integrator_runge_kutta_lssp), intent(in) :: self !< Integrator. - character(*), intent(in), optional :: prefix !< Prefixing string. - character(len=:), allocatable :: desc !< Description. - character(len=:), allocatable :: prefix_ !< Prefixing string, local variable. - character(len=1), parameter :: NL=new_line('a') !< New line character. - integer(I_P) :: s !< Counter. - - prefix_ = '' ; if (present(prefix)) prefix_ = prefix - desc = '' - desc = desc//prefix_//'Linear SSP Runge-Kutta multi-stage schemes class'//NL - desc = desc//prefix_//' Supported schemes:'//NL - do s=lbound(supported_schemes_, dim=1), ubound(supported_schemes_, dim=1) - 1 - desc = desc//prefix_//' + '//supported_schemes_(s)//NL - enddo - desc = desc//prefix_//' + '//supported_schemes_(ubound(supported_schemes_, dim=1)) - endfunction description - elemental function has_fast_mode(self) !< Return .true. if the integrator class has *fast mode* integrate. class(integrator_runge_kutta_lssp), intent(in) :: self !< Integrator. @@ -268,6 +248,7 @@ subroutine initialize(self, scheme, U, stages, stop_on_fail) allocate(self%alpha(1:self%stages)) ; self%alpha = 0._R_P call self%initialize_order_s endselect + self%description_ = trim(adjustl(scheme))//'_stages_'//trim(str(self%stages)) self%registers = self%stages if (present(U)) call self%allocate_integrand_members(U=U) else diff --git a/src/lib/foodie_integrator_runge_kutta_ssp.f90 b/src/lib/foodie_integrator_runge_kutta_ssp.f90 index d66b4369..6803e44b 100644 --- a/src/lib/foodie_integrator_runge_kutta_ssp.f90 +++ b/src/lib/foodie_integrator_runge_kutta_ssp.f90 @@ -129,7 +129,6 @@ module foodie_integrator_runge_kutta_ssp contains ! deferred methods procedure, pass(self) :: class_name !< Return the class name of schemes. - procedure, pass(self) :: description !< Return pretty-printed object description. procedure, pass(self) :: has_fast_mode !< Return .true. if the integrator class has *fast mode* integrate. procedure, pass(lhs) :: integr_assign_integr !< Operator `=`. procedure, pass(self) :: integrate !< Integrate integrand field. @@ -151,25 +150,6 @@ pure function class_name(self) class_name = trim(adjustl(class_name_)) endfunction class_name - pure function description(self, prefix) result(desc) - !< Return a pretty-formatted object description. - class(integrator_runge_kutta_ssp), intent(in) :: self !< Integrator. - character(*), intent(in), optional :: prefix !< Prefixing string. - character(len=:), allocatable :: desc !< Description. - character(len=:), allocatable :: prefix_ !< Prefixing string, local variable. - character(len=1), parameter :: NL=new_line('a') !< New line character. - integer(I_P) :: s !< Counter. - - prefix_ = '' ; if (present(prefix)) prefix_ = prefix - desc = '' - desc = desc//prefix_//'SSP Runge-Kutta multi-stage schemes class'//NL - desc = desc//prefix_//' Supported schemes:'//NL - do s=lbound(supported_schemes_, dim=1), ubound(supported_schemes_, dim=1) - 1 - desc = desc//prefix_//' + '//supported_schemes_(s)//NL - enddo - desc = desc//prefix_//' + '//supported_schemes_(ubound(supported_schemes_, dim=1)) - endfunction description - elemental function has_fast_mode(self) !< Return .true. if the integrator class has *fast mode* integrate. class(integrator_runge_kutta_ssp), intent(in) :: self !< Integrator. @@ -291,6 +271,7 @@ subroutine initialize(self, scheme, U, stop_on_fail) if (self%is_supported(scheme=scheme)) then call self%destroy + self%description_ = trim(adjustl(scheme)) select case(trim(adjustl(scheme))) case('runge_kutta_ssp_stages_1_order_1') self%stages = 1 diff --git a/src/tests/tester/foodie_test_integrand_ladvection.f90 b/src/tests/tester/foodie_test_integrand_ladvection.f90 index 853d343b..0f7dc959 100644 --- a/src/tests/tester/foodie_test_integrand_ladvection.f90 +++ b/src/tests/tester/foodie_test_integrand_ladvection.f90 @@ -9,7 +9,7 @@ module foodie_test_integrand_ladvection use flap, only : command_line_interface use foodie, only : integrand_object use foodie_test_integrand_tester_object, only : integrand_tester_object -use penf, only : FR_P, I_P, R_P, str +use penf, only : FR_P, I_P, R_P, str, strz use wenoof, only : interpolator_object, wenoof_create implicit none @@ -62,6 +62,7 @@ module foodie_test_integrand_ladvection procedure, pass(self), public :: exact_solution !< Return exact solution. procedure, pass(self), public :: output !< Extract integrand state field. ! integrand_tester_object deferred methods + procedure, pass(self), public :: description !< Return an informative description of the test. procedure, pass(self), public :: export_tecplot !< Export integrand to Tecplot file. procedure, pass(self), public :: parse_cli !< Initialize from command line interface. procedure, nopass, public :: set_cli !< Set command line interface. @@ -142,6 +143,17 @@ pure function output(self) result(state) endfunction output ! integrand_tester_object deferred methods + pure function description(self, prefix) result(desc) + !< Return informative integrator description. + class(integrand_ladvection), intent(in) :: self !< Integrator. + character(*), intent(in), optional :: prefix !< Prefixing string. + character(len=:), allocatable :: desc !< Description. + character(len=:), allocatable :: prefix_ !< Prefixing string, local variable. + + prefix_ = '' ; if (present(prefix)) prefix_ = prefix + desc = prefix//'linear_advection-Ni_'//trim(strz(self%Ni, 10)) + endfunction description + subroutine export_tecplot(self, file_name, t, scheme, close_file) !< Export integrand to Tecplot file. class(integrand_ladvection), intent(in) :: self !< Advection field. diff --git a/src/tests/tester/foodie_test_integrand_oscillation.f90 b/src/tests/tester/foodie_test_integrand_oscillation.f90 index 9b7f7d5f..c0d932c6 100644 --- a/src/tests/tester/foodie_test_integrand_oscillation.f90 +++ b/src/tests/tester/foodie_test_integrand_oscillation.f90 @@ -54,6 +54,7 @@ module foodie_test_integrand_oscillation procedure, pass(self), public :: initialize !< Initialize integrand. procedure, pass(self), public :: output !< Extract integrand state field. ! integrand_tester_object deferred methods + procedure, pass(self), public :: description !< Return an informative description of the test. procedure, pass(self), public :: export_tecplot !< Export integrand to Tecplot file. procedure, pass(self), public :: parse_cli !< Initialize from command line interface. procedure, nopass, public :: set_cli !< Set command line interface. @@ -128,6 +129,17 @@ pure function output(self) result(state) endfunction output ! integrand_tester_object deferred methods + pure function description(self, prefix) result(desc) + !< Return informative integrator description. + class(integrand_oscillation), intent(in) :: self !< Integrator. + character(*), intent(in), optional :: prefix !< Prefixing string. + character(len=:), allocatable :: desc !< Description. + character(len=:), allocatable :: prefix_ !< Prefixing string, local variable. + + prefix_ = '' ; if (present(prefix)) prefix_ = prefix + desc = prefix//'oscillation' + endfunction description + subroutine export_tecplot(self, file_name, t, scheme, close_file) !< Export integrand to Tecplot file. class(integrand_oscillation), intent(in) :: self !< Advection field. diff --git a/src/tests/tester/foodie_test_integrand_tester_object.f90 b/src/tests/tester/foodie_test_integrand_tester_object.f90 index e3d4235c..50d3bc54 100644 --- a/src/tests/tester/foodie_test_integrand_tester_object.f90 +++ b/src/tests/tester/foodie_test_integrand_tester_object.f90 @@ -16,14 +16,22 @@ module foodie_test_integrand_tester_object !< !< This abstract provided some auxiliary methods useful for the tester machinery. contains - ! auxiliary methods - procedure(export_tecplot_interface), pass(self), deferred :: export_tecplot !< Export integrand to Tecplot file. - procedure(parse_cli_interface), pass(self), deferred :: parse_cli !< Initialize from command line interface. - procedure(set_cli_interface), nopass, deferred :: set_cli !< Set command line interface. + procedure(description_interface), pass(self), deferred :: description !< Return an informative description of the test. + procedure(export_tecplot_interface), pass(self), deferred :: export_tecplot !< Export integrand to Tecplot file. + procedure(parse_cli_interface), pass(self), deferred :: parse_cli !< Initialize from command line interface. + procedure(set_cli_interface), nopass, deferred :: set_cli !< Set command line interface. endtype integrand_tester_object abstract interface !< Abstract interfaces of [[integrand_tester_object]] class. + pure function description_interface(self, prefix) result(desc) + !< Return informative integrator description. + import :: integrand_tester_object + class(integrand_tester_object), intent(in) :: self !< Integrand. + character(*), intent(in), optional :: prefix !< Prefixing string. + character(len=:), allocatable :: desc !< Description. + endfunction description_interface + subroutine export_tecplot_interface(self, file_name, t, scheme, close_file) !< Export integrand to Tecplot file. import :: integrand_tester_object, R_P @@ -48,4 +56,3 @@ subroutine set_cli_interface(cli) endsubroutine set_cli_interface endinterface endmodule foodie_test_integrand_tester_object - diff --git a/src/tests/tester/foodie_tester.f90 b/src/tests/tester/foodie_tester.f90 index adb40167..33733711 100644 --- a/src/tests/tester/foodie_tester.f90 +++ b/src/tests/tester/foodie_tester.f90 @@ -72,7 +72,6 @@ subroutine execute(self) !< Execute test(s). class(test_object), intent(inout) :: self !< Test. character(99), allocatable :: integrator_schemes(:) !< Name of FOODIE integrator schemes. - character(len=:), allocatable :: output_file_name !< File name of output results file. integer(I_P) :: s !< Counter. integer(I_P) :: t !< Counter. @@ -88,28 +87,15 @@ subroutine execute(self) endif do s=1, size(integrator_schemes, dim=1) do t=1, size(self%Dt) - select type(integrand=>self%integrand_0) - type is(integrand_ladvection) - output_file_name = trim(adjustl(self%output))//'-'//& - trim(adjustl(self%test))//'-'//& - trim(adjustl(integrator_schemes(s)))//'-'//& - trim(strz(integrand%Ni, 10))//'-steps_'//& - trim(strz(int(self%final_time/self%Dt(t)), 10))//'.dat' - type is(integrand_oscillation) - output_file_name = trim(adjustl(self%output))//'-'//& - trim(adjustl(self%test))//'-'//& - trim(adjustl(integrator_schemes(s)))//'-steps_'//& - trim(strz(int(self%final_time/self%Dt(t)), 10))//'.dat' - endselect - call integrate(scheme=trim(integrator_schemes(s)), & - integrand_0=self%integrand_0, & - Dt=self%Dt(t), & - final_time=self%final_time, & - iterations=self%implicit_iterations, & - stages=self%stages, & - is_fast=self%is_fast, & - save_results=self%save_results, & - output_file_name=output_file_name, & + call integrate(scheme=trim(integrator_schemes(s)), & + integrand_0=self%integrand_0, & + Dt=self%Dt(t), & + final_time=self%final_time, & + iterations=self%implicit_iterations, & + stages=self%stages, & + is_fast=self%is_fast, & + save_results=self%save_results, & + output_base_name=trim(adjustl(self%output)), & save_frequency=self%save_frequency) enddo enddo @@ -241,7 +227,7 @@ subroutine check_scheme_has_fast_mode(scheme, integrator) endif endsubroutine check_scheme_has_fast_mode - subroutine integrate(scheme, integrand_0, Dt, final_time, iterations, stages, is_fast, save_results, output_file_name, & + subroutine integrate(scheme, integrand_0, Dt, final_time, iterations, stages, is_fast, save_results, output_base_name, & save_frequency) !< Integrate integrand by means of the given scheme. character(*), intent(in) :: scheme !< Selected scheme. @@ -252,7 +238,7 @@ subroutine integrate(scheme, integrand_0, Dt, final_time, iterations, stages, is integer(I_P), intent(in) :: stages !< Number of stages. logical, intent(in) :: is_fast !< Activate fast mode integration. logical, intent(in) :: save_results !< Save results. - character(*), intent(in) :: output_file_name !< File name of output results file. + character(*), intent(in) :: output_base_name !< Base name of output results file. integer(I_P), intent(in) :: save_frequency !< Save frequency. class(integrator_object), allocatable :: integrator !< The integrator. type(integrator_runge_kutta_ssp) :: integrator_start !< The (auto) start integrator. @@ -270,7 +256,11 @@ subroutine integrate(scheme, integrand_0, Dt, final_time, iterations, stages, is step = 0 time = 0._R_P - if (save_results) call integrand%export_tecplot(file_name=output_file_name, t=time, scheme=scheme) + if (save_results) call integrand%export_tecplot(file_name=output_base_name// & + integrand%description(prefix='-')// & + integrator%description(prefix='-')// & + '-steps_'//trim(strz(int(final_time/Dt), 10))//'.dat', & + t=time, scheme=scheme) select type(integrator) class is(integrator_multistage_object)