module checkpoint_monitor_m !! Module containing general driver for monitoring checkpoints use precision_grillix_m, only : GP, GP_EPS use error_handling_grillix_m, only : handle_error, error_info_t use status_codes_grillix_m, only : GRILLIX_ERR_OTHER implicit none type, public :: checkpoint_monitor_t !! Datatype for checkpoint monitor real(GP), private :: major_interval !! Time interval of major cycle real(GP), private :: minor_interval !! Time interval of minor cycle integer, private :: major_tally !! Tally of elapsed major cycles integer, private :: minor_tally_fwd !! Tally of elapsed minor cycles, starting count at major checkpt integer, private :: minor_tally_bwd !! Tally of elapsed minor cycles, starting count after major checkpt logical, private :: reset_minor_tally_bwd !! Flag set when minor_tally_bwd must be reset after a major checkpt logical, private :: major_checkpoint !! Flag set when current time aligns with major cycle logical, private :: minor_checkpoint !! Flag set when current time aligns with minor cycle contains procedure, public :: get_major_tally procedure, public :: get_minor_tally_fwd procedure, public :: get_minor_tally_bwd procedure, public :: on_major_checkpoint procedure, public :: on_minor_checkpoint procedure, public :: init => init_monitor procedure, public :: drive end type contains integer pure function get_minor_tally_fwd(self) !! Return current fwd tally for the minor cycle class(checkpoint_monitor_t), intent(in) :: self !! Instance of class get_minor_tally_fwd = self%minor_tally_fwd end function get_minor_tally_fwd integer pure function get_minor_tally_bwd(self) !! Return current bwd tally for the minor cycle class(checkpoint_monitor_t), intent(in) :: self !! Instance of class get_minor_tally_bwd = self%minor_tally_bwd end function get_minor_tally_bwd integer pure function get_major_tally(self) !! Return current tally for the major cycle class(checkpoint_monitor_t), intent(in) :: self !! Instance of class get_major_tally = self%major_tally end function get_major_tally logical pure function on_minor_checkpoint(self) !! Return current checkpoint state for the minor cycle class(checkpoint_monitor_t), intent(in) :: self !! Instance of class on_minor_checkpoint = self%minor_checkpoint end function on_minor_checkpoint logical pure function on_major_checkpoint(self) !! Return current checkpoint state for the major cycle class(checkpoint_monitor_t), intent(in) :: self !! Instance of class on_major_checkpoint = self%major_checkpoint end function on_major_checkpoint subroutine init_monitor(self, major_interval, minor_interval, & major_tally_offset) !! Initialize checkpoint monitor class(checkpoint_monitor_t), intent(inout) :: self !! Instance of class real(GP), intent(in) :: major_interval !! Time interval of major cycle real(GP), optional, intent(in) :: minor_interval !! Time interval of minor cycle !! If not provided, minor cycle is set to match major cycle integer, optional, intent(in) :: major_tally_offset !! Offset of tally of elapsed major cycles !! If not given, tally starts at 0 (1 after first major checkpoint) ! Assert that major interval is well-defined if (major_interval < GP_EPS) then call handle_error('Major interval must be larger than 0', & GRILLIX_ERR_OTHER, __LINE__, __FILE__, & error_info_t('Major interval: ', & r_info=[major_interval])) endif self%major_interval = major_interval self%minor_tally_fwd = 0 self%minor_tally_bwd = 0 self%reset_minor_tally_bwd = .false. ! Set optional arguments if (present(minor_interval)) then ! Assert that minor interval is well-defined if (minor_interval < GP_EPS) then call handle_error('Minor interval must be larger than 0', & GRILLIX_ERR_OTHER, __LINE__, __FILE__, & error_info_t('Major interval: ', & r_info=[minor_interval])) endif if (minor_interval > major_interval) then call handle_error('Major interval must be larger than minor interval', & GRILLIX_ERR_OTHER, __LINE__, __FILE__, & error_info_t('Minor,Major interval: ',& r_info=[minor_interval,major_interval])) endif self%minor_interval = minor_interval else ! If no minor interval specified, its interval will match major ! interval self%minor_interval = major_interval endif if (present(major_tally_offset)) then self%major_tally = major_tally_offset else self%major_tally = 0 endif end subroutine subroutine drive(self, tau, dtau) !! Check if time aligns with cycle and set according checkpoint flag class(checkpoint_monitor_t), intent(inout) :: self !! Instance of class real(GP), intent(in) :: tau !! Current time real(GP), intent(in) :: dtau !! Time step real(GP) :: tau_mod_major, tau_mod_minor tau_mod_minor = mod(tau, self%minor_interval) tau_mod_major = mod(tau, self%major_interval) ! Reset bwd minor tally if ( self%reset_minor_tally_bwd ) then self%minor_tally_bwd = 0 self%reset_minor_tally_bwd = .false. endif ! Check if time aligns with major cycle if ( ( tau_mod_major < dtau/2.0_GP ) .or. & ( tau_mod_major > self%major_interval - dtau/2.0_GP ) ) then self%major_checkpoint = .true. ! Increment major tally self%major_tally = self%major_tally + 1 ! Reset fwd minor tally self%minor_tally_fwd = 0 ! Reset bwd minor tally in next timestep self%reset_minor_tally_bwd = .true. else self%major_checkpoint = .false. endif ! Check if time aligns with minor cycle if ( ( tau_mod_minor < dtau/2.0_GP ) .or. & ( tau_mod_minor > self%minor_interval - dtau/2.0_GP ) ) then self%minor_checkpoint = .true. ! Increment minor tally self%minor_tally_fwd = self%minor_tally_fwd + 1 self%minor_tally_bwd = self%minor_tally_bwd + 1 else self%minor_checkpoint = .false. endif end subroutine end module