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