Skip to content

Commit

Permalink
Merge pull request #19 from geoschem/feature/error_handling
Browse files Browse the repository at this point in the history
Improve error handling
  • Loading branch information
lizziel authored Jul 9, 2024
2 parents 2d75997 + 0af1e9d commit 5eabcbe
Show file tree
Hide file tree
Showing 10 changed files with 2,515 additions and 1,913 deletions.
5 changes: 5 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,11 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),

### Added
- Added CLOUDJ_STANDALONE c-proprocessor switch to generalize code to use instead within a parent model
- Added integer status flag RC to most subroutines and pass it back up to parent model with error messages
- Added subroutine CLOUDJ_ERROR to print error message and set integer status flag RC

### Removed
- Removed subroutine EXITC and replaced it with CLOUDJ_ERROR_STOP in standalone and CLOUDJ_ERROR elsewhere

## [7.7.1] - 2024-04-02
### Changed
Expand Down
210 changes: 131 additions & 79 deletions src/Core/cldj_error_mod.F90
Original file line number Diff line number Diff line change
@@ -1,99 +1,151 @@
! INTERFACE:
MODULE CLDJ_ERROR_MOD

MODULE CLDJ_ERROR_MOD
IMPLICIT NONE

IMPLICIT NONE
PUBLIC :: CLOUDJ_ERROR
PUBLIC :: CLOUDJ_ERROR_STOP
PUBLIC :: SAFE_DIV

PUBLIC :: CLOUDJ_ERROR_STOP
PUBLIC :: SAFE_DIV
INTEGER, PUBLIC, PARAMETER :: CLDJ_SUCCESS = 0 ! Routine returns success
INTEGER, PUBLIC, PARAMETER :: CLDJ_FAILURE = -1 ! Routine returns failure

CONTAINS
CONTAINS

!-----------------------------------------------------------------------
subroutine CLOUDJ_ERROR_STOP( msg, loc )
! This subroutine...
!-----------------------------------------------------------------------
subroutine CLOUDJ_ERROR_STOP( errmsg, loc )

