LCOV - code coverage report
Current view: top level - star/private - timestep.f90 (source / functions) Coverage Total Hit
Test: coverage.info Lines: 65.5 % 1288 843
Test Date: 2025-05-08 18:23:42 Functions: 98.3 % 59 58

            Line data    Source code
       1              : ! ***********************************************************************
       2              : !
       3              : !   Copyright (C) 2010-2019  The MESA Team
       4              : !
       5              : !   This program is free software: you can redistribute it and/or modify
       6              : !   it under the terms of the GNU Lesser General Public License
       7              : !   as published by the Free Software Foundation,
       8              : !   either version 3 of the License, or (at your option) any later version.
       9              : !
      10              : !   This program is distributed in the hope that it will be useful,
      11              : !   but WITHOUT ANY WARRANTY; without even the implied warranty of
      12              : !   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
      13              : !   See the GNU Lesser General Public License for more details.
      14              : !
      15              : !   You should have received a copy of the GNU Lesser General Public License
      16              : !   along with this program. If not, see <https://www.gnu.org/licenses/>.
      17              : !
      18              : ! ***********************************************************************
      19              : 
      20              :       module timestep
      21              : 
      22              :       use star_private_def
      23              :       use utils_lib, only: is_bad
      24              :       use const_def, only: dp, ln10, secyer, msun, lsun, convective_mixing
      25              :       use chem_def
      26              : 
      27              :       implicit none
      28              : 
      29              :       private
      30              :       public :: timestep_controller
      31              :       public :: check_change
      32              :       public :: check_integer_limit
      33              : 
      34              :       logical, parameter :: dbg_timestep = .false.
      35              :       real(dp) :: max_dt
      36              : 
      37              :       contains
      38              : 
      39           11 :       integer function timestep_controller(s, max_timestep)
      40              :          ! if don't return keep_going, then set result_reason to say why.
      41              :          type (star_info), pointer :: s
      42              :          real(dp), intent(in) :: max_timestep
      43              : 
      44              :          include 'formats'
      45              : 
      46           11 :          timestep_controller = do_timestep_limits(s, s% dt)
      47           11 :          if (timestep_controller /= keep_going) s% result_reason = timestep_limits
      48              : 
      49           11 :          if (s% force_timestep > 0) then
      50            0 :             s% dt_next = s% force_timestep
      51            0 :             s% why_Tlim = Tlim_force_timestep
      52            0 :             return
      53              :          end if
      54              : 
      55              :          ! strictly enforce maximum timestep
      56           11 :          max_dt = max_timestep
      57           11 :          if (max_dt <= 0) max_dt = 1d99
      58           11 :          if (s% dt_next > max_dt) then
      59            0 :             s% dt_next = max_dt
      60            0 :             s% why_Tlim = Tlim_max_timestep
      61              :          end if
      62              : 
      63           11 :          if (s% timestep_hold > s% model_number .and. s% dt_next > s% dt) then
      64            0 :             s% dt_next = s% dt
      65            0 :             s% why_Tlim = Tlim_timestep_hold
      66            0 :             if (s% report_dt_hard_limit_retries .and. timestep_controller == keep_going) &
      67            0 :                write(*,3) 'timestep_hold > model_number, so no timestep increase', &
      68            0 :                   s% timestep_hold, s% model_number
      69              :          end if
      70              : 
      71           11 :          if (is_bad_num(s% dt_next)) then
      72            0 :             write(*, *) 'timestep_controller: dt_next', s% dt_next
      73            0 :             if (s% stop_for_bad_nums) call mesa_error(__FILE__,__LINE__,'timestep_controller')
      74            0 :             timestep_controller = terminate
      75            0 :             s% termination_code = t_timestep_controller
      76            0 :             return
      77              :          end if
      78              : 
      79              :          if (dbg_timestep) then
      80              :             write(*,*) 'final result from timestep_controller for model_number', &
      81              :                timestep_controller, s% model_number
      82              :             write(*,1) 'lg dt/secyer', log10(s% dt/secyer)
      83              :             write(*,1) 'lg dt_next/secyer', log10(s% dt_next/secyer)
      84              :             write(*,1) 'dt_next/dt', s% dt_next/s% dt
      85              :             write(*,'(A)')
      86              :             write(*,'(A)')
      87              :             call mesa_error(__FILE__,__LINE__,'timestep_controller')
      88              :          end if
      89              : 
      90              :       end function timestep_controller
      91              : 
      92              : 
      93           11 :       integer function do_timestep_limits(s, dt)
      94              :          use rates_def, only: i_rate
      95              :          type (star_info), pointer :: s
      96              :          real(dp), intent(in) :: dt  ! timestep just completed
      97              : 
      98          649 :          real(dp) :: dt_limit_ratio(numTlim), order, max_timestep_factor
      99              :          integer :: i_limit, nz, ierr
     100              :          logical :: skip_hard_limit
     101              :          integer :: num_mix_boundaries  ! boundaries of regions with mixing_type /= no_mixing
     102           11 :          real(dp), pointer :: mix_bdy_q(:)  ! (num_mix_boundaries)
     103           11 :          integer, pointer :: mix_bdy_loc(:)  ! (num_mix_boundaries)
     104              : 
     105              :          include 'formats'
     106              : 
     107           11 :          if (s% never_skip_hard_limits) then
     108           11 :             skip_hard_limit = .false.
     109              :          else
     110              :             skip_hard_limit = (s% timestep_hold >= s% model_number) .or. &
     111              :                (s% relax_hard_limits_after_retry .and. &
     112            0 :                 s% model_number_for_last_retry == s% model_number)
     113              :          end if
     114              : 
     115           11 :          nz = s% nz
     116              : 
     117              :          ! NOTE: when we get here, complete_model has called the report routine,
     118              :          ! so we can use information that it has calculated
     119              : 
     120           11 :          ierr = 0
     121              : 
     122           11 :          num_mix_boundaries = s% num_mix_boundaries
     123           11 :          mix_bdy_q => s% mix_bdy_q
     124           11 :          mix_bdy_loc => s% mix_bdy_loc
     125              : 
     126           11 :          dt_limit_ratio(:) = 0d0
     127              : 
     128              :          do_timestep_limits = check_varcontrol_limit( &
     129           11 :             s, dt_limit_ratio(Tlim_struc))
     130           11 :          if (return_now(Tlim_struc)) return
     131              : 
     132           11 :          if (.not. s% doing_first_model_of_run) then
     133              : 
     134           10 :             if (s% use_other_timestep_limit) then
     135              :                do_timestep_limits = s% other_timestep_limit( &
     136            0 :                   s% id, skip_hard_limit, dt, dt_limit_ratio(Tlim_other_timestep_limit))
     137            0 :                if (return_now(Tlim_other_timestep_limit)) return
     138              :             end if
     139              : 
     140              :             do_timestep_limits = check_solver_iters_timestep_limit( &
     141           10 :                s, skip_hard_limit, dt, dt_limit_ratio(Tlim_solver))
     142           10 :             if (return_now(Tlim_solver)) return
     143              : 
     144              :             do_timestep_limits = check_burn_steps_limit( &
     145           10 :                s, skip_hard_limit, dt, dt_limit_ratio(Tlim_num_burn_steps))
     146           10 :             if (return_now(Tlim_num_burn_steps)) return
     147              : 
     148              :             do_timestep_limits = check_diffusion_steps_limit( &
     149           10 :                s, skip_hard_limit, dt, dt_limit_ratio(Tlim_num_diff_solver_steps))
     150           10 :             if (return_now(Tlim_num_diff_solver_steps)) return
     151              : 
     152              :             do_timestep_limits = check_diffusion_iters_limit( &
     153           10 :                s, skip_hard_limit, dt, dt_limit_ratio(Tlim_num_diff_solver_iters))
     154           10 :             if (return_now(Tlim_num_diff_solver_iters)) return
     155              : 
     156              :             do_timestep_limits = check_dX(s, skip_hard_limit, dt, &
     157              :                num_mix_boundaries, mix_bdy_loc, mix_bdy_q, &
     158           10 :                dt_limit_ratio(Tlim_dX), dt_limit_ratio(Tlim_dX_div_X))
     159           10 :             if (return_now(Tlim_dX_div_X)) return
     160              : 
     161              :             do_timestep_limits = check_dL_div_L( &
     162           10 :                s, skip_hard_limit, dt, dt_limit_ratio(Tlim_dL_div_L))
     163           10 :             if (return_now(Tlim_dL_div_L)) return
     164              : 
     165              :             do_timestep_limits = check_dlgP_change( &
     166           10 :                s, skip_hard_limit, dt_limit_ratio(Tlim_dlgP))
     167           10 :             if (return_now(Tlim_dlgP)) return
     168              : 
     169              :             do_timestep_limits = check_dlgRho_change( &
     170           10 :                s, skip_hard_limit, dt_limit_ratio(Tlim_dlgRho))
     171           10 :             if (return_now(Tlim_dlgRho)) return
     172              : 
     173              :             do_timestep_limits = check_dlgT_change( &
     174           10 :                s, skip_hard_limit, dt_limit_ratio(Tlim_dlgT))
     175           10 :             if (return_now(Tlim_dlgT)) return
     176              : 
     177              :             do_timestep_limits = check_dlgE_change( &
     178           10 :                s, skip_hard_limit, dt_limit_ratio(Tlim_dlgE))
     179           10 :             if (return_now(Tlim_dlgE)) return
     180              : 
     181              :             do_timestep_limits = check_dlgR_change( &
     182           10 :                s, skip_hard_limit, dt_limit_ratio(Tlim_dlgR))
     183           10 :             if (return_now(Tlim_dlgR)) return
     184              : 
     185              :             do_timestep_limits = check_lgL_nuc_cat_change( &
     186              :                s, num_mix_boundaries, mix_bdy_q, &
     187           10 :                skip_hard_limit, dt_limit_ratio(Tlim_dlgL_nuc_cat))
     188           10 :             if (return_now(Tlim_dlgL_nuc_cat)) return
     189              : 
     190              :             do_timestep_limits = check_lgL_H_change( &
     191           20 :                s, skip_hard_limit, dt, dt_limit_ratio(Tlim_dlgL_H))
     192           10 :             if (return_now(Tlim_dlgL_H)) return
     193              : 
     194              :             do_timestep_limits = check_lgL_He_change( &
     195           20 :                s, skip_hard_limit, dt, dt_limit_ratio(Tlim_dlgL_He))
     196           10 :             if (return_now(Tlim_dlgL_He)) return
     197              : 
     198              :             do_timestep_limits = check_lgL_z_change( &
     199           20 :                s, skip_hard_limit, dt, dt_limit_ratio(Tlim_dlgL_z))
     200           10 :             if (return_now(Tlim_dlgL_z)) return
     201              : 
     202              :             do_timestep_limits = check_lgL_power_photo_change( &
     203           20 :                s, skip_hard_limit, dt, dt_limit_ratio(Tlim_dlgL_power_photo))
     204           10 :             if (return_now(Tlim_dlgL_power_photo)) return
     205              : 
     206              :             do_timestep_limits = check_lgL_nuc_change( &
     207           20 :                s, skip_hard_limit, dt, dt_limit_ratio(Tlim_dlgL_nuc))
     208           10 :             if (return_now(Tlim_dlgL_nuc)) return
     209              : 
     210              :             do_timestep_limits = check_dlgTeff_change( &
     211           10 :                s, skip_hard_limit, dt, dt_limit_ratio(Tlim_dlgTeff))
     212           10 :             if (return_now(Tlim_dlgTeff)) return
     213              : 
     214              :             do_timestep_limits = check_dlgRho_cntr_change( &
     215           10 :                s, skip_hard_limit, dt, dt_limit_ratio(Tlim_dlgRho_cntr))
     216           10 :             if (return_now(Tlim_dlgRho_cntr)) return
     217              : 
     218              :             do_timestep_limits = check_dlgT_cntr_change( &
     219           10 :                s, skip_hard_limit, dt, dt_limit_ratio(Tlim_dlgT_cntr))
     220           10 :             if (return_now(Tlim_dlgT_cntr)) return
     221              : 
     222              :             do_timestep_limits = check_dlgT_max_change( &
     223           10 :                s, skip_hard_limit, dt, dt_limit_ratio(Tlim_dlgT_max))
     224           10 :             if (return_now(Tlim_dlgT_max)) return
     225              : 
     226              :             do_timestep_limits = check_dlgT_max_at_high_T_change( &
     227           10 :                s, skip_hard_limit, dt, dt_limit_ratio(Tlim_dlgT_max_at_high_T))
     228           10 :             if (return_now(Tlim_dlgT_max_at_high_T)) return
     229              : 
     230              :             do_timestep_limits = check_dlgP_cntr_change( &
     231           10 :                s, skip_hard_limit, dt, dt_limit_ratio(Tlim_dlgP_cntr))
     232           10 :             if (return_now(Tlim_dlgP_cntr)) return
     233              : 
     234              :             do_timestep_limits = check_dYe_highT_change( &
     235           10 :                s, skip_hard_limit, dt_limit_ratio(Tlim_delta_Ye_highT))
     236           10 :             if (return_now(Tlim_delta_Ye_highT)) return
     237              : 
     238              :             do_timestep_limits = check_dlog_eps_nuc_change( &
     239           10 :                s, skip_hard_limit, dt, dt_limit_ratio(Tlim_dlog_eps_nuc))
     240           10 :             if (return_now(Tlim_dlog_eps_nuc)) return
     241              : 
     242              :             do_timestep_limits = check_dX_div_X_cntr( &
     243           10 :                s, skip_hard_limit, dt_limit_ratio(Tlim_dX_div_X_cntr))
     244           10 :             if (return_now(Tlim_dX_div_X_cntr)) return
     245              : 
     246              :             do_timestep_limits = check_lg_XH_cntr( &
     247           10 :                s, skip_hard_limit, dt_limit_ratio(Tlim_lg_XH_cntr))
     248           10 :             if (return_now(Tlim_lg_XH_cntr)) return
     249              : 
     250              :             do_timestep_limits = check_lg_XHe_cntr( &
     251           10 :                s, skip_hard_limit, dt_limit_ratio(Tlim_lg_XHe_cntr))
     252           10 :             if (return_now(Tlim_lg_XHe_cntr)) return
     253              : 
     254              :             do_timestep_limits = check_lg_XC_cntr( &
     255           10 :                s, skip_hard_limit, dt_limit_ratio(Tlim_lg_XC_cntr))
     256           10 :             if (return_now(Tlim_lg_XC_cntr)) return
     257              : 
     258              :             do_timestep_limits = check_lg_XNe_cntr( &
     259           10 :                s, skip_hard_limit, dt_limit_ratio(Tlim_lg_XNe_cntr))
     260           10 :             if (return_now(Tlim_lg_XNe_cntr)) return
     261              : 
     262              :             do_timestep_limits = check_lg_XO_cntr( &
     263           10 :                s, skip_hard_limit, dt_limit_ratio(Tlim_lg_XO_cntr))
     264           10 :             if (return_now(Tlim_lg_XO_cntr)) return
     265              : 
     266              :             do_timestep_limits = check_lg_XSi_cntr( &
     267           10 :                s, skip_hard_limit, dt_limit_ratio(Tlim_lg_XSi_cntr))
     268           10 :             if (return_now(Tlim_lg_XSi_cntr)) return
     269              : 
     270              :             do_timestep_limits = check_XH_cntr( &
     271           10 :                s, skip_hard_limit, dt_limit_ratio(Tlim_XH_cntr))
     272           10 :             if (return_now(Tlim_XH_cntr)) return
     273              : 
     274              :             do_timestep_limits = check_XHe_cntr( &
     275           10 :                s, skip_hard_limit, dt_limit_ratio(Tlim_XHe_cntr))
     276           10 :             if (return_now(Tlim_XHe_cntr)) return
     277              : 
     278              :             do_timestep_limits = check_XC_cntr( &
     279           10 :                s, skip_hard_limit, dt_limit_ratio(Tlim_XC_cntr))
     280           10 :             if (return_now(Tlim_XC_cntr)) return
     281              : 
     282              :             do_timestep_limits = check_XNe_cntr( &
     283           10 :                s, skip_hard_limit, dt_limit_ratio(Tlim_XNe_cntr))
     284           10 :             if (return_now(Tlim_XNe_cntr)) return
     285              : 
     286              :             do_timestep_limits = check_XO_cntr( &
     287           10 :                s, skip_hard_limit, dt_limit_ratio(Tlim_XO_cntr))
     288           10 :             if (return_now(Tlim_XO_cntr)) return
     289              : 
     290              :             do_timestep_limits = check_XSi_cntr( &
     291           10 :                s, skip_hard_limit, dt_limit_ratio(Tlim_XSi_cntr))
     292           10 :             if (return_now(Tlim_XSi_cntr)) return
     293              : 
     294              :             do_timestep_limits = check_delta_mstar( &
     295           10 :                s, skip_hard_limit, dt, dt_limit_ratio(Tlim_dmstar))
     296           10 :             if (return_now(Tlim_dmstar)) return
     297              : 
     298              :             do_timestep_limits = check_delta_mdot( &
     299           10 :                s, skip_hard_limit, dt, dt_limit_ratio(Tlim_del_mdot))
     300           10 :             if (return_now(Tlim_del_mdot)) return
     301              : 
     302              :             do_timestep_limits = check_adjust_J_q( &
     303           10 :                s, skip_hard_limit, dt_limit_ratio(Tlim_adjust_J_q))
     304           10 :             if (return_now(Tlim_adjust_J_q)) return
     305              : 
     306              :             do_timestep_limits = check_delta_lgL( &
     307           10 :                s, skip_hard_limit, dt_limit_ratio(Tlim_lgL))
     308           10 :             if (return_now(Tlim_lgL)) return
     309              : 
     310              :             do_timestep_limits = check_dt_div_dt_cell_collapse( &
     311           10 :                s, skip_hard_limit, dt, dt_limit_ratio(Tlim_dt_div_dt_cell_collapse))
     312           10 :             if (return_now(Tlim_dt_div_dt_cell_collapse)) return
     313              : 
     314              :             do_timestep_limits = check_dt_div_min_dr_div_cs( &
     315           10 :                s, skip_hard_limit, dt, dt_limit_ratio(Tlim_dt_div_min_dr_div_cs))
     316           10 :             if (return_now(Tlim_dt_div_min_dr_div_cs)) return
     317              : 
     318              :             do_timestep_limits = check_delta_HR( &
     319           10 :                s, skip_hard_limit, dt_limit_ratio(Tlim_delta_HR))
     320           10 :             if (return_now(Tlim_delta_HR)) return
     321              : 
     322              :             do_timestep_limits = check_rel_error_in_energy( &
     323           10 :                s, skip_hard_limit, dt_limit_ratio(Tlim_error_in_energy_conservation))
     324           10 :             if (return_now(Tlim_error_in_energy_conservation)) return
     325              : 
     326              :             do_timestep_limits = check_dX_nuc_drop( &
     327           10 :                s, skip_hard_limit, dt, dt_limit_ratio(Tlim_dX_nuc_drop))
     328           10 :             if (return_now(Tlim_dX_nuc_drop)) return
     329              : 
     330              :          end if
     331              : 
     332          660 :          i_limit = maxloc(dt_limit_ratio(1:numTlim), dim=1)
     333              : 
     334           11 :          order = 1
     335           11 :          call filter_dt_next(s, order, dt_limit_ratio(i_limit))  ! sets s% dt_next
     336              : 
     337           11 :          if (s% log_max_temperature > s% min_logT_for_max_timestep_factor_at_high_T) then
     338            0 :             max_timestep_factor = s% max_timestep_factor_at_high_T
     339              :          else
     340           11 :             max_timestep_factor = s% max_timestep_factor
     341              :          end if
     342              : 
     343           11 :          if (max_timestep_factor > 0 .and. s% dt_next > max_timestep_factor*s% dt) then
     344           11 :             s% dt_next = max_timestep_factor*s% dt
     345           11 :             if (s% report_solver_dt_info) then
     346            0 :                write(*,2) 's% dt', s% model_number, s% dt
     347            0 :                write(*,2) 'max_timestep_factor', s% model_number, max_timestep_factor
     348            0 :                write(*,2) 's% dt_next', s% model_number, s% dt_next
     349              :             end if
     350           11 :             if (s% dt_next == 0d0) call mesa_error(__FILE__,__LINE__,'filter_dt_next')
     351           11 :             if (i_limit == Tlim_struc) i_limit = Tlim_max_timestep_factor
     352              :          end if
     353              : 
     354           11 :          if (s% min_timestep_factor > 0 .and. s% dt_next < s% min_timestep_factor*s% dt) then
     355            0 :             s% dt_next = s% min_timestep_factor*s% dt
     356            0 :             if (s% report_solver_dt_info) then
     357            0 :                write(*,2) 's% dt', s% model_number, s% dt
     358            0 :                write(*,2) 'min_timestep_factor', s% model_number, s% min_timestep_factor
     359            0 :                write(*,2) 's% dt_next', s% model_number, s% dt_next
     360              :             end if
     361            0 :             if (s% dt_next == 0d0) call mesa_error(__FILE__,__LINE__,'filter_dt_next')
     362            0 :             if (i_limit == Tlim_struc) i_limit = Tlim_min_timestep_factor
     363              :          end if
     364              : 
     365           11 :          s% why_Tlim = i_limit
     366           22 :          if (i_limit > 0) s% dt_why_count(i_limit) = s% dt_why_count(i_limit) + 1
     367              : 
     368              :          contains
     369              : 
     370          481 :          logical function return_now(i_limit)
     371              :             integer, intent(in) :: i_limit
     372          481 :             if (do_timestep_limits == keep_going) then
     373          481 :                return_now = .false.
     374              :                return
     375              :             end if
     376            0 :             return_now = .true.
     377            0 :             s% why_Tlim = i_limit
     378            0 :             if (i_limit > 0) s% dt_why_retry_count(i_limit) = s% dt_why_retry_count(i_limit) + 1
     379           11 :          end function return_now
     380              : 
     381              :       end function do_timestep_limits
     382              : 
     383              : 
     384           10 :       integer function check_integer_limit( &
     385              :             s, limit, hard_limit, value, msg, skip_hard_limit, dt, dt_limit_ratio)
     386              :          type (star_info), pointer :: s
     387              :          integer, intent(in) :: limit, hard_limit, value
     388              :          character (len=*), intent(in) :: msg
     389              :          logical, intent(in) :: skip_hard_limit
     390              :          real(dp), intent(in) :: dt
     391              :          real(dp), intent(inout) :: dt_limit_ratio
     392              :          include 'formats'
     393           10 :          if (value > hard_limit .and. hard_limit > 0 .and. (.not. skip_hard_limit)) then
     394            0 :             check_integer_limit = retry
     395            0 :             s% retry_message = trim(msg) // ' hard limit'
     396            0 :             if (s% report_dt_hard_limit_retries) then
     397            0 :                write(*,*) trim(msg) // ' hard limit', hard_limit, value
     398            0 :                write(*,3) trim(msg), s% model_number, value
     399            0 :                write(*,3) trim(msg) // ' hard limit', s% model_number, hard_limit
     400              :             end if
     401            0 :             return
     402              :          end if
     403           10 :          check_integer_limit = keep_going
     404           10 :          if (value <= 0 .or. limit <= 0) return
     405           10 :          dt_limit_ratio = dble(value)/dble(limit) - 0.05d0
     406              :             ! subtract a bit so that allow dt to grow even if value == limit
     407           10 :          if (dt_limit_ratio <= 1d0) dt_limit_ratio = 0
     408              :       end function check_integer_limit
     409              : 
     410              : 
     411           10 :       integer function check_burn_steps_limit(s, skip_hard_limit, dt, dt_limit_ratio)
     412              :          type (star_info), pointer :: s
     413              :          logical, intent(in) :: skip_hard_limit
     414              :          real(dp), intent(in) :: dt
     415              :          real(dp), intent(inout) :: dt_limit_ratio
     416              :          integer :: max_steps
     417           10 :          check_burn_steps_limit = keep_going
     418        10643 :          if (.not. s% op_split_burn .or. maxval(s% T_start(1:s%nz)) < s% op_split_burn_min_T) return
     419              : 
     420            0 :          max_steps = maxval(s% burn_num_iters(1:s% nz),mask=s% T(1:s%nz)>s% op_split_burn_min_T)
     421              :          check_burn_steps_limit = check_integer_limit( &
     422              :            s, s% burn_steps_limit, s% burn_steps_hard_limit, max_steps,  &
     423            0 :            'num_burn_solver_steps', skip_hard_limit, dt, dt_limit_ratio)
     424            0 :       end function check_burn_steps_limit
     425              : 
     426              : 
     427           10 :       integer function check_solver_iters_timestep_limit(s, skip_hard_limit, dt, dt_limit_ratio)
     428              :          type (star_info), pointer :: s
     429              :          logical, intent(in) :: skip_hard_limit
     430              :          real(dp), intent(in) :: dt
     431              :          real(dp), intent(inout) :: dt_limit_ratio
     432              :          integer :: iters, limit, hard_limit
     433              :          include 'formats'
     434           10 :          check_solver_iters_timestep_limit = keep_going
     435           10 :          iters = s% num_solver_iterations
     436           10 :          limit = s% solver_iters_timestep_limit
     437           10 :          hard_limit = -1
     438           10 :          if (s% using_gold_tolerances) then
     439           10 :             limit = s% gold_solver_iters_timestep_limit
     440              :          end if
     441           10 :          if (s% used_extra_iter_in_solver_for_accretion) iters = iters - 1
     442              :          check_solver_iters_timestep_limit = check_integer_limit( &
     443              :            s, limit, hard_limit, &
     444           10 :            iters, 'num_solver_iterations', skip_hard_limit, dt, dt_limit_ratio)
     445           10 :       end function check_solver_iters_timestep_limit
     446              : 
     447              : 
     448           10 :       integer function check_diffusion_steps_limit(s, skip_hard_limit, dt, dt_limit_ratio)
     449              :          type (star_info), pointer :: s
     450              :          logical, intent(in) :: skip_hard_limit
     451              :          real(dp), intent(in) :: dt
     452              :          real(dp), intent(inout) :: dt_limit_ratio
     453           10 :          check_diffusion_steps_limit = keep_going
     454           10 :          if (.not. s% do_element_diffusion) return
     455              :          check_diffusion_steps_limit = check_integer_limit( &
     456              :            s, s% diffusion_steps_limit, s% diffusion_steps_hard_limit, &
     457              :            s% num_diffusion_solver_steps,  &
     458            0 :            'num_diffusion_solver_steps', skip_hard_limit, dt, dt_limit_ratio)
     459            0 :       end function check_diffusion_steps_limit
     460              : 
     461              : 
     462           10 :       integer function check_diffusion_iters_limit(s, skip_hard_limit, dt, dt_limit_ratio)
     463              :          type (star_info), pointer :: s
     464              :          logical, intent(in) :: skip_hard_limit
     465              :          real(dp), intent(in) :: dt
     466              :          real(dp), intent(inout) :: dt_limit_ratio
     467           10 :          check_diffusion_iters_limit = keep_going
     468           10 :          if (.not. s% do_element_diffusion) return
     469              :          check_diffusion_iters_limit = check_integer_limit( &
     470              :            s, s% diffusion_iters_limit, s% diffusion_iters_hard_limit, &
     471              :            s% num_diffusion_solver_iters,  &
     472            0 :            'num_diffusion_solver_iters', skip_hard_limit, dt, dt_limit_ratio)
     473            0 :       end function check_diffusion_iters_limit
     474              : 
     475              : 
     476           10 :       integer function check_dX(s, skip_hard_limit, dt, &
     477              :             n_mix_bdy, mix_bdy_loc, mix_bdy_q, &
     478              :             dX_dt_limit_ratio, dX_div_X_dt_limit_ratio)
     479              :          use num_lib, only: binary_search
     480              :          logical, intent(in) :: skip_hard_limit
     481              :          integer, intent(in) :: n_mix_bdy, mix_bdy_loc(:)
     482              :          real(dp), intent(in) :: dt
     483              :          real(dp), intent(in), pointer :: mix_bdy_q(:)
     484              :          real(dp), intent(inout) :: dX_dt_limit_ratio, dX_div_X_dt_limit_ratio
     485              : 
     486              :          type (star_info), pointer :: s
     487           20 :          real(dp) :: X, X_old, delta_X, delta_X_div_X, max_dX, max_dX_div_X, &
     488           20 :             bdy_dist_dm, max_dX_bdy_dist_dm, max_dX_div_X_bdy_dist_dm, cz_dist_limit, &
     489           10 :             D_mix_cutoff, ratio_tmp_dX, ratio_tmp_dX_div_X
     490              :          integer :: i, j, k, cid, bdy, max_dX_j, max_dX_k, max_dX_div_X_j, max_dX_div_X_k
     491         2010 :          real(dp), dimension(max_dX_limit_ctrls) :: dX_limit, dX_hard_limit, &
     492         2010 :             dX_div_X_limit, dX_div_X_hard_limit
     493              :          character (len=strlen) :: sp
     494              : 
     495              :          include 'formats'
     496              : 
     497           10 :          check_dX = keep_going
     498           10 :          dX_dt_limit_ratio = 0d0
     499           10 :          dX_div_X_dt_limit_ratio = 0d0
     500              : 
     501           10 :          if (s% mix_factor == 0d0 .and. s% dxdt_nuc_factor == 0d0) return
     502              : 
     503         1010 :          do i=1, max_dx_limit_ctrls  ! go over all potential species + XYZ
     504              :             if (s% dX_limit(i) >= 1 .and. &      ! as soon as all of these are >= 1
     505              :                 s% dX_hard_limit(i) >= 1 .and. &  ! we'd have nothing to do
     506         1000 :                 s% dX_div_X_limit(i) >= 1 .and. &
     507              :                 s% dX_div_X_hard_limit(i) >= 1) then
     508              :                cycle  ! go to next
     509              :             end if
     510              : 
     511         2020 :             dX_limit = s% dX_limit(i) * s% time_delta_coeff
     512         2020 :             dX_hard_limit = s% dX_hard_limit(i) * s% time_delta_coeff
     513              : 
     514           20 :             if (s% log_max_temperature > s% dX_div_X_at_high_T_limit_lgT_min(i)) then
     515            0 :                dX_div_X_limit = s% dX_div_X_at_high_T_limit(i)
     516            0 :                dX_div_X_hard_limit = s% dX_div_X_at_high_T_hard_limit(i)
     517              :             else
     518         2020 :                dX_div_X_limit = s% dX_div_X_limit(i)
     519         2020 :                dX_div_X_hard_limit = s% dX_div_X_hard_limit(i)
     520              :             end if
     521              : 
     522         2020 :             dX_div_X_limit = dX_div_X_limit * s% time_delta_coeff
     523         2020 :             dX_div_X_hard_limit = dX_div_X_hard_limit * s% time_delta_coeff
     524              : 
     525           20 :             max_dX = -1; max_dX_j = -1; max_dX_k = -1
     526           20 :             max_dX_div_X = -1; max_dX_div_X_j = -1; max_dX_div_X_k = -1
     527           20 :             bdy = 0
     528           20 :             max_dX_bdy_dist_dm = 0
     529           20 :             max_dX_div_X_bdy_dist_dm = 0
     530           20 :             cz_dist_limit = s% dX_mix_dist_limit*Msun
     531              : 
     532           20 :             if (s% set_min_D_mix .and. s% ye(s% nz) >= s% min_center_Ye_for_min_D_mix) then
     533            0 :                D_mix_cutoff = s% min_D_mix
     534              :             else
     535              :                D_mix_cutoff = 0
     536              :             end if
     537              : 
     538           20 :             sp = s% dX_limit_species(i)
     539              : 
     540        21266 :             do k = 1, s% nz
     541              : 
     542        21246 :                if (s% D_mix(k) > D_mix_cutoff) then
     543              :                   cycle
     544              :                end if
     545        18378 :                if (k < s% nz) then
     546        18378 :                   if (s% D_mix(k+1) > D_mix_cutoff) then
     547              :                      cycle
     548              :                   end if
     549              :                end if
     550              : 
     551              :                ! find the nearest mixing boundary
     552        18338 :                bdy = binary_search(n_mix_bdy, mix_bdy_q, bdy, s% q(k))
     553              :                ! don't check cells near a mixing boundary
     554        18338 :                if (bdy > 0 .and. bdy < n_mix_bdy) then
     555        16398 :                   bdy_dist_dm = s% xmstar*abs(s% q(k) - mix_bdy_q(bdy))
     556        16398 :                   if (bdy_dist_dm < cz_dist_limit) cycle
     557              :                else
     558              :                   bdy_dist_dm = 0
     559              :                end if
     560              : 
     561       165062 :                do j = 1, s% species
     562              : 
     563       146704 :                   cid = s% chem_id(j)
     564       146704 :                   if (sp == 'X') then  ! any hydrogen
     565            0 :                      if (cid /= ih1 .or. cid /= ih2 .or. cid /= ih3) cycle
     566       146704 :                   else if (sp == 'Y') then  ! any helium
     567            0 :                      if (cid /= ihe4 .or. cid /= ihe3) cycle
     568       146704 :                   else if (sp == 'Z') then  ! any metal
     569            0 :                      if (chem_isos% Z(cid) <= 2) cycle
     570              :                   else  ! single isotope
     571       146704 :                      if (trim(chem_isos% name(s% chem_id(j))) /= trim(sp)) cycle
     572              :                   end if
     573              : 
     574        18338 :                   X = s% xa(j,k)
     575        18338 :                   X_old = s% xa_old(j,k)
     576        18338 :                   delta_X = X_old - X  ! decrease in abundance
     577              : 
     578        18338 :                   if ((.not. s% dX_decreases_only(j)) .and. delta_X < 0) delta_X = -delta_X
     579              : 
     580        18338 :                   if (X >= s% dX_limit_min_X(i)) then  ! any check for dX_limit_* < 1 is useless since X <= 1 anyway
     581            0 :                      if ((.not. skip_hard_limit) .and. delta_X > dX_hard_limit(i)) then
     582            0 :                         check_dX = retry
     583            0 :                         s% why_Tlim = Tlim_dX
     584            0 :                         s% Tlim_dX_species = j
     585            0 :                         s% Tlim_dX_cell = k
     586            0 :                         s% retry_message = 'dX ' // trim(chem_isos% name(s% chem_id(j))) // ' hard limit'
     587            0 :                         s% retry_message_k = k
     588            0 :                         if (s% report_dt_hard_limit_retries) then
     589            0 :                            write(*,2) 'old xa', s% model_number, X_old
     590            0 :                            write(*,2) 'new xa', s% model_number, X
     591            0 :                            write(*,2) 'delta xa', s% model_number, delta_X
     592            0 :                            write(*,2) 'hard limit delta xa', s% model_number, dX_hard_limit
     593              :                         end if
     594            0 :                         return
     595              :                      end if
     596            0 :                      if (delta_X > max_dX) then
     597        18338 :                         max_dX = delta_X
     598        18338 :                         max_dX_j = j
     599        18338 :                         max_dX_k = k
     600        18338 :                         max_dX_bdy_dist_dm = bdy_dist_dm
     601              :                      end if
     602              :                   end if
     603        39584 :                   if (X >= s% dX_div_X_limit_min_X(i)) then
     604        18338 :                      delta_X_div_X = delta_X/X
     605        18338 :                      if ((.not. skip_hard_limit) .and. delta_X_div_X > dX_div_X_hard_limit(i)) then
     606            0 :                         check_dX = retry
     607            0 :                         s% why_Tlim = Tlim_dX_div_X
     608            0 :                         s% Tlim_dX_div_X_species = j
     609            0 :                         s% Tlim_dX_div_X_cell = k
     610            0 :                         s% retry_message = 'dX_div_X ' // trim(chem_isos% name(s% chem_id(j))) // ' hard limit'
     611            0 :                         s% retry_message_k = k
     612            0 :                         if (s% report_dt_hard_limit_retries) then
     613              :                            write(*, '(a30, i5, 99(/,a30,e20.10))') &
     614            0 :                               'delta_X_div_X ' // trim(chem_isos% name(s% chem_id(j))), &
     615            0 :                               k, 'delta_X_div_X', delta_X_div_X, &
     616            0 :                               'dX_div_X_hard_limit', dX_div_X_hard_limit
     617            0 :                            write(*,2) 'old xa', s% model_number, X_old
     618            0 :                            write(*,2) 'new xa', s% model_number, X
     619            0 :                            write(*,2) 'delta_X_div_X', s% model_number, delta_X_div_X
     620            0 :                            write(*,2) 'dX_div_X_hard_limit', s% model_number, dX_div_X_hard_limit
     621              :                         end if
     622            0 :                         return
     623              :                      end if
     624        18338 :                      if (delta_X_div_X > max_dX_div_X) then
     625         3787 :                         max_dX_div_X = delta_X_div_X
     626         3787 :                         max_dX_div_X_j = j
     627         3787 :                         max_dX_div_X_k = k
     628         3787 :                         max_dX_div_X_bdy_dist_dm = bdy_dist_dm
     629              :                      end if
     630              :                   end if
     631              :                end do
     632              :             end do
     633              : 
     634           20 :             if (dX_limit(i) > 0) then
     635           20 :                ratio_tmp_dX = max_dX/dX_limit(i)
     636           20 :                if (ratio_tmp_dX > dX_dt_limit_ratio) then
     637            0 :                   dX_dt_limit_ratio = ratio_tmp_dX
     638            0 :                   if (dX_dt_limit_ratio <= 1d0) then
     639            0 :                      dX_dt_limit_ratio = 0
     640              :                   else
     641            0 :                      s% Tlim_dX_species = max_dX_j
     642            0 :                      s% Tlim_dX_cell = max_dX_k
     643              :    !                  write(*, '(a30, i5, 99e20.10)') &
     644              :    !                     ' limit dt because of large dX '// &
     645              :    !                        trim(chem_isos% name(s% chem_id(max_dX_j))) // &
     646              :    !                     ' k, max, lim, m ', &
     647              :    !                     max_dX_k, max_dX, dX_limit(i), &
     648              :    !                     max_dX_bdy_dist_dm/Msun
     649              :                   end if
     650              :                end if
     651              :             end if
     652              : 
     653           30 :             if (dX_div_X_limit(i) > 0) then
     654           20 :                ratio_tmp_dX_div_X = max_dX_div_X/dX_div_X_limit(i)
     655           20 :                if (ratio_tmp_dX_div_X > dX_div_X_dt_limit_ratio) then  ! pick out largest culprit only!
     656           10 :                   dX_div_X_dt_limit_ratio = ratio_tmp_dX_div_X
     657           10 :                   if (dX_div_X_dt_limit_ratio <= 1d0) then
     658           10 :                      dX_div_X_dt_limit_ratio = 0
     659              :                   else
     660            0 :                      s% Tlim_dX_div_X_species = max_dX_div_X_j
     661            0 :                      s% Tlim_dX_div_X_cell = max_dX_div_X_k
     662              :    !                  write(*, '(a35, i5, 99e20.10)') &  ! shouldn't be written as is isn't guarantueed
     663              :                                                          ! this control will trigger timestep reduction
     664              :    !                     ' limit dt because of large dX_div_X ' // &
     665              :    !                        trim(chem_isos% name(s% chem_id(max_dX_div_X_j))) // &
     666              :    !                     ' k, max, lim, m ', &
     667              :    !                     max_dX_div_X_k, max_dX_div_X, dX_div_X_limit(i), &
     668              :    !                     max_dX_div_X_bdy_dist_dm/Msun
     669              :                   end if
     670              :                end if
     671              :             end if
     672              :          end do
     673           10 :       end function check_dX
     674              : 
     675              : 
     676           10 :       integer function check_dL_div_L(s, skip_hard_limit, dt, dL_div_L_dt_ratio)
     677              :          type (star_info), pointer :: s
     678              :          logical, intent(in) :: skip_hard_limit
     679              :          real(dp), intent(in) :: dt
     680              :          real(dp), intent(inout) :: dL_div_L_dt_ratio
     681              : 
     682           10 :          real(dp) :: L, abs_dL, abs_dL_div_L, max_dL_div_L
     683              :          integer :: k, max_dL_div_L_k
     684           10 :          real(dp) :: dL_div_L_limit_min_L, dL_div_L_limit, dL_div_L_hard_limit
     685              : 
     686              :          include 'formats'
     687              : 
     688           10 :          check_dL_div_L = keep_going
     689              : 
     690           10 :          dL_div_L_limit_min_L = Lsun*s% dL_div_L_limit_min_L
     691           10 :          dL_div_L_limit = s% dL_div_L_limit*s% time_delta_coeff
     692           10 :          dL_div_L_hard_limit = s% dL_div_L_hard_limit*s% time_delta_coeff
     693              : 
     694           10 :          if (dL_div_L_limit_min_L <= 0) return
     695           10 :          if (dL_div_L_limit <= 0 .and. dL_div_L_hard_limit <= 0) return
     696              : 
     697            0 :          max_dL_div_L = -1
     698            0 :          max_dL_div_L_k = -1
     699            0 :          abs_dL_div_L = 0; L=0  ! to quiet gfortran
     700              : 
     701            0 :          do k = 1, s% nz
     702            0 :             L = s% L(k)
     703            0 :             abs_dL = abs(L - s% L_start(k))
     704            0 :             if (L >= dL_div_L_limit_min_L) then
     705            0 :                abs_dL_div_L = abs_dL/L
     706              :                if (dL_div_L_hard_limit > 0 .and. (.not. skip_hard_limit) &
     707            0 :                      .and. abs_dL_div_L > dL_div_L_hard_limit) then
     708            0 :                   check_dL_div_L= retry
     709            0 :                   s% retry_message = 'dL_div_L hard limit'
     710            0 :                   s% retry_message_k = k
     711            0 :                   if (s% report_dt_hard_limit_retries) then
     712            0 :                      write(*,2) 'L', L
     713            0 :                      write(*,2) 'L_start', s% L_start(k)
     714            0 :                      write(*,2) 'abs_dL_div_L', abs_dL_div_L
     715            0 :                      write(*,2) 'dL_div_L_hard_limit', dL_div_L_hard_limit
     716              :                   end if
     717            0 :                   return
     718              :                end if
     719            0 :                if (abs_dL_div_L > max_dL_div_L) then
     720            0 :                   max_dL_div_L = abs_dL_div_L
     721            0 :                   max_dL_div_L_k = k
     722              :                end if
     723              :             end if
     724              :          end do
     725              : 
     726            0 :          if (dL_div_L_limit <= 0) return
     727            0 :          dL_div_L_dt_ratio = max_dL_div_L/dL_div_L_limit
     728              : 
     729           10 :       end function check_dL_div_L
     730              : 
     731              : 
     732          160 :       integer function check_change( &
     733              :             s, delta_value, lim_in, hard_lim_in, max_k, msg, &
     734              :             skip_hard_limit, dt_limit_ratio, relative_excess)
     735              :          type (star_info), pointer :: s
     736              :          real(dp), intent(in) :: delta_value, lim_in, hard_lim_in
     737              :          integer, intent(in) :: max_k
     738              :          character (len=*), intent(in) :: msg
     739              :          logical, intent(in) :: skip_hard_limit
     740              :          real(dp), intent(inout) :: dt_limit_ratio
     741              :          real(dp), intent(out) :: relative_excess
     742          160 :          real(dp) :: abs_change, lim, hard_lim
     743              :          include 'formats'
     744          160 :          if (is_bad(delta_value)) then
     745            0 :             write(*,1) trim(msg) // ' delta_value', delta_value
     746            0 :             call mesa_error(__FILE__,__LINE__,'check_change')
     747              :          end if
     748          160 :          check_change = keep_going
     749          160 :          abs_change = abs(delta_value)
     750          160 :          lim = lim_in*s% time_delta_coeff
     751          160 :          hard_lim = hard_lim_in*s% time_delta_coeff
     752          160 :          if (hard_lim > 0 .and. abs_change > hard_lim .and. (.not. skip_hard_limit)) then
     753            0 :             s% retry_message = trim(msg) // ' hard limit'
     754            0 :             s% retry_message_k = max_k
     755            0 :             check_change = retry
     756            0 :             return
     757              :          end if
     758          160 :          if (lim <= 0) return
     759          120 :          relative_excess = (abs_change - lim) / lim
     760          120 :          dt_limit_ratio = abs_change/lim  ! 1d0/(s% timestep_dt_factor**relative_excess)
     761          120 :          if (is_bad(dt_limit_ratio)) then
     762            0 :             write(*,1) trim(msg) // ' dt_limit_ratio', dt_limit_ratio, abs_change, lim
     763            0 :             call mesa_error(__FILE__,__LINE__,'check_change')
     764              :          end if
     765          120 :          if (dt_limit_ratio <= 1d0) dt_limit_ratio = 0
     766              :       end function check_change
     767              : 
     768              : 
     769           10 :       subroutine get_dlgP_info(s, i, max_dlnP)
     770              :          type (star_info), pointer :: s
     771              :          integer, intent(out) :: i
     772              :          real(dp), intent(out) :: max_dlnP
     773           10 :          real(dp) :: lim, dlnP
     774              :          integer :: k
     775              :          include 'formats'
     776           10 :          lim = ln10*s% delta_lgP_limit_min_lgP
     777           10 :          i = 0
     778           10 :          max_dlnP = 0
     779        10633 :          do k=1,s% nz
     780        10623 :             if (s% lnPeos(k) < lim) cycle
     781            0 :             dlnP = abs(s% lnPeos(k) - s% lnPeos_start(k))
     782           10 :             if (dlnP > max_dlnP) then
     783            0 :                max_dlnP = dlnP
     784            0 :                i = k
     785              :             end if
     786              :          end do
     787           10 :       end subroutine get_dlgP_info
     788              : 
     789              : 
     790           10 :       integer function check_dlgP_change(s, skip_hard_limit, dt_limit_ratio)
     791              :          type (star_info), pointer :: s
     792              :          logical, intent(in) :: skip_hard_limit
     793              :          real(dp), intent(inout) :: dt_limit_ratio
     794           10 :          real(dp) :: relative_excess, max_dlnP
     795              :          integer :: i
     796              :          include 'formats'
     797           10 :          check_dlgP_change = keep_going
     798           10 :          call get_dlgP_info(s, i, max_dlnP)
     799           10 :          if (i == 0) return
     800              :          check_dlgP_change = check_change(s, max_dlnP/ln10, &
     801              :             s% delta_lgP_limit, s% delta_lgP_hard_limit, &
     802            0 :             i, 'delta_lgP', skip_hard_limit, dt_limit_ratio, relative_excess)
     803            0 :          if (check_dlgP_change /= keep_going .and. s% report_dt_hard_limit_retries) then
     804            0 :             write(*,3) 'lgP', i, s% lnPeos(i)/ln10
     805            0 :             write(*,3) 'lgP_old', i, s% lnPeos_start(i)/ln10
     806            0 :             write(*,3) 'dlgP', i, (s% lnPeos(i) - s% lnPeos_start(i))/ln10
     807            0 :             write(*,3) 'hard_limit', i, s% delta_lgP_hard_limit
     808              :          end if
     809              :       end function check_dlgP_change
     810              : 
     811              : 
     812           10 :       subroutine get_dlgRho_info(s, i, max_dlnRho)
     813              :          type (star_info), pointer :: s
     814              :          integer, intent(out) :: i
     815              :          real(dp), intent(out) :: max_dlnRho
     816           10 :          real(dp) :: lim, dlnRho, max_abs_dlnRho
     817              :          integer :: k
     818              :          include 'formats'
     819           10 :          lim = ln10*s% delta_lgRho_limit_min_lgRho
     820           10 :          i = 0
     821           10 :          max_abs_dlnRho = 0
     822        10633 :          do k=1,s% nz
     823        10623 :             if (s% lnd(k) < lim) cycle
     824            0 :             dlnRho = s% lnd(k) - s% lnd_start(k)
     825           10 :             if (abs(dlnRho) > max_abs_dlnRho) then
     826            0 :                max_dlnRho = dlnRho
     827            0 :                max_abs_dlnRho = abs(dlnRho)
     828            0 :                i = k
     829              :             end if
     830              :          end do
     831           10 :       end subroutine get_dlgRho_info
     832              : 
     833              : 
     834           10 :       integer function check_dlgRho_change(s, skip_hard_limit, dt_limit_ratio)
     835              :          ! check max change in log10(density)
     836              :          type (star_info), pointer :: s
     837              :          logical, intent(in) :: skip_hard_limit
     838              :          real(dp), intent(inout) :: dt_limit_ratio
     839           10 :          real(dp) :: relative_excess, max_dlnd
     840              :          integer :: i
     841              :          include 'formats'
     842           10 :          check_dlgRho_change = keep_going
     843           10 :          call get_dlgRho_info(s, i, max_dlnd)
     844           10 :          if (i == 0) return
     845              :          check_dlgRho_change = check_change(s, abs(max_dlnd)/ln10, &
     846              :             s% delta_lgRho_limit, s% delta_lgRho_hard_limit, &
     847            0 :             i, 'delta_lgRho', skip_hard_limit, dt_limit_ratio, relative_excess)
     848            0 :          if (check_dlgRho_change /= keep_going .and. s% report_dt_hard_limit_retries) then
     849            0 :             write(*,3) 'lgRho', i, s% lnd(i)/ln10
     850            0 :             write(*,3) 'lgRho_old', i, s% lnd_start(i)/ln10
     851            0 :             write(*,3) 'dlgRho', i, (s% lnd(i) - s% lnd_start(i))/ln10
     852            0 :             write(*,3) 'hard_limit', i, s% delta_lgRho_hard_limit
     853              :          end if
     854              :       end function check_dlgRho_change
     855              : 
     856              : 
     857           10 :       subroutine get_dlgT_info(s, i, max_dlnT)
     858              :          type (star_info), pointer :: s
     859              :          integer, intent(out) :: i
     860              :          real(dp), intent(out) :: max_dlnT
     861           10 :          real(dp) :: lim, dlnT, abs_max_dlnT
     862              :          integer :: k
     863              :          include 'formats'
     864           10 :          lim = ln10*s% delta_lgT_limit_min_lgT
     865           10 :          i = 0
     866           10 :          abs_max_dlnT = 0
     867        10633 :          do k=1,s% nz
     868        10623 :             if (s% lnT(k) < lim) cycle
     869            0 :             dlnT = s% lnT(k) - s% lnT_start(k)
     870           10 :             if (abs(dlnT) > abs_max_dlnT) then
     871            0 :                max_dlnT = dlnT
     872            0 :                abs_max_dlnT = abs(dlnT)
     873            0 :                i = k
     874              :             end if
     875              :          end do
     876           10 :       end subroutine get_dlgT_info
     877              : 
     878              : 
     879           10 :       integer function check_dlgT_change(s, skip_hard_limit, dt_limit_ratio)
     880              :          ! check max change in log10(temperature)
     881              :          type (star_info), pointer :: s
     882              :          logical, intent(in) :: skip_hard_limit
     883              :          real(dp), intent(inout) :: dt_limit_ratio
     884           10 :          real(dp) :: relative_excess, max_dlnT
     885              :          integer :: i
     886              :          include 'formats'
     887           10 :          check_dlgT_change = keep_going
     888           10 :          call get_dlgT_info(s, i, max_dlnT)
     889           10 :          if (i == 0) return
     890              :          check_dlgT_change = check_change(s, abs(max_dlnT)/ln10, &
     891              :             s% delta_lgT_limit, s% delta_lgT_hard_limit, &
     892            0 :             i, 'delta_lgT', skip_hard_limit, dt_limit_ratio, relative_excess)
     893            0 :          if (check_dlgT_change /= keep_going .and. s% report_dt_hard_limit_retries) then
     894            0 :             write(*,3) 'lgT', i, s% lnT(i)/ln10
     895            0 :             write(*,3) 'lgT_old', i, s% lnT_start(i)/ln10
     896            0 :             write(*,3) 'dlgT', i, (s% lnT(i) - s% lnT_start(i))/ln10
     897            0 :             write(*,3) 'hard_limit', i, s% delta_lgT_hard_limit
     898              :          end if
     899              :       end function check_dlgT_change
     900              : 
     901              : 
     902           10 :       subroutine get_dlgE_info(s, i, max_dlnE)
     903              :          type (star_info), pointer :: s
     904              :          integer, intent(out) :: i
     905              :          real(dp), intent(out) :: max_dlnE
     906           10 :          real(dp) :: lim, dlnE
     907              :          integer :: k
     908              :          include 'formats'
     909           10 :          lim = ln10*s% delta_lgE_limit_min_lgE
     910           10 :          i = 0
     911           10 :          max_dlnE = 0
     912        10633 :          do k=1,s% nz
     913        10623 :             if (s% lnE(k) < lim) cycle
     914            0 :             dlnE = abs(s% energy(k) - s% energy_start(k))/s% energy(k)
     915           10 :             if (dlnE > max_dlnE) then
     916            0 :                max_dlnE = dlnE
     917            0 :                i = k
     918              :             end if
     919              :          end do
     920           10 :       end subroutine get_dlgE_info
     921              : 
     922              : 
     923           10 :       integer function check_dlgE_change(s, skip_hard_limit, dt_limit_ratio)
     924              :          ! check max change in log10(internal energy)
     925              :          type (star_info), pointer :: s
     926              :          logical, intent(in) :: skip_hard_limit
     927              :          real(dp), intent(inout) :: dt_limit_ratio
     928           10 :          real(dp) :: relative_excess, max_dlnE
     929              :          integer :: i
     930              :          include 'formats'
     931           10 :          check_dlgE_change = keep_going
     932           10 :          call get_dlgE_info(s, i, max_dlnE)
     933           10 :          if (i == 0) return
     934              :          check_dlgE_change = check_change(s, max_dlnE/ln10, &
     935              :             s% delta_lgE_limit, s% delta_lgE_hard_limit, &
     936            0 :             i, 'delta_lgE', skip_hard_limit, dt_limit_ratio, relative_excess)
     937            0 :          if (check_dlgE_change /= keep_going .and. s% report_dt_hard_limit_retries) then
     938            0 :             write(*,3) 'lgE', i, safe_log10(s% energy(i))
     939            0 :             write(*,3) 'lgE_old', i, safe_log10(s% energy_start(i))
     940            0 :             write(*,3) 'dlgE', i, (s% energy(i) - s% energy_start(i))/s% energy(i)/ln10
     941            0 :             write(*,3) 'hard_limit', i, s% delta_lgE_hard_limit
     942              :          end if
     943              :       end function check_dlgE_change
     944              : 
     945              : 
     946           10 :       subroutine get_dlgR_info(s, i, max_dlnR)
     947              :          type (star_info), pointer :: s
     948              :          integer, intent(out) :: i
     949              :          real(dp), intent(out) :: max_dlnR
     950           10 :          real(dp) :: lim, dlnR
     951              :          integer :: k
     952              :          include 'formats'
     953           10 :          lim = ln10*s% delta_lgR_limit_min_lgR
     954           10 :          i = 0
     955           10 :          max_dlnR = 0
     956        10633 :          do k=1,s% nz
     957        10623 :             if (s% lnR(k) < lim) cycle
     958            0 :             dlnR = abs(s% lnR(k) - s% lnR_start(k))
     959           10 :             if (dlnR > max_dlnR) then
     960            0 :                max_dlnR = dlnR
     961            0 :                i = k
     962              :             end if
     963              :          end do
     964           10 :       end subroutine get_dlgR_info
     965              : 
     966              : 
     967           10 :       integer function check_dlgR_change(s, skip_hard_limit, dt_limit_ratio)
     968              :          type (star_info), pointer :: s
     969              :          logical, intent(in) :: skip_hard_limit
     970              :          real(dp), intent(inout) :: dt_limit_ratio
     971           10 :          real(dp) :: relative_excess, max_dlnR
     972              :          integer :: i
     973              :          include 'formats'
     974           10 :          check_dlgR_change = keep_going
     975           10 :          call get_dlgR_info(s, i, max_dlnR)
     976           10 :          if (i == 0) return
     977              :          check_dlgR_change = check_change(s, max_dlnR/ln10, &
     978              :             s% delta_lgR_limit, s% delta_lgR_hard_limit, &
     979            0 :             i, 'delta_lgR', skip_hard_limit, dt_limit_ratio, relative_excess)
     980            0 :          if (check_dlgR_change /= keep_going .and. s% report_dt_hard_limit_retries) then
     981            0 :             write(*,3) 'lgR', i, s% lnR(i)/ln10
     982            0 :             write(*,3) 'lgR_old', i, s% lnR_start(i)/ln10
     983            0 :             write(*,3) 'dlgR', i, (s% lnR(i) - s% lnR_start(i))/ln10
     984            0 :             write(*,3) 'hard_limit', i, s% delta_lgR_hard_limit
     985              :          end if
     986              :       end function check_dlgR_change
     987              : 
     988              : 
     989           50 :       integer function check_lgL( &
     990              :             s, iso_in, msg, skip_hard_limit, dt, dt_limit_ratio)
     991              :          type (star_info), pointer :: s
     992              :          integer, intent(in) :: iso_in
     993              :          character (len=*), intent(in) :: msg
     994              :          logical, intent(in) :: skip_hard_limit
     995              :          real(dp), intent(in) :: dt
     996              :          real(dp), intent(inout) :: dt_limit_ratio
     997              : 
     998              :          real(dp) :: &
     999           50 :             new_L, max_other_L, old_L, lim, hard_lim, lgL_min, &
    1000           50 :             drop_factor, relative_limit, lgL, max_other_lgL, lgL_old, &
    1001           50 :             abs_change, relative_excess
    1002              :          logical, parameter :: dbg = .false.
    1003              :          integer :: iso
    1004              :          include 'formats'
    1005           50 :          check_lgL = keep_going
    1006              : 
    1007           50 :          iso = iso_in
    1008           50 :          if (iso == iprot) then  ! check_lgL_power_photo_change
    1009           10 :             if (s% log_max_temperature < s% min_lgT_for_lgL_power_photo_limit) return
    1010            0 :             new_L = abs(s% power_photo)
    1011            0 :             max_other_L = 0d0
    1012            0 :             old_L = abs(s% power_photo_old)
    1013            0 :             lim = s% delta_lgL_power_photo_limit
    1014            0 :             hard_lim = s% delta_lgL_power_photo_hard_limit
    1015            0 :             lgL_min = s% lgL_power_photo_burn_min
    1016            0 :             drop_factor = s% lgL_power_photo_drop_factor
    1017            0 :             relative_limit = 0d0
    1018           40 :          else if (iso == ineut) then  ! check_lgL_nuc_change
    1019           10 :             if (s% log_max_temperature > s% max_lgT_for_lgL_nuc_limit) return
    1020           10 :             new_L = s% power_nuc_burn
    1021           10 :             max_other_L = 0d0
    1022           10 :             old_L = s% power_nuc_burn_old
    1023           10 :             if (s% log_max_temperature > &
    1024              :                   s% delta_lgL_nuc_at_high_T_limit_lgT_min) then
    1025            0 :                lim = s% delta_lgL_nuc_at_high_T_limit
    1026            0 :                hard_lim = s% delta_lgL_nuc_at_high_T_hard_limit
    1027              :             else
    1028           10 :                lim = s% delta_lgL_nuc_limit
    1029           10 :                hard_lim = s% delta_lgL_nuc_hard_limit
    1030              :             end if
    1031           10 :             lgL_min = s% lgL_nuc_burn_min
    1032           10 :             drop_factor = s% lgL_nuc_drop_factor
    1033           10 :             relative_limit = 0d0
    1034           30 :          else if (iso == ih1) then
    1035           10 :             new_L = s% power_h_burn
    1036           10 :             max_other_L = max(s% power_he_burn, s% power_z_burn)
    1037           10 :             old_L = s% power_h_burn_old
    1038           10 :             lim = s% delta_lgL_H_limit
    1039           10 :             hard_lim = s% delta_lgL_H_hard_limit
    1040           10 :             lgL_min = s% lgL_H_burn_min
    1041           10 :             drop_factor = s% lgL_H_drop_factor
    1042           10 :             relative_limit = s% lgL_H_burn_relative_limit
    1043           20 :          else if (iso == ihe4) then
    1044           10 :             new_L = s% power_he_burn
    1045           10 :             max_other_L = max(s% power_h_burn, s% power_z_burn)
    1046           10 :             old_L = s% power_he_burn_old
    1047           10 :             lim = s% delta_lgL_He_limit
    1048           10 :             hard_lim = s% delta_lgL_He_hard_limit
    1049           10 :             lgL_min = s% lgL_He_burn_min
    1050           10 :             drop_factor = s% lgL_He_drop_factor
    1051           10 :             relative_limit = s% lgL_He_burn_relative_limit
    1052           10 :          else if (iso == isi28) then
    1053           10 :             new_L = s% power_z_burn
    1054           10 :             max_other_L = max(s% power_h_burn, s% power_he_burn)
    1055           10 :             old_L = s% power_z_burn_old
    1056           10 :             lim = s% delta_lgL_z_limit
    1057           10 :             hard_lim = s% delta_lgL_z_hard_limit
    1058           10 :             lgL_min = s% lgL_z_burn_min
    1059           10 :             drop_factor = s% lgL_z_drop_factor
    1060           10 :             relative_limit = s% lgL_z_burn_relative_limit
    1061              :          else
    1062            0 :             call mesa_error(__FILE__,__LINE__,'bad iso arg for check_lgL')
    1063              :          end if
    1064              : 
    1065           40 :          if (old_L < 0d0) return
    1066              : 
    1067           36 :          lim = lim*s% time_delta_coeff
    1068           36 :          hard_lim = hard_lim*s% time_delta_coeff
    1069              : 
    1070           36 :          if (new_L < old_L) then
    1071           12 :             lim = lim*drop_factor
    1072           12 :             hard_lim = hard_lim*drop_factor
    1073              :          end if
    1074              : 
    1075              :          if (dbg) write(*,*)
    1076              :          if (dbg) write(*,1) trim(msg) // ' new_L', new_L
    1077              :          if (dbg) write(*,1) 'old_L', old_L
    1078           36 :          if (new_L <= 0 .or. old_L <= 0) return
    1079              : 
    1080           31 :          lgL = safe_log10(new_L)
    1081              :          if (dbg) write(*,1) 'lgL', lgL
    1082           31 :          if (lgL < lgL_min) return
    1083              : 
    1084           20 :          if (max_other_L > 0) then
    1085           10 :             max_other_lgL = safe_log10(max_other_L)
    1086              :             if (dbg) write(*,1) 'max_other_lgL', max_other_lgL
    1087           10 :             if (max_other_lgL - relative_limit > lgL) return
    1088              :          end if
    1089              : 
    1090           20 :          lgL_old = safe_log10(old_L)
    1091              :          if (dbg) write(*,1) 'lgL_old', lgL_old
    1092           20 :          abs_change = abs(lgL - lgL_old)
    1093              :          if (dbg) write(*,1) 'abs_change', abs_change
    1094              :          if (dbg) write(*,1) 'hard_lim', hard_lim
    1095           20 :          if (hard_lim > 0 .and. abs_change > hard_lim .and. (.not. skip_hard_limit)) then
    1096            0 :             if (s% report_dt_hard_limit_retries) then
    1097            0 :                write(*,1) trim(msg) // ' end', lgL
    1098            0 :                write(*,1) trim(msg) // ' start', lgL_old
    1099            0 :                write(*,1) trim(msg) // ' delta', lgL - lgL_old
    1100            0 :                write(*,1) trim(msg) // ' hard_lim', hard_lim
    1101              :             end if
    1102            0 :             check_lgL = retry
    1103            0 :             s% retry_message = trim(msg) // ' hard limit'
    1104            0 :             return
    1105              :          end if
    1106              : 
    1107              :          if (dbg) write(*,1) 'lim', lim
    1108           20 :          if (lim <= 0) return
    1109              : 
    1110            0 :          relative_excess = (abs_change - lim) / lim
    1111              :          if (dbg) write(*,1) 'relative_excess', relative_excess
    1112            0 :          dt_limit_ratio = 1d0/pow(s% timestep_dt_factor,relative_excess)
    1113            0 :          if (dt_limit_ratio <= 1d0) dt_limit_ratio = 0
    1114              : 
    1115              :       end function check_lgL
    1116              : 
    1117              : 
    1118           10 :       integer function check_lgL_H_change(s, skip_hard_limit, dt, dt_limit_ratio)
    1119              :          type (star_info), pointer :: s
    1120              :          logical, intent(in) :: skip_hard_limit
    1121              :          real(dp), intent(in) :: dt
    1122              :          real(dp), intent(inout) :: dt_limit_ratio
    1123              :          check_lgL_H_change = check_lgL( &
    1124           10 :             s, ih1, 'check_lgL_H_change', skip_hard_limit, dt, dt_limit_ratio)
    1125              :       end function check_lgL_H_change
    1126              : 
    1127              : 
    1128           10 :       integer function check_lgL_He_change(s, skip_hard_limit, dt, dt_limit_ratio)
    1129              :          type (star_info), pointer :: s
    1130              :          logical, intent(in) :: skip_hard_limit
    1131              :          real(dp), intent(in) :: dt
    1132              :          real(dp), intent(inout) :: dt_limit_ratio
    1133              :          check_lgL_He_change = check_lgL( &
    1134           10 :             s, ihe4, 'check_lgL_He_change', skip_hard_limit, dt, dt_limit_ratio)
    1135              :       end function check_lgL_He_change
    1136              : 
    1137              : 
    1138           10 :       integer function check_lgL_z_change(s, skip_hard_limit, dt, dt_limit_ratio)
    1139              :          type (star_info), pointer :: s
    1140              :          logical, intent(in) :: skip_hard_limit
    1141              :          real(dp), intent(in) :: dt
    1142              :          real(dp), intent(inout) :: dt_limit_ratio
    1143              :          check_lgL_z_change = check_lgL( &
    1144           10 :             s, isi28, 'check_lgL_z_change', skip_hard_limit, dt, dt_limit_ratio)
    1145              :       end function check_lgL_z_change
    1146              : 
    1147              : 
    1148           10 :       integer function check_lgL_power_photo_change(s, skip_hard_limit, dt, dt_limit_ratio)
    1149              :          type (star_info), pointer :: s
    1150              :          logical, intent(in) :: skip_hard_limit
    1151              :          real(dp), intent(in) :: dt
    1152              :          real(dp), intent(inout) :: dt_limit_ratio
    1153              :          check_lgL_power_photo_change = check_lgL( &
    1154           10 :             s, iprot, 'check_lgL_power_photo_change', skip_hard_limit, dt, dt_limit_ratio)
    1155              :       end function check_lgL_power_photo_change
    1156              : 
    1157              : 
    1158           10 :       integer function check_lgL_nuc_change(s, skip_hard_limit, dt, dt_limit_ratio)
    1159              :          type (star_info), pointer :: s
    1160              :          logical, intent(in) :: skip_hard_limit
    1161              :          real(dp), intent(in) :: dt
    1162              :          real(dp), intent(inout) :: dt_limit_ratio
    1163              :          include 'formats'
    1164              :          check_lgL_nuc_change = check_lgL( &
    1165           10 :             s, ineut, 'check_lgL_nuc_change', skip_hard_limit, dt, dt_limit_ratio)
    1166              :       end function check_lgL_nuc_change
    1167              : 
    1168              : 
    1169           10 :       integer function check_lgL_nuc_cat_change( &
    1170              :             s, n_mix_bdy, mix_bdy_q, skip_hard_limit, dt_limit_ratio)
    1171              :          use rates_def
    1172              :          use num_lib, only: binary_search
    1173              :          type (star_info), pointer :: s
    1174              :          logical, intent(in) :: skip_hard_limit
    1175              :          integer, intent(in) :: n_mix_bdy
    1176              :          real(dp), intent(in), pointer :: mix_bdy_q(:)
    1177              :          real(dp), intent(inout) :: dt_limit_ratio
    1178              : 
    1179              :          integer :: k, max_j, max_k, bdy
    1180           10 :          real(dp) :: max_lgL_diff, relative_excess, max_diff, cat_burn_min, &
    1181           10 :             max_luminosity, max_luminosity_start
    1182              : 
    1183              :          include 'formats'
    1184              : 
    1185           10 :          check_lgL_nuc_cat_change = keep_going
    1186              : 
    1187           10 :          if (s% delta_lgL_nuc_cat_limit <= 0 .and. s% delta_lgL_nuc_cat_hard_limit <= 0) return
    1188              : 
    1189            0 :          cat_burn_min = exp10(s% lgL_nuc_cat_burn_min)
    1190            0 :          max_diff = 0
    1191            0 :          max_j = -1
    1192            0 :          max_k = -1
    1193            0 :          bdy = -1
    1194              : 
    1195            0 :          do k = 1, s% nz
    1196              : 
    1197              :             ! find the nearest mixing boundary
    1198            0 :             bdy = binary_search(n_mix_bdy, mix_bdy_q, bdy, s% q(k))
    1199              :             ! don't check cells near a mixing boundary
    1200            0 :             if (bdy > 0) then
    1201            0 :                if (abs(s% q(k) - mix_bdy_q(bdy)) < s% lgL_nuc_mix_dist_limit) cycle
    1202              :             end if
    1203              : 
    1204            0 :             call do1_category(ipp,k)
    1205            0 :             call do1_category(icno,k)
    1206            0 :             call do1_category(i3alf,k)
    1207            0 :             call do1_category(i_burn_c,k)
    1208            0 :             call do1_category(i_burn_n,k)
    1209            0 :             call do1_category(i_burn_o,k)
    1210            0 :             call do1_category(i_burn_ne,k)
    1211            0 :             call do1_category(i_burn_na,k)
    1212            0 :             call do1_category(i_burn_mg,k)
    1213            0 :             call do1_category(i_burn_si,k)
    1214            0 :             call do1_category(i_burn_s,k)
    1215            0 :             call do1_category(i_burn_ar,k)
    1216            0 :             call do1_category(i_burn_ca,k)
    1217            0 :             call do1_category(i_burn_ti,k)
    1218            0 :             call do1_category(i_burn_cr,k)
    1219            0 :             call do1_category(i_burn_fe,k)
    1220            0 :             call do1_category(icc,k)
    1221            0 :             call do1_category(ico,k)
    1222            0 :             call do1_category(ioo,k)
    1223              : 
    1224              :          end do
    1225              : 
    1226              : 
    1227            0 :          if (max_diff <= 0) return
    1228              : 
    1229            0 :          max_lgL_diff = log10(max_diff/Lsun)
    1230            0 :          s% Tlim_dlgL_nuc_category = max_j
    1231            0 :          s% Tlim_dlgL_nuc_cell = max_k
    1232              : 
    1233              :          check_lgL_nuc_cat_change = check_change(s, max_lgL_diff, &
    1234              :             s% delta_lgL_nuc_cat_limit, s% delta_lgL_nuc_cat_hard_limit, &
    1235            0 :             max_k, 'delta_lgL_nuc_cat', skip_hard_limit, dt_limit_ratio, relative_excess)
    1236           10 :          if (check_lgL_nuc_cat_change /= keep_going .and. s% report_dt_hard_limit_retries) then
    1237            0 :             write(*,1) 'max_luminosity ' // trim(category_name(max_j)), max_luminosity
    1238            0 :             write(*,1) 'max_luminosity_start ' // trim(category_name(max_j)), max_luminosity_start
    1239              :          end if
    1240              : 
    1241              :          contains
    1242              : 
    1243            0 :          subroutine do1_category(j, k)
    1244              :             integer, intent(in) :: j, k
    1245            0 :             real(dp) :: diff, abs_diff
    1246            0 :             if (s% luminosity_by_category(j,k) < cat_burn_min) return
    1247            0 :             if (s% luminosity_by_category_start(j,k) < cat_burn_min) return
    1248            0 :             diff = s% luminosity_by_category(j,k) - s% luminosity_by_category_start(j,k)
    1249            0 :             abs_diff = abs(diff)
    1250            0 :             if (abs_diff <= max_diff) return
    1251            0 :             max_luminosity = s% luminosity_by_category(j,k)
    1252            0 :             max_luminosity_start = s% luminosity_by_category_start(j,k)
    1253            0 :             max_diff = abs_diff
    1254            0 :             max_j = j
    1255            0 :             max_k = k
    1256           10 :          end subroutine do1_category
    1257              : 
    1258              :       end function check_lgL_nuc_cat_change
    1259              : 
    1260              : 
    1261           10 :       integer function check_dlgTeff_change(s, skip_hard_limit, dt, dt_limit_ratio)
    1262              :          type (star_info), pointer :: s
    1263              :          logical, intent(in) :: skip_hard_limit
    1264              :          real(dp), intent(in) :: dt
    1265              :          real(dp), intent(inout) :: dt_limit_ratio
    1266           10 :          real(dp) :: relative_excess
    1267              :          include 'formats'
    1268           10 :          check_dlgTeff_change = keep_going
    1269           10 :          dt_limit_ratio = 0d0
    1270           10 :          if (s% doing_relax .or. s% Teff_old <= 0 .or. s% Teff <= 0) return
    1271              :          check_dlgTeff_change = check_change(s, safe_log10(s% Teff/s% Teff_old), &
    1272              :             s% delta_lgTeff_limit, s% delta_lgTeff_hard_limit, &
    1273           10 :             0, 'delta_lgTeff', skip_hard_limit, dt_limit_ratio, relative_excess)
    1274           10 :          if (check_dlgTeff_change /= keep_going .and. s% report_dt_hard_limit_retries) then
    1275            0 :             write(*,1) 'lgTeff', safe_log10(s% Teff)
    1276            0 :             write(*,1) 'lgTeff_old', safe_log10(s% Teff_old)
    1277              :          end if
    1278              :       end function check_dlgTeff_change
    1279              : 
    1280              : 
    1281           10 :       integer function check_dYe_highT_change(s, skip_hard_limit, dt_limit_ratio)  ! check max change in Ye
    1282              :          type (star_info), pointer :: s
    1283              :          logical, intent(in) :: skip_hard_limit
    1284              :          real(dp), intent(inout) :: dt_limit_ratio
    1285           10 :          real(dp) :: relative_excess, max_diff, ye_diff, T_limit
    1286              :          integer :: i, k
    1287              :          include 'formats'
    1288           10 :          check_dYe_highT_change = keep_going
    1289           10 :          dt_limit_ratio = 0d0
    1290           10 :          if (s% doing_relax) return
    1291           10 :          i = 0
    1292           10 :          max_diff = 0
    1293           10 :          T_limit = s% minT_for_highT_Ye_limit
    1294        10633 :          do k=1, s% nz
    1295        10623 :             if (s% T(k) < T_limit) cycle
    1296            0 :             ye_diff = abs(s% ye(k) - s% ye_start(k))
    1297            0 :             if (ye_diff <= max_diff) cycle
    1298            0 :             max_diff = ye_diff
    1299        10633 :             i = k
    1300              :          end do
    1301              :          check_dYe_highT_change = check_change(s, max_diff, &
    1302              :             s% delta_Ye_highT_limit, s% delta_Ye_highT_hard_limit, &
    1303           10 :             i, 'delta_Ye_highT', .false., dt_limit_ratio, relative_excess)
    1304           10 :          if (check_dYe_highT_change /= keep_going .and. s% report_dt_hard_limit_retries) then
    1305            0 :             write(*,2) 'ye', i, s% ye(i)
    1306            0 :             write(*,2) 'ye_start', i, s% ye_start(i)
    1307              :          end if
    1308              :       end function check_dYe_highT_change
    1309              : 
    1310              : 
    1311           10 :       integer function check_dlgT_max_change(s, skip_hard_limit, dt, dt_limit_ratio)
    1312              :          type (star_info), pointer :: s
    1313              :          logical, intent(in) :: skip_hard_limit
    1314              :          real(dp), intent(in) :: dt
    1315              :          real(dp), intent(inout) :: dt_limit_ratio
    1316           10 :          real(dp) :: relative_excess, change, lnTmax, lnTmax_start
    1317              :          integer :: lnTmax_k
    1318              :          include 'formats'
    1319           10 :          check_dlgT_max_change = keep_going
    1320           10 :          dt_limit_ratio = 0d0
    1321           10 :          if (s% doing_relax) return
    1322           10 :          if (s% delta_lgT_max_limit_lgT_min < 0d0) return
    1323           10 :          if (s% delta_lgT_max_limit_only_after_near_zams) then
    1324            0 :             if (s% X(s% nz) > 0.1d0 .and. &
    1325              :                 s% L_nuc_burn_total/s% L_phot < s% Lnuc_div_L_zams_limit ) return
    1326              :          end if
    1327        10643 :          lnTmax_k = maxloc(s% lnT(1:s% nz),dim=1)
    1328           10 :          lnTmax = s% lnT(lnTmax_k)
    1329           10 :          if (lnTmax < s% delta_lgT_max_limit_lgT_min*ln10) return
    1330            0 :          lnTmax_start = maxval(s% lnT_start(1:s% nz))
    1331            0 :          change = (lnTmax - lnTmax_start)/ln10
    1332              :          check_dlgT_max_change = check_change(s, change, &
    1333              :             s% delta_lgT_max_limit, s% delta_lgT_max_hard_limit, &
    1334            0 :             lnTmax_k, 'delta_lgT_max', skip_hard_limit, dt_limit_ratio, relative_excess)
    1335            0 :          if (check_dlgT_max_change /= keep_going .and. s% report_dt_hard_limit_retries) then
    1336            0 :             write(*,2) 'lgT_max', lnTmax_k, lnTmax/ln10
    1337            0 :             write(*,2) 'lgT_max_old', lnTmax_k, lnTmax_start/ln10
    1338              :          end if
    1339              :       end function check_dlgT_max_change
    1340              : 
    1341              : 
    1342           10 :       integer function check_dlgT_max_at_high_T_change(s, skip_hard_limit, dt, dt_limit_ratio)
    1343              :          type (star_info), pointer :: s
    1344              :          logical, intent(in) :: skip_hard_limit
    1345              :          real(dp), intent(in) :: dt
    1346              :          real(dp), intent(inout) :: dt_limit_ratio
    1347           10 :          real(dp) :: relative_excess, change, lnTmax_at_high_T, lnTmax_at_high_T_start
    1348              :          integer :: lnTmax_k
    1349              :          include 'formats'
    1350           10 :          check_dlgT_max_at_high_T_change = keep_going
    1351           10 :          dt_limit_ratio = 0d0
    1352           10 :          if (s% doing_relax) return
    1353           10 :          if (s% delta_lgT_max_at_high_T_limit_lgT_min < 0d0) return
    1354            0 :          lnTmax_k = maxloc(s% lnT(1:s% nz),dim=1)
    1355            0 :          lnTmax_at_high_T = s% lnT(lnTmax_k)
    1356            0 :          if (lnTmax_at_high_T < s% delta_lgT_max_at_high_T_limit_lgT_min*ln10) return
    1357            0 :          lnTmax_at_high_T_start = maxval(s% lnT_start(1:s% nz))
    1358            0 :          change = (lnTmax_at_high_T - lnTmax_at_high_T_start)/ln10
    1359              :          check_dlgT_max_at_high_T_change = check_change(s, change, &
    1360              :             s% delta_lgT_max_at_high_T_limit, s% delta_lgT_max_at_high_T_hard_limit, &
    1361            0 :             lnTmax_k, 'delta_lgT_max_at_high_T', skip_hard_limit, dt_limit_ratio, relative_excess)
    1362            0 :          if (check_dlgT_max_at_high_T_change /= keep_going .and. s% report_dt_hard_limit_retries) then
    1363            0 :             write(*,2) 'lgT_max', lnTmax_k, lnTmax_at_high_T/ln10
    1364            0 :             write(*,2) 'lgT_max_old', lnTmax_k, lnTmax_at_high_T_start/ln10
    1365              :          end if
    1366              :       end function check_dlgT_max_at_high_T_change
    1367              : 
    1368              : 
    1369           10 :       integer function check_dlgT_cntr_change(s, skip_hard_limit, dt, dt_limit_ratio)
    1370              :          type (star_info), pointer :: s
    1371              :          logical, intent(in) :: skip_hard_limit
    1372              :          real(dp), intent(in) :: dt
    1373              :          real(dp), intent(inout) :: dt_limit_ratio
    1374           10 :          real(dp) :: relative_excess, change
    1375              :          include 'formats'
    1376           10 :          check_dlgT_cntr_change = keep_going
    1377           10 :          dt_limit_ratio = 0d0
    1378           10 :          if (s% doing_relax) return
    1379           10 :          if (s% delta_lgT_cntr_limit_only_after_near_zams) then
    1380           10 :             if (s% X(s% nz) > 0.1d0 .and. &
    1381              :                 s% L_nuc_burn_total/s% L_phot < s% Lnuc_div_L_zams_limit) return
    1382              :          end if
    1383           10 :          change = (s% lnT(s% nz) - s% lnT_start(s% nz))/ln10
    1384              :          check_dlgT_cntr_change = check_change(s, change, &
    1385              :             s% delta_lgT_cntr_limit, s% delta_lgT_cntr_hard_limit, &
    1386           10 :             s% nz, 'delta_lgT_cntr', skip_hard_limit, dt_limit_ratio, relative_excess)
    1387           10 :          if (check_dlgT_cntr_change /= keep_going .and. s% report_dt_hard_limit_retries) then
    1388            0 :             write(*,1) 'lgT_cntr', s% lnT(s% nz)/ln10
    1389            0 :             write(*,1) 'lgT_cntr_old', s% lnT_start(s% nz)/ln10
    1390              :          end if
    1391              :       end function check_dlgT_cntr_change
    1392              : 
    1393              : 
    1394           10 :       integer function check_dlgP_cntr_change(s, skip_hard_limit, dt, dt_limit_ratio)
    1395              :          type (star_info), pointer :: s
    1396              :          logical, intent(in) :: skip_hard_limit
    1397              :          real(dp), intent(in) :: dt
    1398              :          real(dp), intent(inout) :: dt_limit_ratio
    1399           10 :          real(dp) :: relative_excess, change
    1400              :          include 'formats'
    1401           10 :          check_dlgP_cntr_change = keep_going
    1402           10 :          dt_limit_ratio = 0d0
    1403           10 :          if (s% doing_relax) return
    1404           10 :          change = (s% lnPeos(s% nz) - s% lnPeos_start(s% nz))/ln10
    1405              :          check_dlgP_cntr_change = check_change(s, change, &
    1406              :             s% delta_lgP_cntr_limit, s% delta_lgP_cntr_hard_limit, &
    1407           10 :             s% nz, 'delta_lgP_cntr', skip_hard_limit, dt_limit_ratio, relative_excess)
    1408           10 :          if (check_dlgP_cntr_change /= keep_going .and. s% report_dt_hard_limit_retries) then
    1409            0 :             write(*,1) 'lgP_cntr', s% lnPeos(s% nz)/ln10
    1410            0 :             write(*,1) 'lgP_cntr_old', s% lnPeos_start(s% nz)/ln10
    1411              :          end if
    1412              :       end function check_dlgP_cntr_change
    1413              : 
    1414              : 
    1415           10 :       integer function check_dlgRho_cntr_change(s, skip_hard_limit, dt, dt_limit_ratio)
    1416              :          type (star_info), pointer :: s
    1417              :          logical, intent(in) :: skip_hard_limit
    1418              :          real(dp), intent(in) :: dt
    1419              :          real(dp), intent(inout) :: dt_limit_ratio
    1420           10 :          real(dp) :: relative_excess, dlgRho_cntr
    1421              :          integer :: nz
    1422              :          include 'formats'
    1423           10 :          check_dlgRho_cntr_change = keep_going
    1424           10 :          dt_limit_ratio = 0d0
    1425           10 :          if (s% doing_relax) return
    1426           10 :          nz = s% nz
    1427           10 :          dlgRho_cntr = (s% lnd(nz) - s% lnd_start(nz))/ln10
    1428              :          check_dlgRho_cntr_change = check_change(s, dlgRho_cntr, &
    1429              :             s% delta_lgRho_cntr_limit, s% delta_lgRho_cntr_hard_limit, &
    1430           10 :             nz, 'delta_lgRho_cntr', skip_hard_limit, dt_limit_ratio, relative_excess)
    1431           10 :          if (check_dlgRho_cntr_change /= keep_going .and. s% report_dt_hard_limit_retries) then
    1432            0 :             write(*,1) 'lgRho_cntr', s% lnd(s% nz)/ln10
    1433            0 :             write(*,1) 'lgRho_cntr_old', s% lnd_start(s% nz)/ln10
    1434              :          end if
    1435              :       end function check_dlgRho_cntr_change
    1436              : 
    1437              : 
    1438           10 :       integer function check_dlog_eps_nuc_change(s, skip_hard_limit, dt, dt_limit_ratio)
    1439              :          type (star_info), pointer :: s
    1440              :          logical, intent(in) :: skip_hard_limit
    1441              :          real(dp), intent(in) :: dt
    1442              :          real(dp), intent(inout) :: dt_limit_ratio
    1443           10 :          real(dp) :: relative_excess, max_ratio, ratio, delta, &
    1444           10 :             limit_ratio, delta_r
    1445              :          integer :: k, j, nz, k_max
    1446              :          include 'formats'
    1447           10 :          check_dlog_eps_nuc_change = keep_going
    1448           10 :          nz = s% nz
    1449           10 :          limit_ratio = exp10(s% delta_log_eps_nuc_limit)
    1450           10 :          max_ratio = limit_ratio
    1451           10 :          k_max = 0
    1452        10633 :          zoneloop: do k=1,nz
    1453        10623 :             if (s% eps_nuc_start(k) < 1) cycle zoneloop
    1454         2295 :             ratio = s% eps_nuc(k)/s% eps_nuc_start(k)
    1455              :             if (s% mixing_type(k) /= convective_mixing .and. &
    1456         2295 :                 s% mixing_type(min(nz,k+1)) /= convective_mixing .and. &
    1457           10 :                 ratio > max_ratio) then
    1458          674 :                do j = 1, s% num_conv_boundaries
    1459          541 :                   delta_r = abs(s% r(s% conv_bdy_loc(j)) - s% r(k))
    1460          674 :                   if (delta_r <= s% scale_height(k)) then
    1461              :                      cycle zoneloop  ! skip ones that are too close to convection zone
    1462              :                   end if
    1463              :                end do
    1464          133 :                max_ratio = ratio
    1465          133 :                k_max = k
    1466              :             end if
    1467              :          end do zoneloop
    1468           10 :          if (k_max > 0) then
    1469           10 :             delta = log10(max_ratio)
    1470              :          else
    1471            0 :             delta = 0
    1472              :          end if
    1473              :          check_dlog_eps_nuc_change = check_change(s, delta, &
    1474              :             s% delta_log_eps_nuc_limit, s% delta_log_eps_nuc_hard_limit, &
    1475              :             k_max, 'delta_log_eps_nuc', &
    1476           10 :             skip_hard_limit, dt_limit_ratio, relative_excess)
    1477           10 :          if (check_dlog_eps_nuc_change /= keep_going .and. s% report_dt_hard_limit_retries) then
    1478            0 :             write(*,2) 'log_eps_nuc', k_max, safe_log10(abs(s% eps_nuc(k_max)))
    1479            0 :             write(*,2) 'log_eps_nuc_old', k_max, safe_log10(abs(s% eps_nuc_start(k_max)))
    1480              :          end if
    1481           10 :       end function check_dlog_eps_nuc_change
    1482              : 
    1483              : 
    1484           10 :       integer function check_dX_div_X_cntr(s, skip_hard_limit, dt_limit_ratio)
    1485              :          type (star_info), pointer :: s
    1486              :          logical, intent(in) :: skip_hard_limit
    1487              :          real(dp), intent(inout) :: dt_limit_ratio
    1488           10 :          real(dp) :: relative_excess, max_abs_dX_div_X, X, dX, abs_dX_div_X
    1489              :          integer :: j, nz, j_max
    1490              :          include 'formats'
    1491           10 :          check_dX_div_X_cntr = keep_going
    1492           10 :          if (s% mix_factor == 0d0 .and. s% dxdt_nuc_factor == 0d0) return
    1493           10 :          nz = s% nz
    1494           10 :          max_abs_dX_div_X = -1
    1495           90 :          do j=1,s% species
    1496           80 :             X = s% xa(j,nz)
    1497           80 :             if (X > s% delta_dX_div_X_cntr_max) cycle
    1498            0 :             if (X < s% delta_dX_div_X_cntr_min) cycle
    1499            0 :             if (X <= 0d0) cycle
    1500            0 :             dX = X - s% xa_old(j,nz)
    1501            0 :             if (s% delta_dX_div_X_drop_only .and. dX > 0) cycle
    1502            0 :             abs_dX_div_X = abs(dX/X)
    1503           10 :             if (abs_dX_div_X > max_abs_dX_div_X) then
    1504            0 :                max_abs_dX_div_X = abs_dX_div_X
    1505            0 :                j_max = j
    1506              :             end if
    1507              :          end do
    1508           10 :          if (max_abs_dX_div_X <= 0d0) return
    1509              :          check_dX_div_X_cntr = check_change(s, max_abs_dX_div_X, &
    1510              :             s% delta_dX_div_X_cntr_limit, s% delta_dX_div_X_cntr_hard_limit, &
    1511            0 :             0, 'delta_dX_div_X_cntr', skip_hard_limit, dt_limit_ratio, relative_excess)
    1512            0 :          if (check_dX_div_X_cntr /= keep_going .and. s% report_dt_hard_limit_retries) then
    1513            0 :             write(*,1) chem_isos% name(s% chem_id(j_max)) // ' X', s% xa(j_max,nz)
    1514            0 :             write(*,1) chem_isos% name(s% chem_id(j_max)) // ' X old', s% xa_old(j_max,nz)
    1515              :          end if
    1516              :       end function check_dX_div_X_cntr
    1517              : 
    1518              : 
    1519           10 :       integer function check_lg_XH_cntr(s, skip_hard_limit, dt_limit_ratio)
    1520              :          type (star_info), pointer :: s
    1521              :          logical, intent(in) :: skip_hard_limit
    1522              :          real(dp), intent(inout) :: dt_limit_ratio
    1523           10 :          real(dp) :: relative_excess, lg_XH_cntr, lg_XH_cntr_old
    1524              :          integer :: h1, nz
    1525              :          include 'formats'
    1526           10 :          check_lg_XH_cntr = keep_going
    1527           10 :          if (s% mix_factor == 0d0 .and. s% dxdt_nuc_factor == 0d0) return
    1528           10 :          h1 = s% net_iso(ih1)
    1529           10 :          if (h1 == 0) return
    1530           10 :          nz = s% nz
    1531           10 :          if (s% xa(h1,nz) < 1d-10) return
    1532           10 :          lg_XH_cntr = log10(s% xa(h1,nz))
    1533           10 :          if (lg_XH_cntr > s% delta_lg_XH_cntr_max) return
    1534           10 :          if (lg_XH_cntr < s% delta_lg_XH_cntr_min) return
    1535           10 :          lg_XH_cntr_old = safe_log10(s% xa_old(h1,nz))
    1536           10 :          if (s% delta_lg_XH_drop_only .and. lg_XH_cntr >= lg_XH_cntr_old) return
    1537              :          check_lg_XH_cntr = check_change(s, lg_XH_cntr - lg_XH_cntr_old, &
    1538              :             s% delta_lg_XH_cntr_limit, s% delta_lg_XH_cntr_hard_limit, &
    1539           10 :             nz, 'delta_lg_XH_cntr', skip_hard_limit, dt_limit_ratio, relative_excess)
    1540           10 :          if (check_lg_XH_cntr /= keep_going .and. s% report_dt_hard_limit_retries) then
    1541            0 :             write(*,1) 'lg_XH_cntr', lg_XH_cntr
    1542            0 :             write(*,1) 'lg_XH_cntr_old', lg_XH_cntr_old
    1543            0 :             write(*,1) 'delta', lg_XH_cntr - lg_XH_cntr_old
    1544              :          end if
    1545              :       end function check_lg_XH_cntr
    1546              : 
    1547              : 
    1548           10 :       integer function check_lg_XHe_cntr(s, skip_hard_limit, dt_limit_ratio)
    1549              :          type (star_info), pointer :: s
    1550              :          logical, intent(in) :: skip_hard_limit
    1551              :          real(dp), intent(inout) :: dt_limit_ratio
    1552           10 :          real(dp) :: relative_excess, lg_XHe_cntr, lg_XHe_cntr_old
    1553              :          integer :: h1, he4, nz
    1554           10 :          real(dp) :: xh1, xhe4
    1555              :          include 'formats'
    1556           10 :          check_lg_XHe_cntr = keep_going
    1557           10 :          if (s% mix_factor == 0d0 .and. s% dxdt_nuc_factor == 0d0) return
    1558           10 :          h1 = s% net_iso(ih1)
    1559           10 :          he4 = s% net_iso(ihe4)
    1560           10 :          if (h1 == 0 .or. he4 == 0) return
    1561           10 :          nz = s% nz
    1562           10 :          xh1 = s% xa(h1,nz)
    1563           10 :          xhe4 = s% xa(he4,nz)
    1564           10 :          if (xhe4 < max(xh1, 1d-10)) return
    1565            0 :          lg_XHe_cntr = log10(xhe4)
    1566            0 :          if (lg_XHe_cntr > s% delta_lg_XHe_cntr_max) return
    1567            0 :          if (lg_XHe_cntr < s% delta_lg_XHe_cntr_min) return
    1568            0 :          lg_XHe_cntr_old = safe_log10(s% xa_old(he4,nz))
    1569            0 :          if (s% delta_lg_XHe_drop_only .and. lg_XHe_cntr >= lg_XHe_cntr_old) return
    1570              :          check_lg_XHe_cntr = check_change(s, lg_XHe_cntr - lg_XHe_cntr_old, &
    1571              :             s% delta_lg_XHe_cntr_limit, s% delta_lg_XHe_cntr_hard_limit, &
    1572            0 :             nz, 'delta_lg_XHe_cntr', skip_hard_limit, dt_limit_ratio, relative_excess)
    1573            0 :          if (check_lg_XHe_cntr /= keep_going .and. s% report_dt_hard_limit_retries) then
    1574            0 :             write(*,1) 'lg_XHe_cntr', lg_XHe_cntr
    1575            0 :             write(*,1) 'lg_XHe_cntr_old', lg_XHe_cntr_old
    1576            0 :             write(*,1) 'delta', lg_XHe_cntr - lg_XHe_cntr_old
    1577              :          end if
    1578              :       end function check_lg_XHe_cntr
    1579              : 
    1580              : 
    1581           10 :       integer function check_lg_XC_cntr(s, skip_hard_limit, dt_limit_ratio)
    1582              :          type (star_info), pointer :: s
    1583              :          logical, intent(in) :: skip_hard_limit
    1584              :          real(dp), intent(inout) :: dt_limit_ratio
    1585           10 :          real(dp) :: relative_excess, lg_XC_cntr, lg_XC_cntr_old
    1586              :          integer :: h1, he4, c12, nz
    1587           10 :          real(dp) :: xh1, xhe4, xc12
    1588              :          include 'formats'
    1589           10 :          check_lg_XC_cntr = keep_going
    1590           10 :          if (s% mix_factor == 0d0 .and. s% dxdt_nuc_factor == 0d0) return
    1591           10 :          h1 = s% net_iso(ih1)
    1592           10 :          he4 = s% net_iso(ihe4)
    1593           10 :          c12 = s% net_iso(ic12)
    1594           10 :          if (h1 == 0 .or. he4 == 0 .or. c12 == 0) return
    1595           10 :          nz = s% nz
    1596           10 :          xh1 = s% xa(h1,nz)
    1597           10 :          xhe4 = s% xa(he4,nz)
    1598           10 :          xc12 = s% xa(c12,nz)
    1599           10 :          if (xc12 < max(xh1, xhe4, 1d-10)) return
    1600            0 :          if (s% xa(c12,nz) < 1d-10) return
    1601            0 :          lg_XC_cntr = log10(xc12)
    1602            0 :          if (lg_XC_cntr > s% delta_lg_XC_cntr_max) return
    1603            0 :          if (lg_XC_cntr < s% delta_lg_XC_cntr_min) return
    1604            0 :          lg_XC_cntr_old = safe_log10(s% xa_old(c12,nz))
    1605            0 :          if (s% delta_lg_XC_drop_only .and. lg_XC_cntr >= lg_XC_cntr_old) return
    1606              :          check_lg_XC_cntr = check_change(s, lg_XC_cntr - lg_XC_cntr_old, &
    1607              :             s% delta_lg_XC_cntr_limit, s% delta_lg_XC_cntr_hard_limit, &
    1608            0 :             nz, 'delta_lg_XC_cntr', skip_hard_limit, dt_limit_ratio, relative_excess)
    1609            0 :          if (check_lg_XC_cntr /= keep_going .and. s% report_dt_hard_limit_retries) then
    1610            0 :             write(*,1) 'lg_XC_cntr', lg_XC_cntr
    1611            0 :             write(*,1) 'lg_XC_cntr_old', lg_XC_cntr_old
    1612            0 :             write(*,1) 'delta', lg_XC_cntr - lg_XC_cntr_old
    1613              :          end if
    1614              :       end function check_lg_XC_cntr
    1615              : 
    1616              : 
    1617           10 :       integer function check_lg_XNe_cntr(s, skip_hard_limit, dt_limit_ratio)
    1618              :          type (star_info), pointer :: s
    1619              :          logical, intent(in) :: skip_hard_limit
    1620              :          real(dp), intent(inout) :: dt_limit_ratio
    1621           10 :          real(dp) :: relative_excess, lg_XNe_cntr, lg_XNe_cntr_old
    1622              :          integer :: h1, he4, c12, o16, nz
    1623           10 :          real(dp) :: xh1, xhe4, xc12, XNe16
    1624              :          include 'formats'
    1625           10 :          check_lg_XNe_cntr = keep_going
    1626           10 :          if (s% mix_factor == 0d0 .and. s% dxdt_nuc_factor == 0d0) return
    1627           10 :          h1 = s% net_iso(ih1)
    1628           10 :          he4 = s% net_iso(ihe4)
    1629           10 :          c12 = s% net_iso(ic12)
    1630           10 :          o16 = s% net_iso(io16)
    1631           10 :          if (h1 == 0 .or. he4 == 0 .or. c12 == 0 .or. o16 == 0) return
    1632           10 :          nz = s% nz
    1633           10 :          xh1 = s% xa(h1,nz)
    1634           10 :          xhe4 = s% xa(he4,nz)
    1635           10 :          xc12 = s% xa(c12,nz)
    1636           10 :          XNe16 = s% xa(o16,nz)
    1637           10 :          if (XNe16 < max(xh1, xhe4, xc12, 1d-10)) return
    1638            0 :          lg_XNe_cntr = log10(XNe16)
    1639            0 :          if (lg_XNe_cntr > s% delta_lg_XNe_cntr_max) return
    1640            0 :          if (lg_XNe_cntr < s% delta_lg_XNe_cntr_min) return
    1641            0 :          lg_XNe_cntr_old = safe_log10(s% xa_old(o16,nz))
    1642            0 :          if (s% delta_lg_XNe_drop_only .and. lg_XNe_cntr >= lg_XNe_cntr_old) return
    1643              :          check_lg_XNe_cntr = check_change(s, lg_XNe_cntr - lg_XNe_cntr_old, &
    1644              :             s% delta_lg_XNe_cntr_limit, s% delta_lg_XNe_cntr_hard_limit, &
    1645            0 :             nz, 'delta_lg_XNe_cntr', skip_hard_limit, dt_limit_ratio, relative_excess)
    1646            0 :          if (check_lg_XNe_cntr /= keep_going .and. s% report_dt_hard_limit_retries) then
    1647            0 :             write(*,1) 'lg_XNe_cntr', lg_XNe_cntr
    1648            0 :             write(*,1) 'lg_XNe_cntr_old', lg_XNe_cntr_old
    1649            0 :             write(*,1) 'delta', lg_XNe_cntr - lg_XNe_cntr_old
    1650              :          end if
    1651              :       end function check_lg_XNe_cntr
    1652              : 
    1653              : 
    1654           10 :       integer function check_lg_XO_cntr(s, skip_hard_limit, dt_limit_ratio)
    1655              :          type (star_info), pointer :: s
    1656              :          logical, intent(in) :: skip_hard_limit
    1657              :          real(dp), intent(inout) :: dt_limit_ratio
    1658           10 :          real(dp) :: relative_excess, lg_XO_cntr, lg_XO_cntr_old
    1659              :          integer :: h1, he4, c12, o16, nz
    1660           10 :          real(dp) :: xh1, xhe4, xc12, xo16
    1661              :          include 'formats'
    1662           10 :          check_lg_XO_cntr = keep_going
    1663           10 :          if (s% mix_factor == 0d0 .and. s% dxdt_nuc_factor == 0d0) return
    1664           10 :          h1 = s% net_iso(ih1)
    1665           10 :          he4 = s% net_iso(ihe4)
    1666           10 :          c12 = s% net_iso(ic12)
    1667           10 :          o16 = s% net_iso(io16)
    1668           10 :          if (h1 == 0 .or. he4 == 0 .or. c12 == 0 .or. o16 == 0) return
    1669           10 :          nz = s% nz
    1670           10 :          xh1 = s% xa(h1,nz)
    1671           10 :          xhe4 = s% xa(he4,nz)
    1672           10 :          xc12 = s% xa(c12,nz)
    1673           10 :          xo16 = s% xa(o16,nz)
    1674           10 :          if (xo16 < max(xh1, xhe4, xc12, 1d-10)) return
    1675            0 :          lg_XO_cntr = log10(xo16)
    1676            0 :          if (lg_XO_cntr > s% delta_lg_XO_cntr_max) return
    1677            0 :          if (lg_XO_cntr < s% delta_lg_XO_cntr_min) return
    1678            0 :          lg_XO_cntr_old = safe_log10(s% xa_old(o16,nz))
    1679            0 :          if (s% delta_lg_XO_drop_only .and. lg_XO_cntr >= lg_XO_cntr_old) return
    1680              :          check_lg_XO_cntr = check_change(s, lg_XO_cntr - lg_XO_cntr_old, &
    1681              :             s% delta_lg_XO_cntr_limit, s% delta_lg_XO_cntr_hard_limit, &
    1682            0 :             nz, 'delta_lg_XO_cntr', skip_hard_limit, dt_limit_ratio, relative_excess)
    1683            0 :          if (check_lg_XO_cntr /= keep_going .and. s% report_dt_hard_limit_retries) then
    1684            0 :             write(*,1) 'lg_XO_cntr', lg_XO_cntr
    1685            0 :             write(*,1) 'lg_XO_cntr_old', lg_XO_cntr_old
    1686            0 :             write(*,1) 'delta', lg_XO_cntr - lg_XO_cntr_old
    1687              :          end if
    1688              :       end function check_lg_XO_cntr
    1689              : 
    1690              : 
    1691           10 :       integer function check_lg_XSi_cntr(s, skip_hard_limit, dt_limit_ratio)
    1692              :          type (star_info), pointer :: s
    1693              :          logical, intent(in) :: skip_hard_limit
    1694              :          real(dp), intent(inout) :: dt_limit_ratio
    1695           10 :          real(dp) :: relative_excess, lg_XSi_cntr, lg_XSi_cntr_old
    1696              :          integer :: h1, he4, c12, o16, nz
    1697           10 :          real(dp) :: xh1, xhe4, xc12, XSi16
    1698              :          include 'formats'
    1699           10 :          check_lg_XSi_cntr = keep_going
    1700           10 :          if (s% mix_factor == 0d0 .and. s% dxdt_nuc_factor == 0d0) return
    1701           10 :          h1 = s% net_iso(ih1)
    1702           10 :          he4 = s% net_iso(ihe4)
    1703           10 :          c12 = s% net_iso(ic12)
    1704           10 :          o16 = s% net_iso(io16)
    1705           10 :          if (h1 == 0 .or. he4 == 0 .or. c12 == 0 .or. o16 == 0) return
    1706           10 :          nz = s% nz
    1707           10 :          xh1 = s% xa(h1,nz)
    1708           10 :          xhe4 = s% xa(he4,nz)
    1709           10 :          xc12 = s% xa(c12,nz)
    1710           10 :          XSi16 = s% xa(o16,nz)
    1711           10 :          if (XSi16 < max(xh1, xhe4, xc12, 1d-10)) return
    1712            0 :          lg_XSi_cntr = log10(XSi16)
    1713            0 :          if (lg_XSi_cntr > s% delta_lg_XSi_cntr_max) return
    1714            0 :          if (lg_XSi_cntr < s% delta_lg_XSi_cntr_min) return
    1715            0 :          lg_XSi_cntr_old = safe_log10(s% xa_old(o16,nz))
    1716            0 :          if (s% delta_lg_XSi_drop_only .and. lg_XSi_cntr >= lg_XSi_cntr_old) return
    1717              :          check_lg_XSi_cntr = check_change(s, lg_XSi_cntr - lg_XSi_cntr_old, &
    1718              :             s% delta_lg_XSi_cntr_limit, s% delta_lg_XSi_cntr_hard_limit, &
    1719            0 :             nz, 'delta_lg_XSi_cntr', skip_hard_limit, dt_limit_ratio, relative_excess)
    1720            0 :          if (check_lg_XSi_cntr /= keep_going .and. s% report_dt_hard_limit_retries) then
    1721            0 :             write(*,1) 'lg_XSi_cntr', lg_XSi_cntr
    1722            0 :             write(*,1) 'lg_XSi_cntr_old', lg_XSi_cntr_old
    1723            0 :             write(*,1) 'delta', lg_XSi_cntr - lg_XSi_cntr_old
    1724              :          end if
    1725              :       end function check_lg_XSi_cntr
    1726              : 
    1727              : 
    1728           10 :       integer function check_XH_cntr(s, skip_hard_limit, dt_limit_ratio)
    1729              :          type (star_info), pointer :: s
    1730              :          logical, intent(in) :: skip_hard_limit
    1731              :          real(dp), intent(inout) :: dt_limit_ratio
    1732           10 :          real(dp) :: relative_excess, XH_cntr, XH_cntr_old
    1733              :          integer :: h1, nz
    1734              :          include 'formats'
    1735           10 :          check_XH_cntr = keep_going
    1736           10 :          if (s% mix_factor == 0d0 .and. s% dxdt_nuc_factor == 0d0) return
    1737           10 :          h1 = s% net_iso(ih1)
    1738           10 :          if (h1 == 0) return
    1739           10 :          nz = s% nz
    1740           10 :          XH_cntr = s% xa(h1,nz)
    1741           10 :          XH_cntr_old = s% xa_old(h1,nz)
    1742           10 :          if (s% delta_XH_drop_only .and. XH_cntr >= XH_cntr_old) return
    1743              :          check_XH_cntr = check_change(s, XH_cntr - XH_cntr_old, &
    1744              :             s% delta_XH_cntr_limit, s% delta_XH_cntr_hard_limit, &
    1745           10 :             nz, 'delta_XH_cntr', skip_hard_limit, dt_limit_ratio, relative_excess)
    1746           10 :          if (check_XH_cntr /= keep_going .and. s% report_dt_hard_limit_retries) then
    1747            0 :             write(*,1) 'XH_cntr', XH_cntr
    1748            0 :             write(*,1) 'XH_cntr_old', XH_cntr_old
    1749            0 :             write(*,1) 'delta', XH_cntr - XH_cntr_old
    1750              :          end if
    1751              :       end function check_XH_cntr
    1752              : 
    1753              : 
    1754           10 :       integer function check_XHe_cntr(s, skip_hard_limit, dt_limit_ratio)
    1755              :          type (star_info), pointer :: s
    1756              :          logical, intent(in) :: skip_hard_limit
    1757              :          real(dp), intent(inout) :: dt_limit_ratio
    1758           10 :          real(dp) :: relative_excess, XHe_cntr, XHe_cntr_old
    1759              :          integer :: he4, nz
    1760              :          include 'formats'
    1761           10 :          check_XHe_cntr = keep_going
    1762           10 :          if (s% mix_factor == 0d0 .and. s% dxdt_nuc_factor == 0d0) return
    1763           10 :          he4 = s% net_iso(ihe4)
    1764           10 :          if (he4 == 0) return
    1765           10 :          nz = s% nz
    1766           10 :          XHe_cntr = s% xa(he4,nz)
    1767           10 :          XHe_cntr_old = s% xa_old(he4,nz)
    1768           10 :          if (s% delta_XHe_drop_only .and. XHe_cntr >= XHe_cntr_old) return
    1769              :          check_XHe_cntr = check_change(s, XHe_cntr - XHe_cntr_old, &
    1770              :             s% delta_XHe_cntr_limit, s% delta_XHe_cntr_hard_limit, &
    1771           10 :             nz, 'delta_XHe_cntr', skip_hard_limit, dt_limit_ratio, relative_excess)
    1772           10 :          if (check_XHe_cntr /= keep_going .and. s% report_dt_hard_limit_retries) then
    1773            0 :             write(*,1) 'XHe_cntr', XHe_cntr
    1774            0 :             write(*,1) 'XHe_cntr_old', XHe_cntr_old
    1775            0 :             write(*,1) 'delta', XHe_cntr - XHe_cntr_old
    1776              :          end if
    1777              :       end function check_XHe_cntr
    1778              : 
    1779              : 
    1780           10 :       integer function check_XC_cntr(s, skip_hard_limit, dt_limit_ratio)
    1781              :          type (star_info), pointer :: s
    1782              :          logical, intent(in) :: skip_hard_limit
    1783              :          real(dp), intent(inout) :: dt_limit_ratio
    1784           10 :          real(dp) :: relative_excess, XC_cntr, XC_cntr_old
    1785              :          integer :: c12, nz
    1786              :          include 'formats'
    1787           10 :          check_XC_cntr = keep_going
    1788           10 :          if (s% mix_factor == 0d0 .and. s% dxdt_nuc_factor == 0d0) return
    1789           10 :          c12 = s% net_iso(ic12)
    1790           10 :          if (c12 == 0) return
    1791           10 :          nz = s% nz
    1792           10 :          XC_cntr = s% xa(c12,nz)
    1793           10 :          XC_cntr_old = s% xa_old(c12,nz)
    1794           10 :          if (s% delta_XC_drop_only .and. XC_cntr >= XC_cntr_old) return
    1795              :          check_XC_cntr = check_change(s, XC_cntr - XC_cntr_old, &
    1796              :             s% delta_XC_cntr_limit, s% delta_XC_cntr_hard_limit, &
    1797           10 :             nz, 'delta_XC_cntr', skip_hard_limit, dt_limit_ratio, relative_excess)
    1798           10 :          if (check_XC_cntr /= keep_going .and. s% report_dt_hard_limit_retries) then
    1799            0 :             write(*,1) 'XC_cntr', XC_cntr
    1800            0 :             write(*,1) 'XC_cntr_old', XC_cntr_old
    1801            0 :             write(*,1) 'delta', XC_cntr - XC_cntr_old
    1802              :          end if
    1803              :       end function check_XC_cntr
    1804              : 
    1805              : 
    1806           10 :       integer function check_XNe_cntr(s, skip_hard_limit, dt_limit_ratio)
    1807              :          type (star_info), pointer :: s
    1808              :          logical, intent(in) :: skip_hard_limit
    1809              :          real(dp), intent(inout) :: dt_limit_ratio
    1810           10 :          real(dp) :: relative_excess, XNe_cntr, XNe_cntr_old
    1811              :          integer :: ne20, nz
    1812              :          include 'formats'
    1813           10 :          check_XNe_cntr = keep_going
    1814           10 :          if (s% mix_factor == 0d0 .and. s% dxdt_nuc_factor == 0d0) return
    1815           10 :          ne20 = s% net_iso(ine20)
    1816           10 :          if (ne20 == 0) return
    1817           10 :          nz = s% nz
    1818           10 :          XNe_cntr = s% xa(ne20,nz)
    1819           10 :          XNe_cntr_old = s% xa_old(ne20,nz)
    1820           10 :          if (s% delta_XNe_drop_only .and. XNe_cntr >= XNe_cntr_old) return
    1821              :          check_XNe_cntr = check_change(s, XNe_cntr - XNe_cntr_old, &
    1822              :             s% delta_XNe_cntr_limit, s% delta_XNe_cntr_hard_limit, &
    1823           10 :             nz, 'delta_XNe_cntr', skip_hard_limit, dt_limit_ratio, relative_excess)
    1824           10 :          if (check_XNe_cntr /= keep_going .and. s% report_dt_hard_limit_retries) then
    1825            0 :             write(*,1) 'XNe_cntr', XNe_cntr
    1826            0 :             write(*,1) 'XNe_cntr_old', XNe_cntr_old
    1827            0 :             write(*,1) 'delta', XNe_cntr - XNe_cntr_old
    1828              :          end if
    1829              :       end function check_XNe_cntr
    1830              : 
    1831              : 
    1832           10 :       integer function check_XO_cntr(s, skip_hard_limit, dt_limit_ratio)
    1833              :          type (star_info), pointer :: s
    1834              :          logical, intent(in) :: skip_hard_limit
    1835              :          real(dp), intent(inout) :: dt_limit_ratio
    1836           10 :          real(dp) :: relative_excess, XO_cntr, XO_cntr_old
    1837              :          integer :: o16, nz
    1838              :          include 'formats'
    1839           10 :          check_XO_cntr = keep_going
    1840           10 :          if (s% mix_factor == 0d0 .and. s% dxdt_nuc_factor == 0d0) return
    1841           10 :          o16 = s% net_iso(io16)
    1842           10 :          if (o16 == 0) return
    1843           10 :          nz = s% nz
    1844           10 :          XO_cntr = s% xa(o16,nz)
    1845           10 :          XO_cntr_old = s% xa_old(o16,nz)
    1846           10 :          if (s% delta_XO_drop_only .and. XO_cntr >= XO_cntr_old) return
    1847              :          check_XO_cntr = check_change(s, XO_cntr - XO_cntr_old, &
    1848              :             s% delta_XO_cntr_limit, s% delta_XO_cntr_hard_limit, &
    1849           10 :             nz, 'delta_XO_cntr', skip_hard_limit, dt_limit_ratio, relative_excess)
    1850           10 :          if (check_XO_cntr /= keep_going .and. s% report_dt_hard_limit_retries) then
    1851            0 :             write(*,1) 'XO_cntr', XO_cntr
    1852            0 :             write(*,1) 'XO_cntr_old', XO_cntr_old
    1853            0 :             write(*,1) 'delta', XO_cntr - XO_cntr_old
    1854              :          end if
    1855              :       end function check_XO_cntr
    1856              : 
    1857              : 
    1858           10 :       integer function check_XSi_cntr(s, skip_hard_limit, dt_limit_ratio)
    1859              :          type (star_info), pointer :: s
    1860              :          logical, intent(in) :: skip_hard_limit
    1861              :          real(dp), intent(inout) :: dt_limit_ratio
    1862           10 :          real(dp) :: relative_excess, XSi_cntr, XSi_cntr_old
    1863              :          integer :: si28, nz
    1864              :          include 'formats'
    1865           10 :          check_XSi_cntr = keep_going
    1866           10 :          if (s% mix_factor == 0d0 .and. s% dxdt_nuc_factor == 0d0) return
    1867           10 :          si28 = s% net_iso(isi28)
    1868           10 :          if (si28 == 0) return
    1869            0 :          nz = s% nz
    1870            0 :          XSi_cntr = s% xa(si28,nz)
    1871            0 :          XSi_cntr_old = s% xa_old(si28,nz)
    1872            0 :          if (s% delta_XSi_drop_only .and. XSi_cntr >= XSi_cntr_old) return
    1873              :          check_XSi_cntr = check_change(s, XSi_cntr - XSi_cntr_old, &
    1874              :             s% delta_XSi_cntr_limit, s% delta_XSi_cntr_hard_limit, &
    1875            0 :             nz, 'delta_XSi_cntr', skip_hard_limit, dt_limit_ratio, relative_excess)
    1876            0 :          if (check_XSi_cntr /= keep_going .and. s% report_dt_hard_limit_retries) then
    1877            0 :             write(*,1) 'XSi_cntr', XSi_cntr
    1878            0 :             write(*,1) 'XSi_cntr_old', XSi_cntr_old
    1879            0 :             write(*,1) 'delta', XSi_cntr - XSi_cntr_old
    1880              :          end if
    1881              :       end function check_XSi_cntr
    1882              : 
    1883              : 
    1884           10 :       integer function check_delta_mdot(s, skip_hard_limit, dt, dt_limit_ratio)
    1885              :          type (star_info), pointer :: s
    1886              :          logical, intent(in) :: skip_hard_limit
    1887              :          real(dp), intent(in) :: dt
    1888              :          real(dp), intent(inout) :: dt_limit_ratio
    1889           10 :          real(dp) :: mdot, mdot_old, delta_mdot, lim, hard_lim
    1890           10 :          check_delta_mdot = keep_going
    1891           10 :          mdot = s% mstar_dot
    1892           10 :          mdot_old = s% mstar_dot_old
    1893              :          delta_mdot = abs(mdot - mdot_old)/ &
    1894              :             (s% delta_mdot_atol*Msun/secyer + &
    1895           10 :                s% delta_mdot_rtol*max(abs(mdot),abs(mdot_old)))
    1896           10 :          if (delta_mdot == 0) return
    1897            0 :          lim = s% delta_mdot_limit*s% time_delta_coeff
    1898            0 :          hard_lim = s% delta_mdot_hard_limit*s% time_delta_coeff
    1899            0 :          if (hard_lim > 0 .and. (.not. skip_hard_limit)) then
    1900            0 :             if (delta_mdot > hard_lim) then
    1901            0 :                if (s% report_dt_hard_limit_retries) &
    1902            0 :                   write(*, '(a30, f20.10, 99e20.10)') 'delta_mdot_hard_limit', &
    1903            0 :                      delta_mdot, hard_lim
    1904            0 :                s% retry_message = 'delta_mdot_hard_limit'
    1905            0 :                check_delta_mdot = retry
    1906            0 :                return
    1907              :             end if
    1908              :          end if
    1909            0 :          if (lim <= 0) return
    1910            0 :          dt_limit_ratio = delta_mdot/lim
    1911            0 :          if (dt_limit_ratio <= 1d0) dt_limit_ratio = 0
    1912              :       end function check_delta_mdot
    1913              : 
    1914              : 
    1915           10 :       integer function check_delta_mstar(s, skip_hard_limit, dt, dt_limit_ratio)
    1916              :          type (star_info), pointer :: s
    1917              :          logical, intent(in) :: skip_hard_limit
    1918              :          real(dp), intent(in) :: dt
    1919              :          real(dp), intent(inout) :: dt_limit_ratio
    1920           10 :          real(dp) :: delta_lg_star_mass, lim, hard_lim
    1921           10 :          check_delta_mstar = keep_going
    1922           10 :          delta_lg_star_mass = abs(log10(s% mstar/s% mstar_old))
    1923           10 :          lim = s% delta_lg_star_mass_limit*s% time_delta_coeff
    1924           10 :          hard_lim = s% delta_lg_star_mass_hard_limit*s% time_delta_coeff
    1925           10 :          if (hard_lim > 0 .and. (.not. skip_hard_limit)) then
    1926            0 :             if (delta_lg_star_mass > hard_lim) then
    1927            0 :                if (s% report_dt_hard_limit_retries) &
    1928            0 :                   write(*, '(a30, f20.10, 99e20.10)') 'delta_lg_star_mass_hard_limit', &
    1929            0 :                      delta_lg_star_mass, hard_lim
    1930            0 :                check_delta_mstar = retry
    1931            0 :                s% retry_message = 'delta_lg_star_mass_hard_limit'
    1932            0 :                return
    1933              :             end if
    1934              :          end if
    1935           10 :          if (lim <= 0) return
    1936           10 :          dt_limit_ratio = delta_lg_star_mass/lim
    1937           10 :          if (dt_limit_ratio <= 1d0) dt_limit_ratio = 0
    1938              :       end function check_delta_mstar
    1939              : 
    1940              : 
    1941           10 :       integer function check_adjust_J_q(s, skip_hard_limit, dt_limit_ratio)
    1942              :          type (star_info), pointer :: s
    1943              :          logical, intent(in) :: skip_hard_limit
    1944              :          real(dp), intent(inout) :: dt_limit_ratio
    1945           10 :          real(dp) :: relative_excess
    1946              :          include 'formats'
    1947           10 :          check_adjust_J_q = keep_going
    1948           10 :          dt_limit_ratio = 0d0
    1949           10 :          if (s% doing_relax) return
    1950           10 :          if (.not. (s% rotation_flag .and. s% do_adjust_J_lost .and. s% mstar_dot < 0d0)) return
    1951              :          ! we care about s% adjust_J_q remaining above a given limit
    1952              :          ! so we use 1-S% adjust_J_q
    1953              :          check_adjust_J_q = check_change(s, 1-s% adjust_J_q, &
    1954              :             1-s% adjust_J_q_limit, &
    1955              :             1-s% adjust_J_q_hard_limit, &
    1956              :             0, 'check_adjust_J_q', &
    1957            0 :             .false., dt_limit_ratio, relative_excess)
    1958            0 :       end function check_adjust_J_q
    1959              : 
    1960              : 
    1961           10 :       integer function check_delta_lgL(s, skip_hard_limit, dt_limit_ratio)
    1962              :          type (star_info), pointer :: s
    1963              :          logical, intent(in) :: skip_hard_limit
    1964              :          real(dp), intent(inout) :: dt_limit_ratio
    1965           10 :          real(dp) :: dlgL, relative_excess
    1966              :          include 'formats'
    1967           10 :          check_delta_lgL = keep_going
    1968           10 :          dt_limit_ratio = 0d0
    1969           10 :          if (s% doing_relax) return
    1970           10 :          if (s% L_surf < s% delta_lgL_limit_L_min .or. s% L_surf_old <= 0d0) then
    1971            0 :             dlgL = 0
    1972              :          else
    1973           10 :             dlgL = log10(s% L_surf/s% L_surf_old)
    1974              :          end if
    1975           10 :          if (is_bad(dlgL)) then
    1976            0 :             write(*,2) 's% L_surf', s% model_number, s% L_surf
    1977            0 :             write(*,2) 's% L_surf_old', s% model_number, s% L_surf_old
    1978            0 :             call mesa_error(__FILE__,__LINE__,'check_delta_lgL')
    1979              :          end if
    1980              :          check_delta_lgL = check_change(s, dlgL, &
    1981              :             s% delta_lgL_limit, s% delta_lgL_hard_limit, &
    1982           10 :             0, 'delta_lgL', skip_hard_limit, dt_limit_ratio, relative_excess)
    1983           10 :          if (check_delta_lgL /= keep_going .and. s% report_dt_hard_limit_retries) then
    1984            0 :             write(*,1) 'L_surf', s% L_surf
    1985            0 :             write(*,1) 'L_surf_old', s% L_surf_old
    1986              :          end if
    1987              :       end function check_delta_lgL
    1988              : 
    1989              : 
    1990           10 :       integer function check_delta_HR(s, skip_hard_limit, dt_limit_ratio)
    1991              :          type (star_info), pointer :: s
    1992              :          logical, intent(in) :: skip_hard_limit
    1993              :          real(dp), intent(inout) :: dt_limit_ratio
    1994           10 :          real(dp) :: dlgL, dlgTeff, dHR, relative_excess
    1995              :          include 'formats'
    1996           10 :          check_delta_HR = keep_going
    1997              :          if (s% L_phot_old <= 0 .or. s% Teff_old <= 0 .or. &
    1998           10 :              s% L_phot <= 0 .or. s% Teff <= 0) return
    1999           10 :          dlgL = log10(s% L_phot/s% L_phot_old)
    2000           10 :          dlgTeff = log10(s% Teff/s% Teff_old)
    2001           10 :          dHR = sqrt(pow2(s% delta_HR_ds_L*dlgL) + pow2(s% delta_HR_ds_Teff*dlgTeff))
    2002           10 :          if (is_bad(dHR)) then
    2003            0 :             write(*,1) 's% L_phot_old', s% L_phot_old
    2004            0 :             write(*,1) 's% L_phot', s% L_phot
    2005            0 :             write(*,1) 's% Teff_old', s% Teff_old
    2006            0 :             write(*,1) 's% Teff', s% Teff
    2007            0 :             write(*,1) 'dHR', dHR
    2008            0 :             if (s% stop_for_bad_nums) call mesa_error(__FILE__,__LINE__,'check_delta_HR')
    2009              :          end if
    2010              :          check_delta_HR = check_change(s, dHR, &
    2011              :             s% delta_HR_limit, s% delta_HR_hard_limit, &
    2012           10 :             0, 'delta_HR', skip_hard_limit, dt_limit_ratio, relative_excess)
    2013           10 :          if (check_delta_HR /= keep_going .and. s% report_dt_hard_limit_retries) then
    2014            0 :             write(*,1) 's% L_phot_old', s% L_phot_old
    2015            0 :             write(*,1) 's% L_phot', s% L_phot
    2016            0 :             write(*,1) 's% Teff_old', s% Teff_old
    2017            0 :             write(*,1) 's% Teff', s% Teff
    2018            0 :             write(*,1) 'dHR', dHR
    2019              :          end if
    2020              :       end function check_delta_HR
    2021              : 
    2022              : 
    2023           10 :       integer function check_rel_error_in_energy(s, skip_hard_limit, dt_limit_ratio)
    2024              :          type (star_info), pointer :: s
    2025              :          logical, intent(in) :: skip_hard_limit
    2026              :          real(dp), intent(inout) :: dt_limit_ratio
    2027           10 :          real(dp) :: rel_error, relative_excess
    2028              :          include 'formats'
    2029           10 :          check_rel_error_in_energy = keep_going
    2030           10 :          dt_limit_ratio = 0d0
    2031           10 :          if (s% doing_relax) return
    2032           10 :          rel_error = abs(s% error_in_energy_conservation/s% total_energy_end)
    2033              :          check_rel_error_in_energy = check_change(s, rel_error, &
    2034              :             s% limit_for_rel_error_in_energy_conservation, &
    2035              :             s% hard_limit_for_rel_error_in_energy_conservation, &
    2036              :             0, 'hard_limit_for_rel_error_in_energy_conservation', &
    2037           10 :             .false., dt_limit_ratio, relative_excess)
    2038           10 :          if (check_rel_error_in_energy /= keep_going .and. s% report_dt_hard_limit_retries) then
    2039            0 :             write(*,1) 'error_in_energy_conservation', s% error_in_energy_conservation
    2040            0 :             write(*,1) 'total_energy_end', s% total_energy_end
    2041            0 :             write(*,1) 'rel_error', s% error_in_energy_conservation/s% total_energy_end
    2042              :          end if
    2043              :       end function check_rel_error_in_energy
    2044              : 
    2045              : 
    2046           10 :       integer function check_dt_div_dt_cell_collapse(s, skip_hard_limit, dt, dt_limit_ratio)
    2047              :          use star_utils, only: eval_min_cell_collapse_time
    2048              :          type (star_info), pointer :: s
    2049              :          logical, intent(in) :: skip_hard_limit
    2050              :          real(dp), intent(in) :: dt
    2051              :          real(dp), intent(inout) :: dt_limit_ratio
    2052           10 :          real(dp) :: ratio, dt_timescale, relative_excess
    2053              :          integer :: min_collapse_k, ierr
    2054              :          include 'formats'
    2055           10 :          check_dt_div_dt_cell_collapse = keep_going
    2056           10 :          if (s% doing_relax) return
    2057              :          dt_timescale = eval_min_cell_collapse_time( &
    2058           10 :             s, 2, s% nz, min_collapse_k, ierr)
    2059           10 :          if (ierr /= 0) return
    2060           10 :          if (dt_timescale < 1d-30) return
    2061           10 :          ratio = dt/dt_timescale
    2062              :          !write(*,2) 'dt dt_cell_collapse ratio', min_collapse_k, dt, dt_timescale, ratio
    2063              :          check_dt_div_dt_cell_collapse = check_change(s, ratio, &
    2064              :             s% dt_div_dt_cell_collapse_limit, s% dt_div_dt_cell_collapse_hard_limit, &
    2065           10 :             min_collapse_k, 'dt_div_dt_cell_collapse', skip_hard_limit, dt_limit_ratio, relative_excess)
    2066           10 :          if (check_dt_div_dt_cell_collapse /= keep_going .and. s% report_dt_hard_limit_retries) then
    2067            0 :             write(*,2) 'min dt_cell_collapse', min_collapse_k, dt_timescale
    2068              :          end if
    2069           10 :       end function check_dt_div_dt_cell_collapse
    2070              : 
    2071              : 
    2072           10 :       integer function check_dt_div_min_dr_div_cs(s, skip_hard_limit, dt, dt_limit_ratio)
    2073           10 :          use star_utils, only: min_dr_div_cs
    2074              :          type (star_info), pointer :: s
    2075              :          logical, intent(in) :: skip_hard_limit
    2076              :          real(dp), intent(in) :: dt
    2077              :          real(dp), intent(inout) :: dt_limit_ratio
    2078           10 :          real(dp) :: ratio, dt_x, relative_excess
    2079              :          include 'formats'
    2080           10 :          check_dt_div_min_dr_div_cs = keep_going
    2081           10 :          dt_limit_ratio = 0d0
    2082           10 :          if (s% doing_relax) return
    2083           10 :          if (s% dt_div_min_dr_div_cs_limit <= 0d0) return
    2084            0 :          dt_x = min_dr_div_cs(s, s% Tlim_dt_div_min_dr_div_cs_cell)
    2085              :          !write(*,2) 'log min_dr_div_cs, q, m', s% Tlim_dt_div_min_dr_div_cs_cell, &
    2086              :          !   safe_log10(dt_x), s% q(s% Tlim_dt_div_min_dr_div_cs_cell), s% m(s% Tlim_dt_div_min_dr_div_cs_cell)/Msun
    2087            0 :          ratio = dt/dt_x
    2088              :          !write(*,3) 'dt/dx_x log', s% Tlim_dt_div_min_dr_div_cs_cell, s% model_number, ratio, safe_log10(ratio)
    2089              :          check_dt_div_min_dr_div_cs = check_change(s, ratio, &
    2090              :             s% dt_div_min_dr_div_cs_limit, s% dt_div_min_dr_div_cs_hard_limit, &
    2091              :             s% Tlim_dt_div_min_dr_div_cs_cell, 'dt_div_min_dr_div_cs', &
    2092            0 :             skip_hard_limit, dt_limit_ratio, relative_excess)
    2093            0 :          if ((check_dt_div_min_dr_div_cs /= keep_going .and. s% report_dt_hard_limit_retries) .or. &
    2094              :              (ratio > 1d0 .and. s% report_min_dr_div_cs)) then
    2095            0 :             write(*,2) 'min_dr_div_cs', s% Tlim_dt_div_min_dr_div_cs_cell, dt_x
    2096              :          end if
    2097           10 :       end function check_dt_div_min_dr_div_cs
    2098              : 
    2099              : 
    2100           10 :       integer function check_dX_nuc_drop(s, skip_hard_limit, dt, dt_limit_ratio)
    2101           10 :          use rates_def, only: i_rate
    2102              :          type (star_info), pointer :: s
    2103              :          logical, intent(in) :: skip_hard_limit
    2104              :          real(dp), intent(in) :: dt
    2105              :          real(dp), intent(inout) :: dt_limit_ratio
    2106              : 
    2107              :          integer :: k, nz, max_k, max_j
    2108           10 :          real(dp), pointer, dimension(:) :: sig
    2109           10 :          real(dp) :: max_dx_nuc_drop, X_limit, A_limit, min_dt, limit, hard_limit
    2110              : 
    2111              :          logical, parameter :: dbg = .false.
    2112              : 
    2113              :          include 'formats'
    2114              : 
    2115           10 :          check_dX_nuc_drop = keep_going
    2116           10 :          if (s% mix_factor == 0d0 .and. s% dxdt_nuc_factor == 0d0) return
    2117              : 
    2118           10 :          X_limit = s% dX_nuc_drop_min_X_limit
    2119           10 :          A_limit = s% dX_nuc_drop_max_A_limit
    2120           10 :          nz = s% nz
    2121           10 :          sig => s% sig
    2122              : 
    2123           10 :          max_dx_nuc_drop = 0
    2124           10 :          max_k = 0
    2125           10 :          max_j = 0
    2126        10633 :          do k = 1, nz
    2127        10633 :             call do1(k)
    2128              :          end do
    2129              : 
    2130           10 :          s% Tlim_dXnuc_drop_cell = max_k
    2131           10 :          s% Tlim_dXnuc_drop_species = max_j
    2132              : 
    2133           10 :          hard_limit = s% dX_nuc_drop_hard_limit*s% time_delta_coeff
    2134           10 :          if (hard_limit > 0 .and. (.not. skip_hard_limit) .and. &
    2135              :                max_dx_nuc_drop > hard_limit) then
    2136            0 :             if (s% report_dt_hard_limit_retries) then
    2137            0 :                write(*,2) trim(chem_isos% name(s% chem_id(max_j))), max_k, s% xa(max_j,max_k)
    2138            0 :                write(*,2) trim(chem_isos% name(s% chem_id(max_j))) // ' old', max_k, s% xa_old(max_j,max_k)
    2139            0 :                write(*,2) 'drop', max_k, max_dx_nuc_drop
    2140              :             end if
    2141            0 :             s% retry_message = 'dX_nuc_drop_hard_limit'
    2142            0 :             s% retry_message_k = max_k
    2143            0 :             check_dX_nuc_drop = retry
    2144            0 :             return
    2145              :          end if
    2146              : 
    2147           10 :          limit = s% dX_nuc_drop_limit*s% time_delta_coeff
    2148           10 :          if (s% log_max_temperature >= 9.45d0 .and. s% dX_nuc_drop_limit_at_high_T > 0) &
    2149           10 :             limit = s% dX_nuc_drop_limit_at_high_T
    2150           10 :          if (limit <= 0 .or. max_dx_nuc_drop <= 0) return
    2151              : 
    2152           10 :          if (dt < secyer*s% dX_nuc_drop_min_yrs_for_dt) return
    2153           10 :          min_dt = secyer*s% dX_nuc_drop_min_yrs_for_dt
    2154              :          dt_limit_ratio = min( &
    2155              :             max_dx_nuc_drop/limit, &
    2156           10 :             1d0*dt/min_dt)
    2157           10 :          if (dt_limit_ratio <= 1d0) dt_limit_ratio = 0
    2158              : 
    2159           10 :          s% dX_nuc_drop_max_j = max_j
    2160           20 :          s% dX_nuc_drop_max_k = max_k
    2161              : 
    2162              :          contains
    2163              : 
    2164        10623 :          subroutine do1(k)
    2165              :             integer, intent(in) :: k
    2166              : 
    2167              :             integer :: j
    2168        10623 :             real(dp) :: dx, dx_drop, dm, dt_dm, dx_burning, dx_inflow, dxdt_nuc
    2169        10623 :             real(dp) :: dx00, dxp1, sig00, sigp1, flux00, fluxp1
    2170              : 
    2171              :             include 'formats'
    2172              : 
    2173        10623 :             dm = s% dm(k)
    2174        10623 :             dt_dm = dt/dm
    2175              : 
    2176        95607 :             do j=1, s% species
    2177              : 
    2178        84984 :                if (chem_isos% W(s% chem_id(j)) > A_limit) then
    2179              :                   if (dbg .and. k == 1387) &
    2180              :                      write(*,2) 'dX_nuc_max_A_limit ' // trim(chem_isos% name(s% chem_id(j))), &
    2181              :                         k, s% xa(j,k), chem_isos% W(s% chem_id(j)), A_limit
    2182              :                   cycle
    2183              :                end if
    2184              : 
    2185        84984 :                if (chem_isos% Z(s% chem_id(j)) <= 2) then
    2186              :                   cycle  ! skip the little guys
    2187              :                end if
    2188              : 
    2189        53115 :                if (s% xa(j,k) < X_limit) then
    2190              :                   if (dbg .and. k == 1387) &
    2191              :                      write(*,2) &
    2192              :                         'dX_nuc_drop_min_X_limit ' // trim(chem_isos% name(s% chem_id(j))), &
    2193              :                         k, s% xa(j,k), X_limit
    2194              :                   cycle
    2195              :                end if
    2196              : 
    2197        51836 :                dxdt_nuc = s% dxdt_nuc(j,k)
    2198        51836 :                if (dxdt_nuc >= 0) cycle
    2199              : 
    2200         7651 :                dx_burning = dxdt_nuc*dt
    2201         7651 :                sig00 = sig(k)
    2202              : 
    2203         7651 :                if (k < s% nz) then
    2204         7631 :                   sigp1 = sig(k+1)
    2205              :                else
    2206              :                   sigp1 = 0
    2207              :                end if
    2208              : 
    2209         7651 :                if (k > 1) then
    2210         7651 :                   dx00 = s% xa(j,k-1) - s% xa(j,k)
    2211         7651 :                   flux00 = -sig00*dx00
    2212              :                else
    2213              :                   flux00 = 0
    2214              :                end if
    2215              : 
    2216         7651 :                if (k < s% nz) then
    2217         7631 :                   dxp1 = s% xa(j,k) - s% xa(j,k+1)
    2218         7631 :                   fluxp1 = -sigp1*dxp1
    2219              :                else
    2220              :                   fluxp1 = 0
    2221              :                end if
    2222              : 
    2223         7651 :                dx_inflow = max(0d0, fluxp1, -flux00)*dt_dm
    2224              : 
    2225         7651 :                dx_drop = -(dx_burning + dx_inflow)  ! dx_burning < 0 for drop
    2226              : 
    2227         7651 :                dx = s% xa_old(j,k) - s% xa(j,k)  ! the actual drop
    2228         7651 :                if (dx < dx_drop) dx_drop = dx
    2229              : 
    2230        18274 :                if (dx_drop > max_dx_nuc_drop) then
    2231         2607 :                   max_dx_nuc_drop = dx_drop
    2232         2607 :                   max_k = k
    2233         2607 :                   max_j = j
    2234              :                end if
    2235              : 
    2236              :             end do
    2237              : 
    2238           10 :          end subroutine do1
    2239              : 
    2240              : 
    2241              :       end function check_dX_nuc_drop
    2242              : 
    2243              : 
    2244           11 :       integer function check_varcontrol_limit(s, dt_limit_ratio)
    2245              :          type (star_info), pointer :: s
    2246              :          real(dp), intent(inout) :: dt_limit_ratio
    2247              : 
    2248           11 :          real(dp) :: varcontrol, vc_target
    2249              :          integer :: ierr
    2250              : 
    2251              :          include 'formats'
    2252              : 
    2253              :          ierr = 0
    2254           11 :          check_varcontrol_limit = keep_going
    2255              : 
    2256           11 :          varcontrol = eval_varcontrol(s, ierr)
    2257           11 :          if (ierr /= 0) then
    2258            0 :             check_varcontrol_limit = retry
    2259            0 :             s% retry_message = 'varcontrol hard limit'
    2260            0 :             if (s% report_ierr) write(*, *) 'check_varcontrol_limit: eval_varcontrol ierr', ierr
    2261            0 :             s% result_reason = nonzero_ierr
    2262            0 :             return
    2263              :          end if
    2264              : 
    2265           11 :          if (s% varcontrol_target < s% min_allowed_varcontrol_target) then
    2266            0 :             check_varcontrol_limit = terminate
    2267            0 :             write(*, *) 'ERROR: timestep varcontrol_target < min_allowed_varcontrol_target'
    2268            0 :             s% result_reason = nonzero_ierr
    2269            0 :             return
    2270              :          end if
    2271              : 
    2272           11 :          vc_target = max(1d-99,s% varcontrol_target)
    2273           11 :          dt_limit_ratio = varcontrol/vc_target
    2274              : 
    2275           11 :          if (s% report_solver_dt_info) then
    2276            0 :             write(*, 1) 's% varcontrol_target', s% varcontrol_target
    2277            0 :             write(*, 1) 'vc_target', vc_target
    2278            0 :             write(*, 1) 'varcontrol', varcontrol
    2279            0 :             write(*, 1) 'dt_limit_ratio', dt_limit_ratio
    2280            0 :             write(*, *)
    2281              :          end if
    2282              : 
    2283           11 :          if (dt_limit_ratio > s% varcontrol_dt_limit_ratio_hard_max) then
    2284            0 :             write(*, '(a50, f20.10, 99e20.10)') 'varcontrol_dt_limit_ratio too large', &
    2285            0 :                dt_limit_ratio, varcontrol, vc_target
    2286            0 :             check_varcontrol_limit = retry
    2287            0 :             s% retry_message = 'varcontrol_dt_limit_ratio_hard_max'
    2288            0 :             return
    2289              :          end if
    2290              : 
    2291              :       end function check_varcontrol_limit
    2292              : 
    2293              : 
    2294           22 :       real(dp) function eval_varcontrol(s, ierr) result(varcontrol)
    2295              :          type (star_info), pointer :: s
    2296              :          integer, intent(out) :: ierr
    2297              : 
    2298              :          integer :: j, nterms, nvar_hydro, nz, k
    2299          143 :          real(dp) :: sumj, sumvar, sumscales, sumterm(s% nvar_total)
    2300              :          real(dp), parameter :: xscale_min = 1
    2301              : 
    2302              :          include 'formats'
    2303           11 :          ierr = 0
    2304              : 
    2305           11 :          varcontrol = 1d99
    2306           11 :          nvar_hydro = s% nvar_hydro
    2307           11 :          nz = s% nz
    2308              : 
    2309           11 :          nterms = 0
    2310           11 :          sumvar = 0
    2311           11 :          sumscales = 0
    2312          143 :          sumterm(:) = 0
    2313              : 
    2314           11 :          if (.not. associated(s% xh_old)) then
    2315            0 :             call mesa_error(__FILE__,__LINE__,'not associated xh_old')
    2316              :          end if
    2317              : 
    2318              :          ! use differences in smoothed old and new to filter out high frequency noise.
    2319           55 :          do j = 1, nvar_hydro
    2320              : 
    2321              :             if (j == s% i_lum .or. &
    2322              :                 j == s% i_u .or. &
    2323              :                 j == s% i_v .or. &
    2324              :                 j == s% i_w .or. &
    2325              :                 j == s% i_Hp .or. &
    2326              :                 j == s% i_j_rot .or. &
    2327              :                 j == s% i_w_div_wc .or. &
    2328           44 :                 j == s% i_alpha_RTI .or. &
    2329              :                 j == s% i_Et_RSP) cycle
    2330              : 
    2331           33 :             nterms = nterms + nz
    2332        39162 :             do k = 3, nz-2
    2333       430419 :                sumj = abs(sum(s% xh(j,k-2:k+2)) - sum(s% xh_old(j,k-2:k+2)))/5
    2334        39162 :                sumterm(j) = sumterm(j) + sumj
    2335              :             end do
    2336              :             sumterm(j) = sumterm(j) + &
    2337              :                abs((2*s% xh(j,1) + s% xh(j,2)) - (2*s% xh_old(j,1) + s% xh_old(j,2)))/3 + &
    2338           33 :                abs((2*s% xh(j,nz) + s% xh(j,nz-1)) - (2*s% xh_old(j,nz) + s% xh_old(j,nz-1)))/3
    2339           33 :             k = 2
    2340          231 :             sumj = abs(sum(s% xh(j,k-1:k+1)) - sum(s% xh_old(j,k-1:k+1)))/3
    2341           33 :             sumterm(j) = sumterm(j) + sumj
    2342           33 :             k = nz-1
    2343           33 :             sumj = abs(sum(s% xh(j,k-1:k+1)) - sum(s% xh_old(j,k-1:k+1)))/3
    2344              : 
    2345           33 :             if (j == s% i_lnd) then
    2346           11 :                sumterm(j) = sumterm(j)/3  ! Seems to help. from Eggleton.
    2347              :             end if
    2348              : 
    2349           33 :             sumvar = sumvar + sumterm(j)
    2350           55 :             sumscales = sumscales + max(xscale_min, abs(s% xh_old(j,1)))
    2351              : 
    2352              :          end do
    2353              : 
    2354              :          sumterm(:) = sumterm(:)/sumscales
    2355           11 :          sumvar = sumvar/sumscales
    2356              : 
    2357           11 :          varcontrol = sumvar/nterms
    2358              : 
    2359           11 :       end function eval_varcontrol
    2360              : 
    2361              : 
    2362           11 :       subroutine filter_dt_next(s, order, dt_limit_ratio_in)
    2363              :          ! H211b "low pass" controller.
    2364              :          ! Soderlind & Wang, J of Computational and Applied Math 185 (2006) 225 – 243.
    2365              :          use num_def
    2366              :          type (star_info), pointer :: s
    2367              :          real(dp), intent(in) :: order, dt_limit_ratio_in
    2368              : 
    2369           11 :          real(dp) :: ratio, ratio_prev, limtr, dt_limit_ratio_target, &
    2370           11 :             dt_limit_ratio, beta1, beta2, alpha2
    2371              : 
    2372              :          include 'formats'
    2373              : 
    2374           11 :          beta1 = 0.25d0/order
    2375           11 :          beta2 = 0.25d0/order
    2376           11 :          alpha2 = 0.25d0
    2377              : 
    2378           11 :          dt_limit_ratio = max(1d-10, dt_limit_ratio_in)
    2379           11 :          s% dt_limit_ratio = dt_limit_ratio
    2380           11 :          dt_limit_ratio_target = 1d0
    2381              : 
    2382              :          if (s% use_dt_low_pass_controller .and. &
    2383           11 :                s% dt_limit_ratio_old > 0 .and. s% dt_old > 0) then  ! use 2 values to do "low pass" controller
    2384           10 :             ratio = limiter(dt_limit_ratio_target/dt_limit_ratio)
    2385           10 :             ratio_prev = limiter(dt_limit_ratio_target/s% dt_limit_ratio_old)
    2386              :             limtr = limiter( &
    2387           10 :                pow(ratio,beta1) * pow(ratio_prev,beta2) * pow(s% dt/s% dt_old,-alpha2))
    2388           10 :             s% dt_next = s% dt*limtr
    2389              : 
    2390           10 :             if (s% report_solver_dt_info) then
    2391            0 :                write(*,2) 'dt_limit_ratio_target', s% model_number, dt_limit_ratio_target
    2392            0 :                write(*,2) 'dt_limit_ratio', s% model_number, dt_limit_ratio
    2393            0 :                write(*,2) 's% dt_limit_ratio_old', s% model_number, s% dt_limit_ratio_old
    2394            0 :                write(*,2) 'order', s% model_number, order
    2395            0 :                write(*,2) 'ratio', s% model_number, ratio
    2396            0 :                write(*,2) 'ratio_prev', s% model_number, ratio_prev
    2397            0 :                write(*,2) 'limtr', s% model_number, limtr
    2398            0 :                write(*,2) 's% dt_next', s% model_number, s% dt_next
    2399            0 :                write(*,'(A)')
    2400              :             end if
    2401              : 
    2402              :          else  ! no history available, so fall back to the 1st order controller
    2403            1 :             s% dt_next = s% dt*dt_limit_ratio_target/dt_limit_ratio
    2404            1 :             if (s% report_solver_dt_info) then
    2405            0 :                write(*,2) 's% dt', s% model_number, s% dt
    2406            0 :                write(*,2) 'dt_limit_ratio_target', s% model_number, dt_limit_ratio_target
    2407            0 :                write(*,2) 'dt_limit_ratio', s% model_number, dt_limit_ratio
    2408            0 :                write(*,2) 'filter_dt_next', s% model_number, s% dt_next
    2409              :             end if
    2410            1 :             if (s% dt_next == 0d0) call mesa_error(__FILE__,__LINE__,'filter_dt_next')
    2411              :          end if
    2412              : 
    2413              : 
    2414              :          contains
    2415              : 
    2416              : 
    2417           30 :          real(dp) function limiter(x)
    2418              :             real(dp), intent(in) :: x
    2419              :             real(dp), parameter :: kappa = 10  ! 2
    2420              :             ! for x >= 0 and kappa = 2, limiter value is between 0.07 and 4.14
    2421              :             ! for x >= 0 and kappa = 10, limiter value is between 0.003 and 16.7
    2422              :             ! for x = 1, limiter = 1
    2423           30 :             limiter = 1 + kappa*atan((x-1)/kappa)
    2424           30 :          end function limiter
    2425              : 
    2426              : 
    2427              :       end subroutine filter_dt_next
    2428              : 
    2429              : 
    2430              :       end module timestep
    2431              : 
    2432              : 
        

Generated by: LCOV version 2.0-1