exit_codes.f90 Source File


Contents

Source Code


Source Code

!> Provides the [[exit_code]] type used to represent an exit reason.
!> Also provides a number of specific [[exit_code]] instances for
!> regular expected exit reasons.
module exit_codes
  implicit none
  private

  public :: exit_code
  public :: EXIT_NOT_REQUESTED
  public :: EXIT_NSTEP
  public :: EXIT_MAX_SIM_TIME
  public :: EXIT_LINEAR_CONVERGENCE
  public :: EXIT_NONLINEAR_CONVERGENCE
  public :: EXIT_OUT_OF_TIME
  public :: EXIT_STOP_FILE
  public :: EXIT_SMALL_TIMESTEP
  public :: EXIT_RAPID_TIMESTEP_CHANGE

  !> Length of the exit message string
  integer, parameter :: exit_string_len = 100

  !> Type providing an exit code and message text for exit reasons
  type :: exit_code
     private
     !> A numeric exit code used to identify the exit reason.
     integer :: code = 0
     !> A user friendly message explaining the exit reason.
     character(len=exit_string_len) :: message = "No exit reason specified. Code termination may be unexpected."
   contains
     !> Construct the output message describing the exit reason and return as a string
     procedure :: create_message
     !> Ask for the exit reason output message and write to the [[exit_reason_unit]]
     procedure :: write_exit_file
     !> Ask if this instance is identical to another passed `exit_code`
     procedure :: is_identical
     !> Ask if this instance's code matches the passed value. This can
     !> either be another `exit_code` instance or an integer.
     procedure, private :: code_matches_integer
     procedure, private :: code_matches_instance
     generic :: code_matches => code_matches_integer, code_matches_instance
  end type exit_code

  ! List of all exit codes.
  ! "Good" exits have positive integers, "bad" exits have negative.

  !> Type for exiting without specifying a reason, note this uses the default code and message
  type(exit_code), parameter :: EXIT_NOT_REQUESTED = exit_code()
  !> Type for exiting after completing the specified number of timesteps.
  type(exit_code), parameter :: EXIT_NSTEP = exit_code(code=1, message="nstep timesteps completed.")
  !> Type for exiting after a linear simulation has converged.
  type(exit_code), parameter :: EXIT_LINEAR_CONVERGENCE = exit_code(code=2, message="Linear simulation is converged.")
  !> Type for exiting after a nonlinear simulation has converged.
  type(exit_code), parameter :: EXIT_NONLINEAR_CONVERGENCE = exit_code(code=3, message="Nonlinear simulation is converged.")
  !> Type for exiting after reaching the specified simulation time
  type(exit_code), parameter :: EXIT_MAX_SIM_TIME = exit_code(code=4, &
       message="Requested maximum simulation time (knobs::max_sim_time) reached.")
  !> Type for exiting on running out of CPU time.
  type(exit_code), parameter :: EXIT_OUT_OF_TIME = exit_code(code=-1, message="GS2 internal time limit exceeded.")
  !> Type for exiting on detecting a stop file.
  type(exit_code), parameter :: EXIT_STOP_FILE = exit_code(code=-2, message="Stop file detected.")
  !> Type for exiting after detecting that the timestep is too small.
  type(exit_code), parameter :: EXIT_SMALL_TIMESTEP = exit_code(code=-3, message="Timestep is too small.")
  !> Type for exiting after detecting that the timestep is changing too rapidly.
  type(exit_code), parameter :: EXIT_RAPID_TIMESTEP_CHANGE = exit_code(code=-4, message="Timestep is changing too rapidly.")

contains

  !> Make a string containing the error code and exit reason.
  !> This is kept minimal to make it easier for tests to parse.
  function create_message(self)
    implicit none
    class(exit_code), intent(in) :: self
    character(len=exit_string_len) :: create_message
    write (create_message,'(I2.1," ",A)') self%code, trim(self%message)
  end function create_message

  !> Write exit file containing exit code and message
  subroutine write_exit_file(self)
    use file_utils, only: exit_reason_unit
    implicit none
    class(exit_code), intent(in) :: self
    write(exit_reason_unit(),*) self%create_message()
  end subroutine write_exit_file

  !> Determines if a passed `exit_code` instance is identical
  !> to this instance.
  !>
  !> We could imagine providing an operator(==) overload that makes
  !> use of this but this may not be well supported by all compilers
  !> currently.
  logical function is_identical(self, other)
    implicit none
    class(exit_code), intent(in) :: self
    type(exit_code), intent(in) :: other
    is_identical = (self%code == other%code)
    is_identical = is_identical .and. (self%message == other%message)
  end function is_identical


  !> Determines if a passed `exit_code` instance has the same code
  !> as the passed integer.
  logical function code_matches_integer(self, code)
    implicit none
    class(exit_code), intent(in) :: self
    integer, intent(in) :: code
    code_matches_integer = (self%code == code)
  end function code_matches_integer

  !> Determines if a passed `exit_code` instance has the same code
  !> as this instance.
  logical function code_matches_instance(self, other)
    implicit none
    class(exit_code), intent(in) :: self
    type(exit_code), intent(in) :: other
    code_matches_instance = self%code_matches(other%code)
  end function code_matches_instance

end module exit_codes