MODULE stopping_crit !----------------------------------------------------------------------- ! NAME ! stopping_crit ! ! DESCRIPTION ! Stopping criteria for PEM. ! ! AUTHORS & DATE ! JB Clement, 2025 ! ! NOTES ! !----------------------------------------------------------------------- ! DEPENDENCIES ! ------------ use numerics, only: dp, qp, di, k4, minieps_qp ! DECLARATION ! ----------- implicit none ! PARAMETERS ! ---------- real(dp), protected :: h2oice_crit ! Change of the surface of H2O ice sublimating before stopping the PEM real(dp), protected :: co2ice_crit ! Change of the surface of CO2 ice sublimating before stopping the PEM real(dp), protected :: ps_crit ! Change of averaged surface pressure before stopping the PEM ! VARIABLES ! --------- type :: stopFlags logical(k4) :: surface_h2oice_change = .false. logical(k4) :: h2o_flux_balance_unclosed = .false. logical(k4) :: surface_co2ice_change = .false. logical(k4) :: pressure_change = .false. logical(k4) :: nmax_yr_run_reached = .false. logical(k4) :: nmax_yr_runorb_reached = .false. logical(k4) :: nmax_yr_sim_reached = .false. logical(k4) :: time_limit_reached = .false. contains procedure :: is_any_set procedure :: stop_code procedure :: stop_message end type contains !+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ !======================================================================= SUBROUTINE set_stopping_crit_config(h2oice_crit_in,co2ice_crit_in,ps_crit_in) !----------------------------------------------------------------------- ! NAME ! set_stopping_crit_config ! ! DESCRIPTION ! Setter for "stopping_crit" configuration parameters. ! ! AUTHORS & DATE ! JB Clement, 02/2026 ! ! NOTES ! !----------------------------------------------------------------------- ! DEPENDENCIES ! ------------ use utility, only: real2str use display, only: print_msg, LVL_NFO use stoppage, only: stop_clean ! DECLARATION ! ----------- implicit none ! ARGUMENTS ! --------- real(dp), intent(in) :: h2oice_crit_in, co2ice_crit_in, ps_crit_in ! CODE ! ---- h2oice_crit = h2oice_crit_in co2ice_crit = co2ice_crit_in ps_crit = ps_crit_in call print_msg('h2oice_crit = '//real2str(h2oice_crit),LVL_NFO) call print_msg('co2ice_crit = '//real2str(co2ice_crit),LVL_NFO) call print_msg('ps_crit = '//real2str(ps_crit),LVL_NFO) if (h2oice_crit <= 0._dp .or. h2oice_crit > 1._dp) call stop_clean(__FILE__,__LINE__,'''h2oice_crit'' outside admissible range ]0.,1.]!',1) if (co2ice_crit <= 0._dp .or. co2ice_crit > 1._dp) call stop_clean(__FILE__,__LINE__,'''co2ice_crit'' outside admissible range ]0.,1.]!',1) if (ps_crit <= 0._dp .or. ps_crit > 1._dp) call stop_clean(__FILE__,__LINE__,'''ps_crit'' outside admissible range ]0.,1.]!',1) END SUBROUTINE set_stopping_crit_config !======================================================================= !======================================================================= FUNCTION is_any_set(this) RESULT(stopPEM) !----------------------------------------------------------------------- ! NAME ! is_any_set ! ! DESCRIPTION ! Detect if any stopping flag is set to true. ! ! AUTHORS & DATE ! JB Clement, 2025 ! ! NOTES ! !----------------------------------------------------------------------- ! DECLARATION ! ----------- implicit none ! ARGUMENTS ! --------- class(stopFlags), intent(in) :: this ! Stopping flags object logical(k4) :: stopPEM ! True if any flag is set ! CODE ! ---- stopPEM = this%surface_h2oice_change .or. & this%h2o_flux_balance_unclosed .or. & this%surface_co2ice_change .or. & this%pressure_change .or. & this%nmax_yr_run_reached .or. & this%nmax_yr_runorb_reached .or. & this%nmax_yr_sim_reached .or. & this%time_limit_reached END FUNCTION is_any_set !======================================================================= !======================================================================= FUNCTION stop_code(this) result(code) !----------------------------------------------------------------------- ! NAME ! stop_code ! ! DESCRIPTION ! Return digit code corresponding to the active stopping flag. ! ! AUTHORS & DATE ! JB Clement, 2025 ! ! NOTES ! !----------------------------------------------------------------------- ! DECLARATION ! ----------- implicit none ! ARGUMENTS ! --------- class(StopFlags), intent(in) :: this ! Stopping flags object integer(di) :: code ! Code corresponding to active flag (0 if none) ! CODE ! ---- code = 0 if (this%surface_h2oice_change) then; code = 1 elseif (this%h2o_flux_balance_unclosed) then; code = 2 elseif (this%surface_co2ice_change) then; code = 3 elseif (this%pressure_change) then; code = 4 elseif (this%nmax_yr_run_reached) then; code = 5 elseif (this%nmax_yr_runorb_reached) then; code = 6 elseif (this%nmax_yr_sim_reached) then; code = 7 elseif (this%time_limit_reached) then; code = 8 end if END FUNCTION stop_code !======================================================================= !======================================================================= FUNCTION stop_message(this) result(msg) !----------------------------------------------------------------------- ! NAME ! stop_message ! ! DESCRIPTION ! Return descriptive message corresponding to the active stopping flag. ! ! AUTHORS & DATE ! JB Clement, 2025 ! ! NOTES ! !----------------------------------------------------------------------- ! DECLARATION ! ----------- implicit none ! ARGUMENTS ! --------- class(StopFlags), intent(in) :: this ! Stopping flags object character(:), allocatable :: msg ! Descriptive message for active flag ! CODE ! ---- if (this%surface_h2oice_change) then; msg = "**** STOPPING because surface of H2O ice has changed too much (see message above)." elseif (this%h2o_flux_balance_unclosed) then; msg = "**** STOPPING because H2O flux imbalance cannot be closed under physical bounds (see message above)." elseif (this%surface_co2ice_change) then; msg = "**** STOPPING because surface of CO2 ice has changed too much (see message above)." elseif (this%pressure_change) then; msg = "**** STOPPING because surface global pressure has changed too much (see message above)." elseif (this%nmax_yr_run_reached) then; msg = "**** STOPPING because maximum number of years is reached." elseif (this%nmax_yr_runorb_reached) then; msg = "**** STOPPING because maximum number of years due to orbital parameters is reached." elseif (this%nmax_yr_sim_reached) then; msg = "**** STOPPING because the number of years to be simulated is reached." elseif (this%time_limit_reached) then; msg = "**** STOPPING because the job time limit is going to be reached." else msg = "**** STOPPING for unknown reason (this should not happen!)." end if END FUNCTION stop_message !======================================================================= !======================================================================= SUBROUTINE stopping_crit_h2oice(h2oice_sublim_coverage_ini,h2o_ice,d_h2oice,stopcrit) !----------------------------------------------------------------------- ! NAME ! stopping_crit_h2oice ! ! DESCRIPTION ! Check if H2O ice surface has changed too much. ! ! AUTHORS & DATE ! R. Vandemeulebrouck ! L. Lange, 2023 ! JB Clement, 2023-2025 ! ! NOTES ! !----------------------------------------------------------------------- ! DEPENDENCIES ! ------------ use slopes, only: subslope_dist, def_slope_mean use geometry, only: ngrid, nslope, cell_area use maths, only: pi use display, only: print_msg, LVL_NFO use utility, only: real2str ! DECLARATION ! ----------- implicit none ! ARGUMENTS ! --------- real(dp), dimension(:,:), intent(in) :: h2o_ice, d_h2oice real(dp), intent(in) :: h2oice_sublim_coverage_ini type(stopFlags), intent(inout) :: stopcrit ! LOCAL VARIABLES ! --------------- integer(di) :: i, islope real(dp) :: h2oice_now_surf ! CODE ! ---- ! Check to escape the subroutine (if the PEM should stop already) if (stopcrit%stop_code() > 0) return ! Computation of the present surface of sublimating H2O ice h2oice_now_surf = 0._dp do i = 1,ngrid do islope = 1,nslope if (h2o_ice(i,islope) > 0._dp .and. d_h2oice(i,islope) < 0._dp) h2oice_now_surf = h2oice_now_surf + cell_area(i)*subslope_dist(i,islope)/cos(pi*def_slope_mean(islope)/180._dp) end do end do ! Check of the criterion if (h2oice_now_surf < h2oice_sublim_coverage_ini*(1._dp - h2oice_crit) .or. h2oice_now_surf > h2oice_sublim_coverage_ini*(1. + h2oice_crit)) then stopcrit%surface_h2oice_change = .true. call print_msg("Surface of H2O ice sublimating (ini|now) [m2] = "//real2str(h2oice_sublim_coverage_ini)//' | '//real2str(h2oice_now_surf),LVL_NFO) call print_msg("Change (accepted|current) [%] = +/- "//real2str(h2oice_crit*100._dp)//' | '//real2str(100._dp*(h2oice_now_surf - h2oice_sublim_coverage_ini)/h2oice_sublim_coverage_ini),LVL_NFO) end if END SUBROUTINE stopping_crit_h2oice !======================================================================= !======================================================================= SUBROUTINE stopping_crit_co2ice(co2ice_sublim_coverage_ini,co2_ice,d_co2ice,stopcrit) !----------------------------------------------------------------------- ! NAME ! stopping_crit_co2ice ! ! DESCRIPTION ! Check if CO2 ice surface has changed too much. ! ! AUTHORS & DATE ! R. Vandemeulebrouck ! L. Lange, 2023 ! JB Clement, 2023-2025 ! ! NOTES ! !----------------------------------------------------------------------- ! DEPENDENCIES ! ------------ use slopes, only: subslope_dist, def_slope_mean use geometry, only: ngrid, nslope, cell_area use maths, only: pi use display, only: print_msg, LVL_NFO use utility, only: real2str ! DECLARATION ! ----------- implicit none ! ARGUMENTS ! --------- real(dp), dimension(:,:), intent(in) :: co2_ice, d_co2ice real(dp), intent(in) :: co2ice_sublim_coverage_ini type(stopFlags), intent(inout) :: stopcrit ! LOCAL VARIABLES ! --------------- integer(di) :: i, islope real(dp) :: co2ice_now_surf ! Current surface of CO2 ice ! CODE ! ---- ! Check to escape the subroutine (not relevant in 1D or if the PEM should stop already) if (ngrid == 1 .or. stopcrit%stop_code() > 0) return ! Computation of the present surface of CO2 ice still sublimating co2ice_now_surf = 0. do i = 1,ngrid do islope = 1,nslope if (co2_ice(i,islope) > 0._dp .and. d_co2ice(i,islope) < 0._dp) co2ice_now_surf = co2ice_now_surf + cell_area(i)*subslope_dist(i,islope)/cos(pi*def_slope_mean(islope)/180._dp) end do end do ! Check of the criterion if (co2ice_now_surf < co2ice_sublim_coverage_ini*(1. - co2ice_crit) .or. co2ice_now_surf > co2ice_sublim_coverage_ini*(1._dp + co2ice_crit)) then stopcrit%surface_co2ice_change = .true. call print_msg("Initial surface of CO2 ice sublimating (ini|now) [m2] = "//real2str(co2ice_sublim_coverage_ini)//' | '//real2str(co2ice_now_surf),LVL_NFO) call print_msg("Change (accepted|current) [%] = +/- "//real2str(co2ice_crit*100._dp)//' | '//real2str(100._dp*(co2ice_now_surf - co2ice_sublim_coverage_ini)/co2ice_sublim_coverage_ini),LVL_NFO) end if END SUBROUTINE stopping_crit_co2ice !======================================================================= !======================================================================= SUBROUTINE stopping_crit_pressure(ps_avg_glob_ini,ps_avg_global,stopcrit) !----------------------------------------------------------------------- ! NAME ! stopping_crit_pressure ! ! DESCRIPTION ! Check if pressure has changed too much. ! ! AUTHORS & DATE ! R. Vandemeulebrouck ! L. Lange, 2023 ! JB Clement, 2023-2025 ! ! NOTES ! !----------------------------------------------------------------------- ! DEPENDENCIES ! ------------ use display, only: print_msg, LVL_NFO use utility, only: real2str ! DECLARATION ! ----------- implicit none ! ARGUMENTS ! --------- real(dp), intent(in) :: ps_avg_glob_ini, ps_avg_global type(stopFlags), intent(inout) :: stopcrit ! CODE ! ---- ! Check to escape the subroutine (not relevant if the PEM should stop already) if (stopcrit%stop_code() > 0) return if (ps_avg_global < ps_avg_glob_ini*(1._dp - ps_crit) .or. ps_avg_global > ps_avg_glob_ini*(1._dp + ps_crit)) then stopcrit%pressure_change = .true. call print_msg("Initial global pressure (ini|now) [Pa] = "//real2str(ps_avg_glob_ini)//' | '//real2str(ps_avg_global),LVL_NFO) call print_msg("Change (accepted|current) [%] = +/- "//real2str(ps_crit*100._dp)//' | '//real2str(100._dp*(ps_avg_global - ps_avg_glob_ini)/ps_avg_glob_ini),LVL_NFO) end if END SUBROUTINE stopping_crit_pressure !======================================================================= END MODULE stopping_crit