Line data Source code
1 : ! ***********************************************************************
2 : !
3 : ! Copyright (C) 2011-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 mix_info
21 :
22 : use const_def, only: dp, i8, ln10, pi4, msun, no_mixing, &
23 : minimum_mixing, &
24 : rayleigh_taylor_mixing, &
25 : convective_mixing, &
26 : semiconvective_mixing, &
27 : overshoot_mixing, &
28 : thermohaline_mixing, &
29 : rotation_mixing
30 : use num_lib
31 : use utils_lib
32 : use star_private_def
33 :
34 : implicit none
35 :
36 : private
37 : public :: set_mixing_info
38 : public :: set_RTI_mixing_info
39 : public :: do_smoothing_by_mass
40 : public :: update_rotation_mixing_info
41 : public :: set_dPdr_dRhodr_info
42 : public :: get_convection_sigmas
43 : public :: set_dxdt_mix
44 : public :: set_cz_bdy_mass
45 :
46 : contains
47 :
48 33 : subroutine set_mixing_info(s, skip_set_cz_bdy_mass, ierr)
49 : ! set convection variables cdc and conv_vel starting from local MLT results.
50 : ! overshooting can also be added. and rotation mixing.
51 : use rates_def, only: i_rate
52 : use chem_def, only: ipp, icno, i3alf, ih1, ihe4, ic12
53 : use star_utils, only: start_time, update_time
54 : use overshoot, only: add_overshooting
55 : use predictive_mix, only: add_predictive_mixing
56 : use auto_diff_support, only: get_RSP2_conv_velocity
57 : type (star_info), pointer :: s
58 : logical, intent(in) :: skip_set_cz_bdy_mass
59 : integer, intent(out) :: ierr
60 :
61 : integer :: nz, k, max_conv_bdy, max_mix_bdy, k_Tmax, i_h1, i_he4, i_c12
62 33 : real(dp) :: rho_face, f, Tmax, min_conv_vel_for_convective_mixing_type, &
63 33 : region_bottom_q, region_top_q, L_val
64 33 : real(dp), allocatable, dimension(:) :: eps_h, eps_he, eps_z, cdc_factor
65 :
66 : logical :: RSP2_or_RSP
67 :
68 : integer(i8) :: time0
69 33 : real(dp) :: total
70 :
71 : include 'formats'
72 :
73 33 : ierr = 0
74 33 : nz = s% nz
75 :
76 33 : min_conv_vel_for_convective_mixing_type = 1d0 ! make this a control parameter
77 :
78 33 : RSP2_or_RSP = s% RSP_flag .or. s% RSP2_flag
79 :
80 33 : if (s% doing_timing) call start_time(s, time0, total)
81 :
82 33 : if (s% RTI_flag) then
83 0 : call set_RTI_mixing_info(s, ierr)
84 0 : if (failed('set_RTI_mixing_info')) return
85 0 : call set_dPdr_dRhodr_info(s, ierr)
86 0 : if (failed('set_dPdr_dRhodr_info')) return
87 : end if
88 :
89 33 : max_conv_bdy = 10 ! will automatically be increased if necessary
90 33 : max_mix_bdy = 10 ! will automatically be increased if necessary
91 :
92 33 : s% num_conv_boundaries = 0
93 33 : if (.not. associated(s% conv_bdy_loc)) allocate(s% conv_bdy_loc(max_conv_bdy))
94 33 : if (.not. associated(s% conv_bdy_q)) allocate(s% conv_bdy_q(max_conv_bdy))
95 33 : if (.not. associated(s% top_conv_bdy)) allocate(s% top_conv_bdy(max_conv_bdy))
96 33 : if (.not. associated(s% burn_h_conv_region)) allocate(s% burn_h_conv_region(max_conv_bdy))
97 33 : if (.not. associated(s% burn_he_conv_region)) allocate(s% burn_he_conv_region(max_conv_bdy))
98 33 : if (.not. associated(s% burn_z_conv_region)) allocate(s% burn_z_conv_region(max_conv_bdy))
99 :
100 33 : s% num_mix_boundaries = 0
101 33 : if (.not. associated(s% mix_bdy_loc)) allocate(s% mix_bdy_loc(max_mix_bdy))
102 33 : if (.not. associated(s% mix_bdy_q)) allocate(s% mix_bdy_q(max_mix_bdy))
103 33 : if (.not. associated(s% top_mix_bdy)) allocate(s% top_mix_bdy(max_mix_bdy))
104 33 : if (.not. associated(s% burn_h_mix_region)) allocate(s% burn_h_mix_region(max_mix_bdy))
105 33 : if (.not. associated(s% burn_he_mix_region)) allocate(s% burn_he_mix_region(max_mix_bdy))
106 33 : if (.not. associated(s% burn_z_mix_region)) allocate(s% burn_z_mix_region(max_mix_bdy))
107 :
108 33 : allocate(eps_h(nz), eps_he(nz), eps_z(nz), cdc_factor(nz))
109 :
110 33 : if (.not. RSP2_or_RSP) then
111 40766 : do k = 1, nz
112 40766 : s% mixing_type(k) = s% mlt_mixing_type(k)
113 : end do
114 : end if
115 :
116 33 : cdc_factor(1) = 1d0
117 40733 : do k = 2, nz
118 : rho_face = (s% dq(k-1)*s% rho(k) + s% dq(k)*s% rho(k-1))/&
119 40700 : (s% dq(k-1) + s% dq(k))
120 40700 : f = pi4*s% r(k)*s% r(k)*rho_face
121 40733 : cdc_factor(k) = f*f
122 : end do
123 :
124 33 : if (s% RSP_flag) then
125 0 : do k = 1, nz
126 0 : s% mixing_type(k) = no_mixing
127 0 : s% D_mix(k) = 0d0
128 0 : s% cdc(k) = 0d0
129 0 : s% conv_vel(k) = 0d0
130 : end do
131 33 : else if (s% RSP2_flag) then
132 0 : do k = 1, nz
133 0 : s% conv_vel(k) = get_RSP2_conv_velocity(s,k)
134 0 : s% D_mix(k) = s% conv_vel(k)*s% mixing_length_alpha*s% Hp_face(k)/3d0
135 0 : s% cdc(k) = cdc_factor(k)*s% D_mix(k)
136 0 : L_val = max(1d-99,abs(s% L(k)))
137 0 : if (abs(s% Lt(k)) > &
138 0 : L_val*s% RSP2_min_Lt_div_L_for_overshooting_mixing_type) then
139 0 : s% mixing_type(k) = overshoot_mixing
140 0 : else if (abs(s% Lc(k)) > &
141 : L_val*s% RSP2_min_Lc_div_L_for_convective_mixing_type) then
142 0 : s% mixing_type(k) = convective_mixing
143 : else
144 0 : s% mixing_type(k) = no_mixing
145 : end if
146 : end do
147 : else
148 40766 : do k = 1, nz
149 40733 : s% D_mix(k) = s% mlt_D(k)
150 40733 : s% cdc(k) = s% mlt_cdc(k)
151 40766 : s% conv_vel(k) = s% mlt_vc(k)
152 : end do
153 : end if
154 :
155 33 : call check('after get mlt_D')
156 :
157 33 : if (s% remove_mixing_glitches .and. .not. RSP2_or_RSP) then
158 :
159 33 : call remove_tiny_mixing(s, ierr)
160 33 : if (failed('remove_tiny_mixing')) return
161 :
162 33 : call remove_mixing_singletons(s, ierr)
163 33 : if (failed('remove_mixing_singletons')) return
164 :
165 33 : call close_convection_gaps(s, ierr)
166 33 : if (failed('close_convection_gaps')) return
167 :
168 33 : call close_thermohaline_gaps(s, ierr)
169 33 : if (failed('close_thermohaline_gaps')) return
170 :
171 33 : call remove_thermohaline_dropouts(s, ierr)
172 33 : if (failed('remove_thermohaline_dropouts')) return
173 :
174 33 : call close_semiconvection_gaps(s, ierr)
175 33 : if (failed('close_semiconvection_gaps')) return
176 :
177 33 : call remove_embedded_semiconvection(s, ierr)
178 33 : if (failed('remove_embedded_semiconvection')) return
179 :
180 : end if
181 :
182 33 : call check('after get remove_mixing_glitches')
183 :
184 33 : call do_mix_envelope(s)
185 :
186 40766 : do k=1,s% nz
187 : eps_h(k) = s% eps_nuc_categories(ipp,k) + &
188 40733 : s% eps_nuc_categories(icno,k)
189 40733 : eps_he(k) = s% eps_nuc_categories(i3alf,k)
190 40766 : eps_z(k) = s% eps_nuc(k) - (eps_h(k) + eps_he(k))
191 : end do
192 :
193 33 : if (.not. s% RSP_flag) then
194 :
195 33 : call set_cz_boundary_info(s, ierr)
196 33 : if (failed('set_cz_boundary_info')) return
197 :
198 : call locate_convection_boundaries( &
199 : s, nz, eps_h, eps_he, eps_z, s% mstar, &
200 33 : s% q, s% cdc, ierr)
201 33 : if (failed('locate_convection_boundaries')) return
202 :
203 33 : call add_predictive_mixing(s, ierr)
204 33 : if (failed('add_predictive_mixing')) return
205 :
206 : end if
207 :
208 33 : call check('after add_predictive_mixing')
209 :
210 : ! NB: re-call locate_convection_boundaries to take into
211 : ! account changes from add_predictive_mixing
212 :
213 33 : if (.not. s% RSP_flag) then
214 :
215 : call locate_convection_boundaries( &
216 : s, nz, eps_h, eps_he, eps_z, s% mstar, &
217 33 : s% q, s% cdc, ierr)
218 33 : if (failed('locate_convection_boundaries')) return
219 :
220 33 : call locate_mixing_boundaries(s, eps_h, eps_he, eps_z, ierr)
221 33 : if (failed('locate_mixing_boundaries')) return
222 :
223 33 : call add_overshooting(s, ierr)
224 33 : if (failed('add_overshooting')) return
225 :
226 : end if
227 :
228 33 : call check('after add_overshooting')
229 :
230 33 : call add_RTI_turbulence(s, ierr)
231 33 : if (failed('add_RTI_turbulence')) return
232 :
233 33 : call s% other_after_set_mixing_info(s% id, ierr)
234 33 : if (failed('other_after_set_mixing_info')) return
235 :
236 33 : if (.not. (skip_set_cz_bdy_mass .or. RSP2_or_RSP)) then
237 11 : call set_cz_bdy_mass(s, ierr)
238 11 : if (failed('set_cz_bdy_mass')) return
239 : end if
240 :
241 33 : if (s% set_min_D_mix .and. s% ye(nz) >= s% min_center_Ye_for_min_D_mix) then
242 0 : do k=1,nz
243 0 : if (s% D_mix(k) >= s% min_D_mix) cycle
244 0 : if (s% m(k) > s% mass_upper_limit_for_min_D_mix*Msun) cycle
245 0 : if (s% m(k) < s% mass_lower_limit_for_min_D_mix*Msun) cycle
246 0 : s% D_mix(k) = s% min_D_mix
247 0 : s% mixing_type(k) = minimum_mixing
248 : end do
249 : end if
250 :
251 33 : if (s% set_min_D_mix_below_Tmax) then
252 0 : Tmax = -1
253 0 : k_Tmax = -1
254 0 : do k=1,nz
255 0 : if (s% T(k) > Tmax) then
256 0 : Tmax = s% T(k)
257 0 : k_Tmax = k
258 : end if
259 : end do
260 0 : do k=k_Tmax+1,nz
261 0 : if (s% D_mix(k) >= s% min_D_mix_below_Tmax) cycle
262 0 : s% D_mix(k) = s% min_D_mix_below_Tmax
263 0 : s% mixing_type(k) = minimum_mixing
264 : end do
265 : end if
266 :
267 33 : if (s% set_min_D_mix_in_H_He) then
268 0 : do k=1,nz
269 0 : if (s% X(k) + s% Y(k) < 0.5d0) exit
270 0 : if (s% D_mix(k) >= s% min_D_mix_in_H_He) cycle
271 0 : s% D_mix(k) = s% min_D_mix_in_H_He
272 0 : s% mixing_type(k) = minimum_mixing
273 : end do
274 : end if
275 :
276 33 : if (s% use_other_D_mix) then
277 0 : call s% other_D_mix(s% id, ierr)
278 0 : if (failed('other_D_mix')) return
279 : end if
280 :
281 40766 : do k=1,nz
282 40766 : s% D_mix_non_rotation(k) = s% D_mix(k)
283 : end do
284 :
285 33 : call check('before rotation_flag')
286 :
287 33 : if (s% rotation_flag) then
288 :
289 0 : call update_rotation_mixing_info(s,ierr)
290 0 : if (failed('update_rotation_mixing_info')) return
291 :
292 0 : do k = 2, nz
293 0 : if (s% D_mix(k) < 1d-10) s% D_mix(k) = 0d0
294 0 : s% cdc(k) = s% D_mix(k)*cdc_factor(k)
295 0 : if (s% D_mix(k) /= 0 .and. s% D_mix_non_rotation(k) < s% D_mix_rotation(k)) then
296 0 : s% mixing_type(k) = rotation_mixing
297 : end if
298 : end do
299 0 : s% cdc(1) = s% cdc(2)
300 :
301 : end if
302 :
303 33 : call check('after update_rotation_mixing_info')
304 :
305 33 : region_bottom_q = s% D_mix_zero_region_bottom_q
306 33 : region_top_q = s% D_mix_zero_region_top_q
307 :
308 33 : if (s% dq_D_mix_zero_at_H_He_crossover > 0d0) then
309 0 : i_h1 = s% net_iso(ih1)
310 0 : i_he4 = s% net_iso(ihe4)
311 0 : if (i_h1 > 0 .and. i_he4 > 0) then
312 0 : do k=2,nz
313 0 : if (s% xa(i_h1,k-1) > s% xa(i_he4,k-1) .and. &
314 0 : s% xa(i_h1,k) <= s% xa(i_he4,k)) then ! crossover
315 : region_bottom_q = &
316 0 : s% q(k) - 0.5d0*s% dq_D_mix_zero_at_H_He_crossover
317 : region_top_q = &
318 0 : s% q(k) + 0.5d0*s% dq_D_mix_zero_at_H_He_crossover
319 0 : exit
320 : end if
321 : end do
322 : end if
323 : end if
324 :
325 33 : if (region_bottom_q < region_top_q) then
326 0 : do k=2,nz
327 0 : if (s% q(k) >= region_bottom_q .and. s% q(k) <= region_top_q) then
328 0 : s% D_mix(k) = 0d0
329 0 : s% mixing_type(k) = no_mixing
330 : end if
331 : end do
332 : end if
333 :
334 33 : region_bottom_q = 1d99
335 33 : region_top_q = -1d99
336 33 : if (s% dq_D_mix_zero_at_H_C_crossover > 0d0) then
337 0 : i_h1 = s% net_iso(ih1)
338 0 : i_c12 = s% net_iso(ic12)
339 0 : if (i_h1 > 0 .and. i_c12 > 0) then
340 0 : do k=2,nz
341 0 : if (s% xa(i_h1,k-1) > s% xa(i_c12,k-1) .and. &
342 0 : s% xa(i_h1,k) <= s% xa(i_c12,k)) then ! crossover
343 : region_bottom_q = &
344 0 : s% q(k) - 0.5d0*s% dq_D_mix_zero_at_H_C_crossover
345 : region_top_q = &
346 0 : s% q(k) + 0.5d0*s% dq_D_mix_zero_at_H_C_crossover
347 0 : exit
348 : end if
349 : end do
350 : end if
351 : end if
352 :
353 0 : if (region_bottom_q < region_top_q) then
354 0 : do k=2,nz
355 0 : if (s% q(k) >= region_bottom_q .and. s% q(k) <= region_top_q) then
356 0 : s% D_mix(k) = 0d0
357 0 : s% mixing_type(k) = no_mixing
358 : end if
359 : end do
360 : end if
361 :
362 : ! as last thing, update conv_vel from D_mix and mixing length.
363 40733 : do k=2,nz
364 40733 : if (s% alpha_mlt(k)*s% scale_height(k) > 0) then
365 : s% conv_vel(k) = &
366 40700 : 3*s% D_mix(k)/(s% alpha_mlt(k)*s% scale_height(k))
367 : else
368 0 : s% conv_vel(k) = 0
369 : end if
370 : end do
371 :
372 : ! set these just for plotting. not used.
373 33 : s% mixing_type(1) = s% mixing_type(2)
374 33 : s% D_mix(1) = s% D_mix(2)
375 33 : s% conv_vel(1) = 0d0
376 :
377 33 : call check('final')
378 33 : if (failed('set_mixing_info')) return
379 :
380 33 : if (s% doing_timing) &
381 0 : call update_time(s, time0, total, s% time_set_mixing_info)
382 :
383 99 : s% have_mixing_info = .true.
384 :
385 : contains
386 :
387 539 : logical function failed(str)
388 : character (len=*), intent(in) :: str
389 539 : if (ierr == 0) then
390 : failed = .false.
391 : return
392 : end if
393 0 : if (s% report_ierr) &
394 0 : write(*,*) 'set_mixing_info failed in call to ' // trim(str)
395 : failed = .true.
396 33 : end function failed
397 :
398 231 : subroutine check(str)
399 : character(len=*) :: str
400 : integer :: k
401 : include 'formats'
402 285362 : do k = 1, s% nz
403 285362 : if (is_bad_num(s% D_mix(k))) then
404 0 : ierr = -1
405 0 : if (s% report_ierr) then
406 0 : write(*,3) trim(str) // ' mixing_type, D_mix', k, s% mixing_type(k), s% D_mix(k)
407 0 : if (s% rotation_flag) then
408 0 : if (is_bad_num(s% D_mix_non_rotation(k))) &
409 0 : write(*,2) 's% D_mix_non_rotation(k)', k, s% D_mix_non_rotation(k)
410 0 : if (is_bad_num(s% D_visc(k))) write(*,2) 's% D_visc(k)', k, s% D_visc(k)
411 0 : if (is_bad_num(s% D_DSI(k))) write(*,2) 's% D_DSI(k)', k, s% D_DSI(k)
412 0 : if (is_bad_num(s% D_SH(k))) write(*,2) 's% D_SH(k)', k, s% D_SH(k)
413 0 : if (is_bad_num(s% D_SSI(k))) write(*,2) 's% D_SSI(k)', k, s% D_SSI(k)
414 0 : if (is_bad_num(s% D_ES(k))) write(*,2) 's% D_ES(k)', k, s% D_ES(k)
415 0 : if (is_bad_num(s% D_GSF(k))) write(*,2) 's% D_GSF(k)', k, s% D_GSF(k)
416 0 : if (is_bad_num(s% D_ST(k))) write(*,2) 's% D_ST(k)', k, s% D_ST(k)
417 : end if
418 : end if
419 0 : if (s% stop_for_bad_nums) call mesa_error(__FILE__,__LINE__,'set mixing info')
420 : end if
421 : end do
422 231 : end subroutine check
423 :
424 : end subroutine set_mixing_info
425 :
426 :
427 33 : subroutine set_cz_boundary_info(s, ierr)
428 : type (star_info), pointer :: s
429 : integer, intent(out) :: ierr
430 :
431 : integer :: k, mt1, mt2, nz
432 33 : real(dp) :: dg0, dg1
433 :
434 : include 'formats'
435 :
436 : ! NOTE: this routine must be called BEFORE overshooting is done.
437 :
438 : ! convective zone boundary is where gradL = gradr
439 : ! semi-convective zone boundary is where grada_face = gradr
440 :
441 33 : ierr = 0
442 33 : nz = s% nz
443 40766 : s% cz_bdy_dq(1:nz) = 0d0
444 :
445 40733 : do k = 2, nz
446 40700 : mt1 = s% mixing_type(k-1)
447 40700 : mt2 = s% mixing_type(k)
448 40700 : if (mt1 == mt2) cycle
449 105 : if (mt2 == convective_mixing .or. mt1 == convective_mixing) then
450 105 : dg0 = s% gradL(k-1) - s% gradr(k-1)
451 105 : dg1 = s% gradL(k) - s% gradr(k)
452 0 : else if (mt2 == semiconvective_mixing .or. mt1 == semiconvective_mixing) then
453 0 : dg0 = s% grada_face(k-1) - s% gradr(k-1)
454 0 : dg1 = s% grada_face(k) - s% gradr(k)
455 : else
456 : cycle
457 : end if
458 105 : if (dg0*dg1 >= 0) cycle
459 105 : s% cz_bdy_dq(k-1) = find0(0d0,dg0,s% dq(k-1),dg1)
460 138 : if (s% cz_bdy_dq(k-1) < 0d0 .or. s% cz_bdy_dq(k-1) > s% dq(k-1)) then
461 0 : write(*,2) 'bad cz_bdy_dq', k-1, s% cz_bdy_dq(k-1), s% dq(k-1)
462 0 : call mesa_error(__FILE__,__LINE__,'set_cz_boundary_info')
463 0 : ierr = -1
464 0 : return
465 : end if
466 : end do
467 :
468 : end subroutine set_cz_boundary_info
469 :
470 :
471 11 : subroutine set_cz_bdy_mass(s, ierr)
472 : type (star_info), pointer :: s
473 : integer, intent(out) :: ierr
474 :
475 : logical :: in_convective_region
476 : integer :: k, j, nz
477 : logical, parameter :: dbg = .false.
478 :
479 : include 'formats'
480 11 : ierr = 0
481 11 : nz = s% nz
482 :
483 1111 : s% cz_top_mass(:) = s% mstar
484 1111 : s% cz_bot_mass(:) = s% mstar
485 :
486 11 : s% n_conv_regions = 0
487 11 : in_convective_region = (s% mixing_type(nz) == convective_mixing)
488 11 : if (in_convective_region) then
489 11 : s% n_conv_regions = 1
490 11 : s% cz_bot_mass(1) = s% M_center
491 : end if
492 :
493 : if (dbg) write(*,*) 'initial in_convective_region', in_convective_region
494 :
495 13076 : do k=nz-1, 2, -1
496 13076 : if (in_convective_region) then
497 1894 : if (s% mixing_type(k) /= convective_mixing) then ! top of convective region
498 : s% cz_top_mass(s% n_conv_regions) = &
499 23 : s% M_center + (s% q(k) - s% cz_bdy_dq(k))*s% xmstar
500 23 : in_convective_region = .false.
501 : end if
502 : else
503 11171 : if (s% mixing_type(k) == convective_mixing) then ! bottom of convective region
504 12 : if (s% n_conv_regions < max_num_mixing_regions) then
505 12 : s% n_conv_regions = s% n_conv_regions + 1
506 : s% cz_bot_mass(s% n_conv_regions) = &
507 12 : s% M_center + (s% q(k) - s% cz_bdy_dq(k))*s% xmstar
508 : end if
509 : in_convective_region = .true.
510 : end if
511 : end if
512 : end do
513 11 : if (in_convective_region) then
514 0 : s% cz_top_mass(s% n_conv_regions) = s% mstar
515 : end if
516 :
517 11 : s% have_new_cz_bdy_info = .true.
518 :
519 : if (dbg) then
520 : write(*,'(A)')
521 : write(*,2) 'set_mixing_info s% n_conv_regions', s% n_conv_regions
522 : do j = 1, s% n_conv_regions
523 : write(*,2) 'conv region', j, s% cz_bot_mass(j)/Msun, s% cz_top_mass(j)/Msun
524 : end do
525 : write(*,'(A)')
526 : end if
527 :
528 11 : end subroutine set_cz_bdy_mass
529 :
530 :
531 66 : subroutine locate_convection_boundaries( &
532 66 : s, nz, eps_h, eps_he, eps_z, mstar, q, cdc, ierr)
533 : type (star_info), pointer :: s
534 : integer, intent(in) :: nz
535 : real(dp), dimension(:), intent(in) :: eps_h, eps_he, eps_z
536 : real(dp), intent(in) :: mstar
537 : real(dp), pointer, dimension(:) :: q, cdc
538 : integer, intent(out) :: ierr
539 :
540 : logical :: in_convective_region
541 : integer :: k, k_bot, i, j, iounit, max_conv_bdy
542 66 : real(dp) :: turnover_time, bot_Hp, bot_r, top_Hp, top_r, dr
543 :
544 : logical :: dbg
545 : logical, parameter :: write_debug = .false.
546 :
547 : include 'formats'
548 :
549 66 : ierr = 0
550 66 : dbg = .false.
551 :
552 : if (write_debug) then
553 : open(newunit=iounit, file=trim('debug.data'), action='write', iostat=ierr)
554 : if (ierr /= 0) then
555 : write(*, *) 'open debug.data failed'
556 : return
557 : end if
558 : write(*,*) 'write debug.data'
559 : write(iounit,*) 'nz', nz
560 : write(iounit,1) 'mstar', mstar
561 : do k=1,nz
562 : write(iounit,2) 'q', k, q(k)
563 : write(iounit,2) 'cdc', k, cdc(k)
564 : write(iounit,2) 'eps_h', k, eps_h(k)
565 : write(iounit,2) 'eps_he', k, eps_he(k)
566 : write(iounit,2) 'eps_z', k, eps_z(k)
567 : end do
568 : end if
569 :
570 66 : max_conv_bdy = size(s% conv_bdy_q, dim=1)
571 726 : s% conv_bdy_q(:) = 0
572 726 : s% conv_bdy_loc(:) = 0
573 726 : s% top_conv_bdy(:) = .false.
574 726 : s% burn_h_conv_region(:) = .false.
575 726 : s% burn_he_conv_region(:) = .false.
576 726 : s% burn_z_conv_region(:) = .false.
577 66 : bot_Hp = 0; bot_r = 0; top_Hp = 0; top_r = 0; dr = 0
578 :
579 66 : s% num_conv_boundaries = 0
580 66 : in_convective_region = (s% mixing_type(nz) == convective_mixing)
581 66 : k_bot = nz
582 66 : turnover_time = 0
583 :
584 81400 : do k=nz-1, 2, -1
585 81400 : if (in_convective_region) then
586 12002 : if (s% mixing_type(k) /= convective_mixing) then
587 138 : call end_of_convective_region
588 81334 : else if(s% conv_vel(k) /= 0d0) then
589 81334 : turnover_time = turnover_time + (s% rmid(k-1) - s% rmid(k))/s% conv_vel(k)
590 : end if
591 : else ! in non-convective region
592 69332 : if (s% mixing_type(k) == convective_mixing) then ! start of a convective region
593 72 : if (s% num_conv_boundaries == max_conv_bdy) then
594 0 : call realloc(ierr)
595 0 : if (ierr /= 0) then
596 : return
597 : end if
598 : end if
599 72 : s% num_conv_boundaries = s% num_conv_boundaries+1
600 72 : i = s% num_conv_boundaries
601 72 : k_bot = k+1
602 72 : if (k == 1) then
603 0 : s% conv_bdy_q(i) = 1
604 : else ! bottom of region is between k+1 and k
605 72 : s% conv_bdy_q(i) = s% q(k) - s% cz_bdy_dq(k)
606 : end if
607 72 : s% top_conv_bdy(i) = .false.
608 72 : s% conv_bdy_loc(i) = k_bot
609 : ! bottom of region is between k_bot and k_bot-1
610 72 : in_convective_region = .true.
611 72 : bot_r = s% r(k_bot)
612 : !bot_Hp = scale_height(s,k_bot,.true.)
613 72 : bot_Hp = s% scale_height(k_bot)
614 72 : turnover_time = 0
615 : end if
616 : end if
617 : end do
618 :
619 66 : if (in_convective_region) then
620 0 : k = 1 ! end at top
621 0 : call end_of_convective_region
622 : end if
623 :
624 : if (write_debug) then
625 : write(iounit,*) 's% num_conv_boundaries', s% num_conv_boundaries
626 : do j=1,s% num_conv_boundaries
627 : write(iounit,2) 's% conv_bdy_q', j, s% conv_bdy_q(j)
628 : write(iounit,*) 's% top_conv_bdy', j, s% top_conv_bdy(j)
629 : write(iounit,*) 's% burn_h_conv_region', j, s% burn_h_conv_region(j)
630 : write(iounit,*) 's% burn_he_conv_region', j, s% burn_he_conv_region(j)
631 : write(iounit,*) 's% burn_z_conv_region', j, s% burn_z_conv_region(j)
632 : write(iounit,*) 's% conv_bdy_loc', j, s% conv_bdy_loc(j)
633 : end do
634 : close(iounit)
635 : end if
636 :
637 : if (dbg) then
638 : write(*,*) 's% num_conv_boundaries', s% num_conv_boundaries
639 : do j=1,s% num_conv_boundaries
640 : write(*,*) 's% conv_bdy_q', j, s% conv_bdy_q(j)
641 : write(*,*) 's% top_conv_bdy', j, s% top_conv_bdy(j)
642 : write(*,*) 's% burn_h_conv_region', j, s% burn_h_conv_region(j)
643 : write(*,*) 's% burn_he_conv_region', j, s% burn_he_conv_region(j)
644 : write(*,*) 's% burn_z_conv_region', j, s% burn_z_conv_region(j)
645 : write(*,*) 's% conv_bdy_loc', j, s% conv_bdy_loc(j)
646 : write(*,*) 'mixing type', s% mixing_type(s% conv_bdy_loc(j)-3:s% conv_bdy_loc(j)+3)
647 : end do
648 : write(*,'(A)')
649 : write(*,3) 'mixing_type', 1152, s% mixing_type(1152)
650 : call mesa_error(__FILE__,__LINE__,'locate_convection_boundaries')
651 : end if
652 :
653 :
654 : contains
655 :
656 :
657 138 : subroutine end_of_convective_region()
658 : integer :: max_logT_loc, kk
659 138 : real(dp) :: max_logT, max_X, max_Y, Hp, max_eps
660 : logical :: end_dbg
661 :
662 : 9 format(a40, 3i7, 99(1pd26.16))
663 : include 'formats'
664 :
665 138 : in_convective_region = .false.
666 :
667 138 : end_dbg = .false.
668 :
669 138 : top_r = s% r(k)
670 138 : top_Hp = s% scale_height(k)
671 138 : dr = top_r - bot_r
672 138 : Hp = (bot_Hp + top_Hp)/2
673 :
674 138 : if (dr/Hp < s% prune_bad_cz_min_Hp_height .and. s% prune_bad_cz_min_Hp_height > 0) then
675 0 : max_eps = maxval(eps_h(k:k_bot) + eps_he(k:k_bot) + eps_z(k:k_bot))
676 : if (end_dbg) write(*,3) 'max_eps', k, k_bot, max_eps, &
677 : exp10(s% prune_bad_cz_min_log_eps_nuc)
678 : if (max_eps < exp10(s% prune_bad_cz_min_log_eps_nuc) &
679 0 : .and. all(s% mixing_type(k+1:k_bot-1) /= thermohaline_mixing)) then
680 0 : do kk = k, k_bot ! this includes the radiative points at boundaries
681 0 : call set_use_gradr(s,kk)
682 0 : s% cdc(kk) = 0
683 0 : s% D_mix(kk) = 0
684 0 : s% conv_vel(kk) = 0
685 0 : s% mixing_type(kk) = no_mixing
686 : end do
687 0 : if (s% num_conv_boundaries > 0) &
688 0 : s% num_conv_boundaries = s% num_conv_boundaries-1
689 0 : return
690 : end if
691 : end if
692 :
693 138 : if (s% num_conv_boundaries == max_conv_bdy) then
694 0 : call realloc(ierr)
695 0 : if (ierr /= 0) return
696 : end if
697 :
698 138 : s% num_conv_boundaries = s% num_conv_boundaries+1
699 138 : i = s% num_conv_boundaries
700 :
701 : ! check for burning in region
702 138 : max_logT = -1d99
703 138 : max_X = 0d0
704 138 : max_Y = 0d0
705 138 : max_logT_loc = 0
706 12422 : do kk=k,min(nz,k_bot+1)
707 12284 : if (s% lnT(kk)/ln10 > max_logT) then
708 12284 : max_logT = s% lnT(kk)/ln10
709 12284 : max_logT_loc = kk
710 : end if
711 12284 : if (s% X(kk) > max_X) then
712 138 : max_X = s% X(kk)
713 : end if
714 12422 : if (s% Y(kk) > max_Y) then
715 10058 : max_Y = s% Y(kk)
716 : end if
717 : end do
718 : if (max_logT > s% burn_z_mix_region_logT &
719 138 : .and. max_Y < s% max_Y_for_burn_z_mix_region) then
720 0 : s% burn_z_conv_region(i) = .true.
721 0 : if (i > 1) s% burn_z_conv_region(i-1) = .true.
722 : !write(*,*) 'burn z mix region', i, &
723 : ! s% burn_z_mix_region_logT, max_logT, s% m(max_logT_loc)/Msun
724 : else if (max_logT > s% burn_he_mix_region_logT &
725 138 : .and. max_X < s% max_X_for_burn_he_mix_region) then
726 0 : s% burn_he_conv_region(i) = .true.
727 0 : if (i > 1) s% burn_he_conv_region(i-1) = .true.
728 : !write(*,*) 'burn he mix region', i, &
729 : ! s% burn_he_mix_region_logT, max_logT, s% m(max_logT_loc)/Msun
730 138 : else if (max_logT > s% burn_h_mix_region_logT) then
731 66 : s% burn_h_conv_region(i) = .true.
732 66 : if (i > 1) s% burn_h_conv_region(i-1) = .true.
733 : !write(*,*) 'burn h mix region', i, &
734 : ! s% burn_h_mix_region_logT, max_logT, s% m(max_logT_loc)/Msun
735 : end if
736 :
737 138 : if (k == 1) then
738 0 : s% conv_bdy_q(i) = 1
739 : else
740 : ! top of region is between k+1 and k
741 138 : s% conv_bdy_q(i) = s% q(k) - s% cz_bdy_dq(k)
742 : end if
743 138 : s% top_conv_bdy(i) = .true.
744 138 : s% conv_bdy_loc(i) = k
745 :
746 : end subroutine end_of_convective_region
747 :
748 :
749 0 : subroutine realloc(ierr)
750 : use utils_lib
751 : integer, intent(out) :: ierr
752 :
753 : integer :: sz
754 :
755 0 : sz = size(s% conv_bdy_q, dim=1)
756 :
757 : ierr = 0
758 0 : max_conv_bdy = 2*(10+max_conv_bdy)
759 :
760 0 : call realloc_double(s% conv_bdy_q,max_conv_bdy,ierr)
761 0 : if (ierr /= 0) return
762 :
763 0 : call realloc_integer(s% conv_bdy_loc,max_conv_bdy,ierr)
764 0 : if (ierr /= 0) return
765 :
766 0 : call realloc_logical(s% top_conv_bdy,max_conv_bdy,ierr)
767 0 : if (ierr /= 0) return
768 :
769 0 : call realloc_logical(s% burn_h_conv_region,max_conv_bdy,ierr)
770 0 : if (ierr /= 0) return
771 :
772 0 : call realloc_logical(s% burn_he_conv_region,max_conv_bdy,ierr)
773 0 : if (ierr /= 0) return
774 :
775 0 : call realloc_logical(s% burn_z_conv_region,max_conv_bdy,ierr)
776 0 : if (ierr /= 0) return
777 :
778 0 : s% conv_bdy_q(sz+1:max_conv_bdy) = 0
779 0 : s% conv_bdy_loc(sz+1:max_conv_bdy) = 0
780 0 : s% top_conv_bdy(sz+1:max_conv_bdy) = .false.
781 0 : s% burn_h_conv_region(sz+1:max_conv_bdy) = .false.
782 0 : s% burn_he_conv_region(sz+1:max_conv_bdy) = .false.
783 0 : s% burn_z_conv_region(sz+1:max_conv_bdy) = .false.
784 :
785 : end subroutine realloc
786 :
787 : end subroutine locate_convection_boundaries
788 :
789 :
790 30 : subroutine set_use_gradr(s,k)
791 : use turb_info, only: switch_to_radiative
792 : type (star_info), pointer :: s
793 : integer, intent(in) :: k
794 30 : call switch_to_radiative(s,k)
795 30 : end subroutine set_use_gradr
796 :
797 :
798 33 : subroutine locate_mixing_boundaries(s, eps_h, eps_he, eps_z, ierr)
799 : type (star_info), pointer :: s
800 : real(dp), dimension(:), intent(in) :: eps_h, eps_he, eps_z
801 : integer, intent(out) :: ierr
802 :
803 : logical :: in_mixing_region
804 : integer :: k, k_bot, i, max_mix_bdy, nz
805 :
806 : logical, parameter :: dbg = .false.
807 :
808 : include 'formats'
809 :
810 33 : ierr = 0
811 33 : nz = s% nz
812 :
813 33 : max_mix_bdy = size(s% mix_bdy_q, dim=1)
814 363 : s% mix_bdy_q(:) = 0
815 363 : s% mix_bdy_loc(:) = 0
816 363 : s% top_mix_bdy(:) = .false.
817 363 : s% burn_h_mix_region(:) = .false.
818 363 : s% burn_he_mix_region(:) = .false.
819 363 : s% burn_z_mix_region(:) = .false.
820 :
821 33 : s% num_mix_boundaries = 0
822 33 : s% num_mix_regions = 0
823 33 : in_mixing_region = (s% mixing_type(nz) /= no_mixing)
824 33 : k_bot = nz
825 40700 : do k=nz-1, 2, -1
826 40700 : if (in_mixing_region) then
827 6001 : if (s% mixing_type(k) == no_mixing) call end_of_mixing_region
828 : else ! in non-mixing region
829 34666 : if (s% mixing_type(k) /= no_mixing) then ! start of a mixing region
830 36 : if (s% num_mix_boundaries == max_mix_bdy) then
831 0 : call realloc(ierr)
832 0 : if (ierr /= 0) return
833 : end if
834 36 : s% num_mix_boundaries = s% num_mix_boundaries+1
835 36 : i = s% num_mix_boundaries
836 36 : k_bot = k+1
837 36 : if (k == 1) then
838 0 : s% mix_bdy_q(i) = 1
839 : else ! bottom of region is between k+1 and k
840 36 : s% mix_bdy_q(i) = s% q(k) - s% cz_bdy_dq(k)
841 : end if
842 36 : s% top_mix_bdy(i) = .false.
843 36 : s% mix_bdy_loc(i) = k_bot
844 36 : in_mixing_region = .true.
845 : end if
846 : end if
847 : end do
848 :
849 63 : if (in_mixing_region) then
850 0 : k = 1 ! end at top
851 0 : call end_of_mixing_region
852 : end if
853 :
854 :
855 : !do i=1,s% num_conv_boundaries
856 : ! write(*,*) 'locate_mixing_boundaries region burn_h he z', i, &
857 : ! s% burn_h_mix_region(i), s% burn_he_conv_region(i), s% burn_z_conv_region(i)
858 : !end do
859 :
860 : contains
861 :
862 :
863 69 : subroutine end_of_mixing_region()
864 : integer :: kk, max_logT_loc
865 69 : real(dp) :: max_logT, max_X, max_Y
866 :
867 : 9 format(a40, 3i7, 99(1pd26.16))
868 : include 'formats'
869 :
870 69 : in_mixing_region = .false.
871 :
872 69 : if (s% num_mix_boundaries == max_mix_bdy) then
873 0 : call realloc(ierr)
874 0 : if (ierr /= 0) return
875 : end if
876 :
877 69 : s% num_mix_regions = s% num_mix_regions+1
878 69 : s% num_mix_boundaries = s% num_mix_boundaries+1
879 69 : i = s% num_mix_boundaries
880 :
881 : ! check for burning in region
882 69 : max_logT = -1d99
883 69 : max_X = 0d0
884 69 : max_Y = 0d0
885 69 : max_logT_loc = 0
886 6211 : do kk=k,min(nz,k_bot+1)
887 6142 : if (s% lnT(kk)/ln10 > max_logT) then
888 6142 : max_logT = s% lnT(kk)/ln10
889 6142 : max_logT_loc = kk
890 : end if
891 6142 : if (s% X(kk) > max_X) then
892 69 : max_X = s% X(kk)
893 : end if
894 6211 : if (s% Y(kk) > max_Y) then
895 5029 : max_Y = s% Y(kk)
896 : end if
897 : end do
898 : if (max_logT > s% burn_z_mix_region_logT &
899 69 : .and. max_Y < s% max_Y_for_burn_z_mix_region) then
900 0 : s% burn_z_mix_region(i) = .true.
901 0 : if (i > 1) s% burn_z_mix_region(i-1) = .true.
902 : !write(*,*) 'burn z mix region', i
903 : else if (max_logT > s% burn_he_mix_region_logT &
904 69 : .and. max_X < s% max_X_for_burn_he_mix_region) then
905 0 : s% burn_he_mix_region(i) = .true.
906 0 : if (i > 1) s% burn_he_mix_region(i-1) = .true.
907 : !write(*,*) 'burn he mix region', i
908 69 : else if (max_logT > s% burn_h_mix_region_logT) then
909 33 : s% burn_h_mix_region(i) = .true.
910 33 : if (i > 1) s% burn_h_mix_region(i-1) = .true.
911 : !write(*,*) 'burn h mix region', i
912 : end if
913 :
914 69 : if (k == 1) then
915 0 : s% mix_bdy_q(i) = 1
916 : else
917 : ! top of region is between k+1 and k
918 69 : s% mix_bdy_q(i) = s% q(k) - s% cz_bdy_dq(k)
919 : end if
920 69 : s% top_mix_bdy(i) = .true.
921 69 : s% mix_bdy_loc(i) = k
922 :
923 : end subroutine end_of_mixing_region
924 :
925 :
926 0 : subroutine realloc(ierr)
927 : use utils_lib
928 : integer, intent(out) :: ierr
929 :
930 : integer :: sz
931 :
932 0 : sz = size(s% mix_bdy_q, dim=1)
933 :
934 : ierr = 0
935 0 : max_mix_bdy = 2*(10+max_mix_bdy)
936 :
937 0 : call realloc_double(s% mix_bdy_q,max_mix_bdy,ierr)
938 0 : if (ierr /= 0) return
939 :
940 0 : call realloc_integer(s% mix_bdy_loc,max_mix_bdy,ierr)
941 0 : if (ierr /= 0) return
942 :
943 0 : call realloc_logical(s% top_mix_bdy,max_mix_bdy,ierr)
944 0 : if (ierr /= 0) return
945 :
946 0 : call realloc_logical(s% burn_h_mix_region,max_mix_bdy,ierr)
947 0 : if (ierr /= 0) return
948 :
949 0 : call realloc_logical(s% burn_he_mix_region,max_mix_bdy,ierr)
950 0 : if (ierr /= 0) return
951 :
952 0 : call realloc_logical(s% burn_z_mix_region,max_mix_bdy,ierr)
953 0 : if (ierr /= 0) return
954 :
955 0 : s% mix_bdy_q(sz+1:max_mix_bdy) = 0
956 0 : s% mix_bdy_loc(sz+1:max_mix_bdy) = 0
957 0 : s% top_mix_bdy(sz+1:max_mix_bdy) = .false.
958 0 : s% burn_h_mix_region(sz+1:max_mix_bdy) = .false.
959 0 : s% burn_he_mix_region(sz+1:max_mix_bdy) = .false.
960 0 : s% burn_z_mix_region(sz+1:max_mix_bdy) = .false.
961 :
962 : end subroutine realloc
963 :
964 :
965 : end subroutine locate_mixing_boundaries
966 :
967 :
968 33 : subroutine remove_tiny_mixing(s, ierr)
969 : type (star_info), pointer :: s
970 : integer, intent(out) :: ierr
971 :
972 : integer :: k, nz
973 : logical, parameter :: dbg = .false.
974 33 : real(dp) :: tiny
975 :
976 : include 'formats'
977 :
978 : if (dbg) write(*,*) 'remove_tiny_mixing'
979 :
980 33 : ierr = 0
981 33 : nz = s% nz
982 :
983 33 : tiny = s% clip_D_limit
984 40766 : do k=1,nz
985 40766 : if (s% D_mix(k) < tiny) then
986 0 : s% cdc(k) = 0
987 0 : s% D_mix(k) = 0
988 0 : s% conv_vel(k) = 0
989 0 : s% mixing_type(k) = no_mixing
990 : end if
991 : end do
992 :
993 33 : end subroutine remove_tiny_mixing
994 :
995 :
996 : ! remove single point mixing or non-mixing regions
997 : ! NOTE: does not remove thermohaline singletons
998 33 : subroutine remove_mixing_singletons(s, ierr)
999 : !use star_utils, only: scale_height
1000 : type (star_info), pointer :: s
1001 : integer, intent(out) :: ierr
1002 :
1003 : integer :: k, nz
1004 : logical, parameter :: dbg = .false.
1005 33 : real(dp) :: lambda
1006 :
1007 : include 'formats'
1008 :
1009 : if (dbg) write(*,*) 'remove_mixing_singletons'
1010 :
1011 33 : ierr = 0
1012 33 : nz = s% nz
1013 :
1014 40700 : do k=2,nz-1
1015 40700 : if (s% cdc(k) == 0) then
1016 34669 : if (s% cdc(k-1) /= 0 .and. s% cdc(k+1) /= 0) then
1017 0 : s% cdc(k) = (s% cdc(k-1) + s% cdc(k+1))/2
1018 0 : s% D_mix(k) = s% cdc(k)/pow2(pi4*s% r(k)*s% r(k)*s% rho(k))
1019 : lambda = s% alpha_mlt(k)* &
1020 0 : (s% scale_height(k-1) + s% scale_height(k+1))/2
1021 0 : s% conv_vel(k) = 3*s% D_mix(k)/lambda
1022 0 : s% mixing_type(k) = max(s% mixing_type(k-1), s% mixing_type(k+1))
1023 : if (dbg) write(*,3) 'remove radiative singleton', k, nz
1024 : end if
1025 5998 : else if (s% okay_to_remove_mixing_singleton) then
1026 5998 : if (s% cdc(k-1) == 0 .and. s% cdc(k+1) == 0) then
1027 30 : call set_use_gradr(s,k)
1028 30 : s% cdc(k) = 0
1029 30 : s% D_mix(k) = 0
1030 30 : s% conv_vel(k) = 0
1031 30 : s% mixing_type(k) = no_mixing
1032 : if (dbg) write(*,3) 'remove mixing singleton', k, nz
1033 : end if
1034 : end if
1035 : end do
1036 :
1037 33 : if (s% cdc(1) == 0) then
1038 33 : if (s% cdc(2) /= 0) then
1039 0 : s% cdc(1) = s% cdc(2)
1040 0 : s% D_mix(1) = s% D_mix(2)
1041 0 : s% conv_vel(1) = s% conv_vel(2)
1042 0 : s% mixing_type(1) = s% mixing_type(2)
1043 : if (dbg) write(*,3) 'remove radiative singleton', 1, nz
1044 : end if
1045 : else
1046 0 : if (s% cdc(2) == 0) then
1047 0 : call set_use_gradr(s,1)
1048 0 : s% cdc(1) = 0
1049 0 : s% D_mix(1) = 0
1050 0 : s% conv_vel(1) = 0
1051 0 : s% mixing_type(1) = no_mixing
1052 : if (dbg) write(*,2) 'remove mixing singleton', 1
1053 : end if
1054 : end if
1055 :
1056 33 : if (s% cdc(nz) == 0) then
1057 0 : if (s% cdc(nz-1) /= 0) then
1058 0 : s% cdc(nz) = s% cdc(nz-1)
1059 0 : s% D_mix(nz) = s% D_mix(nz-1)
1060 0 : s% conv_vel(nz) = s% conv_vel(nz-1)
1061 0 : s% mixing_type(nz) = s% mixing_type(nz-1)
1062 : if (dbg) write(*,2) 'remove radiative singleton: s% cdc(nz-1)', nz, s% cdc(nz-1)
1063 : end if
1064 : else
1065 33 : if (s% cdc(nz-1) == 0) then
1066 0 : call set_use_gradr(s,nz)
1067 0 : s% cdc(nz) = 0
1068 0 : s% D_mix(nz) = 0
1069 0 : s% conv_vel(nz) = 0
1070 0 : s% mixing_type(nz) = no_mixing
1071 : if (dbg) write(*,2) 'remove mixing singleton: s% cdc(nz)', nz, s% cdc(nz)
1072 : end if
1073 : end if
1074 :
1075 33 : end subroutine remove_mixing_singletons
1076 :
1077 :
1078 33 : subroutine close_convection_gaps(s, ierr)
1079 : type (star_info), pointer :: s
1080 : integer, intent(out) :: ierr
1081 33 : if (s% use_other_close_gaps) then
1082 0 : call s% other_close_gaps(s% id, convective_mixing, s% min_convective_gap, ierr)
1083 : else
1084 33 : call close_gaps(s, convective_mixing, s% min_convective_gap, ierr)
1085 : end if
1086 33 : end subroutine close_convection_gaps
1087 :
1088 :
1089 33 : subroutine close_thermohaline_gaps(s, ierr)
1090 : type (star_info), pointer :: s
1091 : integer, intent(out) :: ierr
1092 33 : if (s% use_other_close_gaps) then
1093 0 : call s% other_close_gaps(s% id, thermohaline_mixing, s% min_thermohaline_gap, ierr)
1094 : else
1095 33 : call close_gaps(s, thermohaline_mixing, s% min_thermohaline_gap, ierr)
1096 : end if
1097 33 : end subroutine close_thermohaline_gaps
1098 :
1099 :
1100 33 : subroutine close_semiconvection_gaps(s, ierr)
1101 : type (star_info), pointer :: s
1102 : integer, intent(out) :: ierr
1103 33 : if (s% use_other_close_gaps) then
1104 0 : call s% other_close_gaps(s% id, semiconvective_mixing, s% min_semiconvection_gap, ierr)
1105 : else
1106 33 : call close_gaps(s, semiconvective_mixing, s% min_semiconvection_gap, ierr)
1107 : end if
1108 33 : end subroutine close_semiconvection_gaps
1109 :
1110 :
1111 99 : subroutine close_gaps(s, mix_type, min_gap, ierr)
1112 : type (star_info), pointer :: s
1113 : integer, intent(in) :: mix_type
1114 : real(dp), intent(in) :: min_gap
1115 : integer, intent(out) :: ierr
1116 :
1117 : integer :: k, nz
1118 : logical :: in_region, dbg
1119 99 : real(dp) :: rtop, rbot, Hp
1120 : integer :: ktop, kbot ! k's for gap
1121 : include 'formats'
1122 :
1123 99 : dbg = .false.
1124 : !dbg = (mix_type == convective_mixing)
1125 : if (dbg) write(*,*) 'close_gaps convective_mixing'
1126 : if (dbg) write(*,3) 'mixing_type', 1152, s% mixing_type(1152)
1127 99 : ierr = 0
1128 99 : if (min_gap < 0) return
1129 0 : nz = s% nz
1130 0 : in_region = (s% mixing_type(nz) == mix_type)
1131 0 : rbot = 0
1132 0 : kbot = nz
1133 0 : do k=nz-1, 2, -1
1134 0 : if (in_region) then
1135 0 : if (s% mixing_type(k) /= mix_type) then ! end of region
1136 0 : kbot = k+1
1137 0 : rbot = s% r(kbot)
1138 0 : in_region = .false.
1139 : if (dbg) write(*,2) 'end of region', kbot, rbot
1140 : end if
1141 : else
1142 0 : if (s% mixing_type(k) == mix_type) then ! start of region
1143 0 : ktop = k
1144 0 : rtop = s% r(ktop)
1145 0 : Hp = s% Peos(ktop)/(s% rho(ktop)*s% grav(ktop))
1146 : if (dbg) write(*,2) 'start of region', ktop, rtop
1147 : if (dbg) write(*,1) 'rtop - rbot < Hp*min_gap', (rtop - rbot) - Hp*min_gap, &
1148 : rtop - rbot, Hp*min_gap, Hp, min_gap, (rtop-rbot)/Hp
1149 0 : if (rtop - rbot < Hp*min_gap) then
1150 0 : if (kbot < nz) then
1151 0 : s% cdc(ktop+1:kbot-1) = (s% cdc(ktop) + s% cdc(kbot))/2
1152 : s% D_mix(ktop+1:kbot-1) = &
1153 0 : (s% D_mix(ktop) + s% D_mix(kbot))/2
1154 0 : s% conv_vel(ktop+1:kbot-1) = (s% conv_vel(ktop) + s% conv_vel(kbot))/2
1155 0 : s% mixing_type(ktop+1:kbot-1) = mix_type
1156 : if (dbg) write(*,3) 'close mixing gap', &
1157 : ktop+1, kbot-1, (rtop - rbot)/Hp, rtop - rbot, Hp
1158 : else
1159 0 : s% cdc(ktop+1:kbot) = s% cdc(ktop)
1160 0 : s% D_mix(ktop+1:kbot) = s% D_mix(ktop)
1161 0 : s% conv_vel(ktop+1:kbot) = s% conv_vel(ktop)
1162 0 : s% mixing_type(ktop+1:kbot) = mix_type
1163 : if (dbg) write(*,3) 'close mixing gap', &
1164 : ktop+1, kbot, (rtop - rbot)/Hp, rtop - rbot, Hp
1165 : end if
1166 : end if
1167 : in_region = .true.
1168 : end if
1169 : end if
1170 : end do
1171 : if (dbg) write(*,3) 'mixing_type', 1152, s% mixing_type(1152)
1172 : if (dbg) write(*,*) 'done close_gaps'
1173 : !if (dbg) call mesa_error(__FILE__,__LINE__,'done close_gaps')
1174 :
1175 : end subroutine close_gaps
1176 :
1177 :
1178 : ! if find radiative region embedded in thermohaline,
1179 : ! and max(gradL - grada) in region is < 1d-3
1180 : ! and region height is < min_thermohaline_dropout
1181 : ! then convert the region to thermohaline
1182 33 : subroutine remove_thermohaline_dropouts(s, ierr)
1183 : type (star_info), pointer :: s
1184 : integer, intent(out) :: ierr
1185 :
1186 : integer :: k, nz, j
1187 : logical :: in_region
1188 33 : real(dp) :: rtop, rbot, Hp, q_upper, q_lower, alfa, beta
1189 : integer :: ktop, kbot ! k's for gap
1190 : logical :: all_small
1191 : logical, parameter :: dbg = .false.
1192 : include 'formats'
1193 33 : ierr = 0
1194 33 : nz = s% nz
1195 33 : rbot = s% r(nz)
1196 33 : kbot = nz-1
1197 33 : in_region = (s% mixing_type(kbot) == no_mixing)
1198 33 : all_small = .false.
1199 40667 : do k=nz-2, 2, -1
1200 40667 : if (in_region) then
1201 34666 : if (s% mixing_type(k) == no_mixing) then ! check if okay
1202 34630 : if (s% gradL(k) - s% grada_face(k) > s% max_dropout_gradL_sub_grada) &
1203 0 : all_small = .false.
1204 : else ! end of radiative region
1205 36 : ktop = k+1
1206 36 : rtop = s% r(ktop)
1207 36 : Hp = s% Peos(ktop)/(s% rho(ktop)*s% grav(ktop))
1208 36 : q_upper = s% q(ktop-1)
1209 36 : q_lower = s% q(kbot+1)
1210 : if (rtop - rbot < Hp*s% min_thermohaline_dropout .and. &
1211 : s% mixing_type(ktop-1) == thermohaline_mixing .and. &
1212 : s% mixing_type(kbot+1) == thermohaline_mixing .and. &
1213 36 : q_upper - q_lower > 1d-20 .and. all_small) then
1214 0 : do j = ktop, kbot ! interpolate in q
1215 0 : alfa = (s% q(j) - q_lower)/(q_upper - q_lower)
1216 0 : beta = 1 - alfa
1217 0 : s% cdc(j) = alfa*s% cdc(ktop-1) + beta*s% cdc(kbot+1)
1218 0 : s% D_mix(j) = alfa*s% D_mix(ktop-1) + beta*s% D_mix(kbot+1)
1219 0 : s% conv_vel(j) = alfa*s% conv_vel(ktop-1) + beta*s% conv_vel(kbot+1)
1220 0 : s% mixing_type(j) = thermohaline_mixing
1221 : end do
1222 : end if
1223 : in_region = .false.
1224 : end if
1225 : else
1226 5968 : if (s% mixing_type(k) == no_mixing) then ! start of region
1227 69 : kbot = k
1228 69 : rbot = s% r(kbot)
1229 69 : in_region = .true.
1230 : all_small = &
1231 69 : (s% gradL(k) - s% grada_face(k) <= s% max_dropout_gradL_sub_grada)
1232 : end if
1233 : end if
1234 : end do
1235 :
1236 33 : end subroutine remove_thermohaline_dropouts
1237 :
1238 :
1239 33 : subroutine remove_embedded_semiconvection(s, ierr)
1240 : type (star_info), pointer :: s
1241 : integer, intent(out) :: ierr
1242 :
1243 : integer :: k, nz
1244 : logical :: in_region
1245 : integer :: kbot, ktop
1246 :
1247 : logical, parameter :: dbg = .false.
1248 :
1249 : include 'formats'
1250 :
1251 33 : ierr = 0
1252 33 : if (.not. s% remove_embedded_semiconvection) return
1253 :
1254 0 : nz = s% nz
1255 :
1256 0 : in_region = check(nz)
1257 0 : kbot = nz
1258 0 : do k=nz-1, 2, -1
1259 0 : if (in_region) then
1260 0 : if (.not. check(k)) then ! end of region
1261 0 : ktop = k+1
1262 0 : in_region = .false.
1263 0 : call clean_region
1264 : end if
1265 : else ! not in region
1266 0 : if (check(k)) then ! start of region
1267 0 : kbot = k
1268 0 : in_region = .true.
1269 : end if
1270 : end if
1271 : end do
1272 :
1273 0 : if (in_region) then
1274 0 : ktop = 1
1275 0 : call clean_region
1276 : end if
1277 :
1278 :
1279 : contains
1280 :
1281 :
1282 0 : subroutine clean_region
1283 : integer :: kbot1, ktop1
1284 : include 'formats'
1285 : if (dbg) write(*,3) 'clean_region semiconvective', kbot, ktop
1286 : ! move top to below top convective region
1287 0 : do while (s% mixing_type(ktop) == convective_mixing)
1288 0 : ktop = ktop + 1
1289 0 : if (ktop >= kbot) return
1290 : end do
1291 : if (dbg) write(*,2) 'new ktop 1', ktop
1292 : ! move top to below top semiconvective region
1293 0 : do while (s% mixing_type(ktop) == semiconvective_mixing)
1294 0 : ktop = ktop + 1
1295 0 : if (ktop >= kbot) return
1296 : end do
1297 : if (dbg) write(*,2) 'new ktop 2', ktop
1298 : ! move bot to above bottom convective region
1299 0 : do while (s% mixing_type(kbot) == convective_mixing)
1300 0 : kbot = kbot - 1
1301 0 : if (ktop >= kbot) return
1302 : end do
1303 : if (dbg) write(*,2) 'new kbot 1', kbot
1304 : ! move bot to above bottom semiconvective region
1305 0 : do while (s% mixing_type(kbot) == semiconvective_mixing)
1306 0 : kbot = kbot - 1
1307 0 : if (ktop >= kbot) return
1308 : end do
1309 : if (dbg) write(*,2) 'new kbot 2', kbot
1310 : ! convert any semiconvective region between kbot and ktop
1311 : kbot1 = kbot
1312 0 : do while (kbot1 > ktop)
1313 : ! move kbot1 to bottom of next semiconvective region
1314 0 : do while (s% mixing_type(kbot1) == convective_mixing)
1315 0 : kbot1 = kbot1 - 1
1316 0 : if (kbot1 <= ktop) return
1317 : end do
1318 : ktop1 = kbot1
1319 : ! move ktop1 to top of semiconvective region
1320 0 : do while (s% mixing_type(ktop1) == semiconvective_mixing)
1321 0 : ktop1 = ktop1 - 1
1322 0 : if (ktop1 <= ktop) return
1323 : end do
1324 0 : s% D_mix(ktop1+1:kbot1) = s% D_mix(ktop1)
1325 0 : s% mixing_type(ktop1+1:kbot1) = convective_mixing
1326 0 : s% conv_vel(ktop1+1:kbot1) = s% conv_vel(ktop1)
1327 : if (dbg) write(*,3) 'merge semiconvective island', kbot1, ktop1+1
1328 0 : kbot1 = ktop1
1329 : end do
1330 : end subroutine clean_region
1331 :
1332 :
1333 0 : logical function check(k)
1334 : integer, intent(in) :: k
1335 : check = &
1336 : (s% mixing_type(k) == semiconvective_mixing) .or. &
1337 0 : (s% mixing_type(k) == convective_mixing)
1338 0 : end function check
1339 :
1340 : end subroutine remove_embedded_semiconvection
1341 :
1342 :
1343 33 : subroutine do_mix_envelope(s)
1344 : type (star_info), pointer :: s
1345 33 : real(dp) :: T_mix_limit
1346 : integer :: j, k, i, nz
1347 :
1348 : include 'formats'
1349 :
1350 33 : T_mix_limit = s% T_mix_limit
1351 : !write(*,1) 'T_mix_limit', T_mix_limit
1352 33 : if (T_mix_limit <= 0) return
1353 0 : nz = s% nz
1354 0 : j = 0
1355 0 : do k = 1, nz ! search inward until find T >= T_mix_limit
1356 0 : if (s% T(k) >= T_mix_limit) then
1357 : j = k; exit
1358 : end if
1359 : end do
1360 0 : if (j==0) j=nz ! all T < T_mix_limit
1361 : ! find base of innermost convection that has T < T_mix_limit
1362 0 : i = 0
1363 0 : do k = j, 1, -1
1364 0 : if (s% mixing_type(k) == convective_mixing) then
1365 : i = k; exit
1366 : end if
1367 : end do
1368 0 : if (i == 0) then
1369 : return ! no convection in region with T < T_mix_limit
1370 : end if
1371 : ! extend convection region to surface
1372 0 : j = maxloc(s% cdc(1:i), dim=1)
1373 0 : s% conv_vel(1:i) = s% conv_vel(j)
1374 0 : s% cdc(1:i) = s% cdc(j)
1375 0 : do k = 1,i
1376 0 : s% D_mix(k) = s% D_mix(j)
1377 : end do
1378 0 : s% mixing_type(1:i) = convective_mixing
1379 :
1380 : end subroutine do_mix_envelope
1381 :
1382 :
1383 11 : subroutine get_convection_sigmas(s, dt, ierr)
1384 : type (star_info), pointer :: s
1385 : real(dp), intent(in) :: dt
1386 : integer, intent(out) :: ierr
1387 :
1388 : integer :: nz, k, j, species, ktop, kbot, bdy
1389 11 : real(dp) :: sig_term_limit ! sig_term_limit is used to help convergence
1390 :
1391 11 : real(dp) :: siglim, xmstar, dq00, dqm1, cdcterm, dmavg, rho_face, &
1392 11 : cdc, max_sig, D, xm1, x00, dm, dX, X, cushion, limit, &
1393 11 : Tc, full_off, full_on, qbot, qtop, f1, f, alfa
1394 11 : real(dp), dimension(:), pointer :: sig, D_mix
1395 :
1396 : include 'formats'
1397 :
1398 11 : sig_term_limit = s% sig_term_limit
1399 :
1400 11 : ierr = 0
1401 11 : nz = s% nz
1402 11 : xmstar = s% xmstar
1403 11 : sig => s% sig
1404 11 : D_mix => s% D_mix
1405 :
1406 11 : sig(1) = 0d0
1407 13087 : do k = 2, nz
1408 13076 : D = D_mix(k)
1409 13076 : if (D == 0) then
1410 11182 : sig(k) = 0d0
1411 11182 : cycle
1412 : end if
1413 : rho_face = (s% dq(k-1)*s% rho(k) + s% dq(k)*s% rho(k-1))/ &
1414 1894 : (s% dq(k-1) + s% dq(k))
1415 1894 : f1 = pi4*s% r(k)*s% r(k)*rho_face
1416 1894 : f = f1*f1
1417 1894 : cdc = D*f
1418 1894 : cdcterm = s% mix_factor*cdc
1419 1894 : dq00 = s% dq(k)
1420 1894 : dqm1 = s% dq(k-1)
1421 1894 : dmavg = xmstar*(dq00+dqm1)/2
1422 1894 : sig(k) = cdcterm/dmavg
1423 1905 : if (is_bad_num(sig(k))) then
1424 0 : if (s% stop_for_bad_nums) then
1425 0 : write(*,2) 'sig(k)', k, sig(k)
1426 0 : call mesa_error(__FILE__,__LINE__,'get_convection_sigmas')
1427 : end if
1428 0 : sig(k) = 1d99
1429 : end if
1430 : end do
1431 :
1432 : ! can get numerical problems unless limit sig
1433 13109 : max_sig = maxval(sig(1:nz))
1434 22 : if (max_sig < 1) return
1435 13098 : do k = 1, nz
1436 13087 : s% sig_raw(k) = sig(k)
1437 13087 : if (sig(k) == 0) cycle
1438 1894 : if (k > 1) then
1439 1894 : siglim = sig_term_limit*xmstar*min(s% dq(k),s% dq(k-1))/dt
1440 : else
1441 0 : siglim = sig_term_limit*xmstar*s% dq(k)/dt
1442 : end if
1443 1905 : if (sig(k) > siglim) sig(k) = siglim
1444 : end do
1445 :
1446 11 : species = s% species
1447 : ! limit sigma to avoid negative mass fractions
1448 11 : cushion = 10d0
1449 11 : Tc = s% T(s% nz)
1450 11 : full_off = s% Tcenter_max_for_sig_min_factor_full_off
1451 11 : if (Tc <= full_off) return
1452 0 : full_on = s% Tcenter_min_for_sig_min_factor_full_on
1453 0 : limit = s% sig_min_factor_for_high_Tcenter
1454 0 : if (Tc < full_on) then
1455 0 : alfa = (Tc - full_off)/(full_on - full_off)
1456 : ! limit is full on for alfa = 1 and limit is 1 for alfa = 0
1457 0 : limit = limit*alfa + (1d0 - alfa)
1458 : end if
1459 0 : if (limit >= 1d0 .or. s% num_mix_regions == 0) return
1460 : ! boundaries are in order from center to surface
1461 : ! no bottom boundary at loc=nz included if center is mixed
1462 : ! however, do include top boundary at loc=1 if surface is mixed
1463 0 : if (s% top_mix_bdy(1)) then
1464 0 : kbot = s% nz
1465 0 : qbot = 0d0
1466 0 : bdy = 1
1467 : else
1468 0 : kbot = s% mix_bdy_loc(1)
1469 0 : qbot = s% q(kbot)
1470 0 : bdy = 2
1471 : end if
1472 0 : if (.not. s% top_mix_bdy(bdy)) then
1473 0 : call mesa_error(__FILE__,__LINE__,'bad mix bdy info 1')
1474 : end if
1475 0 : ktop = s% mix_bdy_loc(bdy)
1476 0 : qtop = s% q(ktop)
1477 0 : call do1_region
1478 11 : do while (bdy < s% num_mix_boundaries)
1479 0 : bdy = bdy+1
1480 0 : if (s% top_mix_bdy(bdy)) then
1481 0 : call mesa_error(__FILE__,__LINE__,'bad mix bdy info 2')
1482 : end if
1483 0 : kbot = s% mix_bdy_loc(bdy)
1484 0 : qbot = s% q(kbot)
1485 0 : bdy = bdy+1
1486 0 : if (.not. s% top_mix_bdy(bdy)) then
1487 0 : call mesa_error(__FILE__,__LINE__,'bad mix bdy info 3')
1488 : end if
1489 0 : ktop = s% mix_bdy_loc(bdy)
1490 0 : qtop = s% q(ktop)
1491 0 : call do1_region
1492 : end do
1493 :
1494 :
1495 : contains
1496 :
1497 :
1498 0 : subroutine do1_region
1499 0 : real(dp) :: delta_m, max_lim, alfa, beta, delta_m_upper, delta_m_lower
1500 0 : delta_m = s% m(ktop) - s% m(kbot)
1501 0 : delta_m_upper = s% delta_m_upper_for_sig_min_factor
1502 0 : delta_m_lower = s% delta_m_lower_for_sig_min_factor
1503 0 : if (delta_m >= delta_m_upper) then
1504 0 : max_lim = 1d0
1505 0 : else if (delta_m <= delta_m_lower) then
1506 0 : max_lim = limit
1507 : else
1508 0 : alfa = (delta_m - delta_m_lower)/(delta_m_upper - delta_m_lower)
1509 0 : beta = 1d0 - alfa
1510 0 : max_lim = alfa + beta*limit
1511 : end if
1512 0 : do k=max(2,ktop),kbot
1513 : call do1(k, max_lim, &
1514 0 : min(s% q(k) - qbot, qtop - s% q(k))*s% xmstar/Msun)
1515 : end do
1516 0 : end subroutine do1_region
1517 :
1518 :
1519 0 : subroutine do1(k, max_lim, delta_m_to_bdy)
1520 : integer, intent(in) :: k
1521 : real(dp), intent(in) :: max_lim, delta_m_to_bdy
1522 0 : real(dp) :: lim, max_delta_m_to_bdy
1523 : include 'formats'
1524 0 : siglim = sig(k)
1525 0 : if (siglim == 0d0) return
1526 : ! okay to increase limit up to max_lim
1527 0 : max_delta_m_to_bdy = s% max_delta_m_to_bdy_for_sig_min_factor
1528 0 : if (delta_m_to_bdy >= max_delta_m_to_bdy) return ! no change in sig
1529 0 : lim = limit + (max_lim - limit)*delta_m_to_bdy/max_delta_m_to_bdy
1530 0 : if (lim >= 1d0) return
1531 0 : do j=1,species
1532 0 : xm1 = s% xa(j,k-1)
1533 0 : x00 = s% xa(j,k)
1534 0 : if (xm1 > x00) then
1535 0 : X = xm1
1536 0 : dX = xm1 - x00
1537 0 : dm = s% dm(k-1)
1538 : else
1539 0 : X = x00
1540 0 : dX = x00 - xm1
1541 0 : dm = s% dm(k)
1542 0 : dX = -dX
1543 : end if
1544 0 : if (X < 1d-5) cycle
1545 0 : if (cushion*dt*dX*siglim > dm*X) then
1546 0 : siglim = dm*X/(dt*dX*cushion)
1547 : end if
1548 : end do
1549 0 : if (siglim > lim*sig(k)) then
1550 0 : sig(k) = siglim
1551 : else
1552 0 : sig(k) = lim*sig(k)
1553 : end if
1554 : end subroutine do1
1555 :
1556 :
1557 : end subroutine get_convection_sigmas
1558 :
1559 :
1560 0 : subroutine update_rotation_mixing_info(s, ierr)
1561 : use rotation_mix_info, only: set_rotation_mixing_info
1562 : type (star_info), pointer :: s
1563 : integer, intent(out) :: ierr
1564 :
1565 : integer :: k, nz
1566 : logical :: set_min_am_nu_non_rot, okay
1567 : real(dp) :: &
1568 0 : am_nu_visc_factor, &
1569 0 : am_nu_DSI_factor, &
1570 0 : am_nu_SH_factor, &
1571 0 : am_nu_SSI_factor, &
1572 0 : am_nu_ES_factor, &
1573 0 : am_nu_GSF_factor, &
1574 0 : am_nu_ST_factor, &
1575 0 : f, lgT, full_off, full_on, &
1576 0 : full_off_tau, full_on_tau
1577 : real(dp), dimension(:), allocatable :: & ! work vectors for tridiagonal solve
1578 0 : sig, rhs, d, du, dl, bp, vp, xp, x
1579 :
1580 : include 'formats'
1581 :
1582 0 : ierr = 0
1583 0 : nz = s% nz
1584 :
1585 0 : call set_rotation_mixing_info(s, ierr)
1586 0 : if (ierr /= 0) then
1587 0 : if (s% report_ierr) &
1588 0 : write(*,*) 'update_rotation_mixing_info failed in call to set_rotation_mixing_info'
1589 0 : return
1590 : end if
1591 :
1592 0 : call check('after set_rotation_mixing_info')
1593 0 : if (s% D_omega_flag) call check_D_omega('check_D_omega after set_rotation_mixing_info')
1594 :
1595 : ! include rotation part for mixing abundances
1596 0 : full_on = s% D_mix_rotation_max_logT_full_on
1597 0 : full_off = s% D_mix_rotation_min_logT_full_off
1598 :
1599 0 : full_on_tau = s% D_mix_rotation_min_tau_full_on
1600 0 : full_off_tau = s% D_mix_rotation_min_tau_full_off
1601 0 : do k = 2, nz
1602 : ! using tau to limit D_mix rotation in core regions
1603 0 : lgT = s% lnT(k)/ln10
1604 : if (lgT <= full_on) then
1605 0 : f = 1d0
1606 : else if (lgT >= full_off) then
1607 : f = 0d0
1608 : else ! lgT > full_on and < full_off
1609 : f = (lgT - full_on) / (full_off - full_on)
1610 : end if
1611 :
1612 : ! using tau to limit D_mix rotation in surface regions
1613 0 : if (s% tau(k) >= full_on_tau) then
1614 : f = 1d0
1615 0 : else if (s% tau(k) <= full_off_tau) then
1616 : f = 0d0
1617 : else ! tau > full_off_tau and < full_on_tau
1618 0 : f = (lgT - full_on) / (full_off - full_on)
1619 : end if
1620 :
1621 0 : if (s% D_omega_flag) then
1622 0 : s% D_mix_rotation(k) = f*s% am_D_mix_factor*s% D_omega(k)
1623 : else
1624 : s% D_mix_rotation(k) = &
1625 : f*s% am_D_mix_factor *( &
1626 : ! note: have dropped viscosity from mixing
1627 : s% D_DSI_factor * s% D_DSI(k) + &
1628 : s% D_SH_factor * s% D_SH(k) + &
1629 : s% D_SSI_factor * s% D_SSI(k) + &
1630 : s% D_ES_factor * s% D_ES(k) + &
1631 : s% D_GSF_factor * s% D_GSF(k) + &
1632 0 : s% D_ST_factor * s% D_ST(k))
1633 : end if
1634 0 : s% D_mix(k) = s% D_mix_non_rotation(k) + s% D_mix_rotation(k)
1635 : end do
1636 :
1637 0 : call check('after include rotation part for mixing abundances')
1638 :
1639 0 : am_nu_DSI_factor = s% am_nu_DSI_factor
1640 0 : am_nu_SH_factor = s% am_nu_SH_factor
1641 0 : am_nu_SSI_factor = s% am_nu_SSI_factor
1642 0 : am_nu_ES_factor = s% am_nu_ES_factor
1643 0 : am_nu_GSF_factor = s% am_nu_GSF_factor
1644 0 : am_nu_ST_factor = s% am_nu_ST_factor
1645 0 : am_nu_visc_factor = s% am_nu_visc_factor
1646 :
1647 0 : if ((.not. s% am_nu_rot_flag) .and. &
1648 : (s% D_omega_flag .and. .not. s% job% use_D_omega_for_am_nu_rot)) then
1649 : ! check for any am_nu factors > 0 and not same as for D_omega
1650 0 : okay = .true.
1651 0 : if (am_nu_DSI_factor >= 0 .and. am_nu_DSI_factor /= s% D_DSI_factor) okay = .false.
1652 0 : if (am_nu_SH_factor >= 0 .and. am_nu_SH_factor /= s% D_SH_factor) okay = .false.
1653 0 : if (am_nu_SSI_factor >= 0 .and. am_nu_SSI_factor /= s% D_SSI_factor) okay = .false.
1654 0 : if (am_nu_DSI_factor >= 0 .and. am_nu_DSI_factor /= s% D_DSI_factor) okay = .false.
1655 0 : if (am_nu_ES_factor >= 0 .and. am_nu_ES_factor /= s% D_ES_factor) okay = .false.
1656 0 : if (am_nu_GSF_factor >= 0 .and. am_nu_GSF_factor /= s% D_GSF_factor) okay = .false.
1657 0 : if (am_nu_ST_factor >= 0 .and. am_nu_ST_factor /= s% D_ST_factor) okay = .false.
1658 0 : if (.not. okay) then
1659 0 : write(*,*) 'have an am_nu factor >= 0 and not same as corresponding D_omega factor'
1660 0 : write(*,*) 'so if want smoothing like D_omega, must set am_nu_rot_flag true'
1661 0 : write(*,*) 'please fix this'
1662 0 : ierr = -1
1663 0 : return
1664 : end if
1665 : end if
1666 :
1667 : ! If am_nu_..._factor < -1, use the D_..._factor
1668 0 : if (am_nu_DSI_factor < 0) am_nu_DSI_factor = s% D_DSI_factor
1669 0 : if (am_nu_SH_factor < 0) am_nu_SH_factor = s% D_SH_factor
1670 0 : if (am_nu_SSI_factor < 0) am_nu_SSI_factor = s% D_SSI_factor
1671 0 : if (am_nu_ES_factor < 0) am_nu_ES_factor = s% D_ES_factor
1672 0 : if (am_nu_GSF_factor < 0) am_nu_GSF_factor = s% D_GSF_factor
1673 0 : if (am_nu_ST_factor < 0) am_nu_ST_factor = s% D_ST_factor
1674 0 : if (am_nu_visc_factor < 0) am_nu_visc_factor = s% D_visc_factor
1675 :
1676 : ! set set_min_am_nu_non_rot to s% set_min_am_nu_non_rot if
1677 : ! ye > min_center_ye_for_min_am_nu_non_rot
1678 : ! and s% set_min_am_nu_non_rot
1679 : set_min_am_nu_non_rot = &
1680 : s% set_min_am_nu_non_rot .and. &
1681 : s% ye(nz) >= s% min_center_Ye_for_min_am_nu_non_rot .and. &
1682 0 : (.not. s% set_uniform_am_nu_non_rot)
1683 :
1684 0 : if (s% am_nu_rot_flag) then
1685 0 : call set_am_nu_rot(ierr)
1686 0 : if (ierr /= 0) return
1687 : end if
1688 :
1689 0 : do k=1,nz
1690 0 : if (s% set_uniform_am_nu_non_rot) then
1691 0 : s% am_nu_non_rot(k) = s% uniform_am_nu_non_rot
1692 : else
1693 : s% am_nu_non_rot(k) = s% am_nu_factor* &
1694 0 : s% am_nu_non_rotation_factor*s% D_mix_non_rotation(k)
1695 : end if
1696 0 : if (set_min_am_nu_non_rot) &
1697 0 : s% am_nu_non_rot(k) = max(s% min_am_nu_non_rot, s% am_nu_non_rot(k))
1698 0 : if (s% am_nu_rot_flag) then
1699 : ! already have am_nu_rot(k) from calling set_am_nu_rot above
1700 0 : else if (s% D_omega_flag .and. s% job% use_D_omega_for_am_nu_rot) then
1701 0 : s% am_nu_rot(k) = s% am_nu_factor*s% D_omega(k)
1702 : else
1703 : s% am_nu_rot(k) = s% am_nu_factor * ( &
1704 : am_nu_visc_factor*s% D_visc(k) + &
1705 : am_nu_DSI_factor*s% D_DSI(k) + &
1706 : am_nu_SH_factor*s% D_SH(k) + &
1707 : am_nu_SSI_factor*s% D_SSI(k) + &
1708 : am_nu_ES_factor*s% D_ES(k) + &
1709 : am_nu_GSF_factor*s% D_GSF(k) + &
1710 0 : am_nu_ST_factor*s% nu_ST(k))
1711 : end if
1712 0 : if (s% am_nu_rot(k) < 0d0) s% am_nu_rot(k) = 0d0
1713 : s% am_nu_omega(k) = &
1714 : s% am_nu_omega_non_rot_factor*s% am_nu_non_rot(k) + &
1715 0 : s% am_nu_omega_rot_factor*s% am_nu_rot(k)
1716 0 : if (s% am_nu_omega(k) < 0) then
1717 0 : ierr = -1
1718 0 : if (s% report_ierr) write(*,3) &
1719 0 : 'update_rotation_mixing_info: am_nu_omega(k) < 0', k, nz, s% am_nu_omega(k), &
1720 0 : s% am_nu_non_rot(k), s% am_nu_rot(k), s% D_omega(k)
1721 0 : return
1722 : end if
1723 : s% am_nu_j(k) = &
1724 : s% am_nu_j_non_rot_factor*s% am_nu_non_rot(k) + &
1725 0 : s% am_nu_j_rot_factor*s% am_nu_rot(k)
1726 0 : if (s% am_nu_j(k) < 0) then
1727 0 : ierr = -1
1728 0 : if (s% report_ierr) write(*,3) &
1729 0 : 'update_rotation_mixing_info: am_nu_j(k) < 0', k, nz, s% am_nu_j(k), &
1730 0 : s% am_nu_non_rot(k), s% am_nu_rot(k), s% D_omega(k)
1731 0 : return
1732 : end if
1733 : end do
1734 :
1735 0 : if (s% use_other_am_mixing) then
1736 0 : call s% other_am_mixing(s% id, ierr)
1737 0 : if (ierr /= 0) return
1738 : end if
1739 :
1740 : contains
1741 :
1742 0 : subroutine check(str)
1743 : character(len=*) :: str
1744 : integer :: k
1745 : include 'formats'
1746 0 : do k = 2, s% nz
1747 0 : if (is_bad_num(s% D_mix(k))) then
1748 0 : ierr = -1
1749 0 : if (s% report_ierr) then
1750 0 : write(*,3) trim(str) // ' mixing_type, D_mix', k, s% mixing_type(k), s% D_mix(k)
1751 0 : if (s% rotation_flag) then
1752 0 : if (is_bad_num(s% D_mix_non_rotation(k))) &
1753 0 : write(*,2) 's% D_mix_non_rotation(k)', k, s% D_mix_non_rotation(k)
1754 0 : if (is_bad_num(s% D_visc(k))) write(*,2) 's% D_visc(k)', k, s% D_visc(k)
1755 0 : if (is_bad_num(s% D_DSI(k))) write(*,2) 's% D_DSI(k)', k, s% D_DSI(k)
1756 0 : if (is_bad_num(s% D_SH(k))) write(*,2) 's% D_SH(k)', k, s% D_SH(k)
1757 0 : if (is_bad_num(s% D_SSI(k))) write(*,2) 's% D_SSI(k)', k, s% D_SSI(k)
1758 0 : if (is_bad_num(s% D_ES(k))) write(*,2) 's% D_ES(k)', k, s% D_ES(k)
1759 0 : if (is_bad_num(s% D_GSF(k))) write(*,2) 's% D_GSF(k)', k, s% D_GSF(k)
1760 0 : if (is_bad_num(s% D_ST(k))) write(*,2) 's% D_ST(k)', k, s% D_ST(k)
1761 : end if
1762 : end if
1763 0 : if (s% stop_for_bad_nums) call mesa_error(__FILE__,__LINE__,'set mixing info')
1764 : end if
1765 : end do
1766 0 : end subroutine check
1767 :
1768 0 : subroutine check_D_omega(str)
1769 : character(len=*) :: str
1770 : integer :: k
1771 : include 'formats'
1772 0 : do k = 2, s% nz
1773 0 : if (is_bad_num(s% D_omega(k))) then
1774 0 : ierr = -1
1775 0 : if (s% report_ierr) then
1776 0 : write(*,3) trim(str) // ' mixing_type, D_omega', k, s% mixing_type(k), s% D_omega(k)
1777 0 : write(*,*) 's% doing_finish_load_model', s% doing_finish_load_model
1778 0 : if (s% rotation_flag) then
1779 0 : if (is_bad_num(s% D_mix_non_rotation(k))) &
1780 0 : write(*,2) 's% D_mix_non_rotation(k)', k, s% D_mix_non_rotation(k)
1781 0 : if (is_bad_num(s% D_visc(k))) write(*,2) 's% D_visc(k)', k, s% D_visc(k)
1782 0 : if (is_bad_num(s% D_DSI(k))) write(*,2) 's% D_DSI(k)', k, s% D_DSI(k)
1783 0 : if (is_bad_num(s% D_SH(k))) write(*,2) 's% D_SH(k)', k, s% D_SH(k)
1784 0 : if (is_bad_num(s% D_SSI(k))) write(*,2) 's% D_SSI(k)', k, s% D_SSI(k)
1785 0 : if (is_bad_num(s% D_ES(k))) write(*,2) 's% D_ES(k)', k, s% D_ES(k)
1786 0 : if (is_bad_num(s% D_GSF(k))) write(*,2) 's% D_GSF(k)', k, s% D_GSF(k)
1787 0 : if (is_bad_num(s% D_ST(k))) write(*,2) 's% D_ST(k)', k, s% D_ST(k)
1788 : end if
1789 : end if
1790 0 : if (s% stop_for_bad_nums) call mesa_error(__FILE__,__LINE__,'set mixing info')
1791 : end if
1792 : end do
1793 0 : end subroutine check_D_omega
1794 :
1795 0 : subroutine set_am_nu_rot(ierr)
1796 : use alloc
1797 : use rotation_mix_info, only: smooth_for_rotation
1798 : integer, intent(out) :: ierr
1799 : integer :: i, k, nz
1800 : real(dp) :: &
1801 0 : dt, rate, d_ddt_dm1, d_ddt_d00, d_ddt_dp1, m, &
1802 0 : d_dt, d_dt_in, d_dt_out, am_nu_rot_source
1803 : include 'formats'
1804 :
1805 0 : ierr = 0
1806 0 : nz = s% nz
1807 0 : dt = s% dt
1808 :
1809 0 : if (s% am_nu_rot_flag .and. s% doing_finish_load_model) then
1810 0 : do k=1,nz
1811 0 : s% am_nu_rot(k) = 0d0
1812 : end do
1813 0 : else if (s% am_nu_rot_flag) then
1814 :
1815 0 : do k=1,nz
1816 0 : if (s% q(k) <= s% max_q_for_nu_omega_zero_in_convection_region .and. &
1817 : s% mixing_type(k) == convective_mixing) then
1818 0 : s% am_nu_rot(k) = 0d0
1819 0 : cycle
1820 : end if
1821 : am_nu_rot_source = s% am_nu_factor * ( &
1822 : am_nu_visc_factor*s% D_visc(k) + &
1823 : am_nu_DSI_factor*s% D_DSI(k) + &
1824 : am_nu_SH_factor*s% D_SH(k) + &
1825 : am_nu_SSI_factor*s% D_SSI(k) + &
1826 : am_nu_ES_factor*s% D_ES(k) + &
1827 : am_nu_GSF_factor*s% D_GSF(k) + &
1828 0 : am_nu_ST_factor*s% nu_ST(k))
1829 0 : if (is_bad(am_nu_rot_source)) then
1830 0 : write(*,2) 'am_nu_rot_source', k, am_nu_rot_source
1831 0 : call mesa_error(__FILE__,__LINE__,'set am_nu_rot')
1832 : end if
1833 0 : s% am_nu_rot(k) = am_nu_rot_source
1834 0 : if (is_bad(s% am_nu_rot(k))) then
1835 0 : write(*,2) 's% am_nu_rot(k)', k, s% am_nu_rot(k)
1836 0 : write(*,2) 'am_nu_rot_source', k, am_nu_rot_source
1837 0 : call mesa_error(__FILE__,__LINE__,'set am_nu_rot')
1838 : end if
1839 : end do
1840 :
1841 0 : if (s% smooth_am_nu_rot > 0 .or. &
1842 : (s% nu_omega_mixing_rate > 0d0 .and. s% dt > 0)) then
1843 :
1844 0 : allocate(sig(nz), rhs(nz), d(nz), du(nz), dl(nz), bp(nz), vp(nz), xp(nz), x(nz))
1845 :
1846 0 : if (s% smooth_am_nu_rot > 0) then
1847 0 : call smooth_for_rotation(s, s% am_nu_rot, s% smooth_am_nu_rot, sig)
1848 : end if
1849 :
1850 0 : if (s% nu_omega_mixing_rate > 0d0 .and. s% dt > 0) then ! mix am_nu_rot
1851 :
1852 0 : rate = min(s% nu_omega_mixing_rate, 1d0/dt)
1853 0 : do k=2,nz-1
1854 0 : if (s% am_nu_rot(k) == 0 .or. s% am_nu_rot(k+1) == 0) then
1855 0 : sig(k) = 0
1856 : else if ((.not. s% nu_omega_mixing_across_convection_boundary) .and. &
1857 0 : s% mixing_type(k) /= convective_mixing .and. &
1858 : (s% mixing_type(k-1) == convective_mixing .or. &
1859 : s% mixing_type(k+1) == convective_mixing)) then
1860 0 : sig(k) = 0
1861 : else
1862 0 : sig(k) = rate*dt
1863 : end if
1864 : end do
1865 0 : sig(1) = 0
1866 0 : sig(nz) = 0
1867 :
1868 0 : do k=1,nz
1869 0 : if (k < nz) then
1870 0 : d_dt_in = sig(k)*(s% am_nu_rot(k+1) - s% am_nu_rot(k))
1871 : else
1872 0 : d_dt_in = -sig(k)*s% am_nu_rot(k)
1873 : end if
1874 0 : if (k > 1) then
1875 0 : d_dt_out = sig(k-1)*(s% am_nu_rot(k) - s% am_nu_rot(k-1))
1876 0 : d_ddt_dm1 = sig(k-1)
1877 0 : d_ddt_d00 = -(sig(k-1) + sig(k))
1878 : else
1879 0 : d_dt_out = 0
1880 0 : d_ddt_dm1 = 0
1881 0 : d_ddt_d00 = -sig(k)
1882 : end if
1883 0 : d_dt = d_dt_in - d_dt_out
1884 0 : d_ddt_dp1 = sig(k)
1885 0 : rhs(k) = d_dt
1886 0 : d(k) = 1d0 - d_ddt_d00
1887 0 : if (k < nz) then
1888 0 : du(k) = -d_ddt_dp1
1889 : else
1890 0 : du(k) = 0
1891 : end if
1892 0 : if (k > 1) dl(k-1) = -d_ddt_dm1
1893 : end do
1894 0 : dl(nz) = 0
1895 :
1896 : ! solve tridiagonal
1897 0 : bp(1) = d(1)
1898 0 : vp(1) = rhs(1)
1899 0 : do i = 2,nz
1900 0 : if (bp(i-1) == 0) then
1901 0 : write(*,*) 'failed in set_am_nu_rot', s% model_number
1902 0 : call mesa_error(__FILE__,__LINE__,'mix_am_nu_rot')
1903 0 : ierr = -1
1904 0 : return
1905 : end if
1906 0 : m = dl(i-1)/bp(i-1)
1907 0 : bp(i) = d(i) - m*du(i-1)
1908 0 : vp(i) = rhs(i) - m*vp(i-1)
1909 : end do
1910 0 : xp(nz) = vp(nz)/bp(nz)
1911 0 : x(nz) = xp(nz)
1912 0 : do i = nz-1, 1, -1
1913 0 : xp(i) = (vp(i) - du(i)*xp(i+1))/bp(i)
1914 0 : x(i) = xp(i)
1915 : end do
1916 :
1917 0 : do k=2,nz
1918 0 : if (is_bad(x(k))) then
1919 : return
1920 : write(*,3) 's% am_nu_rot(k) prev, x', k, &
1921 : s% model_number, s% am_nu_rot(k), x(k), bp(i)
1922 : call mesa_error(__FILE__,__LINE__,'mix_am_nu_rot')
1923 : end if
1924 : end do
1925 :
1926 : ! update am_nu_rot
1927 0 : do k=2,nz
1928 0 : s% am_nu_rot(k) = s% am_nu_rot(k) + x(k)
1929 0 : if (is_bad(s% am_nu_rot(k))) then
1930 0 : write(*,3) 's% am_nu_rot(k)', k, s% model_number, s% am_nu_rot(k)
1931 0 : call mesa_error(__FILE__,__LINE__,'mix_am_nu_rot')
1932 : end if
1933 0 : if (s% am_nu_rot(k) < 0d0) s% am_nu_rot(k) = 0d0
1934 : end do
1935 0 : s% am_nu_rot(1) = 0d0
1936 :
1937 : end if
1938 :
1939 : end if
1940 :
1941 : end if
1942 :
1943 0 : if (s% am_nu_rot_flag) then ! check
1944 0 : do k=1,nz
1945 0 : if (is_bad(s% am_nu_rot(k))) then
1946 0 : write(*,2) 'before return s% am_nu_rot(k)', k, s% am_nu_rot(k)
1947 0 : call mesa_error(__FILE__,__LINE__,'set_am_nu_rot')
1948 : end if
1949 0 : if (s% am_nu_rot(k) < 0d0) s% am_nu_rot(k) = 0d0
1950 : end do
1951 : end if
1952 :
1953 0 : end subroutine set_am_nu_rot
1954 :
1955 : end subroutine update_rotation_mixing_info
1956 :
1957 :
1958 0 : subroutine set_RTI_mixing_info(s, ierr)
1959 : use chem_def, only: ih1
1960 : use star_utils, only: get_shock_info
1961 : type (star_info), pointer :: s
1962 : integer, intent(out) :: ierr
1963 : real(dp) :: &
1964 0 : C, alpha_face, f, v, &
1965 0 : min_dm, alfa, cs, r, shock_mass_start, &
1966 0 : log_max_boost, m_full_boost, m_no_boost, max_boost, &
1967 0 : dm_for_center_eta_nondecreasing, min_eta
1968 : integer :: k, nz, i_h1
1969 : include 'formats'
1970 0 : ierr = 0
1971 0 : if (.not. s% RTI_flag) return
1972 :
1973 0 : nz = s% nz
1974 :
1975 0 : s% eta_RTI(1:nz) = 0d0
1976 0 : s% etamid_RTI(1:nz) = 0d0
1977 0 : s% boost_for_eta_RTI(1:nz) = 0d0
1978 0 : s% sig_RTI(1:nz) = 0d0
1979 0 : s% sigmid_RTI(1:nz) = 0d0
1980 :
1981 0 : if (s% RTI_C <= 0d0) return
1982 :
1983 0 : i_h1 = s% net_iso(ih1)
1984 :
1985 0 : shock_mass_start = 1d99
1986 0 : do k = 1, nz
1987 0 : if (s% u_flag) then
1988 0 : v = s% u(k)
1989 : else
1990 0 : v = s% v(k)
1991 : end if
1992 0 : if (v > s% csound(k)) then
1993 0 : if (k > 1) shock_mass_start = s% m(k) ! skip this after breakout
1994 : exit
1995 : end if
1996 : end do
1997 :
1998 0 : min_dm = s% RTI_min_dm_behind_shock_for_full_on*Msun
1999 0 : log_max_boost = s% RTI_log_max_boost
2000 0 : max_boost = exp10(log_max_boost)
2001 0 : m_full_boost = s% RTI_m_full_boost*Msun
2002 0 : m_no_boost = s% RTI_m_no_boost*Msun
2003 :
2004 0 : min_eta = -1d0
2005 0 : dm_for_center_eta_nondecreasing = Msun*s% RTI_dm_for_center_eta_nondecreasing
2006 :
2007 0 : do k=1,nz
2008 :
2009 0 : f = max(0d0, s% X(k) - s% RTI_C_X0_frac*s% surface_h1)
2010 0 : C = s% RTI_C*(1d0 + f*f*s% RTI_C_X_factor)
2011 :
2012 0 : if (s% m(k) < m_no_boost) then
2013 0 : if (s% m(k) <= m_full_boost) then
2014 0 : C = C*max_boost
2015 : else
2016 0 : alfa = (m_no_boost - s% m(k))/(m_no_boost - m_full_boost)
2017 0 : C = C*exp10(alfa*log_max_boost)
2018 : end if
2019 : end if
2020 :
2021 0 : if (shock_mass_start - s% m(k) < min_dm) &
2022 0 : C = C*(shock_mass_start - s% m(k))/min_dm
2023 :
2024 0 : if (k > 1) then
2025 : alpha_face = &
2026 : (s% dq(k-1)*s% alpha_RTI(k) + s% dq(k)*s% alpha_RTI(k-1))/ &
2027 0 : (s% dq(k-1) + s% dq(k))
2028 0 : cs = s% csound_face(k)
2029 0 : r = s% r(k)
2030 0 : s% eta_RTI(k) = C*alpha_face*cs*r
2031 :
2032 0 : if (is_bad(s% eta_RTI(k)) .and. s% q(k) <= s% alpha_RTI_src_max_q) then
2033 0 : ierr = -1
2034 0 : return
2035 : if (s% stop_for_bad_nums) then
2036 : write(*,2) 's% eta_RTI(k)', k, s% eta_RTI(k)
2037 : call mesa_error(__FILE__,__LINE__,'set_RTI_mixing_info')
2038 : end if
2039 : end if
2040 :
2041 0 : if (s% m(k) - s% M_center <= dm_for_center_eta_nondecreasing) then
2042 0 : if (min_eta < 0d0) then
2043 : min_eta = s% eta_RTI(k)
2044 0 : else if (min_eta > s% eta_RTI(k)) then
2045 0 : s% eta_RTI(k) = min_eta
2046 : end if
2047 : end if
2048 :
2049 : end if
2050 :
2051 0 : s% etamid_RTI(k) = max(min_eta, C*s% alpha_RTI(k)*s% csound(k)*s% rmid(k))
2052 0 : s% boost_for_eta_RTI(k) = C/s% RTI_C
2053 :
2054 0 : if (is_bad(s% etamid_RTI(k))) then
2055 0 : ierr = -1
2056 0 : return
2057 : end if
2058 :
2059 : end do
2060 :
2061 0 : call get_shock_info(s)
2062 :
2063 : ! sig_RTI(k) is mixing flow across face k in (gm sec^1)
2064 : call get_RTI_sigmas(s, s% sig_RTI, s% eta_RTI, &
2065 0 : s% rho_face, s% r, s% dm_bar, s% dt, ierr)
2066 0 : if (ierr /= 0) return
2067 :
2068 0 : if (s% v_flag) then
2069 : ! sigmid_RTI(k) is mixing flow at center k in (gm sec^1)
2070 : call get_RTI_sigmas(s, s% sigmid_RTI, s% etamid_RTI, &
2071 0 : s% rho, s% rmid, s% dm, s% dt, ierr)
2072 0 : if (ierr /= 0) return
2073 : end if
2074 :
2075 0 : end subroutine set_RTI_mixing_info
2076 :
2077 :
2078 0 : subroutine get_RTI_sigmas(s, sig, eta, rho, r, dm_bar, dt, ierr)
2079 : type (star_info), pointer :: s
2080 : real(dp), dimension(:) :: sig, eta, rho, r, dm_bar
2081 : real(dp), intent(in) :: dt
2082 : integer, intent(out) :: ierr
2083 :
2084 : integer :: nz, k
2085 0 : real(dp) :: D, f1, f, cdcterm, max_sig, &
2086 0 : siglim, sig_term_limit, xmstar
2087 :
2088 : include 'formats'
2089 :
2090 0 : ierr = 0
2091 0 : nz = s% nz
2092 0 : xmstar = s% xmstar
2093 0 : sig_term_limit = s% sig_term_limit
2094 :
2095 0 : sig(1) = 0d0
2096 0 : max_sig = 0d0
2097 0 : do k = 2, nz
2098 0 : D = eta(k)
2099 0 : if (D <= 0 .or. &
2100 : (s% q(k) > s% shock_q .and. s% shock_q > 0d0)) then
2101 0 : sig(k) = 0d0
2102 0 : cycle
2103 : end if
2104 0 : f1 = pi4*r(k)*r(k)*rho(k)
2105 0 : f = f1*f1
2106 0 : cdcterm = s% mix_factor*D*f
2107 0 : sig(k) = cdcterm/dm_bar(k)
2108 0 : if (is_bad(sig(k))) then
2109 0 : if (s% stop_for_bad_nums) then
2110 0 : write(*,2) 'sig(k)', k, sig(k)
2111 0 : call mesa_error(__FILE__,__LINE__,'get_RTI_sigmas')
2112 : end if
2113 0 : sig(k) = 1d99
2114 : end if
2115 0 : if (sig(k) > max_sig) max_sig = sig(k)
2116 : end do
2117 :
2118 0 : if (max_sig < 1) return
2119 0 : do k = 1, nz
2120 0 : if (sig(k) == 0) cycle
2121 0 : siglim = sig_term_limit*dm_bar(k)/dt
2122 0 : if (sig(k) > siglim) sig(k) = siglim
2123 : end do
2124 :
2125 0 : end subroutine get_RTI_sigmas
2126 :
2127 :
2128 0 : subroutine set_dPdr_dRhodr_info(s, ierr)
2129 : type (star_info), pointer :: s
2130 : integer, intent(out) :: ierr
2131 0 : real(dp) :: rho, r00, alfa00, beta00, &
2132 0 : dr_m1, dr_00, c, d, am1, a00, ap1, v, rmid
2133 0 : real(dp), allocatable, dimension(:) :: dPdr, drhodr, P_face, rho_face
2134 : integer :: k, nz
2135 : logical, parameter :: do_slope_limiting = .false.
2136 : include 'formats'
2137 0 : ierr = 0
2138 0 : if (.not. s% RTI_flag) return
2139 0 : if (s% dPdr_dRhodr_info(1) >= 0d0) then
2140 0 : if (is_bad(s% dPdr_dRhodr_info(1))) call mesa_error(__FILE__,__LINE__,'set_dPdr_dRhodr_info')
2141 0 : return ! already set this step
2142 : end if
2143 :
2144 0 : nz = s% nz
2145 :
2146 0 : allocate(dPdr(nz), drhodr(nz), P_face(nz), rho_face(nz))
2147 :
2148 0 : do k=2,nz
2149 0 : rho = s% rho(k)
2150 0 : r00 = s% r(k)
2151 0 : alfa00 = s% dq(k-1)/(s% dq(k-1) + s% dq(k))
2152 0 : beta00 = 1d0 - alfa00
2153 0 : P_face(k) = alfa00*s% Peos(k) + beta00*s% Peos(k-1)
2154 0 : rho_face(k) = alfa00*s% rho(k) + beta00*s% rho(k-1)
2155 : end do
2156 0 : P_face(1) = s% Peos(1)
2157 0 : rho_face(1) = s% rho(1)
2158 :
2159 0 : do k=1,nz
2160 0 : if (s% u_flag) then
2161 0 : v = s% u(k)
2162 : else
2163 0 : v = s% v(k)
2164 : end if
2165 0 : if (k == nz .or. k == 1 .or. &
2166 : (s% alpha_RTI_start(k) == 0d0 .and. &
2167 0 : v/s% csound(k) < s% alpha_RTI_src_min_v_div_cs)) then
2168 0 : drhodr(k) = 0d0
2169 0 : dPdr(k) = 0d0
2170 : else if (do_slope_limiting) then
2171 : dr_m1 = s% r(k-1) - s% r(k)
2172 : dr_00 = s% r(k) - s% r(k+1)
2173 : dPdr(k) = slope_limit(P_face, k, dr_m1, dr_00)
2174 : drhodr(k) = slope_limit(rho_face, k, dr_m1, dr_00)
2175 : else
2176 : !dr_00 = s% r(k) - s% r(k+1)
2177 0 : rmid = 0.5d0*(s% r(k) + s% r(k+1))
2178 0 : dr_00 = s% dm(k)/(pi4*rmid*rmid*s% rho(k)) ! don't subtract r's to get dr
2179 0 : dPdr(k) = (P_face(k) - P_face(k+1))/dr_00
2180 0 : drhodr(k) = (rho_face(k) - rho_face(k+1))/dr_00
2181 : end if
2182 : end do
2183 :
2184 : ! smooth dPdr and drhodr
2185 0 : if (s% RTI_smooth_mass > 0d0 .and. s% RTI_smooth_iterations > 0) then
2186 : call do_smoothing_by_mass( &
2187 0 : s, s% RTI_smooth_mass, s% RTI_smooth_iterations, drhodr, ierr)
2188 0 : if (ierr /= 0) return
2189 : call do_smoothing_by_mass( &
2190 0 : s, s% RTI_smooth_mass, s% RTI_smooth_iterations, dPdr, ierr)
2191 0 : if (ierr /= 0) return
2192 0 : else if (s% RTI_smooth_fraction < 1d0) then
2193 0 : c = s% RTI_smooth_fraction
2194 0 : d = 0.5d0*(1d0 - c)
2195 0 : am1 = 0
2196 0 : a00 = dPdr(1)
2197 0 : ap1 = dPdr(2)
2198 0 : do k=2,nz-1
2199 0 : am1 = a00
2200 0 : a00 = ap1
2201 0 : ap1 = dPdr(k+1)
2202 0 : dPdr(k) = c*a00 + d*(am1 + ap1)
2203 : end do
2204 0 : dPdr(nz) = c*a00 + 2*d*am1
2205 0 : a00 = drhodr(1)
2206 0 : ap1 = drhodr(2)
2207 0 : do k=2,nz-1
2208 0 : am1 = a00
2209 0 : a00 = ap1
2210 0 : ap1 = drhodr(k+1)
2211 0 : if (am1 == 0d0 .and. a00 == 0d0) cycle
2212 0 : drhodr(k) = c*a00 + d*(am1 + ap1)
2213 : end do
2214 0 : drhodr(nz) = c*a00 + 2*d*am1
2215 : end if
2216 :
2217 : ! set
2218 0 : do k=1,nz
2219 0 : s% dPdr_info(k) = dPdr(k)
2220 0 : s% dRhodr_info(k) = drhodr(k)
2221 0 : s% dPdr_dRhodr_info(k) = min(0d0,dPdr(k)*drhodr(k))
2222 : end do
2223 :
2224 : contains
2225 :
2226 : real(dp) function slope_limit(v, k, dr_m1, dr_00)
2227 : real(dp), intent(in) :: v(:), dr_m1, dr_00
2228 : integer, intent(in) :: k
2229 : real(dp) :: s_00, s_p1
2230 : s_00 = (v(k-1) - v(k))/dr_m1
2231 : s_p1 = (v(k) - v(k+1))/dr_00
2232 : if (s_00*s_p1 < 0d0) then
2233 : slope_limit = 0d0
2234 : else if(abs(s_00) > abs(s_p1)) then
2235 : slope_limit = s_p1
2236 : else
2237 : slope_limit = s_00
2238 : end if
2239 : end function slope_limit
2240 :
2241 : end subroutine set_dPdr_dRhodr_info
2242 :
2243 :
2244 0 : subroutine do_smoothing_by_mass( &
2245 0 : s, smooth_mass, number_iterations, val, ierr)
2246 : type (star_info), pointer :: s
2247 : real(dp), intent(in) :: smooth_mass
2248 : integer, intent(in) :: number_iterations
2249 : real(dp) :: val(:)
2250 : integer, intent(out) :: ierr
2251 : integer :: nz, iter, k_center, k_inner, k_outer, k
2252 0 : real(dp) :: mlo, mhi, mmid, smooth_m, v, dm_half, mtotal, mass_from_cell
2253 0 : real(dp), allocatable :: work(:)
2254 : include 'formats'
2255 0 : ierr = 0
2256 0 : nz = s% nz
2257 0 : allocate(work(nz))
2258 0 : do k = 1, nz
2259 0 : work(k) = val(k)
2260 : end do
2261 0 : smooth_m = smooth_mass*Msun
2262 0 : dm_half = 0.5d0*smooth_m
2263 0 : do iter = 1, number_iterations
2264 0 : do k_center = nz-1, 2, -1
2265 0 : mmid = s% m(k_center) - 0.5d0*s% dm(k_center)
2266 0 : mlo = mmid - dm_half
2267 0 : mhi = mmid + dm_half
2268 0 : k_inner = k_center
2269 0 : v = 0d0
2270 0 : mtotal = 0d0
2271 0 : do k=k_center, nz, -1
2272 0 : if (s% m(k) - 0.5d0*s% dm(k) <= mlo) then
2273 0 : k_inner = k
2274 0 : mass_from_cell = s% m(k) - mlo
2275 0 : v = v + val(k)*mass_from_cell
2276 0 : mtotal = mtotal + mass_from_cell
2277 0 : exit
2278 : end if
2279 : end do
2280 0 : k_outer = k_center
2281 0 : do k=k_center,1,-1
2282 0 : if (s% m(k) >= mhi) then
2283 0 : k_outer = k
2284 0 : mass_from_cell = mhi - (s% m(k) - s% dm(k))
2285 0 : v = v + val(k)*mass_from_cell
2286 0 : mtotal = mtotal + mass_from_cell
2287 0 : exit
2288 : end if
2289 : end do
2290 0 : do k=k_outer+1,k_inner-1
2291 0 : v = v + val(k)*s% dm(k)
2292 0 : mtotal = mtotal + s% dm(k)
2293 : end do
2294 0 : if(mtotal>0d0) then
2295 0 : work(k_center) = v/mtotal
2296 : else
2297 0 : work(k_center) = 0d0
2298 : end if
2299 : end do
2300 0 : do k = 2, nz-1
2301 0 : val(k) = work(k)
2302 : end do
2303 : end do
2304 0 : end subroutine do_smoothing_by_mass
2305 :
2306 :
2307 44 : subroutine set_dxdt_mix(s)
2308 : type (star_info), pointer :: s
2309 44 : real(dp) :: x00, xp1, xm1, dx00, dxp1, dm, sig00, sigp1, &
2310 44 : flux00, dflux00_dxm1, dflux00_dx00, &
2311 44 : fluxp1, dfluxp1_dx00, dfluxp1_dxp1
2312 : integer :: j, k
2313 : include 'formats'
2314 :
2315 52392 : do k = 1, s% nz
2316 :
2317 52348 : dm = s% dm(k)
2318 52348 : sig00 = s% sig(k)
2319 :
2320 52348 : if (k < s% nz) then
2321 52304 : sigp1 = s% sig(k+1)
2322 : else
2323 : sigp1 = 0
2324 : end if
2325 :
2326 52348 : if (k > 1) then
2327 52304 : dflux00_dxm1 = -sig00
2328 52304 : dflux00_dx00 = sig00
2329 : else
2330 : dflux00_dxm1 = 0
2331 : dflux00_dx00 = 0
2332 : end if
2333 :
2334 52348 : if (k < s% nz) then
2335 52304 : dfluxp1_dx00 = -sigp1
2336 52304 : dfluxp1_dxp1 = sigp1
2337 : else
2338 : dfluxp1_dx00 = 0
2339 : dfluxp1_dxp1 = 0
2340 : end if
2341 :
2342 52348 : s% d_dxdt_mix_dx00(k) = (dfluxp1_dx00 - dflux00_dx00)/dm
2343 52348 : s% d_dxdt_mix_dxm1(k) = -dflux00_dxm1/dm
2344 52348 : s% d_dxdt_mix_dxp1(k) = dfluxp1_dxp1/dm
2345 :
2346 :
2347 471176 : do j=1, s% species
2348 418784 : x00 = s% xa(j,k)
2349 418784 : if (k > 1) then
2350 418432 : xm1 = s% xa(j,k-1)
2351 418432 : dx00 = xm1 - x00
2352 418432 : flux00 = -sig00*dx00
2353 : else
2354 : flux00 = 0
2355 : end if
2356 418784 : if (k < s% nz) then
2357 418432 : xp1 = s% xa(j,k+1)
2358 418432 : dxp1 = x00 - xp1
2359 418432 : fluxp1 = -sigp1*dxp1
2360 : else
2361 : fluxp1 = 0
2362 : end if
2363 471132 : s% dxdt_mix(j,k) = (fluxp1 - flux00)/dm
2364 : end do
2365 :
2366 : end do
2367 :
2368 44 : end subroutine set_dxdt_mix
2369 :
2370 :
2371 :
2372 33 : subroutine add_RTI_turbulence(s, ierr)
2373 : type (star_info), pointer :: s
2374 : integer, intent(out) :: ierr
2375 :
2376 : integer :: nz, k
2377 33 : real(dp) :: coeff, D, P_face, r_face, q_face, cdc, Hp, vc, &
2378 33 : alfa, beta, rho_face, lg_coeff, full_off, full_on, min_m
2379 : logical :: dbg
2380 :
2381 : include 'formats'
2382 :
2383 33 : dbg = .false.
2384 :
2385 33 : ierr = 0
2386 33 : nz = s% nz
2387 :
2388 33 : if (.not. s% RTI_flag) return
2389 :
2390 0 : coeff = s% composition_RTI_diffusion_factor
2391 0 : if (coeff <= 0) return
2392 0 : lg_coeff = log10(coeff)
2393 0 : full_off = s% min_M_RTI_factors_full_off*Msun
2394 0 : full_on = s% max_M_RTI_factors_full_on*Msun
2395 0 : min_m = s% RTI_min_m_for_D_mix_floor*Msun
2396 0 : do k = 2, nz
2397 0 : D = s% eta_RTI(k)
2398 0 : if (s% m(k) <= full_on) then
2399 0 : D = D*coeff
2400 0 : else if (s% m(k) < full_off) then
2401 : D = D*exp10( &
2402 0 : lg_coeff*(full_off - s% m(k))/(full_off - full_on))
2403 : ! else full off, i.e., coeff = 1
2404 : end if
2405 0 : if (is_bad(D)) then
2406 0 : write(*,2) 'eta_RTI', k, D
2407 0 : if (s% stop_for_bad_nums) call mesa_error(__FILE__,__LINE__,'add_RTI_turbulence')
2408 0 : ierr = -1
2409 0 : cycle
2410 : end if
2411 0 : if (D < s% RTI_D_mix_floor .and. s% m(k) >= min_m) &
2412 0 : D = s% RTI_D_mix_floor
2413 0 : if (D > s% D_mix(k)) &
2414 0 : s% mixing_type(k) = rayleigh_taylor_mixing
2415 0 : D = D + s% D_mix(k)
2416 0 : alfa = s% dq(k-1)/(s% dq(k-1) + s% dq(k))
2417 0 : beta = 1 - alfa
2418 0 : rho_face = alfa*s% rho(k) + beta*s% rho(k-1)
2419 0 : P_face = alfa*s% Peos(k) + beta*s% Peos(k-1)
2420 0 : r_face = s% r(k)
2421 0 : q_face = s% q(k)
2422 0 : cdc = pow2(pi4*s% r(k)*s% r(k)*rho_face)*D ! gm^2/sec
2423 0 : if (s% cgrav(k) <= 0) then
2424 0 : Hp = s% r(k)
2425 : else
2426 : Hp = P_face/(rho_face*s% cgrav(k)* &
2427 0 : (s% M_center + s% xmstar*q_face)/(r_face*r_face))
2428 : end if
2429 0 : vc = 3*D/(s% alpha_mlt(k)*Hp)
2430 0 : s% cdc(k) = cdc
2431 0 : s% D_mix(k) = D
2432 0 : s% conv_vel(k) = vc
2433 : end do
2434 :
2435 : end subroutine add_RTI_turbulence
2436 :
2437 : end module mix_info
|