checkpoint_monitor_m.f90 Source File


Contents


Source Code

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