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 star_utils
21 :
22 : use star_private_def
23 : use const_def, only: dp, i8, pi, pi4, ln10, clight, crad, msun, rsun, lsun, one_third, four_thirds_pi
24 : use num_lib
25 : use utils_lib
26 : use auto_diff_support
27 :
28 : implicit none
29 :
30 : private
31 : public :: eval_min_cell_collapse_time
32 : public :: min_dr_div_cs
33 : public :: get_XYZ
34 : public :: lookup_nameofvar
35 : public :: start_time
36 : public :: update_time
37 : public :: foreach_cell
38 : public :: write_eos_call_info
39 : public :: eval_csound
40 : public :: eval_current_abundance
41 : public :: eval_current_z
42 : public :: eval_ledd
43 : public :: normalize_dqs
44 : public :: set_qs
45 : public :: set_m_and_dm
46 : public :: set_dm_bar
47 : public :: set_rmid
48 : public :: get_r_from_xh
49 : public :: get_r_and_lnr_from_xh
50 : public :: get_t_and_lnt_from_xh
51 : public :: get_lnt_from_xh
52 : public :: get_lnr_from_xh
53 : public :: get_rho_and_lnd_from_xh
54 : public :: store_t_in_xh
55 : public :: store_r_in_xh
56 : public :: store_rho_in_xh
57 : public :: store_lnd_in_xh
58 : public :: store_lnt_in_xh
59 : public :: cell_specific_ke
60 : public :: cell_specific_pe
61 : public :: get_phot_info
62 : public :: init_random
63 : public :: rand
64 : public :: interp_val_to_pt
65 : public :: get_log_concentration
66 : public :: get_lconv
67 : public :: get_ladv
68 : public :: get_lrad_div_ledd
69 : public :: get_lrad
70 : public :: get_ledd
71 : public :: tau_eff
72 : public :: get_rho_face_val
73 : public :: omega_crit
74 : public :: eval_cell_section_total_energy
75 : public :: conv_time_scale
76 : public :: qhse_time_scale
77 : public :: eps_nuc_time_scale
78 : public :: cooling_time_scale
79 : public :: get_face_values
80 : public :: threshold_smoothing
81 : public :: save_eqn_residual_info
82 : public :: calc_ptrb_ad_tw
83 : public :: set_energy_eqn_scal
84 : public :: get_scale_height_face_val
85 : public :: weighed_smoothing
86 : public :: get_kap_face
87 : public :: get_rho_face
88 : public :: get_chirho_face
89 : public :: get_chit_face
90 : public :: get_t_face
91 : public :: get_peos_face
92 : public :: get_cp_face
93 : public :: get_grada_face
94 : public :: get_gradr_face
95 : public :: get_scale_height_face
96 : public :: get_tau
97 : public :: after_c_burn
98 : public :: get_shock_info
99 : public :: reset_starting_vectors
100 : public :: eval_irradiation_heat
101 : public :: set_phot_info
102 : public :: set_m_grav_and_grav
103 : public :: set_scale_height
104 : public :: set_abs_du_div_cs
105 : public :: set_conv_time_scales
106 : public :: set_rv_info
107 : public :: smooth
108 : public :: safe_div_val
109 : public :: center_avg_x
110 : public :: surface_avg_x
111 : public :: get_remnant_mass
112 : public :: get_ejecta_mass
113 : public :: get_phi_joss
114 : public :: center_value
115 : public :: eval_kh_timescale
116 : public :: k_for_q
117 : public :: total_angular_momentum
118 : public :: reset_epsnuc_vectors
119 : public :: yrs_for_init_timestep
120 : public :: set_phase_of_evolution
121 : public :: get_string_for_model_number
122 : public :: e00
123 : public :: em1
124 : public :: ep1
125 : public :: store_partials
126 : public :: save_eqn_dxa_partials
127 : public :: unpack_residual_partials
128 : public :: get_area_info_opt_time_center
129 : public :: calc_ptot_ad_tw
130 : public :: get_face_weights
131 : public :: get_dke_dt_dpe_dt
132 : public :: get_pvsc_ad
133 : public :: show_matrix
134 : public :: no_extra_profile_columns
135 : public :: no_data_for_extra_profile_columns
136 : public :: total_times
137 : public :: current_min_xa_hard_limit
138 : public :: current_sum_xa_hard_limit
139 : public :: lookup_nameofequ
140 : public :: eval_total_energy_integrals
141 : public :: set_luminosity_by_category
142 : public :: eval_deltam_total_energy_integrals
143 : public :: report_xa_bad_nums
144 : public :: eval_current_y
145 : public :: get_name_for_restart_file
146 : public :: eval_integrated_total_energy_profile
147 : public :: use_xh_to_set_rho_to_dm_div_dv
148 : public :: cell_specific_total_energy
149 : public :: store_lnr_in_xh
150 : public :: interp_q
151 : public :: set_zero_alpha_rti
152 : public :: after_he_burn
153 : public :: interp_xa_to_pt
154 : public :: set_xqs
155 : public :: get_tau_at_r
156 : public :: smooth_abundances
157 : public :: do_boxcar_mixing
158 : public :: eval_total_energy_profile
159 : public :: get_delta_pg_traditional
160 : public :: get_delta_pg_bildsten2012
161 : public :: write_to_extra_terminal_output_file
162 :
163 : logical, parameter :: mdb = .false.
164 :
165 : contains
166 :
167 66 : subroutine foreach_cell(s,nzlo,nzhi,use_omp,do1,ierr)
168 : type (star_info), pointer :: s
169 : integer, intent(in) :: nzlo, nzhi
170 : logical, intent(in) :: use_omp
171 : interface
172 : subroutine do1(s,k,ierr)
173 : use star_private_def
174 : implicit none
175 : type (star_info), pointer :: s
176 : integer, intent(in) :: k
177 : integer, intent(out) :: ierr
178 : end subroutine do1
179 : end interface
180 : integer, intent(out) :: ierr
181 :
182 : integer :: k, op_err
183 : logical :: okay
184 66 : ierr = 0
185 :
186 66 : if (nzlo == nzhi) then
187 0 : call do1(s,nzlo,ierr)
188 0 : return
189 : end if
190 :
191 66 : if (use_omp) then
192 66 : okay = .true.
193 66 : !$OMP PARALLEL DO PRIVATE(k,op_err) SCHEDULE(dynamic,2)
194 : do k = nzlo, nzhi
195 : if (.not. okay) cycle
196 : op_err = 0
197 : call do1(s,k,op_err)
198 : if (op_err /= 0) okay = .false. ! cannot just exit from a parallel loop
199 : end do
200 : !$OMP END PARALLEL DO
201 66 : if (.not. okay) ierr = -1
202 : else
203 0 : do k = nzlo, nzhi
204 0 : call do1(s,k,ierr)
205 0 : if (ierr /= 0) exit
206 : end do
207 : end if
208 :
209 : end subroutine foreach_cell
210 :
211 :
212 0 : subroutine get_average_Y_and_Z(s, nzlo, nzhi, y_avg, z_avg, ierr)
213 : use chem_def
214 : type (star_info), pointer :: s
215 : integer, intent(in) :: nzlo, nzhi
216 : real(dp), intent(out) :: y_avg, z_avg
217 : integer, intent(out) :: ierr
218 : integer :: k, nz, h1, h2, he3, he4
219 0 : real(dp) :: total_mass_h, total_mass_he, total_mass_z, cell_mass, total_mass
220 0 : ierr = 0
221 0 : nz = s% nz
222 0 : h1 = s% net_iso(ih1)
223 0 : h2 = s% net_iso(ih2)
224 0 : he3 = s% net_iso(ihe3)
225 0 : he4 = s% net_iso(ihe4)
226 0 : total_mass=0; total_mass_h=0; total_mass_he=0; total_mass_z=0
227 0 : do k=nzlo, nzhi
228 0 : cell_mass = s% dm(k)
229 0 : total_mass = total_mass + cell_mass
230 0 : total_mass_h = total_mass_h + cell_mass*s% xa(h1, k)
231 0 : if (h2 /= 0) total_mass_h = total_mass_h + cell_mass*s% xa(h2, k)
232 0 : total_mass_he = total_mass_he + cell_mass*s% xa(he4, k)
233 0 : if (he3 /= 0) total_mass_he = total_mass_he + cell_mass*s% xa(he3, k)
234 : end do
235 0 : total_mass_z = total_mass - (total_mass_h + total_mass_he)
236 0 : z_avg = total_mass_z / total_mass
237 0 : y_avg = total_mass_he / total_mass
238 0 : end subroutine get_average_Y_and_Z
239 :
240 :
241 0 : real(dp) function eval_current_y(s, nzlo, nzhi, ierr)
242 : type (star_info), pointer :: s
243 : integer, intent(in) :: nzlo, nzhi
244 : integer, intent(out) :: ierr
245 : real(dp) :: y_avg, z_avg
246 0 : call get_average_Y_and_Z(s, nzlo, nzhi, y_avg, z_avg, ierr)
247 0 : eval_current_y = y_avg
248 0 : end function eval_current_y
249 :
250 :
251 0 : real(dp) function eval_current_z(s, nzlo, nzhi, ierr)
252 : type (star_info), pointer :: s
253 : integer, intent(in) :: nzlo, nzhi
254 : integer, intent(out) :: ierr
255 : real(dp) :: y_avg, z_avg
256 0 : call get_average_Y_and_Z(s, nzlo, nzhi, y_avg, z_avg, ierr)
257 0 : eval_current_z = z_avg
258 0 : end function eval_current_z
259 :
260 :
261 11 : real(dp) function eval_current_abundance(s, j, nzlo, nzhi, ierr)
262 : type (star_info), pointer :: s
263 : integer, intent(in) :: j, nzlo, nzhi
264 : integer, intent(out) :: ierr
265 : integer :: k, nz
266 11 : real(dp) :: cell_mass, jmass, total_mass
267 :
268 11 : ierr = 0
269 :
270 11 : if (j == 0) then
271 11 : eval_current_abundance = 0
272 : return
273 : end if
274 :
275 11 : nz = s% nz
276 11 : total_mass=0; jmass=0
277 22 : do k=nzlo, nzhi
278 11 : cell_mass = s% dm(k)
279 11 : total_mass = total_mass + cell_mass
280 22 : jmass = jmass + cell_mass*s% xa(j, k)
281 : end do
282 11 : eval_current_abundance = jmass / total_mass
283 :
284 11 : end function eval_current_abundance
285 :
286 :
287 0 : subroutine smooth_abundances(s, cnt, nzlo, nzhi, ierr)
288 : type (star_info), pointer :: s
289 : integer, intent(in) :: cnt ! make this many passes
290 : integer, intent(in) :: nzlo, nzhi ! only smooth zones nzlo to nzhi inclusive
291 : integer, intent(out) :: ierr
292 : integer :: k, j, nz
293 0 : ierr = 0
294 0 : nz = s% nz
295 0 : do j = 1, cnt
296 0 : do k = max(nzlo,2), min(nzhi, nz)
297 0 : s% xa(:,k) = (s% xa(:,k-1) + s% xa(:,k) + s% xa(:,k+1))/3
298 : end do
299 0 : if (nzhi == nz) s% xa(:,nz) = (s% xa(:,nz-1) + s% xa(:,nz) + s% xa(:,nz))/3
300 0 : if (nzlo == 1) s% xa(:,1) = (s% xa(:,2) + s% xa(:,1) + s% xa(:,1))/3
301 : end do
302 0 : s% need_to_setvars = .true.
303 0 : end subroutine smooth_abundances
304 :
305 :
306 0 : integer function k_for_q(s, q)
307 : ! return k s.t. q(k) >= q > q(k)-dq(k)
308 : type (star_info), pointer :: s
309 : real(dp), intent(in) :: q
310 : integer :: k, nz
311 0 : nz = s% nz
312 0 : if (q >= 1) then
313 0 : k_for_q = 1; return
314 0 : else if (q <= s% q(nz)) then
315 0 : k_for_q = nz; return
316 : end if
317 0 : do k = 1, nz-1
318 0 : if (q > s% q(k+1)) then
319 0 : k_for_q = k; return
320 : end if
321 : end do
322 0 : k_for_q = nz
323 : end function k_for_q
324 :
325 :
326 1 : subroutine get_name_for_restart_file(n, num_digits, num)
327 : integer, intent(in) :: n, num_digits
328 : character (len=*), intent(out) :: num
329 1 : call get_string_for_model_number('x', n, num_digits, num)
330 1 : end subroutine get_name_for_restart_file
331 :
332 :
333 1 : subroutine get_string_for_model_number(prefix, n, num_digits, num)
334 : character (len=*), intent(in) :: prefix
335 : integer, intent(in) :: n, num_digits
336 : character (len=*), intent(out) :: num
337 : integer :: val
338 : character (len=32) :: fstring
339 : include 'formats'
340 1 : val = mod(n, 10**num_digits) ! wrap around
341 1 : if (val == 0) then
342 0 : write(num,*) n
343 0 : num = adjustl(num)
344 0 : return
345 : end if
346 1 : write(fstring,'( "(a,i",i2.2,".",i2.2,")" )') num_digits, num_digits
347 1 : write(num,fstring) trim(prefix), val
348 1 : end subroutine get_string_for_model_number
349 :
350 :
351 0 : subroutine report_xa_bad_nums(s,ierr)
352 : type (star_info), pointer :: s
353 : integer, intent(out) :: ierr
354 : integer :: k, j
355 0 : ierr = 0
356 0 : do k=1,s% nz
357 0 : do j=1,s% species
358 0 : if (is_bad(s% xa(j,k))) then
359 0 : ierr = -1
360 0 : write(*,*) j, k, s% xa(j,k)
361 : end if
362 : end do
363 : end do
364 0 : end subroutine report_xa_bad_nums
365 :
366 :
367 79998 : real(dp) function eval_csound(s,k,ierr) result(cs)
368 : type (star_info), pointer :: s
369 : integer, intent(in) :: k
370 : integer, intent(out) :: ierr
371 79998 : real(dp) :: cs2
372 : include 'formats'
373 79998 : ierr = 0
374 79998 : cs2 = s% gamma1(k)*s% Peos(k)/s% rho(k)
375 79998 : if (cs2 < 0d0) then
376 0 : cs = 0d0
377 0 : ierr = -1
378 0 : return
379 : end if
380 79998 : cs = sqrt(cs2)
381 79998 : end function eval_csound
382 :
383 :
384 55 : subroutine set_m_grav_and_grav(s) ! using mass_corrections
385 : type (star_info), pointer :: s
386 55 : real(dp) :: r, lnR
387 : integer :: k, nz
388 : include 'formats'
389 55 : nz = s% nz
390 55 : if (.not. s% use_mass_corrections) then
391 66962 : do k=1,nz
392 66962 : s% m_grav(k) = s% m(k)
393 : end do
394 : else
395 : s% m_grav(nz) = &
396 0 : s% M_center + s% dm(nz)*s% mass_correction(nz)
397 0 : do k=nz-1,1,-1
398 : s% m_grav(k) = &
399 0 : s% m_grav(k+1) + s% dm(k)*s% mass_correction(k)
400 : end do
401 : end if
402 66962 : do k=1,nz
403 : ! We need to call set_m_grav_and_grav during model loading before we have set all vars
404 66907 : call get_r_and_lnR_from_xh(s, k, r, lnR)
405 66962 : s% grav(k) = s% cgrav(k)*s% m_grav(k)/(r*r)
406 : end do
407 55 : end subroutine set_m_grav_and_grav
408 :
409 :
410 66907 : subroutine get_r_and_lnR_from_xh(s, k, r, lnR, xh_in)
411 : type (star_info), pointer :: s
412 : integer, intent(in) :: k
413 : real(dp), intent(out) :: r, lnR
414 : real(dp), intent(in), pointer, optional :: xh_in(:,:)
415 66907 : real(dp), pointer :: xh(:,:)
416 66907 : if (present(xh_in)) then
417 0 : xh => xh_in
418 : else
419 66907 : xh => s% xh
420 : end if
421 66907 : lnR = xh(s% i_lnR,k)
422 66907 : r = exp(lnR)
423 66907 : end subroutine get_r_and_lnR_from_xh
424 :
425 :
426 14559 : real(dp) function get_r_from_xh(s, k, xh_in) result(r)
427 : type (star_info), pointer :: s
428 : integer, intent(in) :: k
429 : real(dp), intent(in), pointer, optional :: xh_in(:,:)
430 14559 : real(dp), pointer :: xh(:,:)
431 14559 : if (present(xh_in)) then
432 0 : xh => xh_in
433 : else
434 14559 : xh => s% xh
435 : end if
436 14559 : r = exp(xh(s% i_lnR,k))
437 14559 : end function get_r_from_xh
438 :
439 :
440 0 : real(dp) function get_lnR_from_xh(s, k, xh_in) result(lnR)
441 : type (star_info), pointer :: s
442 : integer, intent(in) :: k
443 : real(dp), intent(in), pointer, optional :: xh_in(:,:)
444 0 : real(dp), pointer :: xh(:,:)
445 0 : if (present(xh_in)) then
446 0 : xh => xh_in
447 : else
448 0 : xh => s% xh
449 : end if
450 0 : lnR = xh(s% i_lnR,k)
451 0 : end function get_lnR_from_xh
452 :
453 1436 : subroutine store_r_in_xh(s, k, r, xh_in)
454 : type (star_info), pointer :: s
455 : integer, intent(in) :: k
456 : real(dp), intent(in) :: r
457 : real(dp), intent(in), pointer, optional :: xh_in(:,:)
458 1436 : real(dp), pointer :: xh(:,:)
459 1436 : if (present(xh_in)) then
460 1436 : xh => xh_in
461 : else
462 0 : xh => s% xh
463 : end if
464 1436 : xh(s% i_lnR,k) = log(r)
465 1436 : end subroutine store_r_in_xh
466 :
467 :
468 0 : subroutine store_lnR_in_xh(s, k, lnR, xh_in)
469 : type (star_info), pointer :: s
470 : integer, intent(in) :: k
471 : real(dp), intent(in) :: lnR
472 : real(dp), intent(in), pointer, optional :: xh_in(:,:)
473 0 : real(dp), pointer :: xh(:,:)
474 0 : if (present(xh_in)) then
475 0 : xh => xh_in
476 : else
477 0 : xh => s% xh
478 : end if
479 0 : xh(s% i_lnR,k) = lnR
480 0 : end subroutine store_lnR_in_xh
481 :
482 :
483 0 : subroutine get_T_and_lnT_from_xh(s, k, T, lnT, xh_in)
484 : type (star_info), pointer :: s
485 : integer, intent(in) :: k
486 : real(dp), intent(out) :: T, lnT
487 : real(dp), intent(in), pointer, optional :: xh_in(:,:)
488 0 : real(dp), pointer :: xh(:,:)
489 0 : if (present(xh_in)) then
490 0 : xh => xh_in
491 : else
492 0 : xh => s% xh
493 : end if
494 0 : lnT = xh(s% i_lnT,k)
495 0 : T = exp(lnT)
496 0 : end subroutine get_T_and_lnT_from_xh
497 :
498 :
499 : real(dp) function get_T_from_xh(s, k, xh_in) result(T)
500 : type (star_info), pointer :: s
501 : integer, intent(in) :: k
502 : real(dp), intent(in), pointer, optional :: xh_in(:,:)
503 : real(dp), pointer :: xh(:,:)
504 : if (present(xh_in)) then
505 : xh => xh_in
506 : else
507 : xh => s% xh
508 : end if
509 : T = exp(xh(s% i_lnT,k))
510 : end function get_T_from_xh
511 :
512 :
513 0 : real(dp) function get_lnT_from_xh(s, k, xh_in) result(lnT)
514 : type (star_info), pointer :: s
515 : integer, intent(in) :: k
516 : real(dp), intent(in), pointer, optional :: xh_in(:,:)
517 0 : real(dp), pointer :: xh(:,:)
518 0 : if (present(xh_in)) then
519 0 : xh => xh_in
520 : else
521 0 : xh => s% xh
522 : end if
523 0 : lnT = xh(s% i_lnT,k)
524 0 : end function get_lnT_from_xh
525 :
526 :
527 0 : subroutine store_T_in_xh(s, k, T, xh_in)
528 : type (star_info), pointer :: s
529 : integer, intent(in) :: k
530 : real(dp), intent(in) :: T
531 : real(dp), intent(in), pointer, optional :: xh_in(:,:)
532 0 : real(dp), pointer :: xh(:,:)
533 0 : if (present(xh_in)) then
534 0 : xh => xh_in
535 : else
536 0 : xh => s% xh
537 : end if
538 0 : xh(s% i_lnT,k) = log(T)
539 0 : end subroutine store_T_in_xh
540 :
541 :
542 1472 : subroutine store_lnT_in_xh(s, k, lnT, xh_in)
543 : type (star_info), pointer :: s
544 : integer, intent(in) :: k
545 : real(dp), intent(in) :: lnT
546 : real(dp), intent(in), pointer, optional :: xh_in(:,:)
547 1472 : real(dp), pointer :: xh(:,:)
548 1472 : if (present(xh_in)) then
549 1472 : xh => xh_in
550 : else
551 0 : xh => s% xh
552 : end if
553 1472 : xh(s% i_lnT,k) = lnT
554 1472 : end subroutine store_lnT_in_xh
555 :
556 :
557 0 : subroutine get_rho_and_lnd_from_xh(s, k, rho, lnd, xh_in)
558 : type (star_info), pointer :: s
559 : integer, intent(in) :: k
560 : real(dp), intent(out) :: rho, lnd
561 : real(dp), intent(in), pointer, optional :: xh_in(:,:)
562 0 : real(dp), pointer :: xh(:,:)
563 0 : if (present(xh_in)) then
564 0 : xh => xh_in
565 : else
566 0 : xh => s% xh
567 : end if
568 0 : lnd = xh(s% i_lnd,k)
569 0 : rho = exp(lnd)
570 0 : end subroutine get_rho_and_lnd_from_xh
571 :
572 :
573 17507 : subroutine store_rho_in_xh(s, k, rho, xh_in)
574 : type (star_info), pointer :: s
575 : integer, intent(in) :: k
576 : real(dp), intent(in) :: rho
577 : real(dp), intent(in), pointer, optional :: xh_in(:,:)
578 17507 : real(dp), pointer :: xh(:,:)
579 17507 : if (present(xh_in)) then
580 2948 : xh => xh_in
581 : else
582 14559 : xh => s% xh
583 : end if
584 17507 : xh(s% i_lnd,k) = log(rho)
585 17507 : end subroutine store_rho_in_xh
586 :
587 :
588 493 : subroutine store_lnd_in_xh(s, k, lnd, xh_in)
589 : type (star_info), pointer :: s
590 : integer, intent(in) :: k
591 : real(dp), intent(in) :: lnd
592 : real(dp), intent(in), pointer, optional :: xh_in(:,:)
593 493 : real(dp), pointer :: xh(:,:)
594 493 : if (present(xh_in)) then
595 493 : xh => xh_in
596 : else
597 0 : xh => s% xh
598 : end if
599 493 : xh(s% i_lnd,k) = lnd
600 493 : end subroutine store_lnd_in_xh
601 :
602 :
603 11 : subroutine use_xh_to_set_rho_to_dm_div_dV(s, ierr)
604 : type (star_info), pointer :: s
605 : integer, intent(out) :: ierr
606 : integer :: k, nz, i_lnR, i_lnd
607 11 : real(dp) :: rL, rR, dm, dV, rho
608 : include 'formats'
609 11 : ierr = 0
610 11 : i_lnR = s% i_lnR
611 11 : i_lnd = s% i_lnd
612 11 : if (i_lnd == 0 .or. i_lnR == 0) return
613 11 : nz = s% nz
614 11 : rR = s% R_center
615 14570 : do k = nz, 1, -1
616 14559 : rL = rR
617 14559 : rR = get_r_from_xh(s,k)
618 14559 : dm = s% dm(k)
619 14559 : dV = four_thirds_pi*(rR*rR*rR - rL*rL*rL)
620 14559 : rho = dm/dV
621 14559 : if (rho <= 0d0) then
622 0 : write(*,3) 'set_rho_to_dm_div_dV: rho <= 0', &
623 0 : k, nz, rho, dm, dV, rR, rL
624 0 : ierr = -1
625 0 : return
626 : end if
627 14570 : call store_rho_in_xh(s, k, rho)
628 : end do
629 : end subroutine use_xh_to_set_rho_to_dm_div_dV
630 :
631 :
632 66 : subroutine set_m_and_dm(s)
633 : type (star_info), pointer :: s
634 : integer :: k
635 : include 'formats'
636 81532 : do k = 1, s% nz
637 81466 : s% m(k) = s% M_center + s% q(k)*s% xmstar
638 81466 : s% dm(k) = s% dq(k)*s% xmstar
639 81532 : if (s% dm(k) <= 0d0 .or. is_bad(s% m(k) + s% dm(k))) then
640 0 : write(*,2) 'dm m dq q M_center', k, &
641 0 : s% dm(k), s% m(k), s% dq(k), s% q(k), s% M_center
642 0 : if (s% stop_for_bad_nums) call mesa_error(__FILE__,__LINE__,'set_m_and_dm')
643 : end if
644 : end do
645 66 : end subroutine set_m_and_dm
646 :
647 :
648 66 : subroutine set_dm_bar(s, nz, dm, dm_bar)
649 : type (star_info), pointer :: s
650 : integer, intent(in) :: nz
651 : real(dp), intent(in) :: dm(:) ! (nz)
652 : real(dp), intent(inout) :: dm_bar(:) ! (nz)
653 : integer :: k
654 81400 : do k=2,nz-1
655 81400 : dm_bar(k) = 0.5d0*(dm(k-1) + dm(k))
656 : end do
657 66 : dm_bar(1) = 0.5d0*dm(1)
658 66 : if (s% rsp_flag .or. s% RSP2_flag) then ! rsp and RSP2 use this definition
659 0 : dm_bar(nz) = 0.5d0*(dm(nz-1) + dm(nz))
660 : else
661 66 : dm_bar(nz) = 0.5d0*dm(nz-1) + dm(nz)
662 : end if
663 66 : end subroutine set_dm_bar
664 :
665 :
666 0 : subroutine normalize_dqs(s, nz, dq, ierr)
667 : ! rescale dq's so that add to 1.000
668 : ! work in from boundaries to meet at largest dq
669 : type (star_info), pointer :: s
670 : integer, intent(in) :: nz
671 : real(dp), intent(inout) :: dq(:) ! (nz)
672 : integer, intent(out) :: ierr
673 : integer :: k, midq
674 0 : real(dp) :: dqsum1, dqsum2, dq_min
675 : include 'formats'
676 0 : k = minloc(dq(1:nz),dim=1)
677 0 : dq_min = dq(k)
678 0 : if (dq_min <= 0d0) then
679 0 : write(*,2) 'bad dq', k, dq(k)
680 0 : ierr = -1
681 0 : stop
682 0 : return
683 : end if
684 0 : midq = maxloc(dq(1:nz),dim=1)
685 : ! surface inward
686 0 : dqsum1 = 0
687 0 : do k=1, midq
688 0 : dqsum1 = dqsum1 + dq(k)
689 0 : if (dq(k) <= 0) then
690 0 : ierr = -1
691 0 : return
692 : end if
693 : end do
694 : ! center outward
695 0 : dqsum2 = 0
696 0 : do k=nz, midq+1, -1
697 0 : dqsum2 = dqsum2 + dq(k)
698 0 : if (dq(k) <= 0) then
699 0 : ierr = -1
700 0 : return
701 : end if
702 : end do
703 0 : do k=1,nz
704 0 : dq(k) = dq(k)/(dqsum1 + dqsum2)
705 : end do
706 : end subroutine normalize_dqs
707 :
708 :
709 68 : subroutine set_qs(s, nz, q, dq, ierr) ! set q's using normalized dq's
710 : type (star_info), pointer :: s
711 : integer, intent(in) :: nz
712 : real(dp), intent(inout) :: dq(:) ! (nz)
713 : real(dp), intent(inout) :: q(:) ! (nz)
714 : integer, intent(out) :: ierr
715 : integer :: k, midq
716 68 : real(dp) :: dqsum1, dqsum2
717 : logical :: okay
718 : include 'formats'
719 68 : ierr = 0
720 : ! normalize_dqs destroys bit-for-bit read as inverse of write for models.
721 : ! ok for create pre ms etc., but not for read model
722 68 : if (s% do_normalize_dqs_as_part_of_set_qs) then
723 0 : call normalize_dqs(s, nz, dq, ierr)
724 0 : if (ierr /= 0) return
725 : end if
726 68 : q(1) = 1d0
727 68 : okay = .true.
728 86396 : do k=2,nz
729 86328 : q(k) = q(k-1) - dq(k-1)
730 86396 : if (q(k) < 0d0 .or. q(k) > 1d0) then
731 : okay = .false.
732 : exit
733 : end if
734 : end do
735 68 : if (okay) return
736 0 : midq = maxloc(dq(1:nz),dim=1)
737 : ! surface inward
738 0 : dqsum1 = 0
739 0 : do k=1, midq
740 0 : q(k) = 1d0 - dqsum1
741 0 : dqsum1 = dqsum1 + dq(k)
742 : end do
743 : ! center outward
744 : dqsum2 = 0
745 0 : do k=nz, midq+1, -1
746 0 : dqsum2 = dqsum2 + dq(k)
747 0 : q(k) = dqsum2
748 : end do
749 : end subroutine set_qs
750 :
751 :
752 20 : subroutine set_xqs(nz, xq, dq, ierr) ! set xq's using dq's
753 : integer, intent(in) :: nz
754 : real(dp), intent(inout) :: dq(:) ! (nz)
755 : real(dp), intent(inout) :: xq(:) ! (nz)
756 : integer, intent(out) :: ierr
757 : integer :: k
758 : include 'formats'
759 20 : ierr = 0
760 20 : xq(1) = 0
761 22698 : do k=2,nz-1
762 22698 : xq(k) = xq(k-1) + dq(k-1)
763 : end do
764 20 : xq(nz) = 1 - dq(nz)
765 20 : if (xq(nz) < xq(nz-1)) then
766 0 : xq(nz) = xq(nz-1) + dq(nz-1)
767 0 : dq(nz) = 1 - xq(nz)
768 0 : if (dq(nz) <= 0) then
769 0 : ierr = -1
770 0 : return
771 : end if
772 : end if
773 : end subroutine set_xqs
774 :
775 :
776 0 : real(dp) function interp_val_to_pt(v,k,sz,dq,str)
777 : use interp_1d_lib, only: interp_4_to_1
778 : integer, intent(in) :: k, sz
779 : real(dp), intent(in) :: v(:), dq(:)
780 : character (len=*), intent(in) :: str
781 : integer :: ierr
782 : include 'formats'
783 0 : if (k == 1) then
784 0 : interp_val_to_pt = v(k)
785 0 : return
786 : end if
787 0 : if (k > 2 .and. k < sz) then
788 : ierr = 0
789 : call interp_4_to_1( &
790 : 0.5d0*(dq(k-2)+dq(k-1)), &
791 : 0.5d0*(dq(k-1)+dq(k)), &
792 : 0.5d0*(dq(k)+dq(k+1)), &
793 : 0.5d0*dq(k-2)+dq(k-1), &
794 : v(k-2), v(k-1), v(k), v(k+1), &
795 0 : interp_val_to_pt, str, ierr)
796 0 : if (ierr == 0) return
797 0 : write(*,1) '0.5d0*(dq(k-2)+dq(k-1))', 0.5d0*(dq(k-2)+dq(k-1))
798 0 : write(*,1) '0.5d0*(dq(k-1)+dq(k))', 0.5d0*(dq(k-1)+dq(k))
799 0 : write(*,1) '0.5d0*(dq(k)+dq(k+1))', 0.5d0*(dq(k)+dq(k+1))
800 0 : write(*,2) 'dq(k-2)', k-2, dq(k-2)
801 0 : write(*,2) 'dq(k-1)', k-1, dq(k-1)
802 0 : write(*,2) 'dq(k)', k, dq(k)
803 0 : write(*,2) 'dq(k+1)', k+1, dq(k+1)
804 :
805 0 : call mesa_error(__FILE__,__LINE__,'interp_val_to_pt')
806 : end if
807 0 : interp_val_to_pt = (v(k)*dq(k-1) + v(k-1)*dq(k))/(dq(k-1) + dq(k))
808 0 : end function interp_val_to_pt
809 :
810 :
811 0 : real(dp) function interp_xa_to_pt(xa,j,k,sz,dq,str)
812 0 : use interp_1d_lib, only: interp_4_to_1
813 : real(dp), intent(in) :: xa(:,:), dq(:)
814 : character (len=*), intent(in) :: str
815 : integer, intent(in) :: j, k, sz
816 : integer :: ierr
817 : include 'formats'
818 0 : if (j == 0) then
819 : interp_xa_to_pt = 0
820 : return
821 : end if
822 0 : if (k == 1) then
823 0 : interp_xa_to_pt = xa(j,k)
824 0 : return
825 : end if
826 0 : if (k > 2 .and. k < sz) then
827 : ierr = 0
828 : call interp_4_to_1( &
829 : 0.5d0*(dq(k-2)+dq(k-1)), &
830 : 0.5d0*(dq(k-1)+dq(k)), &
831 : 0.5d0*(dq(k)+dq(k+1)), &
832 : 0.5d0*dq(k-2)+dq(k-1), &
833 : xa(j,k-2), xa(j,k-1), xa(j,k), xa(j,k+1), &
834 0 : interp_xa_to_pt, str, ierr)
835 0 : interp_xa_to_pt = min(1d0,max(0d0,interp_xa_to_pt))
836 0 : if (ierr == 0) return
837 : end if
838 0 : interp_xa_to_pt = (xa(j,k)*dq(k-1) + xa(j,k-1)*dq(k))/(dq(k-1) + dq(k))
839 0 : interp_xa_to_pt = min(1d0,max(0d0,interp_xa_to_pt))
840 0 : end function interp_xa_to_pt
841 :
842 :
843 98 : real(dp) function get_dtau1(s, ierr)
844 : type (star_info), pointer :: s
845 : integer, intent(out) :: ierr
846 : integer :: k
847 98 : real(dp) :: kap
848 : include 'formats'
849 98 : ierr = 0
850 98 : k = 1
851 98 : kap = s% opacity(1)
852 98 : get_dtau1 = s% dm(1)*kap/(pi4*s% rmid(1)*s% rmid(1))
853 98 : if (is_bad(get_dtau1)) then
854 0 : ierr = -1
855 0 : if (.not. s% report_ierr) return
856 : k = 1
857 0 : write(*,2) 'get_dtau1', k, get_dtau1
858 0 : write(*,2) 's% dm(1)', k, s% dm(k)
859 0 : write(*,2) 's% opacity(1)', k, s% opacity(k)
860 0 : write(*,2) 's% rmid(1)', k, s% rmid(k)
861 0 : write(*,2) 's% r(1)', k, s% r(k)
862 0 : write(*,2) 's% r(2)', 2, s% r(2)
863 0 : call mesa_error(__FILE__,__LINE__,'get_dtau1')
864 : end if
865 0 : end function get_dtau1
866 :
867 :
868 77 : subroutine get_tau(s, ierr)
869 : type (star_info), pointer :: s
870 : integer, intent(out) :: ierr
871 : ! tau(k) is optical depth at outer boundary of cell k
872 77 : real(dp) :: dtau, kap, dm_sum, L_sum
873 : integer :: k
874 : logical, parameter :: dbg = .true.
875 : include 'formats'
876 : ierr = 0
877 77 : dtau = get_dtau1(s, ierr)
878 77 : if (ierr /= 0) return
879 77 : s% tau(1) = s% tau_factor*s% tau_base
880 77 : dm_sum = 0
881 77 : L_sum = 0
882 93081 : do k = 2, s% nz
883 93004 : s% tau(k) = s% tau(k-1) + dtau
884 93004 : kap = s% opacity(k)
885 93004 : dtau = s% dm(k)*kap/(pi4*s% rmid(k)*s% rmid(k))
886 93004 : if (is_bad(dtau)) then
887 0 : ierr = -1
888 0 : if (.not. s% report_ierr) return
889 0 : write(*,2) 'dtau', k, dtau
890 0 : write(*,2) 's% dm(k)', k, s% dm(k)
891 0 : write(*,2) 's% opacity(k)', k, s% opacity(k)
892 0 : write(*,2) 's% rmid(k)', k, s% rmid(k)
893 0 : call mesa_error(__FILE__,__LINE__,'get_tau')
894 : end if
895 93081 : if (k == s% nz) s% tau_center = s% tau(k) + dtau
896 : !write(*,*) 'dtau, dlogtau', k, tau(k) - tau(k-1), &
897 : ! log10(tau(k)/tau(k-1))
898 : end do
899 : end subroutine get_tau
900 :
901 :
902 : integer function find_cell_for_mass(s, m)
903 : type (star_info), pointer :: s
904 : real(dp), intent(in) :: m
905 : integer :: k
906 : find_cell_for_mass = s% nz
907 : do k = 1, s% nz-1
908 : if (s% m(k) >= m .and. m > s% m(k+1)) then
909 : find_cell_for_mass = k
910 : return
911 : end if
912 : end do
913 : end function find_cell_for_mass
914 :
915 :
916 33 : subroutine get_delta_Pg_traditional(s, delta_Pg)
917 : type (star_info), pointer :: s
918 : real(dp), intent(out) :: delta_Pg ! seconds
919 : ! g-mode period spacing for l=1
920 33 : real(dp) :: dr, N2, integral, r
921 : integer :: k
922 : logical, parameter :: dbg = .false.
923 : include 'formats'
924 : if (dbg) then
925 : write(*,2) 's% star_mass', s% model_number, s% star_mass
926 : write(*,2) 's% photosphere_r', s% model_number, s% photosphere_r
927 : write(*,2) 's% Teff', s% model_number, s% Teff
928 : end if
929 33 : delta_Pg = 0._dp
930 33 : if (.not. s% calculate_Brunt_N2) return
931 33 : k = 0
932 33 : r = 0._dp
933 33 : N2 = 0._dp
934 33 : dr = 0._dp
935 33 : integral = 0._dp
936 :
937 : ! we integrate at cell edges.
938 40733 : do k = 2, s% nz
939 40700 : N2 = s% brunt_N2(k) ! brunt_N2 at cell_face
940 40700 : r = s% r(k) ! r evalulated at cell_face
941 40700 : dr = s% rmid(k-1) - s% rmid(k) ! dr evalulated at cell face.
942 40733 : if (N2 > 0d0) integral = integral + sqrt(N2)*dr/r
943 : end do
944 :
945 : if (dbg) write(*,2) ' integral ', &
946 : s% model_number,integral
947 :
948 33 : if (integral == 0) return
949 33 : delta_Pg = sqrt(2._dp)*pi*pi/integral
950 33 : if (is_bad(delta_Pg)) delta_Pg = 0._dp
951 :
952 : if (dbg) write(*,2) 'delta_Pg', s% model_number, delta_Pg
953 :
954 : end subroutine get_delta_Pg_traditional
955 :
956 0 : subroutine get_delta_Pg_bildsten2012(s, nu_max, delta_Pg)
957 : type (star_info), pointer :: s
958 : real(dp), intent(in) :: nu_max ! microHz
959 : real(dp), intent(out) :: delta_Pg ! seconds
960 : ! g-mode period spacing for l=1
961 0 : real(dp) :: integral, N2, omega2, kr2, L2, el, &
962 0 : dr, r, r2, cs2, sl2, I_integral, I_integral_limit
963 : integer :: k, k_sl2
964 : logical, parameter :: dbg = .false.
965 : include 'formats'
966 : if (dbg) then
967 : write(*,2) 'nu_max', s% model_number, nu_max
968 : write(*,2) 's% star_mass', s% model_number, s% star_mass
969 : write(*,2) 's% photosphere_r', s% model_number, s% photosphere_r
970 : write(*,2) 's% Teff', s% model_number, s% Teff
971 : end if
972 0 : delta_Pg = 0
973 0 : if (.not. s% calculate_Brunt_N2) return
974 0 : integral = 0
975 0 : I_integral = 0
976 0 : I_integral_limit = 0.5d0
977 0 : omega2 = pow2(2*pi*nu_max/1d6)
978 : if (dbg) write(*,1) 'log omega2', log10(omega2)
979 0 : el = 1
980 0 : L2 = el*(el+1)
981 0 : k_sl2 = 0
982 0 : do k = 2, s% nz
983 0 : N2 = s% brunt_N2(k)
984 0 : r = s% r(k)
985 0 : r2 = r*r
986 0 : cs2 = s% csound_face(k)*s% csound_face(k)
987 0 : sl2 = L2*cs2/r2
988 0 : dr = s% rmid(k-1) - s% rmid(k)
989 0 : if (omega2 >= sl2) then
990 : cycle
991 : end if
992 : if (k_sl2 == 0) then
993 : k_sl2 = k
994 : if (dbg) write(*,2) 'k_sl2', k
995 : end if
996 0 : if (N2 > omega2) then ! in g-cavity
997 : if (dbg .and. integral == 0) write(*,2) 'enter g-cavity', k
998 0 : integral = integral + sqrt(N2)*dr/r
999 : else ! in decay region
1000 0 : if (integral == 0) cycle ! ! haven't been in g-cavity yet
1001 : if (dbg .and. I_integral == 0) write(*,2) 'enter decay', k
1002 : ! in decay region below g-cavity; I_integral estimates decay
1003 0 : kr2 = (1 - n2/omega2)*(1 - Sl2/omega2)*omega2/cs2
1004 0 : I_integral = I_integral + sqrt(-kr2)*dr
1005 0 : if (I_integral > I_integral_limit) exit
1006 : end if
1007 : end do
1008 :
1009 : if (dbg) write(*,2) 'omega2 nu_max integral I_integral', &
1010 : s% model_number, omega2, nu_max, integral, I_integral
1011 :
1012 0 : if (integral == 0) return
1013 0 : delta_Pg = sqrt(2d0)*pi*pi/integral
1014 0 : if (is_bad(delta_Pg)) delta_Pg = 0
1015 :
1016 : if (dbg) write(*,2) 'delta_Pg', s% model_number, delta_Pg
1017 :
1018 : end subroutine get_delta_Pg_bildsten2012
1019 :
1020 :
1021 66 : subroutine set_rmid(s, nzlo, nzhi, ierr)
1022 : type (star_info), pointer :: s
1023 : integer, intent(in) :: nzlo, nzhi
1024 : integer, intent(out) :: ierr
1025 : integer :: k, nz
1026 66 : real(dp) :: r003, rp13, rmid, rmid2
1027 : logical :: dbg
1028 : include 'formats'
1029 66 : ierr = 0
1030 66 : nz = s% nz
1031 66 : dbg = .false.
1032 66 : if (s% RSP_flag) then ! mid = avg r
1033 : !dbg = s% model_number >= s% max_model_number - 1
1034 0 : do k=nzlo, nzhi
1035 0 : if (k < nz) then
1036 0 : rmid = 0.5d0*(s% r(k) + s% r(k+1))
1037 : else
1038 0 : rmid = 0.5d0*(s% r(k) + s% R_center)
1039 : end if
1040 0 : s% rmid(k) = rmid
1041 : if (dbg) write(*,3) 'set_rmid s% r(k)', k, s% model_number, s% r(k)
1042 : if (dbg) write(*,3) 'set_rmid s% rmid(k)', k, s% model_number, s% rmid(k)
1043 0 : if (s% rmid_start(k) < 0) s% rmid_start(k) = s% rmid(k)
1044 0 : rmid2 = rmid*rmid
1045 : end do
1046 66 : return
1047 : end if
1048 : ! mid = middle by volume
1049 80060 : do k=nzlo, nzhi
1050 79994 : r003 = s% r(k)*s% r(k)*s% r(k)
1051 79994 : if (k < nz) then
1052 79928 : rp13 = s% r(k+1)*s% r(k+1)*s% r(k+1)
1053 : else
1054 66 : rp13 = s% R_center*s% R_center*s% R_center
1055 : end if
1056 79994 : rmid = pow(0.5d0*(r003 + rp13),one_third)
1057 79994 : s% rmid(k) = rmid
1058 79994 : if (s% rmid_start(k) < 0) s% rmid_start(k) = s% rmid(k)
1059 80060 : rmid2 = rmid*rmid
1060 : end do
1061 : end subroutine set_rmid
1062 :
1063 :
1064 0 : real(dp) function get_tau_at_r(s, r, ierr)
1065 : type (star_info), pointer :: s
1066 : real(dp), intent(in) :: r
1067 : integer, intent(out) :: ierr
1068 0 : real(dp) :: dtau, tau_m1, tau_00
1069 : integer :: k
1070 : logical, parameter :: dbg = .false.
1071 : include 'formats'
1072 : ierr = 0
1073 0 : dtau = get_dtau1(s, ierr)
1074 0 : if (ierr /= 0) return
1075 0 : tau_00 = s% tau_factor*s% tau_base
1076 0 : get_tau_at_r = tau_00
1077 0 : if (r >= s% r(1)) return
1078 0 : do k = 2, s% nz
1079 0 : tau_m1 = tau_00
1080 0 : tau_00 = tau_m1 + dtau
1081 0 : if (r < s% r(k-1) .and. r >= s% r(k)) then
1082 : get_tau_at_r = &
1083 0 : (tau_00*(s% r(k-1)-r) + tau_m1*(r-s% r(k)))/(s% r(k-1)-s% r(k))
1084 0 : return
1085 : end if
1086 0 : dtau = s% dm(k)*s% opacity(k)/(pi4*s% rmid(k)*s% rmid(k))
1087 : end do
1088 : end function get_tau_at_r
1089 :
1090 :
1091 132 : subroutine set_phot_info(s)
1092 : use atm_lib, only: atm_black_body_T
1093 : type (star_info), pointer :: s
1094 : real(dp) :: luminosity
1095 : include 'formats'
1096 : call get_phot_info(s, &
1097 : s% photosphere_r, s% photosphere_m, s% photosphere_v, &
1098 : s% photosphere_L, s% photosphere_T, s% photosphere_csound, &
1099 : s% photosphere_opacity, s% photosphere_logg, &
1100 132 : s% photosphere_column_density, s% photosphere_cell_k)
1101 : s% photosphere_black_body_T = &
1102 132 : atm_black_body_T(s% photosphere_L, s% photosphere_r)
1103 132 : s% Teff = s% photosphere_black_body_T
1104 132 : s% photosphere_r = s% photosphere_r/Rsun
1105 132 : s% photosphere_m = s% photosphere_m/Msun
1106 132 : s% photosphere_L = s% photosphere_L/Lsun
1107 132 : s% L_phot = s% photosphere_L
1108 132 : luminosity = s% L(1)
1109 132 : if (is_bad(luminosity)) then
1110 0 : write(*,2) 's% L(1)', s% model_number, s% L(1)
1111 0 : write(*,2) 's% xh(s% i_lum,1)', s% model_number, s% xh(s% i_lum,1)
1112 0 : call mesa_error(__FILE__,__LINE__,'set_phot_info')
1113 0 : luminosity = 0d0
1114 : end if
1115 132 : s% L_surf = luminosity/Lsun
1116 132 : s% log_surface_luminosity = log10(max(1d-99,luminosity/Lsun))
1117 : ! log10(stellar luminosity in solar units)
1118 132 : if (is_bad(s% L_surf)) then
1119 0 : write(*,2) 's% L_surf', s% model_number, s% L_surf
1120 0 : call mesa_error(__FILE__,__LINE__,'set_phot_info')
1121 : end if
1122 132 : end subroutine set_phot_info
1123 :
1124 :
1125 132 : subroutine get_phot_info(s,r,m,v,L,T_phot,cs,kap,logg,ysum,k_phot)
1126 : type (star_info), pointer :: s
1127 : real(dp), intent(out) :: r, m, v, L, T_phot, cs, kap, logg, ysum
1128 : integer, intent(out) :: k_phot
1129 :
1130 : integer :: k
1131 132 : real(dp) :: tau00, taup1, dtau, r003, rp13, r3, tau_phot, &
1132 132 : Tface_0, Tface_1
1133 :
1134 : include 'formats'
1135 :
1136 : ! set values for surface as defaults in case phot not in model
1137 132 : r = s% r(1)
1138 132 : m = s% m(1)
1139 132 : if (s% u_flag) then
1140 0 : v = s% u(1)
1141 132 : else if (s% v_flag) then
1142 0 : v = s% v(1)
1143 : else
1144 132 : v = 0d0
1145 : end if
1146 132 : L = max(1d0, s% L(1)) ! don't use negative L(1)
1147 132 : T_phot = s% T(1)
1148 132 : cs = s% csound(1)
1149 132 : kap = s% opacity(1)
1150 132 : logg = safe_log10(s% cgrav(1)*m/(r*r))
1151 132 : k_phot = 1
1152 132 : if (s% tau_factor >= 1) then
1153 : ! This is always true for tables, regardless of tau_base.
1154 132 : return ! just use surface values
1155 : end if
1156 0 : tau_phot = s% tau_base ! this holds for case of tau_factor < 1
1157 0 : tau00 = s% tau_factor*s% tau_base ! start at tau_surf < tau_phot and go inward
1158 0 : taup1 = 0
1159 0 : ysum = 0
1160 0 : do k = 1, s% nz-1
1161 0 : dtau = s% dm(k)*s% opacity(k)/(pi4*s% rmid(k)*s% rmid(k))
1162 0 : taup1 = tau00 + dtau
1163 0 : ysum = ysum + s% rho(k)*(s% r(k) - s% r(k+1))
1164 0 : if (taup1 >= tau_phot .and. dtau > 0d0) then
1165 0 : if (k == 1) then
1166 0 : Tface_0 = s% T_surf
1167 : else
1168 0 : Tface_0 = 0.5d0*(s% T(k) + s% T(k-1))
1169 : end if
1170 0 : Tface_1 = 0.5d0*(s% T(k) + s% T(k+1))
1171 0 : T_phot = Tface_0 + (Tface_1 - Tface_0)*(tau_phot - tau00)/dtau
1172 0 : r003 = s% r(k)*s% r(k)*s% r(k)
1173 0 : rp13 = s% r(k+1)*s% r(k+1)*s% r(k+1)
1174 0 : r3 = r003 + (rp13 - r003)*(tau_phot - tau00)/dtau
1175 0 : r = pow(r3,one_third)
1176 0 : m = s% m(k) - s% dm(k)*(tau_phot - tau00)/dtau
1177 0 : if (s% u_flag) then
1178 0 : v = s% v_center
1179 : ! skip it since get_phot_info can be called before u_face has been set
1180 0 : else if (s% v_flag) then
1181 0 : v = s% v(k) + (s% v(k+1) - s% v(k))*(tau_phot - tau00)/dtau
1182 : end if
1183 : L = s% L(k) + (s% L(k+1) - s% L(k))*(tau_phot - tau00)/dtau
1184 0 : L = max(1d0, s% L(1)) ! don't use negative L(1)
1185 0 : logg = safe_log10(s% cgrav(k_phot)*m/(r*r))
1186 0 : k_phot = k
1187 : ! don't bother interpolating these.
1188 0 : cs = s% csound(k_phot)
1189 0 : kap = s% opacity(k_phot)
1190 0 : return
1191 : end if
1192 0 : tau00 = taup1
1193 : end do
1194 : !write(*,*) 'get_phot_info failed to find photosphere'
1195 0 : k_phot = s% nz
1196 0 : r = s% R_center
1197 0 : m = s% m_center
1198 0 : v = s% v_center
1199 0 : T_phot = s% T(k_phot)
1200 0 : L = max(1d0, s% L_center)
1201 0 : cs = s% csound(k_phot)
1202 0 : kap = s% opacity(k_phot)
1203 0 : logg = safe_log10(s% cgrav(k_phot)*m/(r*r))
1204 132 : end subroutine get_phot_info
1205 :
1206 :
1207 440 : real(dp) function center_value(s, p)
1208 : type (star_info), pointer :: s
1209 : real(dp), intent(in) :: p(:)
1210 440 : real(dp) :: sum_x, sum_dq, dx, dq
1211 : integer :: k
1212 440 : sum_x = 0
1213 440 : sum_dq = 0
1214 440 : do k = s% nz, 1, -1
1215 440 : dq = s% dq(k)
1216 440 : dx = p(k)*dq
1217 440 : if (sum_dq+dq >= s% center_avg_value_dq) then
1218 440 : sum_x = sum_x + dx*(s% center_avg_value_dq - sum_dq)/dq
1219 440 : sum_dq = s% center_avg_value_dq
1220 440 : exit
1221 : end if
1222 0 : sum_x = sum_x + dx
1223 0 : sum_dq = sum_dq + dq
1224 : end do
1225 440 : center_value = sum_x/sum_dq
1226 440 : end function center_value
1227 :
1228 :
1229 2464 : subroutine interp_q( &
1230 2464 : nz2, nvar_hydro, species, qval, xh, xa, q, dq, struct, comp, ierr)
1231 : use num_lib, only: binary_search
1232 : integer, intent(in) :: nz2, nvar_hydro, species
1233 : real(dp), intent(in) :: qval
1234 : real(dp), intent(in) :: xh(:,:), xa(:,:), q(:), dq(:)
1235 : real(dp), intent(inout) :: struct(:), comp(:)
1236 : integer, intent(out) :: ierr
1237 : integer :: k
1238 2464 : real(dp) :: alfa
1239 2464 : ierr = 0
1240 2464 : if (qval <= q(nz2)) then
1241 1 : if (nvar_hydro > 0) &
1242 5 : struct(1:nvar_hydro) = xh(1:nvar_hydro,nz2)
1243 1 : if (species > 0) &
1244 9 : comp(1:species) = xa(1:species,nz2)
1245 1 : return
1246 : end if
1247 2463 : k = binary_search(nz2, q, 0, qval)
1248 2463 : if (k < 1 .or. k >= nz2) then
1249 0 : ierr = -1
1250 0 : return
1251 : end if
1252 2463 : if (qval <= q(k) .and. qval > q(k+1)) then
1253 2463 : alfa = (qval - q(k+1)) / dq(k)
1254 2463 : if (nvar_hydro > 0) &
1255 : struct(1:nvar_hydro) = &
1256 12315 : alfa*xh(1:nvar_hydro,k) + (1-alfa)*xh(1:nvar_hydro,k+1)
1257 2463 : if (species > 0) &
1258 22167 : comp(1:species) = alfa*xa(1:species,k) + (1-alfa)*xa(1:species,k+1)
1259 2463 : return
1260 : end if
1261 0 : ierr = -1
1262 2464 : end subroutine interp_q
1263 :
1264 :
1265 33 : subroutine set_abs_du_div_cs(s)
1266 : type (star_info), pointer :: s
1267 :
1268 : integer :: k, nz, j
1269 33 : real(dp) :: abs_du, cs
1270 : include 'formats'
1271 33 : nz = s% nz
1272 :
1273 33 : if (s% v_flag) then
1274 0 : do k=2,nz
1275 0 : abs_du = abs(s% v_start(k) - s% v_start(k-1))
1276 0 : cs = maxval(s% csound(max(1,k-5):min(nz,k+5)))
1277 0 : s% abs_du_plus_cs(k) = abs_du + cs
1278 0 : s% abs_du_div_cs(k) = abs_du/cs
1279 : end do
1280 0 : k = 1
1281 0 : s% abs_du_plus_cs(k) = s% abs_du_plus_cs(k+1)
1282 0 : s% abs_du_div_cs(k) = s% abs_du_div_cs(k+1)
1283 0 : do j = 1,3
1284 0 : do k=2,nz-1
1285 0 : s% abs_du_div_cs(k) = sum(s% abs_du_div_cs(k-1:k+1))/3d0
1286 : end do
1287 : end do
1288 33 : else if (s% u_flag) then
1289 0 : do k=2,nz-1
1290 : abs_du = &
1291 : max(abs(s% u_start(k) - s% u_start(k+1)), &
1292 0 : abs(s% u_start(k) - s% u_start(k-1)))
1293 0 : cs = maxval(s% csound(max(1,k-5):min(nz,k+5)))
1294 0 : s% abs_du_plus_cs(k) = abs_du + cs
1295 0 : s% abs_du_div_cs(k) = abs_du/cs
1296 : end do
1297 0 : k = nz
1298 : s% abs_du_plus_cs(k) = &
1299 0 : abs(s% u_start(k) - s% u_start(k-1)) + s% csound_start(k)
1300 : s% abs_du_div_cs(k) = &
1301 0 : abs(s% u_start(k) - s% u_start(k-1))/s% csound_start(k)
1302 0 : k = 2
1303 : s% abs_du_plus_cs(k) = &
1304 0 : abs(s% u_start(k) - s% u_start(k+1)) + s% csound_start(k)
1305 : s% abs_du_div_cs(k) = &
1306 0 : abs(s% u_start(k) - s% u_start(k+1))/s% csound_start(k)
1307 0 : k = 1
1308 0 : s% abs_du_plus_cs(k) = s% abs_du_plus_cs(k+1)
1309 0 : s% abs_du_div_cs(k) = s% abs_du_div_cs(k+1)
1310 0 : do j = 1,3
1311 0 : do k=2,nz-1
1312 0 : s% abs_du_div_cs(k) = sum(s% abs_du_div_cs(k-1:k+1))/3d0
1313 : end do
1314 : end do
1315 : else
1316 40766 : do k=1,nz
1317 40733 : s% abs_du_plus_cs(k) = 1d99
1318 40766 : s% abs_du_div_cs(k) = 1d99
1319 : end do
1320 : end if
1321 :
1322 2464 : end subroutine set_abs_du_div_cs
1323 :
1324 :
1325 33 : subroutine get_shock_info(s)
1326 : type (star_info), pointer :: s
1327 : integer :: k, nz
1328 33 : real(dp) :: v_div_cs_00, v_div_cs_m1, v_div_cs_min, v_div_cs_max, shock_radius
1329 : real(dp), pointer :: v(:)
1330 :
1331 : include 'formats'
1332 :
1333 33 : s% shock_mass = 0d0
1334 33 : s% shock_q = 0d0
1335 33 : s% shock_radius = 0d0
1336 33 : s% shock_velocity = 0d0
1337 33 : s% shock_csound = 0d0
1338 33 : s% shock_lgT = 0d0
1339 33 : s% shock_lgRho = 0d0
1340 33 : s% shock_lgP = 0d0
1341 33 : s% shock_gamma1 = 0d0
1342 33 : s% shock_entropy = 0d0
1343 33 : s% shock_tau = 0d0
1344 33 : s% shock_k = 0
1345 :
1346 33 : if (s% u_flag) then
1347 0 : v => s% u
1348 33 : else if (s% v_flag) then
1349 0 : v => s% v
1350 : else
1351 33 : return
1352 : end if
1353 :
1354 0 : nz = s% nz
1355 0 : shock_radius = -1
1356 0 : v_div_cs_00 = v(1)/s% csound(1)
1357 0 : do k = 2,nz-1
1358 0 : v_div_cs_m1 = v_div_cs_00
1359 0 : v_div_cs_00 = v(k)/s% csound(k)
1360 0 : v_div_cs_max = max(v_div_cs_00, v_div_cs_m1)
1361 0 : v_div_cs_min = min(v_div_cs_00, v_div_cs_m1)
1362 0 : if (v_div_cs_max >= 1d0 .and. v_div_cs_min < 1d0) then
1363 0 : if (v(k+1) > s% csound(k+1)) then ! skip single point glitches
1364 : shock_radius = &
1365 0 : find0(s% r(k), v_div_cs_00-1d0, s% r(k-1), v_div_cs_m1-1d0)
1366 0 : if (shock_radius <= 0d0) then
1367 0 : call mesa_error(__FILE__,__LINE__,'get_shock_info 1')
1368 : end if
1369 : exit
1370 : end if
1371 : end if
1372 0 : if (v_div_cs_min <= -1d0 .and. v_div_cs_max > -1d0) then
1373 0 : if (v(k+1) < -s% csound(k+1)) then ! skip single point glitches
1374 : shock_radius = &
1375 0 : find0(s% r(k), v_div_cs_00+1d0, s% r(k-1), v_div_cs_m1+1d0)
1376 0 : if (shock_radius <= 0d0) then
1377 0 : call mesa_error(__FILE__,__LINE__,'get_shock_info 2')
1378 : end if
1379 : exit
1380 : end if
1381 : end if
1382 : end do
1383 0 : if (shock_radius < 0d0) return
1384 :
1385 : call get_shock_location_info( &
1386 : s, .false., k-1, v, shock_radius, &
1387 : s% shock_mass, &
1388 : s% shock_q, &
1389 : s% shock_radius, &
1390 : s% shock_velocity, &
1391 : s% shock_csound, &
1392 : s% shock_lgT, &
1393 : s% shock_lgRho, &
1394 : s% shock_lgP, &
1395 : s% shock_gamma1, &
1396 : s% shock_entropy, &
1397 : s% shock_tau, &
1398 0 : s% shock_k)
1399 :
1400 : end subroutine get_shock_info
1401 :
1402 :
1403 0 : subroutine get_shock_location_info( &
1404 : s, dbg, k_shock, v, r, &
1405 : shock_mass, &
1406 : shock_q, &
1407 : shock_radius, &
1408 : shock_velocity, &
1409 : shock_csound, &
1410 : shock_lgT, &
1411 : shock_lgRho, &
1412 : shock_lgP, &
1413 : shock_gamma1, &
1414 : shock_entropy, &
1415 : shock_tau, &
1416 : shock_k)
1417 : type (star_info), pointer :: s
1418 : integer, intent(in) :: k_shock
1419 : logical, intent(in) :: dbg
1420 : real(dp), intent(in), pointer :: v(:)
1421 : real(dp), intent(in) :: r
1422 : real(dp), intent(out) :: &
1423 : shock_mass, &
1424 : shock_q, &
1425 : shock_radius, &
1426 : shock_velocity, &
1427 : shock_csound, &
1428 : shock_lgT, &
1429 : shock_lgRho, &
1430 : shock_lgP, &
1431 : shock_gamma1, &
1432 : shock_entropy, &
1433 : shock_tau
1434 : integer, intent(out) :: shock_k
1435 :
1436 : integer :: k
1437 0 : real(dp) :: alfa, beta
1438 :
1439 : include 'formats'
1440 :
1441 0 : k = k_shock
1442 : if (r < s% R_center .or. r > s% r(1) .or. &
1443 : k < 1 .or. k > s% nz .or. &
1444 0 : .not. associated(v) .or. &
1445 : .not. (s% v_flag .or. s% u_flag)) then
1446 0 : shock_mass = 0
1447 0 : shock_q = 0
1448 0 : shock_radius = 0
1449 0 : shock_velocity = 0
1450 0 : shock_csound = 0
1451 0 : shock_lgT = 0
1452 0 : shock_lgRho = 0
1453 0 : shock_lgP = 0
1454 0 : shock_gamma1 = 0
1455 0 : shock_entropy = 0
1456 0 : shock_tau = 0
1457 0 : shock_k = 0
1458 0 : return
1459 : end if
1460 :
1461 0 : shock_radius = r/Rsun
1462 0 : shock_k = k
1463 0 : if (k < s% nz) then
1464 0 : alfa = (r - s% r(k))/(s% r(k+1) - s% r(k))
1465 0 : beta = 1d0 - alfa
1466 0 : shock_mass = (alfa*s% m(k+1) + beta*s% m(k))/Msun
1467 0 : shock_q = alfa*s% q(k+1) + beta*s% q(k)
1468 0 : shock_velocity = alfa*v(k+1) + beta*v(k)
1469 : else
1470 0 : shock_mass = s% m(k)/Msun
1471 0 : shock_q = s% q(k)
1472 0 : shock_velocity = v(k)
1473 : end if
1474 0 : shock_csound = s% csound(k)
1475 0 : shock_lgT = s% lnT(k)/ln10
1476 0 : shock_lgRho = s% lnd(k)/ln10
1477 0 : shock_lgP = s% lnPeos(k)/ln10
1478 0 : shock_gamma1 = s% gamma1(k)
1479 0 : shock_entropy = s% entropy(k)
1480 0 : shock_tau = s% tau(k)
1481 :
1482 : end subroutine get_shock_location_info
1483 :
1484 :
1485 0 : real(dp) function min_dr_div_cs(s,min_k) ! seconds
1486 : type (star_info), pointer :: s
1487 : integer, intent(out) :: min_k
1488 : integer :: k, nz, k_min
1489 0 : real(dp) :: dr, dt, min_q, max_q, min_abs_u_div_cs, min_abs_du_div_cs, r00, rp1, dr_div_cs, remnant_mass
1490 : include 'formats'
1491 0 : nz = s% nz
1492 0 : min_k = nz
1493 0 : min_dr_div_cs = 1d99
1494 0 : min_q = s% min_q_for_dt_div_min_dr_div_cs_limit
1495 0 : max_q = s% max_q_for_dt_div_min_dr_div_cs_limit
1496 0 : k_min = max(1, s% min_k_for_dt_div_min_dr_div_cs_limit)
1497 0 : if (s% check_remnant_only_for_dt_div_min_dr_div_cs_limit) then
1498 0 : remnant_mass = get_remnant_mass(s)
1499 : else
1500 0 : remnant_mass = s% m(1)
1501 : end if
1502 : min_abs_u_div_cs = &
1503 0 : s% min_abs_u_div_cs_for_dt_div_min_dr_div_cs_limit
1504 : min_abs_du_div_cs = &
1505 0 : s% min_abs_du_div_cs_for_dt_div_min_dr_div_cs_limit
1506 0 : if (s% v_flag) then
1507 0 : do k = k_min, nz-1
1508 0 : if (s% m(k) > remnant_mass) cycle
1509 0 : if (s% q(k) > max_q) cycle
1510 0 : if (s% q(k) < min_q) exit
1511 0 : if (abs(s% v_start(k))/s% csound(k) < min_abs_u_div_cs) cycle
1512 0 : if (s% abs_du_div_cs(k) < min_abs_du_div_cs) cycle
1513 0 : r00 = s% r(k)
1514 0 : rp1 = s% r(k+1)
1515 0 : dr_div_cs = (r00 - rp1)/s% csound(k)
1516 0 : if (dr_div_cs < min_dr_div_cs) then
1517 0 : min_dr_div_cs = dr_div_cs
1518 0 : min_k = k
1519 : end if
1520 : end do
1521 : !write(*,3) 'min_dr_div_cs', min_k, s% model_number, min_dr_div_cs
1522 0 : return
1523 : end if
1524 0 : if (.not. s% u_flag) return
1525 0 : do k = k_min, nz-1
1526 0 : if (s% m(k) > remnant_mass) cycle
1527 0 : if (s% q(k) > max_q) cycle
1528 0 : if (s% q(k) < min_q) exit
1529 0 : if (abs(s% u_start(k))/s% csound(k) < min_abs_u_div_cs) cycle
1530 0 : if (s% abs_du_div_cs(k) < min_abs_du_div_cs) cycle
1531 0 : dr = s% r(k) - s% r(k+1)
1532 0 : dt = dr/s% abs_du_plus_cs(k)
1533 0 : if (dt < min_dr_div_cs) then
1534 0 : min_dr_div_cs = dt
1535 0 : min_k = k
1536 : end if
1537 : end do
1538 : end function min_dr_div_cs
1539 :
1540 :
1541 12 : subroutine reset_epsnuc_vectors(s)
1542 : type (star_info), pointer :: s
1543 : integer :: k, nz
1544 12 : nz = s% nz
1545 15563 : do k=1,s% nz
1546 15551 : s% eps_nuc(k) = 0d0
1547 15551 : s% d_epsnuc_dlnd(k) = 0d0
1548 15551 : s% d_epsnuc_dlnT(k) = 0d0
1549 139959 : s% d_epsnuc_dx(:,k) = 0d0
1550 388775 : s% eps_nuc_categories(:,k) = 0d0
1551 139959 : s% dxdt_nuc(:,k) = 0d0
1552 139959 : s% d_dxdt_nuc_dRho(:,k) = 0d0
1553 139959 : s% d_dxdt_nuc_dT(:,k) = 0d0
1554 1135223 : s% d_dxdt_nuc_dx(:,:,k) = 0d0
1555 15563 : s% eps_nuc_neu_total(k) = 0d0
1556 : end do
1557 12 : end subroutine reset_epsnuc_vectors
1558 :
1559 :
1560 44 : subroutine reset_starting_vectors(s)
1561 : type (star_info), pointer :: s
1562 : integer :: k, nz
1563 44 : nz = s% nz
1564 55336 : do k=1,s% nz
1565 55292 : s% T_start(k) = -1d99
1566 55292 : s% r_start(k) = -1d99
1567 55292 : s% rmid_start(k) = -1d99
1568 55292 : s% v_start(k) = -1d99
1569 55292 : s% u_start(k) = -1d99
1570 55292 : s% lnd_start(k) = -1d99
1571 55292 : s% lnT_start(k) = -1d99
1572 55292 : s% csound_start(k) = -1d99
1573 55292 : s% rho_start(k) = -1d99
1574 55292 : s% erad_start(k) = -1d99
1575 55292 : s% alpha_RTI_start(k) = -1d99
1576 55292 : s% opacity_start(k) = -1d99
1577 55292 : s% w_start(k) = -1d99
1578 55336 : s% dPdr_dRhodr_info(k) = -1d99
1579 : end do
1580 44 : end subroutine reset_starting_vectors
1581 :
1582 :
1583 104652 : subroutine save_eqn_dxa_partials(&
1584 104652 : s, k, nvar, i_eqn, species, dxam1, dxa00, dxap1, str, ierr)
1585 : type (star_info), pointer :: s
1586 : integer, intent(in) :: k, nvar, i_eqn, species
1587 : real(dp), intent(in), dimension(species) :: dxam1, dxa00, dxap1
1588 : character (len=*), intent(in) :: str
1589 : integer, intent(out) :: ierr
1590 : integer :: j
1591 104652 : ierr = 0
1592 941868 : do j=1,species
1593 837216 : call em1(s, i_eqn, j+s% nvar_hydro, k, nvar, dxam1(j))
1594 837216 : call e00(s, i_eqn, j+s% nvar_hydro, k, nvar, dxa00(j))
1595 941868 : call ep1(s, i_eqn, j+s% nvar_hydro, k, nvar, dxap1(j))
1596 : end do
1597 104652 : end subroutine save_eqn_dxa_partials
1598 :
1599 :
1600 104740 : subroutine save_eqn_residual_info(s, k, nvar, i_eqn, resid, str, ierr)
1601 : type (star_info), pointer :: s
1602 : integer, intent(in) :: k, nvar, i_eqn
1603 : type(auto_diff_real_star_order1), intent(in) :: resid
1604 : character (len=*), intent(in) :: str
1605 : integer, intent(out) :: ierr
1606 4084860 : real(dp) :: d_dm1(nvar), d_d00(nvar), d_dp1(nvar)
1607 : call unpack_residual_partials(s, k, nvar, i_eqn, &
1608 104740 : resid, d_dm1, d_d00, d_dp1)
1609 : call store_partials( &
1610 104740 : s, k, i_eqn, nvar, d_dm1, d_d00, d_dp1, str, ierr)
1611 104740 : end subroutine save_eqn_residual_info
1612 :
1613 :
1614 209392 : subroutine unpack_residual_partials(s, k, nvar, i_eqn, &
1615 209392 : residual, d_dm1, d_d00, d_dp1)
1616 : use auto_diff
1617 : use auto_diff_support
1618 : type (star_info), pointer :: s
1619 : integer, intent(in) :: k, nvar, i_eqn
1620 : type(auto_diff_real_star_order1) :: residual
1621 : real(dp) :: d_dm1(nvar), d_d00(nvar), d_dp1(nvar)
1622 :
1623 : real(dp) :: val, dlnd_m1, dlnd_00, dlnd_p1, dlnT_m1, dlnT_00, dlnT_p1, &
1624 : dw_m1, dw_00, dw_p1, &
1625 : dlnR_m1, dlnR_00, dlnR_p1, &
1626 : dv_m1, dv_00, dv_p1, dL_m1, dL_00, dL_p1, &
1627 : dHp_m1, dHp_00, dHp_p1, &
1628 : dw_div_wc_m1, dw_div_wc_00, dw_div_wc_p1, &
1629 : djrot_m1, djrot_00, djrot_p1, &
1630 : dxtra1_m1, dxtra1_00, dxtra1_p1, &
1631 : dxtra2_m1, dxtra2_00, dxtra2_p1
1632 :
1633 : include 'formats'
1634 :
1635 : call unwrap(residual, val, &
1636 : dlnd_m1, dlnd_00, dlnd_p1, dlnT_m1, dlnT_00, dlnT_p1, &
1637 : dw_m1, dw_00, dw_p1, dlnR_m1, dlnR_00, dlnR_p1, &
1638 : dv_m1, dv_00, dv_p1, dL_m1, dL_00, dL_p1, &
1639 : dHp_m1, dHp_00, dHp_p1, &
1640 : dw_div_wc_m1, dw_div_wc_00, dw_div_wc_p1, &
1641 : djrot_m1, djrot_00, djrot_p1, &
1642 : dxtra1_m1, dxtra1_00, dxtra1_p1, &
1643 209392 : dxtra2_m1, dxtra2_00, dxtra2_p1)
1644 :
1645 8166288 : d_dm1 = 0; d_d00 = 0; d_dp1 = 0
1646 209392 : call unpack1(s% i_lnd, dlnd_m1, dlnd_00, dlnd_p1)
1647 209392 : call unpack1(s% i_lnT, dlnT_m1, dlnT_00, dlnT_p1)
1648 209392 : call unpack1(s% i_lnR, dlnR_m1, dlnR_00, dlnR_p1)
1649 209392 : if (s% i_v /= 0) call unpack1(s% i_v, dv_m1, dv_00, dv_p1)
1650 209392 : if (s% i_u /= 0) call unpack1(s% i_u, dv_m1, dv_00, dv_p1)
1651 209392 : if (s% i_lum /= 0) call unpack1(s% i_lum, dL_m1, dL_00, dL_p1)
1652 209392 : if (s% i_w /= 0) call unpack1(s% i_w, dw_m1, dw_00, dw_p1)
1653 209392 : if (s% i_Hp /= 0) call unpack1(s% i_Hp, dHp_m1, dHp_00, dHp_p1)
1654 209392 : if (s% i_w_div_wc /= 0) call unpack1(s% i_w_div_wc, dw_div_wc_m1, dw_div_wc_00, dw_div_wc_p1)
1655 209392 : if (s% i_j_rot /= 0) call unpack1(s% i_j_rot, djrot_m1, djrot_00, djrot_p1)
1656 :
1657 : contains
1658 :
1659 418784 : subroutine unpack1(j, dvar_m1, dvar_00, dvar_p1)
1660 : integer, intent(in) :: j
1661 : real(dp), intent(in) :: dvar_m1, dvar_00, dvar_p1
1662 418784 : d_dm1(j) = dvar_m1
1663 418784 : d_d00(j) = dvar_00
1664 209392 : d_dp1(j) = dvar_p1
1665 418784 : end subroutine unpack1
1666 :
1667 : end subroutine unpack_residual_partials
1668 :
1669 209392 : subroutine store_partials(s, k, i_eqn, nvar, d_dm1, d_d00, d_dp1, str, ierr)
1670 : type (star_info), pointer :: s
1671 : integer, intent(in) :: k, i_eqn, nvar
1672 : real(dp), intent(in) :: d_dm1(nvar), d_d00(nvar), d_dp1(nvar)
1673 : character (len=*), intent(in) :: str
1674 : integer, intent(out) :: ierr
1675 : integer :: nz, j
1676 : logical, parameter :: checking = .true.
1677 209392 : ierr = 0
1678 209392 : nz = s% nz
1679 2722096 : do j=1,nvar
1680 2512704 : if (k > 1) then
1681 2510592 : if (checking) call check_dequ(d_dm1(j),trim(str) // ' d_dm1')
1682 2510592 : call em1(s, i_eqn, j, k, nvar, d_dm1(j))
1683 : end if
1684 2512704 : if (checking) call check_dequ(d_d00(j),trim(str) // ' d_d00')
1685 2512704 : call e00(s, i_eqn, j, k, nvar, d_d00(j))
1686 2722096 : if (k < nz) then
1687 2510592 : if (checking) call check_dequ(d_dp1(j),trim(str) // ' d_dp1')
1688 2510592 : call ep1(s, i_eqn, j, k, nvar, d_dp1(j))
1689 : end if
1690 : end do
1691 :
1692 : contains
1693 :
1694 7533888 : subroutine check_dequ(dequ, str)
1695 : real(dp), intent(in) :: dequ
1696 : character (len=*), intent(in) :: str
1697 : include 'formats'
1698 7533888 : if (is_bad(dequ)) then
1699 0 : !$omp critical (store_partials_crit)
1700 0 : ierr = -1
1701 0 : if (s% report_ierr) then
1702 0 : write(*,2) 'store_partials: bad ' // trim(str), k, dequ
1703 : end if
1704 0 : if (s% stop_for_bad_nums) call mesa_error(__FILE__,__LINE__,'store_partials')
1705 : !$omp end critical (store_partials_crit)
1706 0 : return
1707 : end if
1708 : end subroutine check_dequ
1709 :
1710 : end subroutine store_partials
1711 :
1712 :
1713 77 : subroutine set_scale_height(s)
1714 : type (star_info), pointer :: s
1715 77 : real(dp) :: Hp, alt_Hp, alfa, beta, rho_face, Peos_face
1716 : integer :: k
1717 : include 'formats'
1718 93158 : do k=1,s% nz
1719 93081 : if (s% cgrav(k) == 0) then
1720 0 : s% scale_height(k) = 0
1721 0 : cycle
1722 : end if
1723 93081 : if (k == 1) then
1724 : alfa = 1
1725 : else
1726 93004 : alfa = s% dq(k-1)/(s% dq(k-1) + s% dq(k))
1727 : end if
1728 93081 : beta = 1 - alfa
1729 93004 : if (alfa == 1) then
1730 77 : rho_face = s% rho(k)
1731 77 : Peos_face = s% Peos(k)
1732 : else
1733 93004 : rho_face = alfa*s% rho(k) + beta*s% rho(k-1)
1734 93004 : Peos_face = alfa*s% Peos(k) + beta*s% Peos(k-1)
1735 : end if
1736 93081 : Hp = Peos_face/(rho_face*s% grav(k))
1737 93081 : if (s% cgrav(k) <= 0) then
1738 0 : alt_Hp = s% r(k)
1739 : else
1740 93081 : alt_Hp = sqrt(Peos_face / s% cgrav(k)) / rho_face
1741 : end if
1742 93158 : s% scale_height(k) = min(Hp, alt_Hp)
1743 : end do
1744 77 : end subroutine set_scale_height
1745 :
1746 :
1747 0 : real(dp) function tau_eff(s,k)
1748 : ! tau_eff = tau that gives the local P == P_atm if this location at surface
1749 : type (star_info), pointer :: s
1750 : integer, intent(in) :: k
1751 0 : real(dp) :: Peos, g, Pextra_factor
1752 0 : if (k == 1) then
1753 0 : tau_eff = s% tau(1)
1754 0 : return
1755 : end if
1756 0 : if (s% cgrav(k) <= 0d0) then
1757 0 : tau_eff = 0d0
1758 : return
1759 : end if
1760 0 : Peos = (s% dq(k-1)*s% Peos(k) + s% dq(k)*s% Peos(k-1))/(s% dq(k-1) + s% dq(k))
1761 0 : g = s% cgrav(k)*s% m_grav(k)/(s% r(k)*s% r(k))
1762 0 : Pextra_factor = s% Pextra_factor
1763 : tau_eff = s% opacity(k)*(Peos/g - &
1764 0 : Pextra_factor*(s% L(k)/s% m_grav(k))/(6d0*pi*clight*s% cgrav(k)))
1765 0 : end function tau_eff
1766 :
1767 :
1768 21 : real(dp) function eval_Ledd(s, ierr)
1769 : type (star_info), pointer :: s
1770 : integer, intent(out) :: ierr
1771 21 : real(dp) :: dtau1, dtau, tau, dqsum, Ledd_sum
1772 : integer :: k
1773 : logical, parameter :: dbg = .false.
1774 : include 'formats'
1775 21 : ierr = 0
1776 21 : eval_Ledd = 0d0
1777 21 : if (s% cgrav(1) <= 0d0) return
1778 21 : dtau1 = get_dtau1(s, ierr)
1779 21 : if (ierr /= 0) return
1780 21 : dtau = dtau1
1781 21 : tau = s% tau_factor*s% tau_base
1782 21 : dqsum = s% dq(1)
1783 21 : Ledd_sum = s% dq(1)*pi4*clight*s% cgrav(1)*s% m_grav(1)/s% opacity(1)
1784 2415 : do k = 2, s% nz
1785 2415 : tau = tau + dtau
1786 2415 : if (tau > s% surf_avg_tau) exit
1787 2394 : dtau = s% dm(k)*s% opacity(k)/(pi4*s% rmid(k)*s% rmid(k))
1788 2394 : dqsum = dqsum + s% dq(k)
1789 : Ledd_sum = Ledd_sum + &
1790 2415 : s% dq(k)*pi4*clight*s% cgrav(1)*s% m_grav(1)/s% opacity(k)
1791 : end do
1792 21 : eval_Ledd = Ledd_sum/dqsum
1793 21 : end function eval_Ledd
1794 :
1795 :
1796 10 : real(dp) function eval_min_cell_collapse_time(s,k_lo,k_hi,min_collapse_k,ierr) &
1797 10 : result(min_collapse_time)
1798 : type (star_info), pointer :: s
1799 : integer, intent(in) :: k_lo, k_hi
1800 : integer, intent(out) :: min_collapse_k, ierr
1801 10 : real(dp) :: rp1, vp1, r00, v00, time
1802 : integer :: k
1803 : logical, parameter :: dbg = .false.
1804 : include 'formats'
1805 10 : ierr = 0
1806 10 : rp1 = s% R_center
1807 10 : vp1 = s% v_center
1808 10 : min_collapse_time = 1d99
1809 10 : min_collapse_k = -1
1810 10 : if (.not. s% v_flag) return
1811 0 : do k = k_hi, k_lo, -1
1812 0 : v00 = s% v(k)
1813 0 : r00 = s% r(k)
1814 0 : if (r00 <= rp1) then
1815 : !ierr = -1
1816 0 : min_collapse_time = -1
1817 0 : min_collapse_k = -1
1818 0 : return
1819 : write(*,2) 'bad radii', k, r00, rp1
1820 : call mesa_error(__FILE__,__LINE__,'eval_min_cell_collapse_time')
1821 : end if
1822 0 : if (vp1 > v00) then
1823 0 : time = (r00 - rp1)/(vp1 - v00)
1824 0 : if (time < min_collapse_time) then
1825 0 : min_collapse_time = time
1826 0 : min_collapse_k = k
1827 : end if
1828 : end if
1829 0 : rp1 = r00
1830 0 : vp1 = v00
1831 : end do
1832 : end function eval_min_cell_collapse_time
1833 :
1834 :
1835 42 : real(dp) function total_angular_momentum(s) result(J)
1836 : type (star_info), pointer :: s
1837 : include 'formats'
1838 42 : if (.not. s% rotation_flag) then
1839 : J = 0
1840 : else
1841 0 : J = dot_product(s% dm_bar(1:s% nz), s% j_rot(1:s% nz))
1842 : end if
1843 42 : end function total_angular_momentum
1844 :
1845 :
1846 0 : real(dp) function eval_irradiation_heat(s,k)
1847 : type (star_info), pointer :: s
1848 : integer, intent(in) :: k
1849 0 : real(dp) :: irradiation_dq, xq, eps
1850 0 : eval_irradiation_heat = 0
1851 0 : if (s% irradiation_flux /= 0) then
1852 0 : irradiation_dq = pi4*s% r(1)*s% r(1)*s% column_depth_for_irradiation/s% xmstar
1853 0 : xq = 1 - s% q(k)
1854 0 : if (irradiation_dq > xq) then ! add irradiation heat for cell k
1855 0 : eps = 0.25d0 * s% irradiation_flux / s% column_depth_for_irradiation
1856 0 : if (irradiation_dq < xq + s% dq(k)) then ! only part of cell gets heated
1857 0 : eval_irradiation_heat = eps*(irradiation_dq - xq)/s% dq(k)
1858 : else ! all of cell gets heated
1859 : eval_irradiation_heat = eps
1860 : end if
1861 : end if
1862 : end if
1863 0 : end function eval_irradiation_heat
1864 :
1865 :
1866 0 : subroutine start_time(s, time0, total_all_before)
1867 : type (star_info), pointer :: s
1868 : integer(i8), intent(out) :: time0
1869 : real(dp), intent(out) :: total_all_before
1870 : integer(i8) :: clock_rate
1871 0 : if (.not. s% doing_timing) return
1872 0 : total_all_before = total_times(s)
1873 0 : call system_clock(time0,clock_rate)
1874 : end subroutine start_time
1875 :
1876 :
1877 0 : subroutine update_time(s, time0, total_all_before, total)
1878 : type (star_info), pointer :: s
1879 : integer(i8), intent(in) :: time0
1880 : real(dp), intent(in) :: total_all_before
1881 : real(dp), intent(inout) :: total
1882 0 : real(dp) :: total_all_after, other_stuff
1883 : integer(i8) :: time1, clock_rate
1884 0 : if (.not. s% doing_timing) return
1885 0 : call system_clock(time1,clock_rate)
1886 0 : total_all_after = total_times(s)
1887 0 : other_stuff = total_all_after - total_all_before
1888 : ! don't double count any other stuff
1889 0 : total = total + (dble(time1-time0)/clock_rate - other_stuff)
1890 : end subroutine update_time
1891 :
1892 :
1893 0 : real(dp) function total_times(s)
1894 : type (star_info), pointer :: s
1895 : total_times = &
1896 : s% time_evolve_step + &
1897 : s% time_remesh + &
1898 : s% time_adjust_mass + &
1899 : s% time_conv_premix + &
1900 : s% time_element_diffusion + &
1901 : s% time_struct_burn_mix + &
1902 : s% time_solver_matrix + &
1903 : s% time_solve_mix + &
1904 : s% time_solve_burn + &
1905 : s% time_solve_omega_mix + &
1906 : s% time_eos + &
1907 : s% time_neu_kap + &
1908 : s% time_nonburn_net + &
1909 : s% time_mlt + &
1910 : s% time_set_hydro_vars + &
1911 0 : s% time_set_mixing_info
1912 0 : end function total_times
1913 :
1914 :
1915 11 : real(dp) function get_remnant_mass(s)
1916 : type (star_info), pointer :: s
1917 11 : get_remnant_mass = s% m(1) - get_ejecta_mass(s)
1918 11 : end function get_remnant_mass
1919 :
1920 :
1921 22 : real(dp) function get_ejecta_mass(s)
1922 : use num_lib, only: find0
1923 : type (star_info), pointer :: s
1924 : integer :: k
1925 22 : real(dp) :: v, vesc, v_div_vesc, v_div_vesc_prev, dm
1926 : include 'formats'
1927 22 : get_ejecta_mass = 0d0
1928 22 : if (.not. (s% u_flag .or. s% v_flag)) return
1929 0 : v_div_vesc_prev = 0d0
1930 0 : do k=1,s% nz
1931 0 : if (s% u_flag) then
1932 : !v = s% u_face_ad(k)%val ! CANNOT USE u_face for this
1933 : ! approximate value is good enough for this estimate
1934 0 : if (k == 1) then
1935 0 : v = s% u(k)
1936 : else
1937 0 : v = 0.5d0*(s% u(k-1) + s% u(k))
1938 : end if
1939 : else
1940 0 : v = s% v(k)
1941 : end if
1942 0 : vesc = sqrt(2d0*s% cgrav(k)*s% m(k)/s% r(k))
1943 0 : v_div_vesc = v/vesc
1944 0 : if (v_div_vesc < 1d0) then
1945 0 : if (k == 1) return
1946 0 : dm = find0(0d0, v_div_vesc_prev-1d0, s% dm(k-1), v_div_vesc-1d0)
1947 0 : if (dm < 0d0) then
1948 0 : write(*,2) 'v_div_vesc_prev-1d0', k, v_div_vesc_prev-1d0
1949 0 : write(*,2) 'v_div_vesc-1d0', k, v_div_vesc-1d0
1950 0 : write(*,2) 's% dm(k-1)', k, s% dm(k-1)
1951 0 : write(*,2) 'dm', k, dm
1952 0 : call mesa_error(__FILE__,__LINE__,'get_ejecta_mass')
1953 : end if
1954 0 : if (k == 2) then
1955 : get_ejecta_mass = dm
1956 : else
1957 0 : get_ejecta_mass = sum(s% dm(1:k-2)) + dm
1958 : end if
1959 0 : return
1960 : end if
1961 0 : v_div_vesc_prev = v_div_vesc
1962 : end do
1963 22 : end function get_ejecta_mass
1964 :
1965 :
1966 220 : subroutine smooth(dc, sz)
1967 : real(dp), intent(inout) :: dc(:)
1968 : integer, intent(in) :: sz
1969 : integer :: k
1970 220 : k = 1
1971 220 : dc(k) = (3*dc(k) + dc(k+1))/4
1972 268880 : do k=2,sz-1
1973 268880 : dc(k) = (dc(k-1) + 2*dc(k) + dc(k+1))/4
1974 : end do
1975 220 : k = sz
1976 220 : dc(k) = (dc(k-1) + 3*dc(k))/4
1977 22 : end subroutine smooth
1978 :
1979 :
1980 0 : subroutine do_boxcar_mixing( &
1981 : s, min_mass, max_mass, boxcar_nominal_mass, number_iterations, ierr)
1982 : ! code based on SNEC
1983 : type (star_info), pointer :: s
1984 : real(dp), intent(in) :: min_mass, max_mass, boxcar_nominal_mass
1985 : integer, intent(in) :: number_iterations
1986 : integer, intent(out) :: ierr
1987 : integer :: nz, iter, k_inner, k_outer, j, k
1988 0 : real(dp) :: dm_sum, target_mass, actual_mass, xa, min_m, max_m
1989 : include 'formats'
1990 0 : ierr = 0
1991 0 : nz = s% nz
1992 0 : target_mass = boxcar_nominal_mass*Msun
1993 0 : min_m = min_mass*Msun
1994 0 : max_m = max_mass*Msun
1995 0 : write(*,2) 'iters min max box', number_iterations, min_mass, max_mass, boxcar_nominal_mass
1996 0 : do iter = 1, number_iterations
1997 0 : do k_inner = nz, 1, -1
1998 0 : if (s% m(k_inner) < min_m) cycle
1999 : dm_sum = 0
2000 0 : k_outer = 1
2001 0 : do k = k_inner, 1, -1
2002 0 : dm_sum = dm_sum + s% dm(k)
2003 0 : if (dm_sum > target_mass) then
2004 : k_outer = k
2005 : exit
2006 : end if
2007 : end do
2008 0 : if (s% m(k_outer) > max_m) cycle
2009 0 : actual_mass = dm_sum
2010 0 : do j=1,s% species
2011 : xa = 0d0
2012 0 : do k=k_outer,k_inner
2013 0 : xa = xa + s% xa(j,k)*s% dm(k)
2014 : end do
2015 0 : do k=k_outer,k_inner
2016 0 : s% xa(j,k) = xa/dm_sum
2017 : end do
2018 : end do
2019 0 : if (actual_mass < target_mass) exit
2020 : end do
2021 : end do
2022 0 : s% need_to_setvars = .true.
2023 0 : end subroutine do_boxcar_mixing
2024 :
2025 :
2026 79994 : subroutine get_XYZ(s, xa, X, Y, Z)
2027 : use chem_def, only: ih1, ih2, ihe3, ihe4
2028 : type (star_info), pointer :: s
2029 : real(dp), intent(in) :: xa(:)
2030 : real(dp), intent(out) :: X, Y, Z
2031 79994 : X = 0d0
2032 79994 : if (s% net_iso(ih1) /= 0) X = X + xa(s% net_iso(ih1))
2033 79994 : if (s% net_iso(ih2) /= 0) X = X + xa(s% net_iso(ih2))
2034 79994 : X = min(1d0, max(0d0, X))
2035 79994 : Y = 0d0
2036 79994 : if (s% net_iso(ihe3) /= 0) Y = Y + xa(s% net_iso(ihe3))
2037 79994 : if (s% net_iso(ihe4) /= 0) Y = Y + xa(s% net_iso(ihe4))
2038 79994 : Y = min(1d0, max(0d0, Y))
2039 79994 : Z = min(1d0, max(0d0, 1d0 - (X + Y)))
2040 79994 : end subroutine get_XYZ
2041 :
2042 :
2043 225 : subroutine get_face_values(s, v_mid, v_face, ierr)
2044 : ! simple interpolation by mass
2045 : type (star_info), pointer :: s
2046 : real(dp), intent(in) :: v_mid(:)
2047 : real(dp), intent(inout) :: v_face(:)
2048 : integer, intent(out) :: ierr
2049 : integer :: k
2050 225 : real(dp) :: dq_sum
2051 225 : ierr = 0
2052 225 : v_face(1) = v_mid(1)
2053 281420 : do k=2, s% nz
2054 281195 : dq_sum = s% dq(k-1) + s% dq(k)
2055 281420 : v_face(k) = (v_mid(k)*s% dq(k-1) + v_mid(k-1)*s% dq(k))/dq_sum
2056 : end do
2057 79994 : end subroutine get_face_values
2058 :
2059 :
2060 0 : real(dp) function get_Ledd(s,k) result(Ledd)
2061 : type (star_info), pointer :: s
2062 : integer, intent(in) :: k
2063 0 : real(dp) :: kap_face
2064 : integer :: j
2065 0 : if (k == 1) then
2066 0 : j = 2
2067 : else
2068 0 : j = k
2069 : end if
2070 0 : kap_face = interp_val_to_pt(s% opacity,j,s% nz,s% dq,'get_Ledd')
2071 0 : Ledd = pi4*clight*s% cgrav(j)*s% m_grav(j)/kap_face
2072 0 : end function get_Ledd
2073 :
2074 :
2075 0 : real(dp) function get_Lrad(s,k)
2076 : type (star_info), pointer :: s
2077 : integer, intent(in) :: k
2078 0 : get_Lrad = s% L(k) - get_Lconv(s,k)
2079 0 : end function get_Lrad
2080 :
2081 :
2082 0 : real(dp) function get_Lconv(s,k)
2083 : type (star_info), pointer :: s
2084 : integer, intent(in) :: k
2085 0 : if (k == 1) then
2086 0 : get_Lconv = 0d0
2087 : return
2088 : end if
2089 0 : if (s% RSP2_flag .or. s% RSP_flag) then
2090 0 : get_Lconv = s% Lc(k)
2091 : else
2092 0 : get_Lconv = s% L_conv(k) ! L_conv set by last call on mlt
2093 : end if
2094 : end function get_Lconv
2095 :
2096 :
2097 0 : real(dp) function get_Ladv(s,k)
2098 : type (star_info), pointer :: s
2099 : integer, intent(in) :: k
2100 0 : real(dp) :: T, Erad, v, r
2101 0 : T = s% T(k)
2102 0 : Erad = crad*T*T*T*T
2103 0 : if (s% u_flag) then
2104 0 : v = s% u(k)
2105 0 : else if (s% v_flag) then
2106 0 : v = s% v(k)
2107 : else
2108 : v = 0d0
2109 : end if
2110 0 : r = s% rmid(k)
2111 0 : get_Ladv = pi4*r*r*v*Erad
2112 0 : end function get_Ladv
2113 :
2114 :
2115 0 : real(dp) function get_Lrad_div_Ledd(s,k) result(L_rad_div_Ledd)
2116 : type (star_info), pointer :: s
2117 : integer, intent(in) :: k
2118 : integer :: j
2119 0 : real(dp) :: del_m, del_T4, area
2120 0 : if (s% cgrav(k) <= 0) then
2121 0 : L_rad_div_Ledd = 0d0
2122 : return
2123 : end if
2124 0 : if (k == 1) then
2125 : j = 2
2126 : else
2127 0 : j = k
2128 : end if
2129 0 : del_m = s% dm_bar(j)
2130 0 : del_T4 = pow4(s% T(j-1)) - pow4(s% T(j))
2131 0 : area = pi4*s% r(j)*s% r(j)
2132 : L_rad_div_Ledd = &
2133 0 : -(area*area*crad*(del_T4/del_m)/3)/(pi4*s% cgrav(j)*s% m_grav(j))
2134 0 : end function get_Lrad_div_Ledd
2135 :
2136 :
2137 : real(dp) function cell_start_specific_KE(s,k)
2138 : type (star_info), pointer :: s
2139 : integer, intent(in) :: k
2140 : cell_start_specific_KE = cell_start_specific_KE_qp(s,k)
2141 : end function cell_start_specific_KE
2142 :
2143 :
2144 52348 : real(qp) function cell_start_specific_KE_qp(s,k)
2145 : ! for consistency with dual cells at faces, use <v**2> instead of <v>**2
2146 : type (star_info), pointer :: s
2147 : integer, intent(in) :: k
2148 52348 : real(qp) :: qhalf, v0, v1, v2, Mbar
2149 52348 : qhalf = 0.5d0
2150 52348 : if (s% use_mass_corrections) then
2151 0 : Mbar = s% mass_correction(k)
2152 : else
2153 : Mbar = 1.0_qp
2154 : end if
2155 52348 : if (s% u_flag) then
2156 0 : v0 = s% u_start(k)
2157 0 : cell_start_specific_KE_qp = qhalf*Mbar*v0**2
2158 52348 : else if (s% v_flag) then
2159 0 : v0 = s% v_start(k)
2160 0 : if (k < s% nz) then
2161 0 : v1 = s% v_start(k+1)
2162 : else
2163 0 : v1 = s% v_center
2164 : end if
2165 0 : v2 = qhalf*(v0**2 + v1**2)
2166 0 : cell_start_specific_KE_qp = qhalf*Mbar*v2
2167 : else ! ignore kinetic energy if no velocity variables
2168 : cell_start_specific_KE_qp = 0d0
2169 : end if
2170 52348 : end function cell_start_specific_KE_qp
2171 :
2172 :
2173 13567 : real(dp) function cell_specific_KE(s,k,d_dv00,d_dvp1)
2174 : type (star_info), pointer :: s
2175 : integer, intent(in) :: k
2176 : real(dp), intent(out) :: d_dv00, d_dvp1
2177 13567 : cell_specific_KE = cell_specific_KE_qp(s,k,d_dv00,d_dvp1)
2178 13567 : end function cell_specific_KE
2179 :
2180 :
2181 65915 : real(qp) function cell_specific_KE_qp(s,k,d_dv00,d_dvp1)
2182 : ! for consistency with dual cells at faces, use <v**2> instead of <v>**2
2183 : type (star_info), pointer :: s
2184 : integer, intent(in) :: k
2185 : real(dp), intent(out) :: d_dv00, d_dvp1
2186 65915 : real(dp) :: dv2_dv00, dv2_dvp1
2187 65915 : real(qp) :: qhalf, v0, v1, v2, Mbar
2188 65915 : qhalf = 0.5d0
2189 65915 : if (s% use_mass_corrections) then
2190 0 : Mbar = s% mass_correction(k)
2191 : else
2192 : Mbar = 1.0_qp
2193 : end if
2194 65915 : if (s% u_flag) then
2195 0 : v0 = s% u(k)
2196 0 : cell_specific_KE_qp = qhalf*Mbar*v0**2
2197 0 : d_dv00 = s% u(k)
2198 0 : d_dvp1 = 0d0
2199 65915 : else if (s% v_flag) then
2200 0 : v0 = s% v(k)
2201 0 : if (k < s% nz) then
2202 0 : v1 = s% v(k+1)
2203 0 : dv2_dvp1 = s% v(k+1)
2204 : else
2205 0 : v1 = s% v_center
2206 0 : dv2_dvp1 = 0d0
2207 : end if
2208 0 : v2 = qhalf*(v0**2 + v1**2)
2209 0 : dv2_dv00 = s% v(k)
2210 0 : cell_specific_KE_qp = qhalf*Mbar*v2
2211 0 : d_dv00 = qhalf*Mbar*dv2_dv00
2212 0 : d_dvp1 = qhalf*Mbar*dv2_dvp1
2213 : else ! ignore kinetic energy if no velocity variables
2214 65915 : cell_specific_KE_qp = 0d0
2215 65915 : d_dv00 = 0d0
2216 65915 : d_dvp1 = 0d0
2217 : end if
2218 65915 : end function cell_specific_KE_qp
2219 :
2220 :
2221 68390 : real(dp) function cell_specific_PE(s,k,d_dlnR00,d_dlnRp1)
2222 : type (star_info), pointer :: s
2223 : integer, intent(in) :: k
2224 : real(dp), intent(out) :: d_dlnR00,d_dlnRp1
2225 13567 : cell_specific_PE = cell_specific_PE_qp(s,k,d_dlnR00,d_dlnRp1)
2226 13567 : end function cell_specific_PE
2227 :
2228 :
2229 120738 : real(qp) function cell_specific_PE_qp(s,k,d_dlnR00,d_dlnRp1)
2230 : ! for consistency with dual cells at faces, <m/r>_cntr => (m(k)/r(k) + m(k+1)/r(k+1))/2 /= m_cntr/r_cntr
2231 : ! i.e., use avg of m/r at faces of cell rather than ratio of cell center mass over cell center r.
2232 : type (star_info), pointer :: s
2233 : integer, intent(in) :: k
2234 : real(dp), intent(out) :: d_dlnR00,d_dlnRp1
2235 120738 : real(qp) :: qhalf, rp1, r00, mp1, m00, Gp1, G00, gravp1, grav00, Mbar
2236 120738 : real(dp) :: d_grav00_dlnR00, d_gravp1_dlnRp1
2237 : include 'formats'
2238 120738 : qhalf = 0.5d0
2239 120738 : if (s% use_mass_corrections) then
2240 0 : Mbar = s% mass_correction(k)
2241 : else
2242 : Mbar = 1.0_qp
2243 : end if
2244 120738 : if (k == s% nz) then
2245 99 : rp1 = s% R_center
2246 99 : mp1 = s% m_center
2247 99 : Gp1 = s% cgrav(s% nz)
2248 : else
2249 120639 : rp1 = s% r(k+1)
2250 120639 : mp1 = s% m_grav(k+1)
2251 120639 : Gp1 = s% cgrav(k+1)
2252 : end if
2253 120738 : if (rp1 <= 0d0) then
2254 99 : gravp1 = 0d0
2255 99 : d_gravp1_dlnRp1 = 0d0
2256 : else
2257 120639 : gravp1 = -Gp1*mp1/rp1
2258 120639 : d_gravp1_dlnRp1 = -gravp1
2259 : end if
2260 120738 : r00 = s% r(k)
2261 120738 : m00 = s% m_grav(k)
2262 120738 : G00 = s% cgrav(k)
2263 120738 : grav00 = -G00*m00/r00
2264 120738 : d_grav00_dlnR00 = -grav00
2265 120738 : cell_specific_PE_qp = qhalf*Mbar*(gravp1 + grav00)
2266 120738 : d_dlnR00 = qhalf*Mbar*d_grav00_dlnR00
2267 120738 : d_dlnRp1 = qhalf*Mbar*d_gravp1_dlnRp1
2268 120738 : if (is_bad(cell_specific_PE_qp)) then
2269 0 : write(*,2) 'cell_specific_PE_qp', k, cell_specific_PE_qp
2270 0 : write(*,2) 'gravp1', k, gravp1
2271 0 : write(*,2) 'grav00', k, grav00
2272 0 : call mesa_error(__FILE__,__LINE__,'cell_specific_PE')
2273 : end if
2274 120738 : end function cell_specific_PE_qp
2275 :
2276 :
2277 : real(dp) function cell_start_specific_PE(s,k)
2278 : type (star_info), pointer :: s
2279 : integer, intent(in) :: k
2280 : cell_start_specific_PE = cell_start_specific_PE_qp(s,k)
2281 : end function cell_start_specific_PE
2282 :
2283 :
2284 52348 : real(dp) function cell_start_specific_PE_qp(s,k)
2285 : ! for consistency with dual cells at faces, <m/r>_cntr => (m(k)/r(k) + m(k+1)/r(k+1))/2 /= m_cntr/r_cntr
2286 : ! i.e., use avg of m/r at faces of cell rather than ratio of cell center mass over cell center r.
2287 : type (star_info), pointer :: s
2288 : integer, intent(in) :: k
2289 52348 : real(qp) :: qhalf, rp1, r00, mp1, m00, Gp1, G00, gravp1, grav00, Mbar
2290 : include 'formats'
2291 52348 : qhalf = 0.5d0
2292 52348 : if (s% use_mass_corrections) then
2293 0 : Mbar = s% mass_correction_start(k)
2294 : else
2295 : Mbar = 1.0_qp
2296 : end if
2297 52348 : if (k == s% nz) then
2298 44 : rp1 = s% R_center
2299 44 : mp1 = s% m_center
2300 44 : Gp1 = s% cgrav(s% nz)
2301 : else
2302 52304 : rp1 = s% r_start(k+1)
2303 52304 : mp1 = s% m_grav_start(k+1)
2304 52304 : Gp1 = s% cgrav(k+1)
2305 : end if
2306 52348 : if (rp1 <= 0d0) then
2307 44 : gravp1 = 0d0
2308 : else
2309 52304 : gravp1 = -Gp1*mp1/rp1
2310 : end if
2311 52348 : r00 = s% r_start(k)
2312 52348 : m00 = s% m_grav_start(k)
2313 52348 : G00 = s% cgrav(k)
2314 52348 : grav00 = -G00*m00/r00
2315 52348 : cell_start_specific_PE_qp = qhalf*Mbar*(gravp1 + grav00)
2316 52348 : if (is_bad(cell_start_specific_PE_qp)) then
2317 0 : write(*,2) 'cell_start_specific_PE_qp', k, cell_start_specific_PE_qp
2318 0 : write(*,2) 'gravp1', k, gravp1
2319 0 : write(*,2) 'grav00', k, grav00
2320 0 : call mesa_error(__FILE__,__LINE__,'cell_start_specific_PE_qp')
2321 : end if
2322 52348 : end function cell_start_specific_PE_qp
2323 :
2324 :
2325 0 : real(dp) function cell_specific_rotational_energy(s,k)
2326 : type (star_info), pointer :: s
2327 : integer, intent(in) :: k
2328 0 : real(dp) :: e_00, e_p1
2329 0 : e_00 = s% i_rot(k)% val*s% omega(k)*s% omega(k)
2330 0 : if (k < s% nz) then
2331 0 : e_p1 = s% i_rot(k+1)% val*s% omega(k+1)*s% omega(k+1)
2332 : else
2333 : e_p1 = 0
2334 : end if
2335 0 : cell_specific_rotational_energy = 0.5d0*(e_p1 + e_00)
2336 0 : end function cell_specific_rotational_energy
2337 :
2338 :
2339 52348 : subroutine get_dke_dt_dpe_dt(s, k, dt, &
2340 : dke_dt, d_dkedt_dv00, d_dkedt_dvp1, &
2341 : dpe_dt, d_dpedt_dlnR00, d_dpedt_dlnRp1, ierr)
2342 : type (star_info), pointer :: s
2343 : integer, intent(in) :: k
2344 : real(dp), intent(in) :: dt
2345 : real(dp), intent(out) :: &
2346 : dke_dt, d_dkedt_dv00, d_dkedt_dvp1, &
2347 : dpe_dt, d_dpedt_dlnR00, d_dpedt_dlnRp1
2348 : integer, intent(out) :: ierr
2349 52348 : real(dp) :: PE_start, PE_new, KE_start, KE_new, q1
2350 : real(dp) :: dpe_dlnR00, dpe_dlnRp1, dke_dv00, dke_dvp1
2351 : include 'formats'
2352 52348 : ierr = 0
2353 : ! rate of change in specific PE (erg/g/s)
2354 52348 : PE_start = cell_start_specific_PE_qp(s,k)
2355 52348 : PE_new = cell_specific_PE_qp(s,k,dpe_dlnR00,dpe_dlnRp1)
2356 52348 : q1 = PE_new - PE_start
2357 52348 : dpe_dt = q1/dt ! erg/g/s
2358 52348 : d_dpedt_dlnR00 = dpe_dlnR00/dt
2359 52348 : d_dpedt_dlnRp1 = dpe_dlnRp1/dt
2360 : ! rate of change in specific KE (erg/g/s)
2361 52348 : KE_start = cell_start_specific_KE_qp(s,k)
2362 52348 : KE_new = cell_specific_KE_qp(s,k,dke_dv00,dke_dvp1)
2363 52348 : q1 = KE_new - KE_start
2364 52348 : dke_dt = q1/dt ! erg/g/s
2365 52348 : d_dkedt_dv00 = dke_dv00/dt
2366 52348 : d_dkedt_dvp1 = dke_dvp1/dt
2367 52348 : end subroutine get_dke_dt_dpe_dt
2368 :
2369 :
2370 : real(dp) function eval_deltaM_total_from_profile( &
2371 : deltaM, premesh_dm, profile)
2372 : real(dp), intent(in) :: deltaM
2373 : real(dp), intent(in) :: premesh_dm(:), profile(:)
2374 : real(dp) :: sum_dm, dm, total, f
2375 : integer :: k
2376 : include 'formats'
2377 : total = 0
2378 : sum_dm = 0
2379 : do k=1,size(premesh_dm,dim=1)
2380 : if (sum_dm >= deltaM) exit
2381 : dm = premesh_dm(k)
2382 : if (sum_dm + dm > deltaM) then
2383 : f = (deltaM - sum_dm)/dm
2384 : total = total + f*profile(k)
2385 : exit
2386 : end if
2387 : total = total + profile(k)
2388 : sum_dm = sum_dm + dm
2389 : end do
2390 : eval_deltaM_total_from_profile = total
2391 : end function eval_deltaM_total_from_profile
2392 :
2393 :
2394 11 : real(dp) function cell_specific_total_energy(s, k) result(cell_total)
2395 : type (star_info), pointer :: s
2396 : integer, intent(in) :: k
2397 11 : real(dp) :: d_dv00,d_dvp1,d_dlnR00,d_dlnRp1
2398 : include 'formats'
2399 11 : cell_total = s% energy(k)
2400 11 : if (s% v_flag .or. s% u_flag) &
2401 0 : cell_total = cell_total + cell_specific_KE(s,k,d_dv00,d_dvp1)
2402 11 : cell_total = cell_total + cell_specific_PE(s,k,d_dlnR00,d_dlnRp1)
2403 11 : if (s% rotation_flag .and. s% include_rotation_in_total_energy) &
2404 0 : cell_total = cell_total + cell_specific_rotational_energy(s,k)
2405 11 : if (s% RSP2_flag) cell_total = cell_total + pow2(s% w(k))
2406 11 : if (s% rsp_flag) cell_total = cell_total + s% RSP_Et(k)
2407 11 : end function cell_specific_total_energy
2408 :
2409 :
2410 0 : subroutine eval_integrated_total_energy_profile(s, arr, direction, ierr)
2411 : type (star_info), pointer :: s
2412 : integer, intent(in) :: direction
2413 : integer, intent(out) :: ierr
2414 : real(dp), intent(out) :: arr(:)
2415 : integer :: k, start, finish
2416 :
2417 0 : ierr = 0
2418 0 : if (direction == 1) then
2419 0 : start = 1
2420 0 : finish = s%nz
2421 0 : else if (direction == -1) then
2422 0 : start = s%nz
2423 0 : finish = 1
2424 : else
2425 0 : ierr = 1
2426 0 : call mesa_error(__FILE__,__LINE__)
2427 : end if
2428 :
2429 0 : arr(start) = cell_specific_total_energy(s,start) * s%dm(start)
2430 0 : do k=start+direction, finish, direction
2431 0 : arr(k) = arr(k-direction) + cell_specific_total_energy(s,k) * s%dm(k)
2432 : end do
2433 :
2434 0 : end subroutine eval_integrated_total_energy_profile
2435 :
2436 45 : subroutine eval_deltaM_total_energy_integrals( &
2437 : s, klo, khi, deltaM, save_profiles, &
2438 45 : total_energy_profile, &
2439 : total_internal_energy, total_gravitational_energy, &
2440 : total_radial_kinetic_energy, total_rotational_kinetic_energy, &
2441 : total_turbulent_energy, sum_total)
2442 : type (star_info), pointer :: s
2443 : integer, intent(in) :: klo, khi ! sum from klo to khi
2444 : real(dp), intent(in) :: deltaM
2445 : logical, intent(in) :: save_profiles
2446 : real(dp), intent(out), dimension(:) :: total_energy_profile
2447 : real(dp), intent(out) :: &
2448 : total_internal_energy, total_gravitational_energy, &
2449 : total_radial_kinetic_energy, total_rotational_kinetic_energy, &
2450 : total_turbulent_energy, sum_total
2451 : integer :: k
2452 45 : real(dp) :: dm, sum_dm, cell_total, cell1, d_dv00, d_dvp1, d_dlnR00, d_dlnRp1
2453 : include 'formats'
2454 :
2455 45 : total_internal_energy = 0d0
2456 45 : total_gravitational_energy = 0d0
2457 45 : total_radial_kinetic_energy = 0d0
2458 45 : total_rotational_kinetic_energy = 0d0
2459 45 : total_turbulent_energy = 0d0
2460 45 : sum_total = 0d0
2461 :
2462 45 : if (klo < 1 .or. khi > s% nz .or. klo > khi) return
2463 :
2464 45 : sum_dm = 0
2465 54857 : do k=klo,khi
2466 54812 : if (sum_dm >= deltaM) exit
2467 54812 : cell_total = 0
2468 54812 : dm = s% dm(k)
2469 54812 : if (sum_dm + dm > deltaM) dm = deltaM - sum_dm
2470 54812 : cell1 = dm*s% energy(k)
2471 54812 : cell_total = cell_total + cell1
2472 54812 : total_internal_energy = total_internal_energy + cell1
2473 54812 : if (s% v_flag .or. s% u_flag) then
2474 0 : cell1 = dm*cell_specific_KE(s,k,d_dv00,d_dvp1)
2475 0 : cell_total = cell_total + cell1
2476 0 : total_radial_kinetic_energy = total_radial_kinetic_energy + cell1
2477 : end if
2478 54812 : cell1 = dm*cell_specific_PE(s,k,d_dlnR00,d_dlnRp1)
2479 54812 : cell_total = cell_total + cell1
2480 54812 : total_gravitational_energy = total_gravitational_energy + cell1
2481 54812 : if (s% rotation_flag) then
2482 0 : cell1 = dm*cell_specific_rotational_energy(s,k)
2483 0 : total_rotational_kinetic_energy = total_rotational_kinetic_energy + cell1
2484 0 : if (s% include_rotation_in_total_energy) &
2485 0 : cell_total = cell_total + cell1
2486 : end if
2487 54812 : if (s% RSP2_flag) then
2488 0 : cell1 = dm*pow2(s% w(k))
2489 0 : cell_total = cell_total + cell1
2490 0 : total_turbulent_energy = total_turbulent_energy + cell1
2491 : end if
2492 54812 : if (s% rsp_flag) then
2493 0 : cell1 = dm*s% RSP_Et(k)
2494 0 : cell_total = cell_total + cell1
2495 0 : total_turbulent_energy = total_turbulent_energy + cell1
2496 : end if
2497 54857 : if (save_profiles) then
2498 13087 : total_energy_profile(k) = cell_total
2499 : end if
2500 : end do
2501 :
2502 : sum_total = total_internal_energy + total_gravitational_energy + &
2503 45 : total_radial_kinetic_energy + total_turbulent_energy
2504 :
2505 45 : if (s% include_rotation_in_total_energy) &
2506 0 : sum_total = sum_total + total_rotational_kinetic_energy
2507 :
2508 : end subroutine eval_deltaM_total_energy_integrals
2509 :
2510 :
2511 0 : subroutine eval_total_energy_profile(s, total_energy_profile)
2512 : type (star_info), pointer :: s
2513 : real(dp), intent(out), dimension(:) :: total_energy_profile
2514 :
2515 : integer :: k
2516 0 : real(dp) :: dm, cell_total, cell1, d_dv00, d_dvp1, d_dlnR00, d_dlnRp1
2517 : include 'formats'
2518 :
2519 0 : do k=1, s%nz
2520 0 : cell_total = 0
2521 0 : dm = s% dm(k)
2522 0 : cell1 = dm*s% energy(k)
2523 0 : cell_total = cell_total + cell1
2524 0 : if (s% v_flag .or. s% u_flag) then
2525 0 : cell1 = dm*cell_specific_KE(s,k,d_dv00,d_dvp1)
2526 0 : cell_total = cell_total + cell1
2527 : end if
2528 0 : cell1 = dm*cell_specific_PE(s,k,d_dlnR00,d_dlnRp1)
2529 0 : cell_total = cell_total + cell1
2530 0 : if (s% rotation_flag) then
2531 0 : cell1 = dm*cell_specific_rotational_energy(s,k)
2532 0 : if (s% include_rotation_in_total_energy) &
2533 0 : cell_total = cell_total + cell1
2534 : end if
2535 0 : if (s% RSP2_flag) then
2536 0 : cell1 = dm*pow2(s% w(k))
2537 0 : cell_total = cell_total + cell1
2538 : end if
2539 0 : if (s% rsp_flag) then
2540 0 : cell1 = dm*s% RSP_Et(k)
2541 0 : cell_total = cell_total + cell1
2542 : end if
2543 0 : total_energy_profile(k) = cell_total
2544 : end do
2545 :
2546 0 : end subroutine eval_total_energy_profile
2547 :
2548 :
2549 0 : real(dp) function eval_cell_section_total_energy( &
2550 : s, klo, khi) result(sum_total)
2551 : type (star_info), pointer :: s
2552 : integer, intent(in) :: klo, khi ! sum from klo to khi
2553 : real(dp) :: &
2554 : total_internal_energy, total_gravitational_energy, &
2555 : total_radial_kinetic_energy, total_rotational_kinetic_energy, &
2556 : total_turbulent_energy
2557 0 : real(dp), allocatable, dimension(:) :: total_energy_profile
2558 0 : allocate(total_energy_profile(1:s% nz))
2559 : call eval_deltaM_total_energy_integrals( &
2560 : s, klo, khi, s% mstar, .false., &
2561 : total_energy_profile, &
2562 : total_internal_energy, total_gravitational_energy, &
2563 : total_radial_kinetic_energy, total_rotational_kinetic_energy, &
2564 0 : total_turbulent_energy, sum_total)
2565 0 : end function eval_cell_section_total_energy
2566 :
2567 :
2568 33 : subroutine eval_total_energy_integrals(s, &
2569 : total_internal_energy, total_gravitational_energy, &
2570 : total_radial_kinetic_energy, total_rotational_kinetic_energy, &
2571 : total_turbulent_energy, sum_total)
2572 : type (star_info), pointer :: s
2573 : real(dp), intent(out) :: &
2574 : total_internal_energy, total_gravitational_energy, &
2575 : total_radial_kinetic_energy, total_rotational_kinetic_energy, &
2576 : total_turbulent_energy, sum_total
2577 33 : real(dp), allocatable, dimension(:) :: total_energy_profile
2578 33 : allocate(total_energy_profile(1:s% nz))
2579 : call eval_deltaM_total_energy_integrals( &
2580 : s, 1, s% nz, s% mstar, .false., &
2581 : total_energy_profile, &
2582 : total_internal_energy, total_gravitational_energy, &
2583 : total_radial_kinetic_energy, total_rotational_kinetic_energy, &
2584 33 : total_turbulent_energy, sum_total)
2585 33 : end subroutine eval_total_energy_integrals
2586 :
2587 :
2588 : subroutine eval_total_energy_integrals_and_profile(s, &
2589 : total_energy_profile, &
2590 : total_internal_energy, total_gravitational_energy, &
2591 : total_radial_kinetic_energy, total_rotational_kinetic_energy, &
2592 : total_turbulent_energy, sum_total)
2593 : type (star_info), pointer :: s
2594 : real(dp), intent(out) :: total_energy_profile(:), &
2595 : total_internal_energy, total_gravitational_energy, &
2596 : total_radial_kinetic_energy, total_rotational_kinetic_energy, &
2597 : total_turbulent_energy, sum_total
2598 : call eval_deltaM_total_energy_integrals( &
2599 : s, 1, s% nz, s% mstar, .true., &
2600 : total_energy_profile, &
2601 : total_internal_energy, total_gravitational_energy, &
2602 : total_radial_kinetic_energy, total_rotational_kinetic_energy, &
2603 : total_turbulent_energy, sum_total)
2604 : end subroutine eval_total_energy_integrals_and_profile
2605 :
2606 :
2607 : real(dp) function get_total_energy_integral(s,k) result(sum_total)
2608 : ! from surface down to k
2609 : type (star_info), pointer :: s
2610 : integer, intent(in) :: k
2611 : real(dp) :: &
2612 : total_internal_energy, total_gravitational_energy, &
2613 : total_radial_kinetic_energy, total_rotational_kinetic_energy, &
2614 : total_turbulent_energy
2615 : real(dp), allocatable, dimension(:) :: total_energy_profile
2616 : allocate(total_energy_profile(1:s% nz))
2617 : call eval_deltaM_total_energy_integrals( &
2618 : s, 1, k, s% mstar, .false., &
2619 : total_energy_profile, &
2620 : total_internal_energy, total_gravitational_energy, &
2621 : total_radial_kinetic_energy, total_rotational_kinetic_energy, &
2622 : total_turbulent_energy, sum_total)
2623 : end function get_total_energy_integral
2624 :
2625 :
2626 : real(dp) function get_total_energy_integral_outward(s,k) result(sum_total)
2627 : ! from surface down to k
2628 : type (star_info), pointer :: s
2629 : integer, intent(in) :: k
2630 : real(dp) :: &
2631 : total_internal_energy, total_gravitational_energy, &
2632 : total_radial_kinetic_energy, total_rotational_kinetic_energy, &
2633 : total_turbulent_energy
2634 : real(dp), allocatable, dimension(:) :: total_energy_profile
2635 : allocate(total_energy_profile(1:s% nz))
2636 : call eval_deltaM_total_energy_integrals( &
2637 : s, k, s% nz, s% mstar, .false., &
2638 : total_energy_profile, &
2639 : total_internal_energy, total_gravitational_energy, &
2640 : total_radial_kinetic_energy, total_rotational_kinetic_energy, &
2641 : total_turbulent_energy, sum_total)
2642 : end function get_total_energy_integral_outward
2643 :
2644 :
2645 0 : real(dp) function get_log_concentration(s,j,k) result(log_c)
2646 : use chem_def, only: chem_isos
2647 : type (star_info), pointer :: s
2648 : integer, intent(in) :: j, k
2649 : ! concentration = number density / number density of electrons
2650 : ! Ci = (Xi/Ai) / sum(Zi*Xi/Ai) [see Thoul et al, ApJ 421:828-842, 1994]
2651 : integer :: i, cid, species
2652 0 : real(dp) :: tmp, c
2653 0 : log_c = -1d99
2654 0 : if (s% chem_id(j) == 0) return
2655 0 : species = s% species
2656 0 : tmp = 0d0
2657 0 : do i=1,species
2658 0 : cid = s% chem_id(i)
2659 0 : tmp = tmp + chem_isos% Z(cid)*s% xa(i,k)/chem_isos% Z_plus_N(cid)
2660 : end do
2661 0 : cid = s% chem_id(j)
2662 0 : c = (s% xa(j,k)/chem_isos% Z_plus_N(cid))/tmp
2663 0 : log_c = safe_log10(c)
2664 0 : end function get_log_concentration
2665 :
2666 :
2667 0 : real(dp) function get_phi_Joss(s,k) result(phi)
2668 0 : use eos_def, only: i_lnPgas
2669 : ! Joss, Salpeter, Ostriker, 1973. density inversion when Lrad/Ledd > phi.
2670 : type (star_info), pointer :: s
2671 : integer, intent(in) :: k
2672 0 : phi = 1d0/(1d0 + (s% Pgas(k)/(4* s% Prad(k)))*s% d_eos_dlnT(i_lnPgas,k))
2673 0 : end function get_phi_Joss
2674 :
2675 :
2676 0 : logical function after_He_burn(s, he4_limit)
2677 0 : use chem_def
2678 : type (star_info), pointer :: s
2679 : real(dp), intent(in) :: he4_limit
2680 : integer :: nz, h1, he4
2681 : real(dp), parameter :: small = 1d-4
2682 0 : after_He_burn = .false.
2683 0 : nz = s% nz
2684 0 : h1 = s% net_iso(ih1)
2685 0 : he4 = s% net_iso(ihe4)
2686 0 : if (h1 == 0 .or. he4 == 0) return
2687 0 : if (s% xa(h1,nz) > small .or. s% xa(he4,nz) > he4_limit) return
2688 0 : after_He_burn = .true.
2689 0 : end function after_He_burn
2690 :
2691 :
2692 0 : logical function after_C_burn(s, c12_limit)
2693 0 : use chem_def
2694 : type (star_info), pointer :: s
2695 : real(dp), intent(in) :: c12_limit
2696 : integer :: nz, h1, he4, c12
2697 : real(dp), parameter :: small = 1d-4
2698 0 : after_C_burn = .false.
2699 0 : nz = s% nz
2700 0 : h1 = s% net_iso(ih1)
2701 0 : he4 = s% net_iso(ihe4)
2702 0 : c12 = s% net_iso(ic12)
2703 0 : if (h1 == 0 .or. he4 == 0 .or. c12 == 0) return
2704 0 : if (s% xa(h1,nz) > small .or. s% xa(he4,nz) > small .or. &
2705 0 : s% xa(c12,nz) > c12_limit) return
2706 0 : after_C_burn = .true.
2707 0 : end function after_C_burn
2708 :
2709 :
2710 0 : integer function lookup_nameofvar(s, namestr)
2711 : type (star_info), pointer :: s
2712 : character (len=*), intent(in) :: namestr
2713 : integer :: i
2714 0 : lookup_nameofvar = 0
2715 0 : do i=1,s% nvar_total
2716 0 : if (namestr == s% nameofvar(i)) then
2717 0 : lookup_nameofvar = i
2718 0 : return
2719 : end if
2720 : end do
2721 0 : end function lookup_nameofvar
2722 :
2723 :
2724 0 : integer function lookup_nameofequ(s, namestr)
2725 : type (star_info), pointer :: s
2726 : character (len=*), intent(in) :: namestr
2727 : integer :: i
2728 0 : lookup_nameofequ = 0
2729 0 : do i=1,s% nvar_total
2730 0 : if (namestr == s% nameofequ(i)) then
2731 0 : lookup_nameofequ = i
2732 0 : return
2733 : end if
2734 : end do
2735 : end function lookup_nameofequ
2736 :
2737 :
2738 0 : real(dp) function omega_crit(s, k) ! result always is > 0
2739 : type (star_info), pointer :: s
2740 : integer, intent(in) :: k
2741 0 : real(dp) :: Ledd, gamma_factor, Lrad_div_Ledd, rmid, r003, rp13
2742 : include 'formats'
2743 0 : if (s% rotation_flag) then
2744 : ! Use equatorial radius (at center of cell by volume)
2745 0 : r003 = s% r_equatorial(k)*s% r_equatorial(k)*s% r_equatorial(k)
2746 0 : if (k < s% nz) then
2747 0 : rp13 = s% r_equatorial(k+1)*s% r_equatorial(k+1)*s% r_equatorial(k+1)
2748 : else
2749 0 : rp13 = s% R_center*s% R_center*s% R_center
2750 : end if
2751 0 : rmid = pow(0.5d0*(r003 + rp13),one_third)
2752 : else
2753 0 : rmid = s% rmid(k)
2754 : end if
2755 :
2756 0 : Ledd = pi4*clight*s% cgrav(k)*s% m_grav(k)/s% opacity(k)
2757 0 : Lrad_div_Ledd = get_Lrad_div_Ledd(s,k)
2758 0 : gamma_factor = 1d0 - min(Lrad_div_Ledd, 0.9999d0)
2759 0 : omega_crit = sqrt(gamma_factor*s% cgrav(k)*s% m_grav(k)/pow3(rmid))
2760 0 : end function omega_crit
2761 :
2762 :
2763 89 : subroutine weighed_smoothing(dd, n, ns, preserve_sign, ddold)
2764 : ! based on routine written by S.-C. Yoon, 18 Sept. 2002
2765 : ! for smoothing any variable (dd) with size n over 2*ns+1 cells.
2766 : real(dp), intent(inout) :: dd(:) ! (n)
2767 : integer, intent(in) :: n, ns
2768 : logical, intent(in) :: preserve_sign
2769 : real(dp), intent(inout) :: ddold(:) ! (n) work array
2770 :
2771 : integer :: nweight, mweight, i, j, k
2772 622 : real(dp) :: weight(2*ns+1), sweight, v0
2773 :
2774 : include 'formats'
2775 :
2776 110193 : do i = 1,n
2777 110193 : ddold(i) = dd(i)
2778 : end do
2779 :
2780 : !--preparation for smoothing --------
2781 : nweight = ns
2782 : mweight = 2*nweight+1
2783 622 : do i = 1,mweight
2784 622 : weight(i) = 0d0
2785 : end do
2786 89 : weight(1) = 1d0
2787 533 : do i = 1,mweight-1
2788 1907 : do j = i+1,2,-1
2789 1818 : weight(j) = weight(j) + weight(j-1)
2790 : end do
2791 : end do
2792 :
2793 : !--smoothing ------------------------
2794 110015 : do i=2,n-1
2795 109926 : sweight=0d0
2796 109926 : dd(i)=0d0
2797 109926 : v0 = ddold(i)
2798 493259 : do j = i, max(1,i-nweight), -1
2799 383333 : k=j-i+nweight+1
2800 383333 : if (preserve_sign .and. v0*ddold(j) <= 0) exit
2801 383333 : sweight = sweight+weight(k)
2802 493259 : dd(i) = dd(i)+ddold(j)*weight(k)
2803 : end do
2804 383333 : do j = i+1, min(n,i+nweight)
2805 273407 : k=j-i+nweight+1
2806 273407 : if (preserve_sign .and. v0*ddold(j) <= 0) exit
2807 273407 : sweight = sweight+weight(k)
2808 383333 : dd(i) = dd(i)+ddold(j)*weight(k)
2809 : end do
2810 110015 : if (sweight > 0) then
2811 109926 : sweight = 1d0/sweight
2812 109926 : dd(i) = dd(i)*sweight
2813 : end if
2814 : end do
2815 :
2816 89 : end subroutine weighed_smoothing
2817 :
2818 :
2819 89 : subroutine threshold_smoothing (dd, dd_thresh, n, ns, preserve_sign, ddold)
2820 :
2821 : ! Same as weighed_smoothing, but only smooth contiguous regions where |dd| >= dd_thresh
2822 :
2823 : real(dp), intent(inout) :: dd(:) ! (n)
2824 : real(dp), intent(in) :: dd_thresh
2825 : integer, intent(in) :: n
2826 : integer, intent(in) :: ns
2827 : logical, intent(in) :: preserve_sign
2828 : real(dp), intent(inout) :: ddold(:) ! (n) work array
2829 :
2830 : logical :: in_region
2831 : integer :: i
2832 : integer :: i_a
2833 : integer :: i_b
2834 :
2835 : include 'formats'
2836 :
2837 : ! Process regions
2838 :
2839 89 : in_region = .FALSE.
2840 :
2841 89 : i_a = 1
2842 110193 : do i = 1, n
2843 :
2844 110193 : if (in_region) then
2845 :
2846 110015 : if (ABS(dd(i)) < dd_thresh) then
2847 0 : i_b = i-1
2848 0 : if (i_b > i_a) call weighed_smoothing(dd(i_a:i_b), i_b-i_a+1, ns, preserve_sign, ddold(i_a:i_b))
2849 : in_region = .FALSE.
2850 : end if
2851 :
2852 : else
2853 89 : if (ABS(dd(i)) >= dd_thresh) then
2854 110104 : i_a = i
2855 110104 : in_region = .TRUE.
2856 : end if
2857 :
2858 : end if
2859 :
2860 : end do
2861 :
2862 : ! Handle the final region
2863 :
2864 89 : if (in_region) then
2865 :
2866 89 : i_b = n
2867 89 : if (i_b > i_a) call weighed_smoothing(dd(i_a:i_b), i_b-i_a+1, ns, preserve_sign, ddold(i_a:i_b))
2868 :
2869 : end if
2870 :
2871 89 : return
2872 :
2873 : end subroutine threshold_smoothing
2874 :
2875 :
2876 33 : real(dp) function eval_kh_timescale(G,M,R,L) result(kh)
2877 : real(dp), intent(in) :: G,M,R,L
2878 33 : if (L <= 0) then
2879 : kh = 0d0
2880 : else
2881 33 : kh = 0.75d0*G*M*M/(R*L) ! 0.75 is based on sun. Hansen & Kawaler eqn 1.30
2882 : end if
2883 33 : end function eval_kh_timescale
2884 :
2885 :
2886 1 : real(dp) function yrs_for_init_timestep(s)
2887 : type (star_info), pointer :: s
2888 1 : if (s% initial_mass <= 1) then
2889 : yrs_for_init_timestep = 1d5
2890 : else
2891 1 : yrs_for_init_timestep = 1d5 / pow(s% initial_mass,2.5d0)
2892 : end if
2893 1 : end function yrs_for_init_timestep
2894 :
2895 :
2896 12 : subroutine set_phase_of_evolution(s) ! from evolve after call do_report
2897 : use rates_def, only: i_rate
2898 : use chem_def
2899 : type (star_info), pointer :: s
2900 12 : real(dp) :: center_h1, center_he4
2901 : integer :: nz, j
2902 : include 'formats'
2903 12 : nz = s% nz
2904 :
2905 12 : s% phase_of_evolution = phase_starting
2906 12 : if (s%doing_first_model_of_run) return
2907 :
2908 10 : j = s% net_iso(ih1)
2909 10 : if (j > 0) then
2910 10 : center_h1 = center_avg_x(s,j)
2911 : else
2912 : center_h1 = 1d99
2913 : end if
2914 10 : j = s% net_iso(ihe4)
2915 10 : if (j > 0) then
2916 10 : center_he4 = center_avg_x(s,j)
2917 : else
2918 : center_he4 = 1d99
2919 : end if
2920 :
2921 10 : if (s% doing_relax) then
2922 0 : s% phase_of_evolution = phase_relax
2923 10 : else if (s% photosphere_logg > 6d0) then
2924 0 : s% phase_of_evolution = phase_WDCS
2925 10 : else if (s% L_by_category(i_burn_si) > 1d2) then
2926 0 : s% phase_of_evolution = phase_Si_Burn
2927 10 : else if ( (s% L_by_category(ioo) + s% L_by_category(ico)) > 1d2 .and. center_he4 < 1d-4) then
2928 0 : s% phase_of_evolution = phase_O_Burn
2929 10 : else if (s% L_by_category(i_burn_ne) > 1d2 .and. center_he4 < 1d-4) then
2930 0 : s% phase_of_evolution = phase_Ne_Burn
2931 10 : else if (s% L_by_category(icc) > 1d2 .and. center_he4 < 1d-4) then
2932 0 : s% phase_of_evolution = phase_C_Burn
2933 : else if (center_he4 < 1d-4 .and. &
2934 40 : s% he_core_mass - s% co_core_mass <= 0.1d0 .and. &
2935 : any(s% burn_he_conv_region(1:s% num_conv_boundaries))) then
2936 0 : s% phase_of_evolution = phase_TP_AGB
2937 10 : else if (center_he4 <= 1d-4) then
2938 0 : s% phase_of_evolution = phase_TACHeB
2939 10 : else if (s% center_eps_burn(i3alf) > 1d2) then
2940 0 : s% phase_of_evolution = phase_ZACHeB
2941 10 : else if (s% L_by_category(i3alf) > 1d2) then
2942 0 : s% phase_of_evolution = phase_He_Burn
2943 10 : else if (center_h1 <= 1d-6) then
2944 0 : s% phase_of_evolution = phase_TAMS
2945 10 : else if (center_h1 <= 0.3d0) then
2946 0 : s% phase_of_evolution = phase_IAMS
2947 10 : else if (s% L_nuc_burn_total >= s% L_phot*s% Lnuc_div_L_zams_limit) then
2948 10 : s% phase_of_evolution = phase_ZAMS
2949 0 : else if (s% log_center_temperature > 5d0) then
2950 0 : s% phase_of_evolution = phase_PreMS
2951 : else
2952 : s% phase_of_evolution = phase_starting
2953 : end if
2954 :
2955 12 : end subroutine set_phase_of_evolution
2956 :
2957 :
2958 79994 : subroutine set_rv_info(s,k)
2959 : type (star_info), pointer :: s
2960 : integer, intent(in) :: k
2961 : include 'formats'
2962 79994 : if (s% v_flag) then
2963 0 : if (s% using_velocity_time_centering) then
2964 0 : s% vc(k) = 0.5d0*(s% v_start(k) + s% v(k))
2965 : else
2966 0 : s% vc(k) = s% v(k)
2967 : end if
2968 : else
2969 79994 : s% vc(k) = 0d0
2970 : end if
2971 12 : end subroutine set_rv_info
2972 :
2973 :
2974 0 : subroutine show_matrix(s, dmat, nvar)
2975 : type (star_info), pointer :: s
2976 : integer, intent(in) :: nvar
2977 : real(dp) :: dmat(nvar,nvar)
2978 : integer :: i, j
2979 0 : write(*,'(A)')
2980 0 : write(*,'(18x)', advance = 'no')
2981 0 : do j = 1, nvar
2982 0 : write(*,'(a15)', advance = 'no') s% nameofvar(j)
2983 : end do
2984 0 : write(*,'(A)')
2985 0 : do i = 1, nvar
2986 0 : write(*,'(a15)', advance = 'no') s% nameofequ(i)
2987 0 : do j = 1, nvar
2988 0 : write(*,'(e13.4,2x)', advance = 'no') dmat(i,j)
2989 : end do
2990 0 : write(*,'(A)')
2991 : end do
2992 0 : write(*,'(A)')
2993 0 : end subroutine show_matrix
2994 :
2995 :
2996 : ! e00(i,j,k) is partial of equ(i,k) wrt var(j,k)
2997 8375328 : subroutine e00(s,i,j,k,nvar,v)
2998 : type (star_info), pointer :: s
2999 : integer, intent(in) :: i, j, k, nvar
3000 : real(dp), intent(in) :: v
3001 : logical, parameter :: dbg = .false.
3002 : include 'formats'
3003 :
3004 : if (mdb .and. k==397 .and. v /= 0d0) &
3005 : write(*,4) 'e00(i,j,k) ' // &
3006 : trim(s% nameofequ(i)) // ' ' // trim(s% nameofvar(j)), i, j, k, v
3007 :
3008 : !if (j == s% i_lnd .and. k /= s% nz) return ! this variable is being held constant
3009 :
3010 8375328 : if (v == 0d0) return
3011 :
3012 : if (.false. .and. j == s% i_lnT .and. k == 30) then
3013 : write(*,4) 'e00(i,j,k) ' // &
3014 : trim(s% nameofequ(i)) // ' ' // trim(s% nameofvar(j)), i, j, k, v, s% x_scale(j,k)
3015 : end if
3016 :
3017 3641728 : if (is_bad(v)) then
3018 0 : !$omp critical (star_utils_e00_crit1)
3019 : write(*,4) 'e00(i,j,k) ' // &
3020 0 : trim(s% nameofequ(i)) // ' ' // trim(s% nameofvar(j)), i, j, k, v
3021 0 : if (s% stop_for_bad_nums) call mesa_error(__FILE__,__LINE__,'1 e00')
3022 : !$omp end critical (star_utils_e00_crit1)
3023 : end if
3024 :
3025 3641728 : if (i <= 0 .or. j <= 0 .or. k <= 0 .or. k > s% nz) then
3026 : write(*,4) 'bad i,j,k e00(i,j,k) ' // &
3027 0 : trim(s% nameofequ(i)) // ' ' // trim(s% nameofvar(j)), i, j, k, v
3028 0 : call mesa_error(__FILE__,__LINE__,'2 e00')
3029 : end if
3030 :
3031 3641728 : if (j > nvar) return ! hybrid
3032 :
3033 3641728 : if (i > nvar) then
3034 0 : !$omp critical (star_utils_e00_crit2)
3035 : write(*,5) 'bad i e00(i,j,k) ' // &
3036 0 : trim(s% nameofequ(i)) // ' ' // trim(s% nameofvar(j)), &
3037 0 : s% solver_iter, i, j, k, v
3038 0 : call mesa_error(__FILE__,__LINE__,'3 e00')
3039 : !$omp end critical (star_utils_e00_crit2)
3040 : end if
3041 :
3042 3641728 : if (abs(v) < 1d-250) return
3043 :
3044 3641728 : s% dblk(i,j,k) = s% dblk(i,j,k) + v*s% x_scale(j,k)
3045 :
3046 : end subroutine e00
3047 :
3048 :
3049 : ! em1(i,j,k) is partial of equ(i,k) wrt var(j,k-1)
3050 3766240 : subroutine em1(s,i,j,k,nvar,v)
3051 : type (star_info), pointer :: s
3052 : integer, intent(in) :: i, j, k, nvar
3053 : real(dp), intent(in) :: v
3054 : logical, parameter :: dbg = .false.
3055 3766240 : if (k == 1) return
3056 : include 'formats'
3057 :
3058 : if (mdb .and. k==397 .and. v /= 0d0) &
3059 : write(*,4) 'em1(i,j,k) ' // &
3060 : trim(s% nameofequ(i)) // ' ' // trim(s% nameofvar(j)), i, j, k, v
3061 :
3062 3765888 : if (v == 0d0) return
3063 :
3064 : if (.false. .and. j == s% i_lnT .and. k == 31) then
3065 : write(*,4) 'em1(i,j,k) ' // &
3066 : trim(s% nameofequ(i)) // ' ' // trim(s% nameofvar(j)), i, j, k, v, s% x_scale(j,k-1)
3067 : end if
3068 :
3069 887140 : if (is_bad(v)) then
3070 0 : !$omp critical (star_utils_em1_crit1)
3071 : write(*,4) 'em1(i,j,k) ' // &
3072 0 : trim(s% nameofequ(i)) // ' ' // trim(s% nameofvar(j)), i, j, k, v
3073 0 : if (s% stop_for_bad_nums) call mesa_error(__FILE__,__LINE__,'em1')
3074 : !$omp end critical (star_utils_em1_crit1)
3075 : end if
3076 :
3077 887140 : if (i <= 0 .or. j <= 0 .or. k <= 0 .or. k > s% nz) then
3078 : write(*,4) 'bad i,j,k em1(i,j,k) ' // &
3079 0 : trim(s% nameofequ(i)) // ' ' // trim(s% nameofvar(j)), i, j, k, v
3080 0 : call mesa_error(__FILE__,__LINE__,'em1')
3081 : end if
3082 :
3083 887140 : if (j > nvar) return ! hybrid
3084 :
3085 887140 : if (i > nvar) then
3086 : write(*,5) 'bad i em1(i,j,k) ' // &
3087 0 : trim(s% nameofequ(i)) // ' ' // trim(s% nameofvar(j)), &
3088 0 : s% solver_iter, i, j, k, v
3089 0 : call mesa_error(__FILE__,__LINE__,'em1')
3090 : end if
3091 :
3092 887140 : if (abs(v) < 1d-250) return
3093 :
3094 887140 : s% lblk(i,j,k) = s% lblk(i,j,k) + v*s% x_scale(j,k-1)
3095 :
3096 : end subroutine em1
3097 :
3098 :
3099 : ! ep1(i,j,k) is partial of equ(i,k) wrt var(j,k+1)
3100 3766240 : subroutine ep1(s,i,j,k,nvar,v)
3101 : type (star_info), pointer :: s
3102 : integer, intent(in) :: i, j, k, nvar
3103 : real(dp), intent(in) :: v
3104 : logical, parameter :: dbg = .false.
3105 : include 'formats'
3106 :
3107 : if (mdb .and. k==397 .and. v /= 0d0) &
3108 : write(*,4) 'ep1(i,j,k) ' // &
3109 : trim(s% nameofequ(i)) // ' ' // trim(s% nameofvar(j)), i, j, k, v
3110 :
3111 3766240 : if (v == 0d0) return
3112 :
3113 : if (.false. .and. j == s% i_lnT .and. k == 29) then
3114 : write(*,4) 'ep1(i,j,k) ' // &
3115 : trim(s% nameofequ(i)) // ' ' // trim(s% nameofvar(j)), i, j, k, v, s% x_scale(j,k+1)
3116 : end if
3117 :
3118 526718 : if (is_bad(v)) then
3119 0 : !$omp critical (star_utils_ep1_crit1)
3120 : write(*,4) 'ep1(i,j,k) ' // &
3121 0 : trim(s% nameofequ(i)) // ' ' // trim(s% nameofvar(j)), i, j, k, v
3122 0 : if (s% stop_for_bad_nums) call mesa_error(__FILE__,__LINE__,'ep1')
3123 : !$omp end critical (star_utils_ep1_crit1)
3124 : end if
3125 :
3126 526718 : if (i <= 0 .or. j <= 0 .or. k <= 0 .or. k > s% nz) then
3127 : write(*,4) 'bad i,j,k ep1(i,j,k) ' // &
3128 0 : trim(s% nameofequ(i)) // ' ' // trim(s% nameofvar(j)), i, j, k, v
3129 0 : call mesa_error(__FILE__,__LINE__,'ep1')
3130 : end if
3131 :
3132 526718 : if (j > nvar) return
3133 :
3134 526718 : if (i > nvar) then
3135 : write(*,5) 'bad i ep1(i,j,k) ' // &
3136 0 : trim(s% nameofequ(i)) // ' ' // trim(s% nameofvar(j)), &
3137 0 : s% solver_iter, i, j, k, v
3138 0 : call mesa_error(__FILE__,__LINE__,'ep1')
3139 : end if
3140 :
3141 526718 : if (abs(v) < 1d-250) return
3142 :
3143 526718 : s% ublk(i,j,k) = s% ublk(i,j,k) + v*s% x_scale(j,k+1)
3144 :
3145 : end subroutine ep1
3146 :
3147 :
3148 66 : real(dp) function current_min_xa_hard_limit(s) result(min_xa_hard_limit)
3149 : type (star_info), pointer :: s
3150 66 : real(dp) :: logTc, alfa
3151 66 : logTc = s% lnT(s% nz)/ln10
3152 66 : if (logTc <= s% logT_max_for_min_xa_hard_limit) then
3153 66 : min_xa_hard_limit = s% min_xa_hard_limit
3154 0 : else if (logTc >= s% logT_min_for_min_xa_hard_limit_for_highT) then
3155 0 : min_xa_hard_limit = s% min_xa_hard_limit_for_highT
3156 : else
3157 : alfa = (logTc - s% logT_max_for_min_xa_hard_limit) / &
3158 0 : (s% logT_min_for_min_xa_hard_limit_for_highT - s% logT_max_for_min_xa_hard_limit)
3159 : min_xa_hard_limit = &
3160 0 : alfa*s% min_xa_hard_limit_for_highT + (1d0 - alfa)*s% min_xa_hard_limit
3161 : end if
3162 66 : end function current_min_xa_hard_limit
3163 :
3164 :
3165 33 : real(dp) function current_sum_xa_hard_limit(s) result(sum_xa_hard_limit)
3166 : type (star_info), pointer :: s
3167 33 : real(dp) :: logTc, alfa
3168 : include 'formats'
3169 33 : logTc = s% lnT(s% nz)/ln10
3170 33 : if (logTc <= s% logT_max_for_sum_xa_hard_limit) then
3171 33 : sum_xa_hard_limit = s% sum_xa_hard_limit
3172 0 : else if (logTc >= s% logT_min_for_sum_xa_hard_limit_for_highT) then
3173 0 : sum_xa_hard_limit = s% sum_xa_hard_limit_for_highT
3174 : else
3175 : alfa = (logTc - s% logT_max_for_sum_xa_hard_limit) / &
3176 0 : (s% logT_min_for_sum_xa_hard_limit_for_highT - s% logT_max_for_sum_xa_hard_limit)
3177 : sum_xa_hard_limit = &
3178 0 : alfa*s% sum_xa_hard_limit_for_highT + (1d0 - alfa)*s% sum_xa_hard_limit
3179 : end if
3180 : !write(*,1) 'logTc hard_limit', logTc, sum_xa_hard_limit
3181 33 : end function current_sum_xa_hard_limit
3182 :
3183 :
3184 0 : integer function no_extra_profile_columns(id)
3185 : use star_def, only: star_info
3186 : integer, intent(in) :: id
3187 0 : no_extra_profile_columns = 0
3188 0 : end function no_extra_profile_columns
3189 :
3190 :
3191 0 : subroutine no_data_for_extra_profile_columns(id, n, nz, names, vals, ierr)
3192 0 : use star_def, only: maxlen_profile_column_name, star_info
3193 : integer, intent(in) :: id, n, nz
3194 : character (len=maxlen_profile_column_name) :: names(n)
3195 : real(dp) :: vals(nz,n)
3196 : integer, intent(out) :: ierr
3197 0 : ierr = 0
3198 0 : end subroutine no_data_for_extra_profile_columns
3199 :
3200 :
3201 : ! Stiriba, Youssef, Appl, Numer. Math. 45, 499-511. 2003.
3202 :
3203 : ! LPP-HARMOD -- local piecewise parabolic reconstruction
3204 :
3205 : ! interpolant is derived to conserve integral of v in cell k
3206 : ! interpolant slope at cell midpoint is harmonic mean of slopes between adjacent cells
3207 : ! where these slopes between cells are defined as the difference between cell averages
3208 : ! divided by the distance between cell midpoints.
3209 : ! interpolant curvature based on difference between the midpoint slope
3210 : ! and the smaller in magnitude of the slopes between adjacent cells.
3211 :
3212 : ! interpolant f(dq) = a + b*dq + (c/2)*dq^2, with dq = q - q_midpoint
3213 : ! c0 holds a's, c1 holds b's, and c2 holds c's.
3214 :
3215 :
3216 : subroutine get1_lpp(k, nz, &
3217 : dm1, d00, dp1, vm1, v00, vp1, quadratic, monotonic, dbg, c0, c1, c2)
3218 : integer, intent(in) :: k, nz
3219 : real(dp), intent(in) :: dm1, d00, dp1, vm1, v00, vp1
3220 : logical, intent(in) :: quadratic, monotonic
3221 : logical, intent(in) :: dbg
3222 : real(dp), intent(out) :: c0, c1, c2
3223 : real(dp) :: vbdy1, vbdy2, dhalf, sm1, s00, sp1, sprod, dv1, dv2
3224 : logical :: okay
3225 : include 'formats'
3226 :
3227 : c0 = v00
3228 : c2 = 0d0
3229 : if (k == 1) then
3230 : sm1 = 0d0
3231 : sp1 = (v00 - vp1) / (0.5d0*(d00 + dp1))
3232 : c1 = sp1
3233 : else if (k == nz) then
3234 : sp1 = 0d0
3235 : sm1 = (vm1 - v00) / (0.5d0*(dm1 + d00))
3236 : c1 = sm1
3237 : if (dbg) then
3238 : write(*,2) 'get1_lpp c1', k, c1
3239 : end if
3240 : else
3241 : sm1 = (vm1 - v00) / (0.5d0*(dm1 + d00))
3242 : sp1 = (v00 - vp1) / (0.5d0*(d00 + dp1))
3243 : sprod = sm1*sp1
3244 : if (sprod <= 0d0) then
3245 : ! at local min or max, so set slope and curvature to 0.
3246 : c1 = 0d0
3247 : return
3248 : end if
3249 : if (.not. quadratic) then ! minmod
3250 : s00 = (vm1 - vp1)/(d00 + (dm1 + dp1)/2)
3251 : c1 = sm1
3252 : if (sm1*s00 < 0d0) c1 = 0d0
3253 : if (abs(s00) < abs(c1)) c1 = s00
3254 : if (s00*sp1 < 0d0) c1 = 0d0
3255 : if (abs(sp1) < abs(c1)) c1 = sp1
3256 : else
3257 : c1 = sprod*2/(sp1 + sm1) ! harmonic mean slope
3258 : if (abs(sm1) <= abs(sp1)) then
3259 : c2 = (sm1 - c1)/(2d0*d00)
3260 : else
3261 : c2 = (c1 - sp1)/(2d0*d00)
3262 : end if
3263 : c0 = v00 - c2*d00*d00/24d0
3264 : end if
3265 : end if
3266 :
3267 : if (.not. monotonic) return
3268 :
3269 : dhalf = 0.5d0*d00
3270 : dv1 = c1*dhalf
3271 : dv2 = 0.5d0*c2*dhalf*dhalf
3272 : vbdy1 = c0 + dv1 + dv2 ! value at face(k)
3273 : vbdy2 = c0 - dv1 + dv2 ! value at face(k+1)
3274 :
3275 : okay = .true.
3276 :
3277 : if (k > 1) then ! check v00 <= vbdy1 <= vm1 or v00 >= vbdy1 >= vm1
3278 : if ((vm1 - vbdy1)*(vbdy1 - v00) < 0d0) okay = .false.
3279 : end if
3280 :
3281 : if (k < nz) then ! check vp1 <= vdby2 <= v00 or vp1 >= vdby2 >= v00
3282 : if ((v00 - vbdy2)*(vbdy2 - vp1) < 0d0) okay = .false.
3283 : end if
3284 :
3285 : if (okay) return
3286 :
3287 : c0 = v00
3288 : c2 = 0d0
3289 :
3290 : if (k == 1) then
3291 : c1 = (v00 - vp1) / (0.5d0*(d00 + dp1))
3292 : else if (k == nz) then
3293 : c1 = (vm1 - v00) / (0.5d0*(dm1 + d00))
3294 : else if (abs(sm1) <= abs(sp1)) then
3295 : c1 = sm1
3296 : else
3297 : c1 = sp1
3298 : end if
3299 :
3300 0 : end subroutine get1_lpp
3301 :
3302 :
3303 0 : subroutine calc_Ptrb_ad_tw(s, k, Ptrb, Ptrb_div_etrb, ierr)
3304 : ! note: Ptrb_div_etrb is not time weighted
3305 : ! erg cm^-3 = g cm^2 s^-2 cm^-3 = g cm^-1 s^-2
3306 : use auto_diff
3307 : use auto_diff_support
3308 : type (star_info), pointer :: s
3309 : integer, intent(in) :: k
3310 : type(auto_diff_real_star_order1), intent(out) :: Ptrb, Ptrb_div_etrb
3311 : integer, intent(out) :: ierr
3312 : type(auto_diff_real_star_order1) :: etrb, rho
3313 0 : real(dp) :: Ptrb_start
3314 : real(dp), parameter :: x_ALFAP = 2.d0/3.d0
3315 : logical :: time_center, test_partials
3316 : include 'formats'
3317 0 : ierr = 0
3318 : if (s% RSP2_alfap == 0 .or. s% mixing_length_alpha == 0 .or. &
3319 0 : k <= s% RSP2_num_outermost_cells_forced_nonturbulent .or. &
3320 : k > s% nz - int(s% nz/s% RSP_nz_div_IBOTOM)) then
3321 0 : Ptrb_div_etrb = 0d0
3322 0 : Ptrb = 0d0
3323 : return
3324 : end if
3325 0 : rho = wrap_d_00(s,k)
3326 0 : etrb = wrap_etrb_00(s,k)
3327 0 : Ptrb_div_etrb = s% RSP2_alfap*x_ALFAP*etrb*rho
3328 0 : Ptrb = Ptrb_div_etrb*etrb ! cm^2 s^-2 g cm^-3 = erg cm^-3
3329 : time_center = (s% using_velocity_time_centering .and. &
3330 0 : s% include_P_in_velocity_time_centering)
3331 : if (time_center) then
3332 0 : Ptrb_start = s% RSP2_alfap*get_etrb_start(s,k)*s% rho_start(k)
3333 : Ptrb = s% P_theta_for_velocity_time_centering*Ptrb + &
3334 0 : (1d0 - s% P_theta_for_velocity_time_centering)*Ptrb_start
3335 : end if
3336 :
3337 0 : if (is_bad(Ptrb%val)) then
3338 0 : !$omp critical (calc_Ptrb_ad_tw_crit)
3339 0 : write(*,2) 'Ptrb', k, Ptrb%val
3340 0 : call mesa_error(__FILE__,__LINE__,'calc_Ptrb_tw')
3341 : !$omp end critical (calc_Ptrb_ad_tw_crit)
3342 : end if
3343 :
3344 : !test_partials = (k == s% solver_test_partials_k)
3345 0 : test_partials = .false.
3346 : if (test_partials) then
3347 : s% solver_test_partials_val = Ptrb%val
3348 : !s% solver_test_partials_var = i_var_R
3349 : !s% solver_test_partials_dval_dx = 0 ! d_residual_dr_00
3350 : write(*,*) 'calc_Ptrb_ad_tw', s% solver_test_partials_var
3351 : end if
3352 :
3353 0 : end subroutine calc_Ptrb_ad_tw
3354 :
3355 :
3356 : ! Ptot_ad = Peos_ad + Pvsc_ad + Ptrb_ad + mlt_Pturb_ad with time weighting
3357 104608 : subroutine calc_Ptot_ad_tw( &
3358 104608 : s, k, skip_Peos, skip_mlt_Pturb, Ptot_ad, d_Ptot_dxa, ierr)
3359 0 : use auto_diff_support
3360 : type (star_info), pointer :: s
3361 : integer, intent(in) :: k
3362 : logical, intent(in) :: skip_Peos, skip_mlt_Pturb
3363 : type(auto_diff_real_star_order1), intent(out) :: Ptot_ad
3364 : real(dp), dimension(s% species), intent(out) :: d_Ptot_dxa
3365 : integer, intent(out) :: ierr
3366 : integer :: j
3367 104608 : real(dp) :: mlt_Pturb_start, alfa, beta
3368 : type(auto_diff_real_star_order1) :: &
3369 : Peos_ad, Pvsc_ad, Ptrb_ad, mlt_Pturb_ad, Ptrb_ad_div_etrb
3370 : logical :: time_center
3371 : include 'formats'
3372 :
3373 104608 : ierr = 0
3374 941472 : d_Ptot_dxa = 0d0
3375 :
3376 : time_center = (s% using_velocity_time_centering .and. &
3377 104608 : s% include_P_in_velocity_time_centering)
3378 : if (time_center) then
3379 0 : alfa = s% P_theta_for_velocity_time_centering
3380 : else
3381 104608 : alfa = 1d0
3382 : end if
3383 104608 : beta = 1d0 - alfa
3384 :
3385 104608 : Peos_ad = 0d0
3386 104608 : if (.not. skip_Peos) then
3387 104608 : Peos_ad = wrap_peos_00(s, k)
3388 104608 : Peos_ad = alfa*Peos_ad + beta*s% Peos_start(k)
3389 941472 : do j=1,s% species
3390 836864 : d_Ptot_dxa(j) = s% Peos(k)*s% dlnPeos_dxa_for_partials(j,k)
3391 941472 : d_Ptot_dxa(j) = alfa*d_Ptot_dxa(j)
3392 : end do
3393 : end if
3394 :
3395 104608 : Pvsc_ad = 0d0
3396 104608 : if (s% use_Pvsc_art_visc) then
3397 0 : call get_Pvsc_ad(s, k, Pvsc_ad, ierr) ! no time centering for Pvsc
3398 0 : if (ierr /= 0) return
3399 : ! NO TIME CENTERING FOR Pvsc: Pvsc_ad = alfa*Pvsc_ad + beta*s% Pvsc_start(k)
3400 : end if
3401 :
3402 104608 : Ptrb_ad = 0d0
3403 104608 : if (s% RSP2_flag) then
3404 0 : call calc_Ptrb_ad_tw(s, k, Ptrb_ad, Ptrb_ad_div_etrb, ierr)
3405 0 : if (ierr /= 0) return
3406 : ! note that Ptrb_ad is already time weighted
3407 : end if
3408 :
3409 104608 : mlt_Pturb_ad = 0d0
3410 104608 : if ((.not. skip_mlt_Pturb) .and. s% mlt_Pturb_factor > 0d0 .and. k > 1) then
3411 0 : mlt_Pturb_ad = s% mlt_Pturb_factor*pow2(s% mlt_vc_old(k))*get_rho_face(s,k)/3d0
3412 0 : if (time_center) then
3413 : mlt_Pturb_start = &
3414 0 : s% mlt_Pturb_factor*pow2(s% mlt_vc_old(k))*(s% rho_start(k-1) + s% rho_start(k))/6d0
3415 0 : mlt_Pturb_ad = alfa*mlt_Pturb_ad + beta*mlt_Pturb_start
3416 : end if
3417 : end if
3418 :
3419 104608 : Ptot_ad = Peos_ad + Pvsc_ad + Ptrb_ad + mlt_Pturb_ad
3420 :
3421 104608 : if (s% use_other_pressure) Ptot_ad = Ptot_ad + s% extra_pressure(k)
3422 :
3423 104608 : end subroutine calc_Ptot_ad_tw
3424 :
3425 :
3426 0 : subroutine get_Pvsc_ad(s, k, Pvsc, ierr)
3427 104608 : use auto_diff
3428 : use auto_diff_support
3429 : type (star_info), pointer :: s
3430 : integer, intent(in) :: k
3431 : type(auto_diff_real_star_order1), intent(out) :: Pvsc
3432 : integer, intent(out) :: ierr
3433 : type(auto_diff_real_star_order1) :: v00, vp1, Peos, rho, &
3434 : Peos_div_rho, dv
3435 0 : real(dp) :: Pvsc_start, cq, zsh
3436 0 : Pvsc = 0
3437 0 : s% Pvsc(k) = 0d0
3438 0 : Pvsc_start = s% Pvsc_start(k)
3439 0 : if (Pvsc_start < 0d0) s% Pvsc_start(k) = 0d0
3440 0 : if (.not. (s% v_flag .and. s% use_Pvsc_art_visc)) return
3441 0 : cq = s% Pvsc_cq
3442 0 : if (cq == 0d0) return
3443 0 : zsh = s% Pvsc_zsh
3444 0 : v00 = wrap_v_00(s,k)
3445 0 : vp1 = wrap_v_p1(s,k)
3446 0 : Peos = wrap_Peos_00(s,k)
3447 0 : rho = wrap_d_00(s,k)
3448 0 : Peos_div_rho = Peos/rho
3449 0 : dv = (vp1 - v00) - zsh*sqrt(Peos_div_rho)
3450 0 : if (dv%val <= 0d0) return
3451 0 : Pvsc = cq*rho*pow2(dv)
3452 0 : s% Pvsc(k) = Pvsc%val
3453 0 : if (Pvsc_start < 0d0) s% Pvsc_start(k) = s% Pvsc(k)
3454 0 : end subroutine get_Pvsc_ad
3455 :
3456 :
3457 : ! marsaglia and zaman random number generator. period is 2**43 with
3458 : ! 900 million different sequences. the state of the generator (for restarts)
3459 2 : subroutine init_random(s)
3460 : type (star_info), pointer :: s
3461 : integer :: ijkl,ij,kl,i,j,k,l,ii,jj,m
3462 2 : real(dp) :: x,t
3463 2 : ijkl = 54217137
3464 2 : ij = ijkl/30082
3465 2 : kl = ijkl - 30082 * ij
3466 2 : i = mod(ij/177,177) + 2
3467 2 : j = mod(ij,177) + 2
3468 2 : k = mod(kl/169,178) + 1
3469 2 : l = mod(kl,169)
3470 196 : do ii=1,97
3471 : x = 0.0d0
3472 : t = 0.5d0
3473 4850 : do jj =1,24
3474 4656 : m = mod(mod(i*j,179)*k,179)
3475 4656 : i = j
3476 4656 : j = k
3477 4656 : k = m
3478 4656 : l = mod(53*l + 1, 169)
3479 4656 : if (mod(l*m,64) >= 32) x = x + t
3480 4850 : t = 0.5d0 * t
3481 : end do
3482 196 : s% rand_u(ii) = x
3483 : end do
3484 2 : s% rand_c = 362436.0d0/16777216.0d0
3485 2 : s% rand_cd = 7654321.0d0/16777216.0d0
3486 2 : s% rand_cm = 16777213.0d0/16777216.0d0
3487 2 : s% rand_i97 = 97
3488 2 : s% rand_j97 = 33
3489 0 : end subroutine init_random
3490 :
3491 :
3492 0 : real(dp) function rand(s)
3493 : type (star_info), pointer :: s
3494 0 : real(dp) :: uni
3495 0 : uni = s% rand_u(s% rand_i97) - s% rand_u(s% rand_j97)
3496 0 : if (uni < 0.0d0) uni = uni + 1.0d0
3497 0 : s% rand_u(s% rand_i97) = uni
3498 0 : s% rand_i97 = s% rand_i97 - 1
3499 0 : if (s% rand_i97 == 0) s% rand_i97 = 97
3500 0 : s% rand_j97 = s% rand_j97 - 1
3501 0 : if (s% rand_j97 == 0) s% rand_j97 = 97
3502 0 : s% rand_c = s% rand_c - s% rand_cd
3503 0 : if (s% rand_c < 0.0d0) s% rand_c = s% rand_c + s% rand_cm
3504 0 : uni = uni - s% rand_c
3505 0 : if (uni < 0.0d0) uni = uni + 1.0d0
3506 0 : rand = uni
3507 0 : end function rand
3508 :
3509 :
3510 4 : subroutine write_to_extra_terminal_output_file(s, str, advance)
3511 : type (star_info), pointer :: s
3512 : character(len=*), intent(in) :: str
3513 : logical, intent(in) :: advance
3514 : integer :: ierr, io
3515 4 : if (len_trim(s% extra_terminal_output_file) > 0) then
3516 0 : ierr = 0
3517 : open(newunit=io, file=trim(s% extra_terminal_output_file), &
3518 0 : action='write', position='append', iostat=ierr)
3519 0 : if (ierr == 0) then
3520 0 : if (advance) then
3521 0 : write(io,'(a)') trim(str)
3522 : else
3523 0 : write(io,'(a)',advance='no') trim(str)
3524 : end if
3525 0 : close(io)
3526 : else
3527 : write(*,*) 'failed to open extra_terminal_output_file ' // &
3528 0 : trim(s% extra_terminal_output_file)
3529 : end if
3530 : end if
3531 4 : end subroutine write_to_extra_terminal_output_file
3532 :
3533 :
3534 0 : subroutine write_eos_call_info(s,k)
3535 : use chem_def
3536 : type (star_info), pointer :: s
3537 : integer, intent(in) :: k ! 0 means not being called for a particular cell
3538 : integer :: j
3539 : include 'formats'
3540 0 : !$OMP critical (omp_write_eos_call_info)
3541 0 : write(*,'(A)')
3542 0 : do j=1,s% species
3543 0 : write(*,4) 'xa(j,k) ' // trim(chem_isos% name(s% chem_id(j))), j, j+s% nvar_hydro, k, s% xa(j,k)
3544 : end do
3545 0 : write(*,1) 'sum(xa) =', sum(s% xa(:,k))
3546 0 : write(*,1) 'Pgas = ', s% Pgas(k)
3547 0 : write(*,1) 'logPgas = ', s% lnPgas(k)/ln10
3548 0 : write(*,1) 'rho = ', s% rho(k)
3549 0 : write(*,1) 'T = ', s% T(k)
3550 0 : write(*,1) 'logQ = ', s% lnd(k)/ln10 - 2*s% lnT(k)/ln10 + 12
3551 0 : write(*,'(A)')
3552 0 : write(*,1) 'eos_frac_OPAL_SCVH', s% eos_frac_OPAL_SCVH(k)
3553 0 : write(*,1) 'eos_frac_HELM', s% eos_frac_HELM(k)
3554 0 : write(*,1) 'eos_frac_Skye', s% eos_frac_Skye(k)
3555 0 : write(*,1) 'eos_frac_PC', s% eos_frac_PC(k)
3556 0 : write(*,1) 'eos_frac_FreeEOS', s% eos_frac_FreeEOS(k)
3557 0 : write(*,1) 'eos_frac_CMS', s% eos_frac_CMS(k)
3558 0 : write(*,1) 'eos_frac_ideal', s% eos_frac_ideal(k)
3559 0 : write(*,'(A)')
3560 0 : write(*,1) 'Peos = ', s% Peos(k)
3561 0 : write(*,1) 'Prad = ', s% Prad(k)
3562 0 : write(*,1) 'logPeos = ', s% lnPeos(k)/ln10
3563 0 : write(*,1) 'logS = ', s% lnS(k)/ln10
3564 0 : write(*,1) 'logE = ', s% lnE(k)/ln10
3565 0 : write(*,1) 'energy = ', s% energy(k)
3566 0 : write(*,1) 'grada = ', s% grada(k)
3567 0 : write(*,1) 'Cv = ', s% Cv(k)
3568 0 : write(*,1) 'dE_dRho = ', s% dE_dRho(k)
3569 0 : write(*,1) 'cp = ', s% cp(k)
3570 0 : write(*,1) 'gamma1 = ', s% gamma1(k)
3571 0 : write(*,1) 'gamma3 = ', s% gamma3(k)
3572 0 : write(*,1) 'eta = ', s% eta(k)
3573 0 : write(*,1) 'gam = ', s% gam(k)
3574 0 : write(*,1) 'mu = ', s% mu(k)
3575 0 : write(*,1) 'log_free_e = ', s% lnfree_e(k)/ln10
3576 0 : write(*,1) 'chiRho = ', s% chiRho(k)
3577 0 : write(*,1) 'chiT = ', s% chiT(k)
3578 0 : write(*,'(A)')
3579 0 : write(*,*) 'do_eos_for_cell k, nz', k, s% nz
3580 0 : write(*,1) 'logRho = ', s% lnd(k)/ln10
3581 0 : write(*,1) 'logT = ', s% lnT(k)/ln10
3582 0 : write(*,1) 'z = ', s% Z(k)
3583 0 : write(*,1) 'x = ', s% X(k)
3584 0 : write(*,1) 'abar = ', s% abar(k)
3585 0 : write(*,1) 'zbar = ', s% zbar(k)
3586 0 : write(*,'(A)')
3587 0 : write(*,1) 'tau = ', s% tau(k)
3588 0 : write(*,'(A)')
3589 0 : write(*,*) 's% eos_rq% tiny_fuzz', s% eos_rq% tiny_fuzz
3590 0 : write(*,'(A)')
3591 : !call mesa_error(__FILE__,__LINE__,'write_eos_call_info')
3592 : !$OMP end critical (omp_write_eos_call_info)
3593 0 : end subroutine write_eos_call_info
3594 :
3595 :
3596 239 : real(dp) function surface_avg_x(s,j)
3597 : type (star_info), pointer :: s
3598 : integer, intent(in) :: j
3599 239 : real(dp) :: sum_x, sum_dq
3600 : integer :: k
3601 : include 'formats'
3602 239 : if (j == 0) then
3603 239 : surface_avg_x = 0d0
3604 : return
3605 : end if
3606 239 : sum_x = 0
3607 239 : sum_dq = 0
3608 50668 : do k = 1, s% nz
3609 50668 : sum_x = sum_x + s% xa(j,k)*s% dq(k)
3610 50668 : sum_dq = sum_dq + s% dq(k)
3611 50668 : if (sum_dq >= s% surface_avg_abundance_dq) exit
3612 : end do
3613 239 : surface_avg_x = sum_x/sum_dq
3614 239 : end function surface_avg_x
3615 :
3616 :
3617 300 : real(dp) function center_avg_x(s,j)
3618 : type (star_info), pointer :: s
3619 : integer, intent(in) :: j
3620 300 : real(dp) :: sum_x, sum_dq, dx, dq
3621 : integer :: k
3622 300 : if (j == 0) then
3623 300 : center_avg_x = 0d0
3624 : return
3625 : end if
3626 267 : sum_x = 0
3627 267 : sum_dq = 0
3628 267 : do k = s% nz, 1, -1
3629 267 : dq = s% dq(k)
3630 267 : dx = s% xa(j,k)*dq
3631 267 : if (sum_dq+dq >= s% center_avg_value_dq) then
3632 267 : sum_x = sum_x+ dx*(s% center_avg_value_dq - sum_dq)/dq
3633 267 : sum_dq = s% center_avg_value_dq
3634 267 : exit
3635 : end if
3636 0 : sum_x = sum_x + dx
3637 0 : sum_dq = sum_dq + dq
3638 : end do
3639 267 : center_avg_x = sum_x/sum_dq
3640 267 : end function center_avg_x
3641 :
3642 :
3643 209260 : subroutine get_area_info_opt_time_center(s, k, area, inv_R2, ierr)
3644 : use auto_diff_support
3645 : type (star_info), pointer :: s
3646 : integer, intent(in) :: k
3647 : type(auto_diff_real_star_order1), intent(out) :: area, inv_R2
3648 : integer, intent(out) :: ierr
3649 : type(auto_diff_real_star_order1) :: r_00, r2_00
3650 209260 : ierr = 0
3651 209260 : r_00 = wrap_r_00(s,k)
3652 209260 : r2_00 = pow2(r_00)
3653 209260 : if (s% using_velocity_time_centering) then
3654 0 : area = 4d0*pi*(r2_00 + r_00*s% r_start(k) + s% r_start(k)**2)/3d0
3655 0 : inv_R2 = 1d0/(r_00*s% r_start(k))
3656 : else
3657 209260 : area = 4d0*pi*r2_00
3658 209260 : inv_R2 = 1d0/r2_00
3659 : end if
3660 209260 : end subroutine get_area_info_opt_time_center
3661 :
3662 :
3663 52348 : subroutine set_energy_eqn_scal(s, k, scal, ierr) ! 1/(erg g^-1 s^-1)
3664 : type (star_info), pointer :: s
3665 : integer, intent(in) :: k
3666 : real(dp), intent(out) :: scal
3667 : integer, intent(out) :: ierr
3668 52348 : real(dp) :: cell_energy_fraction_start
3669 : include 'formats'
3670 52348 : ierr = 0
3671 52348 : if (k > 1) then
3672 52304 : scal = 1d0
3673 : else
3674 44 : scal = 1d-6
3675 : end if
3676 52348 : if (s% dedt_eqn_r_scale > 0d0) then
3677 : cell_energy_fraction_start = &
3678 52348 : s% energy_start(k)*s% dm(k)/s% total_internal_energy_old
3679 52348 : scal = min(scal, cell_energy_fraction_start*s% dedt_eqn_r_scale)
3680 : end if
3681 52348 : scal = scal*s% dt/s% energy_start(k)
3682 209260 : end subroutine set_energy_eqn_scal
3683 :
3684 :
3685 107640 : real(dp) function conv_time_scale(s,k_in) result(tau_conv)
3686 : type (star_info), pointer :: s
3687 : integer, intent(in) :: k_in
3688 : integer :: k
3689 53820 : real(dp) :: brunt_B, alfa, beta, rho_face, Peos_face, chiT_face, chiRho_face, &
3690 53820 : f, dlnP, dlnT, grada_face, gradT_actual, brunt_N2
3691 53820 : if (.not. s% calculate_Brunt_B) then
3692 19823 : tau_conv = 0d0
3693 : return
3694 : end if
3695 53820 : k = max(2,k_in)
3696 53820 : brunt_B = s% brunt_B(k)
3697 53820 : call get_face_weights(s, k, alfa, beta)
3698 53820 : rho_face = alfa*s% rho(k) + beta*s% rho(k-1)
3699 53820 : Peos_face = alfa*s% Peos(k) + beta*s% Peos(k-1)
3700 53820 : chiT_face = alfa*s% chiT(k) + beta*s% chiT(k-1)
3701 53820 : chiRho_face = alfa*s% chiRho(k) + beta*s% chiRho(k-1)
3702 53820 : f = pow2(s% grav(k))*rho_face/Peos_face*chiT_face/chiRho_face
3703 53820 : dlnP = s% lnPeos(k-1) - s% lnPeos(k)
3704 53820 : dlnT = s% lnT(k-1) - s% lnT(k)
3705 53820 : grada_face = alfa*s% grada(k) + beta*s% grada(k-1)
3706 53820 : gradT_actual = safe_div_val(s, dlnT, dlnP) ! mlt has not been called yet when doing this
3707 53820 : brunt_N2 = f*(brunt_B - (gradT_actual - grada_face))
3708 53820 : if(abs(brunt_B) > 0d0) then
3709 33997 : tau_conv = 1d0/sqrt(abs(brunt_N2))
3710 : else
3711 : tau_conv = 0d0
3712 : end if
3713 : end function conv_time_scale
3714 :
3715 :
3716 44 : subroutine set_conv_time_scales(s)
3717 : type (star_info), pointer :: s
3718 : integer :: k
3719 44 : real(dp) :: tau_conv
3720 : include 'formats'
3721 44 : s% min_conv_time_scale = 1d99
3722 44 : s% max_conv_time_scale = 0d0
3723 53864 : do k=1,s%nz
3724 53820 : if (s% X(k) > s% max_X_for_conv_timescale) cycle
3725 53820 : if (s% X(k) < s% min_X_for_conv_timescale) cycle
3726 53820 : if (s% q(k) > s% max_q_for_conv_timescale) cycle
3727 53820 : if (s% q(k) < s% min_q_for_conv_timescale) exit
3728 53820 : tau_conv = conv_time_scale(s,k)
3729 53820 : if (tau_conv < s% min_conv_time_scale) &
3730 44 : s% min_conv_time_scale = tau_conv
3731 53820 : if (tau_conv > s% max_conv_time_scale) &
3732 1837 : s% max_conv_time_scale = tau_conv
3733 : end do
3734 44 : if (s% max_conv_time_scale == 0d0) s% max_conv_time_scale = 1d99
3735 44 : if (s% min_conv_time_scale == 1d99) s% min_conv_time_scale = 0d0
3736 44 : end subroutine set_conv_time_scales
3737 :
3738 :
3739 0 : real(dp) function QHSE_time_scale(s,k) result(tau_qhse)
3740 : type (star_info), pointer :: s
3741 : integer, intent(in) :: k
3742 0 : real(dp) :: abs_dv
3743 0 : if (s% v_flag) then
3744 0 : abs_dv = abs(s% v(k) - s% v_start(k))
3745 0 : else if (s% u_flag) then
3746 0 : abs_dv = abs(s% u_face_ad(k)%val - s% u_face_start(k))
3747 : else
3748 : abs_dv = 0d0
3749 : end if
3750 0 : tau_qhse = abs_dv/(s% cgrav(k)*s% m_grav(k)/pow2(s% r(k)))
3751 0 : end function QHSE_time_scale
3752 :
3753 :
3754 0 : real(dp) function eps_nuc_time_scale(s,k) result(tau_epsnuc)
3755 : type (star_info), pointer :: s
3756 : integer, intent(in) :: k
3757 0 : tau_epsnuc = s% Cp(k)*s% T(k)/max(1d-10,abs(s% eps_nuc(k)))
3758 0 : end function eps_nuc_time_scale
3759 :
3760 :
3761 0 : real(dp) function cooling_time_scale(s,k) result(tau_cool)
3762 : type (star_info), pointer :: s
3763 : integer, intent(in) :: k
3764 0 : real(dp) :: thermal_conductivity
3765 0 : thermal_conductivity = (4d0*crad*clight*pow3(s% T(k)))/(3d0*s% opacity(k)*s% rho(k)*s% Cp(k))
3766 0 : tau_cool = pow2(s% scale_height(k)) / thermal_conductivity
3767 0 : end function cooling_time_scale
3768 :
3769 :
3770 479766 : function get_rho_face(s,k) result(rho_face)
3771 : type (star_info), pointer :: s
3772 : integer, intent(in) :: k
3773 : type(auto_diff_real_star_order1) :: rho_face
3774 239982 : real(dp) :: alfa, beta
3775 239982 : if (k == 1) then
3776 198 : rho_face = wrap_d_00(s,k)
3777 198 : return
3778 : end if
3779 239784 : call get_face_weights(s, k, alfa, beta)
3780 239784 : rho_face = alfa*wrap_d_00(s,k) + beta*wrap_d_m1(s,k)
3781 239784 : end function get_rho_face
3782 :
3783 :
3784 0 : real(dp) function get_rho_face_val(s,k) result(rho_face)
3785 : type (star_info), pointer :: s
3786 : integer, intent(in) :: k
3787 0 : real(dp) :: alfa, beta
3788 0 : if (k == 1) then
3789 0 : rho_face = s% rho(1)
3790 0 : return
3791 : end if
3792 0 : call get_face_weights(s, k, alfa, beta)
3793 0 : rho_face = alfa*s% rho(k) + beta*s% rho(k-1)
3794 0 : end function get_rho_face_val
3795 :
3796 :
3797 319844 : function get_T_face(s,k) result(T_face)
3798 : type (star_info), pointer :: s
3799 : integer, intent(in) :: k
3800 : type(auto_diff_real_star_order1) :: T_face
3801 159988 : real(dp) :: alfa, beta
3802 159988 : if (k == 1) then
3803 132 : T_face = wrap_T_00(s,k)
3804 132 : return
3805 : end if
3806 159856 : call get_face_weights(s, k, alfa, beta)
3807 159856 : T_face = alfa*wrap_T_00(s,k) + beta*wrap_T_m1(s,k)
3808 159856 : end function get_T_face
3809 :
3810 :
3811 79994 : function get_Prad_face(s,k) result(Prad_face)
3812 : type (star_info), pointer :: s
3813 : integer, intent(in) :: k
3814 : type(auto_diff_real_star_order1) :: Prad_face
3815 79994 : Prad_face = crad*pow4(get_T_face(s,k))/3d0
3816 79994 : end function get_Prad_face
3817 :
3818 :
3819 479766 : function get_Peos_face(s,k) result(Peos_face)
3820 : type (star_info), pointer :: s
3821 : integer, intent(in) :: k
3822 : type(auto_diff_real_star_order1) :: Peos_face
3823 239982 : real(dp) :: alfa, beta
3824 239982 : if (k == 1) then
3825 198 : Peos_face = wrap_Peos_00(s,k)
3826 198 : return
3827 : end if
3828 239784 : call get_face_weights(s, k, alfa, beta)
3829 239784 : Peos_face = alfa*wrap_Peos_00(s,k) + beta*wrap_Peos_m1(s,k)
3830 239784 : end function get_Peos_face
3831 :
3832 :
3833 159922 : function get_Cp_face(s,k) result(Cp_face)
3834 : type (star_info), pointer :: s
3835 : integer, intent(in) :: k
3836 : type(auto_diff_real_star_order1) :: Cp_face
3837 79994 : real(dp) :: alfa, beta
3838 79994 : if (k == 1) then
3839 66 : Cp_face = wrap_Cp_00(s,k)
3840 66 : return
3841 : end if
3842 79928 : call get_face_weights(s, k, alfa, beta)
3843 79928 : Cp_face = alfa*wrap_Cp_00(s,k) + beta*wrap_Cp_m1(s,k)
3844 79928 : end function get_Cp_face
3845 :
3846 :
3847 159922 : function get_ChiRho_face(s,k) result(ChiRho_face)
3848 : type (star_info), pointer :: s
3849 : integer, intent(in) :: k
3850 : type(auto_diff_real_star_order1) :: ChiRho_face
3851 79994 : real(dp) :: alfa, beta
3852 79994 : if (k == 1) then
3853 66 : ChiRho_face = wrap_ChiRho_00(s,k)
3854 66 : return
3855 : end if
3856 79928 : call get_face_weights(s, k, alfa, beta)
3857 79928 : ChiRho_face = alfa*wrap_ChiRho_00(s,k) + beta*wrap_ChiRho_m1(s,k)
3858 79928 : end function get_ChiRho_face
3859 :
3860 :
3861 159922 : function get_ChiT_face(s,k) result(ChiT_face)
3862 : type (star_info), pointer :: s
3863 : integer, intent(in) :: k
3864 : type(auto_diff_real_star_order1) :: ChiT_face
3865 79994 : real(dp) :: alfa, beta
3866 79994 : if (k == 1) then
3867 66 : ChiT_face = wrap_ChiT_00(s,k)
3868 66 : return
3869 : end if
3870 79928 : call get_face_weights(s, k, alfa, beta)
3871 79928 : ChiT_face = alfa*wrap_ChiT_00(s,k) + beta*wrap_ChiT_m1(s,k)
3872 79928 : end function get_ChiT_face
3873 :
3874 :
3875 319844 : function get_kap_face(s,k) result(kap_face)
3876 : type (star_info), pointer :: s
3877 : integer, intent(in) :: k
3878 : type(auto_diff_real_star_order1) :: kap_face
3879 159988 : real(dp) :: alfa, beta
3880 159988 : if (k == 1) then
3881 132 : kap_face = wrap_kap_00(s,k)
3882 132 : return
3883 : end if
3884 159856 : call get_face_weights(s, k, alfa, beta)
3885 159856 : kap_face = alfa*wrap_kap_00(s,k) + beta*wrap_kap_m1(s,k)
3886 159856 : end function get_kap_face
3887 :
3888 :
3889 159922 : function get_grada_face(s,k) result(grada_face)
3890 : type (star_info), pointer :: s
3891 : integer, intent(in) :: k
3892 : type(auto_diff_real_star_order1) :: grada_face
3893 79994 : real(dp) :: alfa, beta
3894 79994 : if (k == 1) then
3895 66 : grada_face = wrap_grad_ad_00(s,k)
3896 66 : return
3897 : end if
3898 79928 : call get_face_weights(s, k, alfa, beta)
3899 79928 : grada_face = alfa*wrap_grad_ad_00(s,k) + beta*wrap_grad_ad_m1(s,k)
3900 79928 : end function get_grada_face
3901 :
3902 :
3903 79994 : function get_gradr_face(s,k) result(gradr)
3904 : type (star_info), pointer :: s
3905 : integer, intent(in) :: k
3906 : type(auto_diff_real_star_order1) :: gradr
3907 : type(auto_diff_real_star_order1) :: P, opacity, L, Pr
3908 : !include 'formats'
3909 79994 : P = get_Peos_face(s,k)
3910 79994 : opacity = get_kap_face(s,k)
3911 79994 : L = wrap_L_00(s,k)
3912 79994 : Pr = get_Prad_face(s,k)
3913 79994 : gradr = P*opacity*L/(16d0*pi*clight*s% m_grav(k)*s% cgrav(k)*Pr)
3914 79994 : end function get_gradr_face
3915 :
3916 :
3917 79994 : function get_scale_height_face(s,k) result(scale_height)
3918 : type (star_info), pointer :: s
3919 : integer, intent(in) :: k
3920 : type(auto_diff_real_star_order1) :: scale_height
3921 : type(auto_diff_real_star_order1) :: grav, scale_height2, P, rho
3922 : real(dp) :: G
3923 : include 'formats'
3924 79994 : G = s% cgrav(k)
3925 79994 : grav = G*s% m_grav(k)/pow2(wrap_r_00(s,k))
3926 79994 : P = get_Peos_face(s,k)
3927 79994 : rho = get_rho_face(s,k)
3928 79994 : scale_height = P/(grav*rho) ! this assumes HSE
3929 79994 : if (s% alt_scale_height_flag) then
3930 : ! consider sound speed*hydro time scale as an alternative scale height
3931 : ! (this comes from Eggleton's code.)
3932 79994 : scale_height2 = sqrt(P/G)/rho
3933 79994 : if (scale_height2 < scale_height) then
3934 1905 : scale_height = scale_height2
3935 : end if
3936 : end if
3937 79994 : end function get_scale_height_face
3938 :
3939 :
3940 0 : real(dp) function get_scale_height_face_val(s,k) result(scale_height)
3941 : type (star_info), pointer :: s
3942 : integer, intent(in) :: k
3943 0 : real(dp) :: G, grav, scale_height2, P, rho
3944 : type(auto_diff_real_star_order1) :: P_face, rho_face
3945 0 : G = s% cgrav(k)
3946 0 : grav = G*s% m_grav(k)/pow2(s% r(k))
3947 0 : P_face = get_Peos_face(s,k)
3948 0 : P = P_face%val
3949 0 : rho_face = get_rho_face(s,k)
3950 0 : rho = rho_face%val
3951 0 : scale_height = P/(grav*rho) ! this assumes HSE
3952 0 : if (s% alt_scale_height_flag) then
3953 : ! consider sound speed*hydro time scale as an alternative scale height
3954 : ! (this comes from Eggleton's code.)
3955 0 : scale_height2 = sqrt(P/G)/rho
3956 0 : if (scale_height2 < scale_height) then
3957 0 : scale_height = scale_height2
3958 : end if
3959 : end if
3960 0 : end function get_scale_height_face_val
3961 :
3962 :
3963 : function get_QQ_cell(s,k) result(QQ_cell)
3964 : type (star_info), pointer :: s
3965 : integer, intent(in) :: k
3966 : type(auto_diff_real_star_order1) :: QQ_cell
3967 : type(auto_diff_real_star_order1) :: &
3968 : T_00, d_00, chiT_00, chiRho_00
3969 : T_00 = wrap_T_00(s,k)
3970 : d_00 = wrap_d_00(s,k)
3971 : chiT_00 = wrap_chiT_00(s,k)
3972 : chiRho_00 = wrap_chiRho_00(s,k)
3973 : QQ_cell = chiT_00/(d_00*T_00*chiRho_00)
3974 : end function get_QQ_cell
3975 :
3976 :
3977 1172812 : subroutine get_face_weights(s, k, alfa, beta)
3978 : type (star_info), pointer :: s
3979 : integer, intent(in) :: k
3980 : real(dp), intent(out) :: alfa, beta
3981 : ! face_value(k) = alfa*cell_value(k) + beta*cell_value(k-1)
3982 1172812 : if (k == 1) call mesa_error(__FILE__,__LINE__,'bad k==1 for get_face_weights')
3983 1172812 : alfa = s% dq(k-1)/(s% dq(k-1) + s% dq(k))
3984 1172812 : beta = 1d0 - alfa
3985 1172812 : end subroutine get_face_weights
3986 :
3987 :
3988 161368 : real(dp) function safe_div_val(s, x, y, lim) result(x_div_y)
3989 : type (star_info), pointer :: s
3990 : real(dp), intent(in) :: x, y, lim
3991 : optional :: lim
3992 107548 : real(dp) :: limit
3993 107548 : if (present(lim)) then
3994 0 : limit = lim
3995 : else
3996 : limit = 1d-20
3997 : end if
3998 161368 : if (abs(y) < limit) then
3999 : x_div_y = 0d0
4000 : else
4001 161368 : x_div_y = x/y
4002 : end if
4003 107548 : end function safe_div_val
4004 :
4005 :
4006 : function safe_div(s, x, y, lim) result(x_div_y)
4007 : type (star_info), pointer :: s
4008 : type(auto_diff_real_star_order1), intent(in) :: x, y
4009 : type(auto_diff_real_star_order1) :: x_div_y
4010 : real(dp), intent(in) :: lim
4011 : optional :: lim
4012 : real(dp) :: limit
4013 : if (present(lim)) then
4014 : limit = lim
4015 : else
4016 : limit = 1d-20
4017 : end if
4018 : if (abs(y) < limit) then
4019 : x_div_y = 0d0
4020 : else
4021 : x_div_y = x/y
4022 : end if
4023 : end function safe_div
4024 :
4025 :
4026 43 : subroutine set_luminosity_by_category(s) ! integral by mass from center out
4027 : use chem_def, only: category_name
4028 : use rates_def, only: i_rate
4029 : use utils_lib, only: is_bad
4030 : type (star_info), pointer :: s
4031 : integer :: k, j
4032 1075 : real(dp) :: L_burn_by_category(num_categories)
4033 : include 'formats'
4034 43 : L_burn_by_category(:) = 0
4035 51399 : do k = s% nz, 1, -1
4036 1283943 : do j = 1, num_categories
4037 : L_burn_by_category(j) = &
4038 1232544 : L_burn_by_category(j) + s% dm(k)*s% eps_nuc_categories(j, k)
4039 1232544 : if (is_bad(L_burn_by_category(j))) then
4040 0 : write(*,2) trim(category_name(j)) // ' eps_nuc logT', k, s% eps_nuc_categories(j,k), s% lnT(k)/ln10
4041 0 : if (s% stop_for_bad_nums) call mesa_error(__FILE__,__LINE__,'set_luminosity_by_category')
4042 : end if
4043 1283900 : s% luminosity_by_category(j,k) = L_burn_by_category(j)
4044 : end do
4045 : end do
4046 43 : end subroutine set_luminosity_by_category
4047 :
4048 :
4049 0 : subroutine set_zero_alpha_RTI(id, ierr)
4050 : integer, intent(in) :: id
4051 : integer, intent(out) :: ierr
4052 : type (star_info), pointer :: s
4053 : include 'formats'
4054 : ierr = 0
4055 0 : call get_star_ptr(id, s, ierr)
4056 0 : if (ierr /= 0) return
4057 0 : if (.not. s% u_flag) return
4058 0 : s% xh(s% i_alpha_RTI,1:s% nz) = 0d0
4059 0 : s% alpha_RTI(1:s% nz) = 0d0
4060 0 : s% need_to_setvars = .true.
4061 43 : end subroutine set_zero_alpha_RTI
4062 :
4063 : end module star_utils
|