LCOV - code coverage report
Current view: top level - star/private - star_utils.f90 (source / functions) Coverage Total Hit
Test: coverage.info Lines: 48.2 % 1978 954
Test Date: 2025-12-14 16:52:03 Functions: 62.5 % 144 90

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

Generated by: LCOV version 2.0-1