!> 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