! This subroutine is based on the equivalent function in GEOS-Chem
! (https://github.com/geoschem/geos-chem).
!-----------------------------------------------------------------------
#if defined( MAPL_ESMF )
#include "MAPL_Generic.h"
USE MAPLBase_Mod
USE MAPLBase_Mod
#elif defined( MODEL_CESM )
! if using cesm
USE CAM_ABORTUTILS, ONLY : ENDRUN
USE CAM_ABORTUTILS, ONLY : ENDRUN
#endif

character(len=*), intent(in) :: msg
character(len=*), intent(in), optional :: loc
character(len=*), intent(in) :: errmsg
character(len=*), intent(in) :: loc

character(len=512) :: tmpmsg
character(len=1023) :: msg
#if defined( MAPL_ESMF )
integer :: rc
#endif

! Define message
msg = 'CLOUDJ_ERROR_STOP: '//TRIM(errmsg)//' --> LOCATION: '//TRIM(loc)

! Stop run
#if defined( MAPL_ESMF )
__Iam__('CLOUDJ_ERROR_STOP')
RC = CLDJ_FAILURE
_ASSERT(RC==CLDJ_SUCCESS,TRIM(msg))
#elif defined( MODEL_CESM )
call endrun('Cloud-J failure!')
#elif defined( MODEL_GEOSCHEM )
call exit( 99999 )
call endrun(msg)
#elif defined( MODEL_GCCLASSIC )
WRITE(6,*) TRIM(msg)
call exit( 99999 )
#else
WRITE(*,*) TRIM(msg)
stop
#endif

end subroutine CLOUDJ_ERROR_STOP

!-----------------------------------------------------------------------
subroutine CLOUDJ_ERROR( errmsg, loc, rc )

#if defined( MODEL_CESM )
USE CAM_ABORTUTILS, ONLY : ENDRUN
#elif MAPL_ESMF
#include "MAPL_Generic.h"
USE ESMF
USE MAPLBase_Mod
#endif

CHARACTER(LEN=*), INTENT(IN ) :: errmsg ! Message to display
CHARACTER(LEN=*), INTENT(IN ) :: loc ! Location of error
INTEGER, INTENT(INOUT) :: rc ! Error code

CHARACTER(LEN=1023) :: msg
#if defined( MAPL_ESMF )
INTEGER :: localPET, status
CHARACTER(4) :: localPETchar
TYPE(ESMF_VM) :: vm
#endif

#ifdef MAPL_ESMF
! Get current thread number
CALL ESMF_VMGetCurrent(vm, RC=STATUS)
CALL ESMF_VmGet( vm, localPET=localPET, __RC__ )
WRITE(localPETchar,'(I4.4)') localPET
msg = 'CLOUDJ_ERROR ['//TRIM(localPETchar)//']: '//TRIM(errmsg) &
//' --> LOCATION: ' // TRIM(loc)
WRITE(*,*) TRIM(msg)
#elif MODEL_CESM
CALL ENDRUN('CLOUDJ_ERROR: '//TRIM(errmsg)//' --> LOCATION: '//TRIM(loc))
#else
stop
msg = 'CLOUDJ_ERROR: '//TRIM(errmsg)// ' --> LOCATION: '//TRIM(loc)
WRITE(6,*) TRIM(msg)
CALL Flush( 6 )
#endif

end subroutine CLOUDJ_ERROR_STOP
! Return with failure, but preserve existing error code
IF ( rc == CLDJ_SUCCESS ) THEN
rc = CLDJ_FAILURE
ENDIF

end subroutine CLOUDJ_ERROR

!-----------------------------------------------------------------------
function SAFE_DIV( numer, denom, alt_nan, alt_overflow, alt_underflow ) &
!-----------------------------------------------------------------------
function SAFE_DIV( numer, denom, alt_nan, alt_overflow, alt_underflow ) &
result( quot )
! This funtion performs "safe division", that is to prevent overflow,
! underlow, NaN, or infinity errors. An alternate value is returned
! if the division cannot be performed.

! This function is based on the equivalent function in GEOS-Chem
! (https://github.com/geoschem/geos-chem).
!-----------------------------------------------------------------------

! Numerator and denominator
real*8, intent(in) :: numer
real*8, intent(in) :: denom

! Alternate value to be returned if the division is either NAN (0/0) or
! leads to overflow (i.e., a too large number)
real*8, intent(in) :: alt_nan

! Alternate value to be returned if the division leads to overflow
! (default is ALT_NAN)
real*8, optional, intent(in) :: alt_overflow
! Alternate value to be returned if the division leads to underflow
! (default is 0, but you could use TINY() if you want a non-zero result).
real*8, optional, intent(in) :: alt_underflow

! Return value is output from division
real*8 :: quot

! NaN
if ( numer == 0 .and. denom == 0 ) THEN
quot = alt_nan

! Overflow
else if ( EXPONENT(numer) - EXPONENT(denom) >= MAXEXPONENT(numer) &
.OR. Denom == 0 ) then
quot = alt_nan
if ( PRESENT(alt_overflow) ) quot = alt_overflow

! Underflow
else if ( EXPONENT(numer) - EXPONENT(denom) <= MINEXPONENT(numer) ) then

quot = 0D0
if ( PRESENT(alt_underflow) ) quot = alt_underflow
else
! No problem
quot = numer / denom
endif

end function SAFE_DIV

END MODULE CLDJ_ERROR_MOD
! This funtion performs "safe division", that is to prevent overflow,
! underlow, NaN, or infinity errors. An alternate value is returned
! if the division cannot be performed.

! This function is based on the equivalent function in GEOS-Chem
! (https://github.com/geoschem/geos-chem).
!-----------------------------------------------------------------------

! Numerator and denominator
real*8, intent(in) :: numer
real*8, intent(in) :: denom

! Alternate value to be returned if the division is either NAN (0/0) or
! leads to overflow (i.e., a too large number)
real*8, intent(in) :: alt_nan

! Alternate value to be returned if the division leads to overflow
! (default is ALT_NAN)
real*8, optional, intent(in) :: alt_overflow

! Alternate value to be returned if the division leads to underflow
! (default is 0, but you could use TINY() if you want a non-zero result).
real*8, optional, intent(in) :: alt_underflow

! Return value is output from division
real*8 :: quot

! NaN
if ( numer == 0 .and. denom == 0 ) THEN
quot = alt_nan

! Overflow
else if ( EXPONENT(numer) - EXPONENT(denom) >= MAXEXPONENT(numer) &
.OR. Denom == 0 ) then
quot = alt_nan
if ( PRESENT(alt_overflow) ) quot = alt_overflow

! Underflow
else if ( EXPONENT(numer) - EXPONENT(denom) <= MINEXPONENT(numer) ) then

quot = 0D0
if ( PRESENT(alt_underflow) ) quot = alt_underflow

else

! No problem
quot = numer / denom

endif

end function SAFE_DIV

END MODULE CLDJ_ERROR_MOD
Loading

0 comments on commit 5eabcbe

Please sign in to comment.