From ad43b7b0dc2870576e6bacc3b3cec26e21deaf22 Mon Sep 17 00:00:00 2001 From: Stefano Zaghi Date: Tue, 30 May 2017 14:22:14 +0200 Subject: [PATCH 1/2] add lcce test to tester --- .../foodie_test_integrand_ladvection.f90 | 47 +++--- .../foodie_test_integrand_lcce.f90 | 138 ++++++++++++++---- .../foodie_test_integrand_oscillation.f90 | 20 ++- .../foodie_test_integrand_tester_object.f90 | 6 +- src/tests/tester/foodie_tester.f90 | 71 +++++---- 5 files changed, 195 insertions(+), 87 deletions(-) rename src/tests/{lcce => tester}/foodie_test_integrand_lcce.f90 (69%) diff --git a/src/tests/tester/foodie_test_integrand_ladvection.f90 b/src/tests/tester/foodie_test_integrand_ladvection.f90 index f8d4d09c..dbbba16e 100644 --- a/src/tests/tester/foodie_test_integrand_ladvection.f90 +++ b/src/tests/tester/foodie_test_integrand_ladvection.f90 @@ -151,7 +151,7 @@ pure function output(self) result(state) ! integrand_tester_object deferred methods pure function description(self, prefix) result(desc) !< Return informative integrator description. - class(integrand_ladvection), intent(in) :: self !< Integrator. + class(integrand_ladvection), intent(in) :: self !< Integrand. character(*), intent(in), optional :: prefix !< Prefixing string. character(len=:), allocatable :: desc !< Description. character(len=:), allocatable :: prefix_ !< Prefixing string, local variable. @@ -160,10 +160,11 @@ pure function description(self, prefix) result(desc) desc = prefix//'linear_advection-Ni_'//trim(strz(self%Ni, 10)) endfunction description - pure function error(self, t, U0) + pure function error(self, t, t0, U0) !< Return error. class(integrand_ladvection), intent(in) :: self !< Integrand. real(R_P), intent(in) :: t !< Time. + real(R_P), intent(in), optional :: t0 !< Initial time. class(integrand_object), intent(in), optional :: U0 !< Initial conditions. real(R_P), allocatable :: error(:) !< Error. integer(I_P) :: i !< Counter. @@ -182,10 +183,11 @@ pure function error(self, t, U0) endif endfunction error - pure function exact_solution(self, t, U0) result(exact) + pure function exact_solution(self, t, t0, U0) result(exact) !< Return exact solution. class(integrand_ladvection), intent(in) :: self !< Integrand. real(R_P), intent(in) :: t !< Time. + real(R_P), intent(in), optional :: t0 !< Initial time. class(integrand_object), intent(in), optional :: U0 !< Initial conditions. real(R_P), allocatable :: exact(:) !< Exact solution. @@ -252,14 +254,14 @@ subroutine parse_cli(self, cli) 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=self%initial_state, error=cli%error) ; if (cli%error/=0) stop + call cli%get(group='linear_advection', switch='--cfl', val=self%CFL, error=cli%error) ; if (cli%error/=0) stop + call cli%get(group='linear_advection', switch='--w-scheme', val=self%w_scheme, error=cli%error) ; if (cli%error/=0) stop + call cli%get(group='linear_advection', switch='--weno-order', val=self%weno_order, error=cli%error) ; if (cli%error/=0) stop + call cli%get(group='linear_advection', switch='--weno-eps', val=self%weno_eps, error=cli%error) ; if (cli%error/=0) stop + call cli%get(group='linear_advection', switch='-a', val=self%a, error=cli%error) ; if (cli%error/=0) stop + call cli%get(group='linear_advection', switch='--length', val=self%length, error=cli%error) ; if (cli%error/=0) stop + call cli%get(group='linear_advection', switch='--Ni', val=self%Ni, error=cli%error) ; if (cli%error/=0) stop + call cli%get(group='linear_advection', switch='-is', val=self%initial_state, error=cli%error) ; if (cli%error/=0) stop self%Ng = (self%weno_order + 1) / 2 self%Dx = self%length / self%Ni @@ -274,16 +276,19 @@ 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_group(description='linear advection test settings', group='linear_advection') + call cli%add(group='linear_advection', 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(group='linear_advection', switch='--weno-order', help='WENO order', required=.false., act='store', def='1') + call cli%add(group='linear_advection', switch='--weno-eps', help='WENO epsilon parameter', required=.false., act='store', & + def='0.000001') + call cli%add(group='linear_advection', switch='--cfl', help='CFL value', required=.false., act='store', def='0.8') + call cli%add(group='linear_advection', switch='-a', help='advection coefficient', required=.false., act='store', def='1.0') + call cli%add(group='linear_advection', switch='--length', help='domain lenth', required=.false., act='store', def='1.0') + call cli%add(group='linear_advection', switch='--Ni', help='number finite volumes used', required=.false., act='store', & + def='100') + call cli%add(group='linear_advection', switch='--initial_state', switch_ab='-is', help='initial state', required=.false., & + act='store', def='square_wave', choices='square_wave') endsubroutine set_cli ! integrand_object deferred methods diff --git a/src/tests/lcce/foodie_test_integrand_lcce.f90 b/src/tests/tester/foodie_test_integrand_lcce.f90 similarity index 69% rename from src/tests/lcce/foodie_test_integrand_lcce.f90 rename to src/tests/tester/foodie_test_integrand_lcce.f90 index ca935f00..c5e1cce2 100644 --- a/src/tests/lcce/foodie_test_integrand_lcce.f90 +++ b/src/tests/tester/foodie_test_integrand_lcce.f90 @@ -5,14 +5,16 @@ module foodie_test_integrand_lcce !< Define [[integrand_lcce]], the linear constant coefficients equation 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 : I_P, R_P +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_lcce -type, extends(integrand_object) :: integrand_lcce +type, extends(integrand_tester_object) :: integrand_lcce !< The linear constant coefficient equation field. !< !< It is a FOODIE integrand class concrete extension. @@ -47,10 +49,16 @@ module foodie_test_integrand_lcce real(R_P) :: U0=0._R_P !< Integrand initial state. contains ! auxiliary methods - 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 + ! integrand_tester_object deferred methods + procedure, pass(self), public :: description !< Return an informative description of the test. + procedure, pass(self), public :: error !< Return error. + 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 field. + 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 @@ -82,39 +90,113 @@ module foodie_test_integrand_lcce contains ! auxiliary methods - pure function exact_solution(self, t, t0) result(exact) - !< Return exact solution. - class(integrand_lcce), intent(in) :: self !< Integrand. - real(R_P), intent(in) :: t !< Time. - real(R_P), intent(in), optional :: t0 !< Initial time. - real(R_P) :: exact !< Exact solution. - real(R_P) :: t0_ !< Initial time, local variable. + pure function output(self) result(state) + !< Extract integrand state field. + class(integrand_lcce), intent(in) :: self !< Integrand. + real(R_P) :: state !< State. + state = self%U + endfunction output + + ! integrand_tester_object deferred methods + pure function description(self, prefix) result(desc) + !< Return informative integrator description. + class(integrand_lcce), intent(in) :: self !< Integrand. + 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_constant_coefficients_eq' + endfunction description + + pure function error(self, t, t0, U0) + !< Return error. + class(integrand_lcce), intent(in) :: self !< Integrand. + real(R_P), intent(in) :: t !< Time. + real(R_P), intent(in), optional :: t0 !< Initial time. + class(integrand_object), intent(in), optional :: U0 !< Initial conditions. + real(R_P), allocatable :: error(:) !< Error. + + allocate(error(1:1)) + error = abs([self%U] - self%exact_solution(t=t, t0=t0)) + endfunction error + + pure function exact_solution(self, t, t0, U0) result(exact) + !< Return exact solution. + class(integrand_lcce), intent(in) :: self !< Integrand. + real(R_P), intent(in) :: t !< Time. + real(R_P), intent(in), optional :: t0 !< Initial time. + class(integrand_object), intent(in), optional :: U0 !< Initial conditions. + real(R_P), allocatable :: exact(:) !< Exact solution. + real(R_P) :: t0_ !< Initial time, local variable. + + allocate(exact(1:1)) t0_ = 0._R_P ; if (present(t0)) t0_ = t0 - exact = (self%U0 + self%b / self%a) * exp(self%a * (t - t0_)) - self%b / self%a + exact(1) = (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) + subroutine export_tecplot(self, file_name, t, scheme, close_file) + !< Export integrand to Tecplot file. + class(integrand_lcce), 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. + + 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="t" "x"' + endif + if (present(t) .and. present(scheme) .and. is_open) then + write(unit=file_unit, fmt='(A)') 'ZONE T="'//trim(adjustl(scheme))//'"' + write(unit=file_unit, fmt='(2('//FR_P//',1X))') t, self%U + elseif (present(t) .and. is_open) then + write(unit=file_unit, fmt='(2('//FR_P//',1X))') t, self%U + endif + endif + endsubroutine export_tecplot + + pure subroutine initialize(self, Dt) !< Initialize integrand. + !< + !< Intentionally empty, all is done in `parse_cli` method. 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 + real(R_P), intent(in) :: Dt !< Time step. endsubroutine initialize - pure function output(self) result(state) - !< Extract integrand state field. - class(integrand_lcce), intent(in) :: self !< Integrand. - real(R_P) :: state !< State. + subroutine parse_cli(self, cli) + !< Initialize from command line interface. + class(integrand_lcce), intent(inout) :: self !< Advection field. + type(command_line_interface), intent(inout) :: cli !< Command line interface handler. - state = self%U - endfunction output + call cli%get(group='lcce', switch='-a', val=self%a, error=cli%error) ; if (cli%error/=0) stop + call cli%get(group='lcce', switch='-b', val=self%b, error=cli%error) ; if (cli%error/=0) stop + call cli%get(group='lcce', 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_group(description='linear constant coefficient equation test settings', group='lcce') + call cli%add(group='lcce', switch='-a', help='"a" coeff of "a * x + b" equation', required=.false., def='-1.0', act='store') + call cli%add(group='lcce', switch='-b', help='"b" coeff of "a * x + b" equation', required=.false., def='0.0', act='store') + call cli%add(group='lcce', switch='-U0', help='initial state', required=.false., def='1.0', act='store') + endsubroutine set_cli - ! deferred methods + ! integrand_object deferred methods pure function integrand_dimension(self) !< return integrand dimension. class(integrand_lcce), intent(in) :: self !< integrand. diff --git a/src/tests/tester/foodie_test_integrand_oscillation.f90 b/src/tests/tester/foodie_test_integrand_oscillation.f90 index 7dbf54c4..003c9a77 100644 --- a/src/tests/tester/foodie_test_integrand_oscillation.f90 +++ b/src/tests/tester/foodie_test_integrand_oscillation.f90 @@ -111,7 +111,7 @@ pure function output(self) result(state) ! integrand_tester_object deferred methods pure function description(self, prefix) result(desc) !< Return informative integrator description. - class(integrand_oscillation), intent(in) :: self !< Integrator. + class(integrand_oscillation), intent(in) :: self !< Integrand. character(*), intent(in), optional :: prefix !< Prefixing string. character(len=:), allocatable :: desc !< Description. character(len=:), allocatable :: prefix_ !< Prefixing string, local variable. @@ -120,10 +120,11 @@ pure function description(self, prefix) result(desc) desc = prefix//'oscillation' endfunction description - pure function error(self, t, U0) + pure function error(self, t, t0, U0) !< Return error. class(integrand_oscillation), intent(in) :: self !< Integrand. real(R_P), intent(in) :: t !< Time. + real(R_P), intent(in), optional :: t0 !< Initial time. class(integrand_object), intent(in), optional :: U0 !< Initial conditions. real(R_P), allocatable :: error(:) !< Error. @@ -131,10 +132,11 @@ pure function error(self, t, U0) error = abs(self%U - self%exact_solution(t=t)) endfunction error - pure function exact_solution(self, t, U0) result(exact) + pure function exact_solution(self, t, t0, U0) result(exact) !< Return exact solution. class(integrand_oscillation), intent(in) :: self !< Integrand. real(R_P), intent(in) :: t !< Time. + real(R_P), intent(in), optional :: t0 !< Initial time. class(integrand_object), intent(in), optional :: U0 !< Initial conditions. real(R_P), allocatable :: exact(:) !< Exact solution. @@ -151,7 +153,6 @@ subroutine export_tecplot(self, file_name, t, scheme, close_file) 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 @@ -187,8 +188,8 @@ subroutine parse_cli(self, cli) 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 + call cli%get(group='oscillation', switch='-f', val=self%f, error=cli%error) ; if (cli%error/=0) stop + call cli%get(group='oscillation', switch='-U0', val=self%U0, error=cli%error) ; if (cli%error/=0) stop self%U = self%U0 endsubroutine parse_cli @@ -196,8 +197,11 @@ subroutine set_cli(cli) !< Set command line interface. type(command_line_interface), intent(inout) :: cli !< Command line interface handler. - 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') + call cli%add_group(description='oscillation test settings', group='oscillation') + call cli%add(group='oscillation', switch='--frequency', switch_ab='-f', help='frequency', required=.false., def='1e-4', & + act='store') + call cli%add(group='oscillation', switch='--U0', switch_ab='-U0', nargs='2', help='initial state', required=.false., & + def='0.0 1.0', act='store') endsubroutine set_cli ! integrand_object deferred methods diff --git a/src/tests/tester/foodie_test_integrand_tester_object.f90 b/src/tests/tester/foodie_test_integrand_tester_object.f90 index 17e7e4bc..0ed67ea0 100644 --- a/src/tests/tester/foodie_test_integrand_tester_object.f90 +++ b/src/tests/tester/foodie_test_integrand_tester_object.f90 @@ -35,20 +35,22 @@ pure function description_interface(self, prefix) result(desc) character(len=:), allocatable :: desc !< Description. endfunction description_interface - pure function error_interface(self, t, U0) result(error) + pure function error_interface(self, t, t0, U0) result(error) !< Return error. import :: integrand_object, integrand_tester_object, R_P class(integrand_tester_object), intent(in) :: self !< Integrand. real(R_P), intent(in) :: t !< Time. + real(R_P), intent(in), optional :: t0 !< Initial time. class(integrand_object), intent(in), optional :: U0 !< Initial conditions. real(R_P), allocatable :: error(:) !< Error. endfunction error_interface - pure function exact_solution_interface(self, t, U0) result(exact) + pure function exact_solution_interface(self, t, t0, U0) result(exact) !< Return exact solution. import :: integrand_object, integrand_tester_object, R_P class(integrand_tester_object), intent(in) :: self !< Integrand. real(R_P), intent(in) :: t !< Time. + real(R_P), intent(in), optional :: t0 !< Initial time. class(integrand_object), intent(in), optional :: U0 !< Initial conditions. real(R_P), allocatable :: exact(:) !< Exact solution. endfunction exact_solution_interface diff --git a/src/tests/tester/foodie_tester.f90 b/src/tests/tester/foodie_tester.f90 index 348eae0c..2f16e4e7 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_lcce, only : integrand_lcce 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 @@ -45,7 +46,6 @@ module foodie_test_object 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. @@ -55,6 +55,7 @@ module foodie_test_object logical :: save_results !< Flag for activating results saving. character(99) :: output !< Output files basename. integer(I_P) :: save_frequency !< Save frequency. + type(integrand_lcce) :: lcce_0 !< Initial conditions for linear constant coefficients eq. 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. @@ -88,6 +89,7 @@ subroutine execute(self) endif allocate(error(1:size(self%integrand_0%error(t=0._R_P), dim=1), 1:size(self%Dt, dim=1))) if (size(self%Dt, dim=1) > 1) allocate(order(1:size(error, dim=1), 1:size(error, dim=2)-1)) + print '(A)', self%integrand_0%description() do s=1, size(integrator_schemes, dim=1) print '(A)', trim(integrator_schemes(s)) do t=1, size(self%Dt) @@ -128,20 +130,28 @@ subroutine set_cli() 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='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='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') + examples = ["foodie_tester test --scheme euler_explicit --save_results ", & + "foodie_tester test --scheme all -r "]) + call cli%add_group(description='general test settings', group='test') + call cli%add(group='test', switch='--scheme', switch_ab='-s', help='integrator scheme used', required=.false., def='all', & + act='store') + call cli%add(group='test', switch='--time_step', switch_ab='-Dt', nargs='+', help='time step', required=.false., & + def='1e2', act='store') + call cli%add(group='test', switch='--fast', help='activate fast solvers', required=.false., act='store_true', & + def='.false.') + call cli%add(group='test', switch='--iterations', help='iterations number for implicit schemes', required=.false., & + act='store', def='5') + call cli%add(group='test', switch='--stages', help='stages number', required=.false., def='2', act='store') + call cli%add(group='test', switch='--final_time', switch_ab='-ft', help='integration time', required=.false., def='1e6', & + act='store') + call cli%add(group='test', switch='--save_results', switch_ab='-r',help='save result', required=.false., & + act='store_true', def='.false.') + call cli%add(group='test', switch='--output', help='output file basename', required=.false., act='store', & + def='foodie_test') + call cli%add(group='test', switch='--save_frequency', help='save frequency', required=.false., act='store', & + def='1') endassociate + call self%lcce_0%set_cli(cli=self%cli) call self%ladvection_0%set_cli(cli=self%cli) call self%oscillation_0%set_cli(cli=self%cli) endsubroutine set_cli @@ -154,27 +164,32 @@ 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_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='-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(group='test', switch='-s', val=self%scheme, error=self%error) ; if (self%error/=0) stop + call self%cli%get_varying(group='test', switch='-Dt', val=self%Dt, error=self%error) ; if (self%error/=0) stop + call self%cli%get(group='test', switch='--fast', val=self%is_fast, error=self%error) ; if (self%error/=0) stop + call self%cli%get(group='test', switch='--iterations',val=self%implicit_iterations,error=self%error) ; if (self%error/=0) stop + call self%cli%get(group='test', switch='--stages', val=self%stages, error=self%error) ; if (self%error/=0) stop + call self%cli%get(group='test', switch='-ft', val=self%final_time, error=self%error) ; if (self%error/=0) stop + call self%cli%get(group='test', switch='-r', val=self%save_results, error=self%error) ; if (self%error/=0) stop + call self%cli%get(group='test', switch='--output', val=self%output, error=self%error) ; if (self%error/=0) stop + call self%cli%get(group='test', switch='--save_frequency',val=self%save_frequency,error=self%error) ; if (self%error/=0) stop + call self%lcce_0%parse_cli(cli=self%cli) 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') + if (self%cli%run_command('lcce')) then + allocate(integrand_lcce :: self%integrand_0) + self%integrand_0 = self%lcce_0 + elseif (self%cli%run_command('linear_advection')) then allocate(integrand_ladvection :: self%integrand_0) self%integrand_0 = self%ladvection_0 - case('oscillation') + elseif (self%cli%run_command('oscillation')) then allocate(integrand_oscillation :: self%integrand_0) self%integrand_0 = self%oscillation_0 - endselect + else + allocate(integrand_oscillation :: self%integrand_0) + self%integrand_0 = self%oscillation_0 + endif if (.not.is_dt_valid()) then write(stderr, '(A)') 'error: the final integration time must be an exact multiple of the time step used' From c7f2bda435520bdb58171802f63880da52b5e154 Mon Sep 17 00:00:00 2001 From: Stefano Zaghi Date: Thu, 1 Jun 2017 17:20:43 +0200 Subject: [PATCH 2/2] sanitize tester --- fobos | 22 +++-- .../foodie_test_integrand_ladvection.f90 | 83 ++++++++++++++----- .../tester/foodie_test_integrand_lcce.f90 | 38 ++++++--- .../foodie_test_integrand_oscillation.f90 | 38 ++++++--- .../foodie_test_integrand_tester_object.f90 | 16 ++-- src/tests/tester/foodie_tester.f90 | 20 +++-- 6 files changed, 147 insertions(+), 70 deletions(-) diff --git a/fobos b/fobos index 3902fbbc..0fa3beba 100644 --- a/fobos +++ b/fobos @@ -219,16 +219,20 @@ 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/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_2 = ./build/tests/tester/foodie_tester lcce test -ft 2 -Dt 1e-1 1e-2 +rule_3 = ./build/tests/tester/foodie_tester linear_advection -is sin_wave --weno-order 3 test -s runge_kutta_ls -ft 1 -Dt 8e-3 2e-3 +rule_4 = ./build/tests/tester/foodie_tester oscillation test -ft 1e4 -Dt 1e1 0.5e1 +rule_5 = rm -f build/tests/tester/obj/penf* build/tests/tester/obj/face* build/tests/tester/obj/flap* build/tests/tester/obj/penf* build/tests/tester/obj/wenoof* +rule_6 = gcov -o build/tests/tester/obj/ src/lib/foodie* +rule_7 = 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/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 +rule_2 = ./build/tests/tester/foodie_tester lcce test -ft 2 -Dt 1e-1 1e-2 +rule_3 = ./build/tests/tester/foodie_tester linear_advection -is sin_wave --weno-order 3 test -s runge_kutta_ls -ft 1 -Dt 8e-3 2e-3 +rule_4 = ./build/tests/tester/foodie_tester oscillation test -ft 1e4 -Dt 1e1 0.5e1 +rule_5 = rm -f build/tests/tester/obj/penf* build/tests/tester/obj/face* build/tests/tester/obj/flap* build/tests/tester/obj/penf* build/tests/tester/obj/wenoof* +rule_6 = gcov -o build/tests/tester/obj/ src/lib/foodie* +rule_7 = FoBiS.py rule -gcov_analyzer wiki/ Coverage-Analysis +rule_8 = rm -f *.gcov diff --git a/src/tests/tester/foodie_test_integrand_ladvection.f90 b/src/tests/tester/foodie_test_integrand_ladvection.f90 index dbbba16e..90733c0c 100644 --- a/src/tests/tester/foodie_test_integrand_ladvection.f90 +++ b/src/tests/tester/foodie_test_integrand_ladvection.f90 @@ -101,6 +101,7 @@ module foodie_test_integrand_ladvection ! 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 :: set_sin_wave_initial_state !< Set initial state as a sin wave. procedure, pass(self), private :: set_square_wave_initial_state !< Set initial state as a square wave. endtype integrand_ladvection @@ -157,7 +158,7 @@ pure function description(self, prefix) result(desc) character(len=:), allocatable :: prefix_ !< Prefixing string, local variable. prefix_ = '' ; if (present(prefix)) prefix_ = prefix - desc = prefix//'linear_advection-Ni_'//trim(strz(self%Ni, 10)) + desc = prefix//'linear_advection-'//trim(self%initial_state)//'-Ni_'//trim(strz(self%Ni, 10)) endfunction description pure function error(self, t, t0, U0) @@ -175,11 +176,10 @@ pure function error(self, t, t0, U0) select type(U0) type is(integrand_ladvection) do i=1, self%Ni - ! error = error + (U0%u(i) - self%u(i)) ** 2 - error = max(error, abs(U0%u(i) - self%u(i))) + error = error + (U0%u(i) - self%u(i)) ** 2 enddo endselect - ! error = sqrt(error) + error = self%Dx * sqrt(error) endif endfunction error @@ -190,27 +190,40 @@ pure function exact_solution(self, t, t0, U0) result(exact) real(R_P), intent(in), optional :: t0 !< Initial time. class(integrand_object), intent(in), optional :: U0 !< Initial conditions. real(R_P), allocatable :: exact(:) !< Exact solution. + integer(I_P) :: offset !< Cells offset. + integer(I_P) :: i !< Counter. + allocate(exact(1:self%Ni)) if (present(U0)) then select type(U0) type is(integrand_ladvection) - exact = U0%u(1:self%Ni) + offset = nint(mod(self%a * t, self%length) / self%Dx) + do i=1, self%Ni - offset + exact(i + offset) = U0%u(i) + enddo + do i=self%Ni - offset + 1, self%Ni + exact(i - self%Ni + offset) = U0%u(i) + enddo endselect else exact = self%u(1:self%Ni) * 0._R_P endif endfunction exact_solution - subroutine export_tecplot(self, file_name, t, scheme, close_file) + subroutine export_tecplot(self, file_name, t, scheme, close_file, with_exact_solution, U0) !< 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. - integer(I_P) :: i !< Counter. + 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, intent(in), optional :: with_exact_solution !< Flag for export also exact solution. + class(integrand_object), intent(in), optional :: U0 !< Initial conditions. + logical :: with_exact_solution_ !< Flag for export also exact solution, local variable. + logical, save :: is_open=.false. !< Flag for checking if file is open. + integer(I_P), save :: file_unit !< File unit. + real(R_P), allocatable :: exact_solution(:) !< Exact solution. + integer(I_P) :: i !< Counter. if (present(close_file)) then if (close_file .and. is_open) then @@ -218,6 +231,7 @@ subroutine export_tecplot(self, file_name, t, scheme, close_file) is_open = .false. endif else + with_exact_solution_ = .false. ; if (present(with_exact_solution)) with_exact_solution_ = with_exact_solution if (present(file_name)) then if (is_open) close(unit=file_unit) open(newunit=file_unit, file=trim(adjustl(file_name))) @@ -229,6 +243,13 @@ subroutine export_tecplot(self, file_name, t, scheme, close_file) 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 + if (with_exact_solution_) then + exact_solution = self%exact_solution(t=t, U0=U0) + write(unit=file_unit, fmt='(A)') 'ZONE T="'//str(t)//' exact solution"' + do i=1, self%Ni + write(unit=file_unit, fmt='(2('//FR_P//',1X))') self%Dx * i - 0.5_R_P * self%Dx, exact_solution(i) + enddo + endif endif endif endsubroutine export_tecplot @@ -242,6 +263,8 @@ subroutine initialize(self, Dt) self%Ni = nint(self%length / self%Dx) select case(trim(adjustl(self%initial_state))) + case('sin_wave') + call self%set_sin_wave_initial_state case('square_wave') call self%set_square_wave_initial_state endselect @@ -288,7 +311,7 @@ subroutine set_cli(cli) call cli%add(group='linear_advection', switch='--Ni', help='number finite volumes used', required=.false., act='store', & def='100') call cli%add(group='linear_advection', switch='--initial_state', switch_ab='-is', help='initial state', required=.false., & - act='store', def='square_wave', choices='square_wave') + act='store', def='sin_wave', choices='sin_wave,square_wave') endsubroutine set_cli ! integrand_object deferred methods @@ -310,7 +333,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%Ng:self%Ni+self%Ng)) + allocate(dState_dt(1:self%Ni)) do i=1, self%Ni dState_dt(i) = (f(i - 1) - f(i)) / self%Dx enddo @@ -561,20 +584,34 @@ subroutine reconstruct_interfaces(self, conservative, r_conservative) 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. + class(integrand_ladvection), intent(inout) :: self !< Advection field. + real(R_P) :: x !< Cell center x-abscissa values. + integer(I_P) :: i !< Space counter. - if (allocated(self%u)) deallocate(self%u) ; allocate(self%u(1-self%Ng:self%Ni+self%Ng)) + if (allocated(self%u)) deallocate(self%u) ; allocate(self%u(1:self%Ni)) do i=1, self%Ni - x(i) = self%Dx * i - 0.5_R_P * self%Dx - if (x(i) < 0.25_R_P) then + x = self%Dx * i - 0.5_R_P * self%Dx + if (x < 0.25_R_P) then self%u(i) = 0._R_P - elseif (0.25_R_P <= x(i) .and. x(i) < 0.75_R_P) then + elseif (0.25_R_P <= x .and. x < 0.75_R_P) then self%u(i) = 1._R_P else self%u(i) = 0._R_P endif enddo endsubroutine set_square_wave_initial_state + + subroutine set_sin_wave_initial_state(self) + !< Set initial state as a sin wave. + class(integrand_ladvection), intent(inout) :: self !< Advection field. + real(R_P) :: x !< Cell center x-abscissa values. + real(R_P), parameter :: pi=4._R_P*atan(1._R_P) !< Pi greek. + integer(I_P) :: i !< Space counter. + + if (allocated(self%u)) deallocate(self%u) ; allocate(self%u(1:self%Ni)) + do i=1, self%Ni + x = self%Dx * i - 0.5_R_P * self%Dx + self%u(i) = sin(x * 2 * pi) + enddo + endsubroutine set_sin_wave_initial_state endmodule foodie_test_integrand_ladvection diff --git a/src/tests/tester/foodie_test_integrand_lcce.f90 b/src/tests/tester/foodie_test_integrand_lcce.f90 index c5e1cce2..a5320f05 100644 --- a/src/tests/tester/foodie_test_integrand_lcce.f90 +++ b/src/tests/tester/foodie_test_integrand_lcce.f90 @@ -136,15 +136,18 @@ pure function exact_solution(self, t, t0, U0) result(exact) exact(1) = (self%U0 + self%b / self%a) * exp(self%a * (t - t0_)) - self%b / self%a endfunction exact_solution - subroutine export_tecplot(self, file_name, t, scheme, close_file) + subroutine export_tecplot(self, file_name, t, scheme, close_file, with_exact_solution, U0) !< Export integrand to Tecplot file. - class(integrand_lcce), 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. + class(integrand_lcce), 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, intent(in), optional :: with_exact_solution !< Flag for export also exact solution. + class(integrand_object), intent(in), optional :: U0 !< Initial conditions. + logical :: with_exact_solution_ !< Flag for export also exact solution, local variable. + logical, save :: is_open=.false. !< Flag for checking if file is open. + integer(I_P), save :: file_unit !< File unit. if (present(close_file)) then if (close_file .and. is_open) then @@ -152,17 +155,30 @@ subroutine export_tecplot(self, file_name, t, scheme, close_file) is_open = .false. endif else + with_exact_solution_ = .false. ; if (present(with_exact_solution)) with_exact_solution_ = with_exact_solution 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="t" "x"' + if (with_exact_solution_) then + write(unit=file_unit, fmt='(A)') 'VARIABLES="t" "x" "x_exact"' + else + write(unit=file_unit, fmt='(A)') 'VARIABLES="t" "x"' + endif endif if (present(t) .and. present(scheme) .and. is_open) then write(unit=file_unit, fmt='(A)') 'ZONE T="'//trim(adjustl(scheme))//'"' - write(unit=file_unit, fmt='(2('//FR_P//',1X))') t, self%U + if (with_exact_solution_) then + write(unit=file_unit, fmt='(3('//FR_P//',1X))') t, self%U, self%exact_solution(t=t) + else + write(unit=file_unit, fmt='(2('//FR_P//',1X))') t, self%U + endif elseif (present(t) .and. is_open) then - write(unit=file_unit, fmt='(2('//FR_P//',1X))') t, self%U + if (with_exact_solution_) then + write(unit=file_unit, fmt='(3('//FR_P//',1X))') t, self%U, self%exact_solution(t=t) + else + write(unit=file_unit, fmt='(2('//FR_P//',1X))') t, self%U + endif endif endif endsubroutine export_tecplot diff --git a/src/tests/tester/foodie_test_integrand_oscillation.f90 b/src/tests/tester/foodie_test_integrand_oscillation.f90 index 003c9a77..e40a223f 100644 --- a/src/tests/tester/foodie_test_integrand_oscillation.f90 +++ b/src/tests/tester/foodie_test_integrand_oscillation.f90 @@ -144,15 +144,18 @@ pure function exact_solution(self, t, t0, U0) result(exact) 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) + subroutine export_tecplot(self, file_name, t, scheme, close_file, with_exact_solution, U0) !< 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. + 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, intent(in), optional :: with_exact_solution !< Flag for export also exact solution. + class(integrand_object), intent(in), optional :: U0 !< Initial conditions. + logical :: with_exact_solution_ !< Flag for export also exact solution, local variable. + logical, save :: is_open=.false. !< Flag for checking if file is open. + integer(I_P), save :: file_unit !< File unit. if (present(close_file)) then if (close_file .and. is_open) then @@ -160,17 +163,30 @@ subroutine export_tecplot(self, file_name, t, scheme, close_file) is_open = .false. endif else + with_exact_solution_ = .false. ; if (present(with_exact_solution)) with_exact_solution_ = with_exact_solution 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="t" "x" "y" "amplitude" "phase"' + if (with_exact_solution_) then + write(unit=file_unit, fmt='(A)') 'VARIABLES="t" "x" "y" "amplitude" "phase" "x_e" "y_e"' + else + write(unit=file_unit, fmt='(A)') 'VARIABLES="t" "x" "y" "amplitude" "phase"' + endif endif if (present(t) .and. present(scheme) .and. is_open) then 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() + if (with_exact_solution_) then + write(unit=file_unit, fmt='(7('//FR_P//',1X))') t, self%U, self%amplitude_phase(), self%exact_solution(t=t) + else + write(unit=file_unit, fmt='(5('//FR_P//',1X))') t, self%U, self%amplitude_phase() + endif elseif (present(t) .and. is_open) then - write(unit=file_unit, fmt='(5('//FR_P//',1X))') t, self%U, self%amplitude_phase() + if (with_exact_solution_) then + write(unit=file_unit, fmt='(7('//FR_P//',1X))') t, self%U, self%amplitude_phase(), self%exact_solution(t=t) + else + write(unit=file_unit, fmt='(5('//FR_P//',1X))') t, self%U, self%amplitude_phase() + endif endif endif endsubroutine export_tecplot diff --git a/src/tests/tester/foodie_test_integrand_tester_object.f90 b/src/tests/tester/foodie_test_integrand_tester_object.f90 index 0ed67ea0..78b82dbd 100644 --- a/src/tests/tester/foodie_test_integrand_tester_object.f90 +++ b/src/tests/tester/foodie_test_integrand_tester_object.f90 @@ -55,14 +55,16 @@ pure function exact_solution_interface(self, t, t0, U0) result(exact) real(R_P), allocatable :: exact(:) !< Exact solution. endfunction exact_solution_interface - subroutine export_tecplot_interface(self, file_name, t, scheme, close_file) + subroutine export_tecplot_interface(self, file_name, t, scheme, close_file, with_exact_solution, U0) !< Export integrand to Tecplot file. - import :: integrand_tester_object, R_P - class(integrand_tester_object), intent(in) :: self !< Integrand. - 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. + import :: integrand_object, integrand_tester_object, R_P + class(integrand_tester_object), intent(in) :: self !< Integrand. + 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, intent(in), optional :: with_exact_solution !< Flag for export also exact solution. + class(integrand_object), intent(in), optional :: U0 !< Initial conditions. endsubroutine export_tecplot_interface subroutine initialize_interface(self, Dt) diff --git a/src/tests/tester/foodie_tester.f90 b/src/tests/tester/foodie_tester.f90 index 2f16e4e7..f6590ee2 100644 --- a/src/tests/tester/foodie_tester.f90 +++ b/src/tests/tester/foodie_tester.f90 @@ -268,7 +268,6 @@ subroutine integrate(scheme, integrand_0, Dt, final_time, iterations, stages, is real(R_P), allocatable :: error_(:) !< Error of integrand integration. class(integrand_tester_object) , allocatable :: integrand !< Integrand. class(integrator_object), allocatable :: integrator !< The integrator. - type(integrator_runge_kutta_ssp) :: integrator_start !< The (auto) start integrator. real(R_P) :: time !< Time. integer(I_P) :: step !< Time steps counter. @@ -278,15 +277,16 @@ 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()) call integrator_start%initialize(scheme='runge_kutta_ssp_stages_5_order_4', U=integrand_0) - step = 0 time = 0._R_P 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) + t=time, & + scheme=scheme, & + with_exact_solution=.true., & + U0=integrand_0) select type(integrator) class is(integrator_multistage_object) @@ -306,11 +306,11 @@ 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) - integrator%previous(step) = integrand time = time + Dt integrator%Dt(step) = Dt integrator%t(step) = time + integrator%previous(step) = integrand%exact_solution(t=time, U0=integrand_0) + integrand = integrator%previous(step) else if (is_fast) then call integrator%integrate_fast(U=integrand, Dt=Dt, t=time) @@ -327,11 +327,11 @@ 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) - integrator%previous(step) = integrand time = time + Dt integrator%Dt(step) = Dt integrator%t(step) = time + integrator%previous(step) = integrand%exact_solution(t=time, U0=integrand_0) + integrand = integrator%previous(step) else if (is_fast) then call integrator%integrate_fast(U=integrand, Dt=Dt,t=time) @@ -366,10 +366,12 @@ subroutine integrand_export_tecplot !< Export current integrand solution to tecplot file. select type(integrand) + type is(integrand_lcce) + if (save_results .and. mod(step, save_frequency)==0) call integrand%export_tecplot(t=time, with_exact_solution=.true.) 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) + if (save_results .and. mod(step, save_frequency)==0) call integrand%export_tecplot(t=time, with_exact_solution=.true.) endselect endsubroutine integrand_export_tecplot endsubroutine integrate