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

Generated by: LCOV version 2.0-1