|
SUBROUTINE Integrate( TIN, TOUT, ICNTRL_U , RCNTRL_U, & |
|
ISTATUS_U, RSTATUS_U, IERR_U ) |
|
! ICNTRL(16) |
|
! 0 -> do nothing. |
|
! 1 -> set negative values to zero |
|
! 2 -> return with error code |
|
! 3 -> stop at negative |
|
! |
|
! ICNTRL(17) = verbose error output |
|
|
|
!~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ |
|
! User interface routine to the KPP forward Euler integrator |
|
!~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ |
|
|
|
USE KPP_ROOT_Util, ONLY : Integrator_Update_Options |
|
|
|
!~~~> Inputs |
|
KPP_REAL, INTENT(IN) :: TIN ! Start Time |
|
KPP_REAL, INTENT(IN) :: TOUT ! End Time |
|
INTEGER, INTENT(IN), OPTIONAL :: ICNTRL_U(20) ! Input options |
|
KPP_REAL, INTENT(IN), OPTIONAL :: RCNTRL_U(20) ! Input options |
|
|
|
!~~~> Outputs |
|
INTEGER, INTENT(IN), OPTIONAL :: ISTATUS_U(20) ! Returned status values |
|
KPP_REAL, INTENT(OUT), OPTIONAL :: RSTATUS_U(20) ! Returned status values |
|
INTEGER, INTENT(OUT), OPTIONAL :: IERR_U ! Error code |
|
|
|
! Local variables |
|
INTEGER :: ICNTRL(20) |
|
KPP_REAL :: RSTATUS(20) |
|
INTEGER :: IERR |
|
|
|
!~~~> Zero input and output arrays for safety's sake |
|
ICNTRL = 0 |
|
RSTATUS = 0.0_dp |
|
|
|
!~~~> fine-tune the integrator: |
|
ICNTRL(1 ) = 0 ! Verbose error output |
|
ICNTRL(2 ) = 0 ! Stop upon negative results |
|
ICNTRL(15) = 5 ! Call Update_SUN and Update_RCONST from w/in the int. |
|
|
|
!~~~> if optional parameters are given, and if they are /= 0, |
|
! then use them to overwrite default settings |
|
IF ( PRESENT( ICNTRL_U ) ) THEN |
|
WHERE( ICNTRL_U /= 0 ) ICNTRL = ICNTRL_U |
|
ENDIF |
|
|
|
!~~~> Determine the settings of the Do_Update_* flags, which determine |
|
!~~~> whether or not we need to call Update_* routines in the integrator |
|
!~~~> (or not, if we are calling them from a higher-level) |
|
! ICNTRL(15) = -1 ! Do not call Update_* functions within the integrator |
|
! = 0 ! Status quo |
|
! = 1 ! Call Update_RCONST from within the integrator |
|
! = 2 ! Call Update_PHOTO from within the integrator |
|
! = 3 ! Call Update_RCONST and Update_PHOTO from w/in the int. |
|
! = 4 ! Call Update_SUN from within the integrator |
|
! = 5 ! Call Update_SUN and Update_RCONST from within the int. |
|
! = 6 ! Call Update_SUN and Update_PHOTO from within the int. |
|
! = 7 ! Call Update_SUN, Update_PHOTO, Update_RCONST w/in int. |
|
CALL Integrator_Update_Options( ICNTRL(15), & |
|
Do_Update_RCONST, & |
|
Do_Update_PHOTO, & |
|
Do_Update_Sun ) |
|
|
|
!~~~> In order to remove the prior EQUIVALENCE statements (which |
|
!~~~> are not thread-safe), we now have declared VAR and FIX as |
|
!~~~> threadprivate pointer variables that can point to C. |
|
VAR => C(1:NVAR) |
|
FIX => C(NVAR+1:NSPEC) |
|
|
|
!~~~> Call the integrator |
|
CALL ForwardEuler( NVAR, C(1:NVAR), TIN, TOUT, ICNTRL, IERR ) |
|
|
|
!~~~> Free pointers |
|
VAR => NULL() |
|
FIX => NULL() |
|
|
|
!~~~> Return error status (NOTE: ISTATUS_U does nothing) |
|
IF ( PRESENT( IERR_U ) ) IERR_U = IERR |
|
IF ( PRESENT( RSTATUS_U ) ) RSTATUS_U = RSTATUS |
|
|
|
END SUBROUTINE Integrate |
While helping @cschooling debug a problem with the GEOS-Chem carbon gases mechanism in box model mode, I discovered that the Forward Euler integrator does not return the ending timestep to the calling program.
In the
Integrateroutine in theint/feuler.f90module, the ending timestep (TEND) should be saved asRSTATUS(1)but is not:KPP/int/feuler.f90
Lines 36 to 117 in b717a0d
The problem is that the
generalbox-model driver relies on the value ofRSTATUS(1)as returned by the integrator in order to get the ending timestep of the integration. This value is then compared againstTENDto see if it is time to exit the loop, as shown here:KPP/drv/general.f90
Lines 35 to 61 in b717a0d
But because the
RSTATUS(1)is not returned, then the loop will execute infinitely.I will make a PR to fix this and will also add a C-I test for the Forward Euler integrator in a subsequent PR.