LCOV - code coverage report
Current view: top level - star/private - hydro_temperature.f90 (source / functions) Coverage Total Hit
Test: coverage.info Lines: 32.0 % 122 39
Test Date: 2025-05-08 18:23:42 Functions: 50.0 % 4 2

            Line data    Source code
       1              : ! ***********************************************************************
       2              : !
       3              : !   Copyright (C) 2018-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 hydro_temperature
      21              : 
      22              :       use star_private_def
      23              :       use const_def, only: dp, ln10, pi4, crad, clight, convective_mixing
      24              :       use utils_lib, only: mesa_error, is_bad
      25              :       use auto_diff
      26              :       use auto_diff_support
      27              : 
      28              :       implicit none
      29              : 
      30              :       private
      31              :       public :: do1_alt_dlnT_dm_eqn
      32              :       public :: do1_gradT_eqn
      33              :       public :: do1_dlnT_dm_eqn
      34              : 
      35              :       contains
      36              : 
      37              :       ! just relate L_rad to T gradient.
      38              :       ! d_P_rad/dm = -<opacity_face>*L_rad/(clight*area^2) -- see, e.g., K&W (5.12)
      39              :       ! P_rad = (1/3)*crad*T^4
      40              :       ! d_P_rad/dm = (crad/3)*(T(k-1)^4 - T(k)^4)/dm_bar
      41              :       ! L_rad = L - L_non_rad, L_non_rad = L_start - L_rad_start
      42              :       ! L_rad_start = (-d_P_rad/dm_bar*clight*area^2/<opacity_face>)_start
      43        52304 :       subroutine do1_alt_dlnT_dm_eqn(s, k, nvar, ierr)
      44              :          use eos_def
      45              :          use star_utils, only: save_eqn_residual_info, get_face_weights
      46              :          type (star_info), pointer :: s
      47              :          integer, intent(in) :: k, nvar
      48              :          integer, intent(out) :: ierr
      49              : 
      50            0 :          real(dp) :: alfa, beta, scale, dm_bar
      51              :          type(auto_diff_real_star_order1) :: L_ad, r_00, area, area2, Lrad_ad, &
      52              :             kap_00, kap_m1, kap_face, d_P_rad_expected_ad, T_m1, T4_m1, T_00, T4_00, &
      53              :             P_rad_m1, P_rad_00, d_P_rad_actual_ad, resid
      54              :          type(auto_diff_real_star_order1) :: flxR, flxLambda
      55              : 
      56              :          integer :: i_equL
      57              :          logical :: dbg
      58              :          logical :: test_partials
      59              : 
      60              :          include 'formats'
      61            0 :          ierr = 0
      62            0 :          i_equL = s% i_equL
      63            0 :          if (i_equL == 0) return
      64              : 
      65            0 :          if (.not. s% use_dPrad_dm_form_of_T_gradient_eqn) then
      66            0 :             ierr = -1
      67            0 :             return
      68              :          end if
      69              : 
      70              :          !test_partials = (k == s% solver_test_partials_k)
      71            0 :          test_partials = .false.
      72              : 
      73            0 :          dbg = .false.
      74              : 
      75            0 :          call get_face_weights(s, k, alfa, beta)
      76              : 
      77            0 :          scale = s% energy_start(k)*s% rho_start(k)
      78            0 :          dm_bar = s% dm_bar(k)
      79            0 :          L_ad = wrap_L_00(s,k)
      80            0 :          r_00 = wrap_r_00(s,k)
      81            0 :          area = pi4*pow2(r_00); area2 = pow2(area)
      82              : 
      83              :          if (s% lnT(k)/ln10 <= s% max_logT_for_mlt &
      84              :                .and. s% mixing_type(k) == convective_mixing .and. s% gradr(k) > 0d0 &
      85            0 :                .and. abs(s% gradr(k) - s% gradT(k)) > abs(s% gradr(k))*1d-5) then
      86            0 :             Lrad_ad = L_ad*s% gradT_ad(k)/s% gradr_ad(k)  ! C&G 14.109
      87              :          else
      88            0 :             Lrad_ad = L_ad
      89              :          end if
      90              : 
      91            0 :          kap_00 = wrap_kap_00(s,k)
      92            0 :          kap_m1 = wrap_kap_m1(s,k)
      93            0 :          kap_face = alfa*kap_00 + beta*kap_m1
      94            0 :          if (kap_face%val < s% min_kap_for_dPrad_dm_eqn) &
      95            0 :             kap_face = s% min_kap_for_dPrad_dm_eqn
      96              : 
      97              :          ! calculate expected d_P_rad from current L_rad
      98            0 :          d_P_rad_expected_ad = -dm_bar*kap_face*Lrad_ad/(clight*area2)
      99              : 
     100              :          ! calculate actual d_P_rad in current model
     101            0 :          T_m1 = wrap_T_m1(s,k); T4_m1 = pow4(T_m1)
     102            0 :          T_00 = wrap_T_00(s,k); T4_00 = pow4(T_00)
     103              : 
     104              :          !d_P_rad_expected = d_P_rad_expected*s% gradr_factor(k) !TODO(Pablo): check this
     105              : 
     106            0 :          P_rad_m1 = (crad/3._dp)*T4_m1
     107            0 :          P_rad_00 = (crad/3._dp)*T4_00
     108            0 :          d_P_rad_actual_ad = P_rad_m1 - P_rad_00
     109              : 
     110              :          ! enable flux-limited radiation transport derived by Levermore & Pomraning 1981
     111            0 :          s% flux_limit_R(k) = 0._dp
     112            0 :          s% flux_limit_lambda(k) =0._dp
     113            0 :          if (s% use_flux_limiting_with_dPrad_dm_form) then
     114              :             ! calculate the flux ratio R
     115              :             flxR = area * abs(T4_m1 - T4_00) / dm_bar / &
     116            0 :                   (kap_face * 0.5_dp * (T4_m1 + T4_00))
     117              : 
     118            0 :             s% flux_limit_R(k) = flxR%val
     119              : 
     120              :             ! calculate the flux limiter lambda
     121            0 :             flxLambda = (6._dp + 3._dp*flxR) / (6._dp + (3._dp + flxR)*flxR)
     122              : 
     123            0 :             s% flux_limit_lambda(k) = flxLambda%val
     124              : 
     125              :             ! calculate d_P_rad given the flux limiter
     126            0 :             d_P_rad_expected_ad = d_P_rad_expected_ad / flxLambda
     127              :          end if
     128              : 
     129              :          ! residual
     130            0 :          resid = (d_P_rad_expected_ad - d_P_rad_actual_ad)/scale
     131            0 :          s% equ(i_equL, k) = resid%val
     132              : 
     133            0 :          if (is_bad(resid%val)) then
     134            0 : !$OMP critical (star_alt_dlntdm_bad_num)
     135            0 :             write(*,2) 'resid%val', k, resid%val
     136            0 :             if (s% stop_for_bad_nums) call mesa_error(__FILE__,__LINE__,'do1_alt_dlnT_dm_eqn')
     137              : !$OMP end critical (star_alt_dlntdm_bad_num)
     138              :          end if
     139              : 
     140              :          if (test_partials) then
     141              :             s% solver_test_partials_val = s% gradT(k)
     142              :          end if
     143              : 
     144              :          call save_eqn_residual_info( &
     145            0 :             s, k, nvar, i_equL, resid, 'do1_alt_dlnT_dm_eqn', ierr)
     146              : 
     147            0 :          if (test_partials) then
     148              :             s% solver_test_partials_var = 0
     149              :             s% solver_test_partials_dval_dx = 0
     150              :             write(*,*) 'do1_alt_dlnT_dm_eqn', s% solver_test_partials_var
     151              :          end if
     152              : 
     153              :          contains
     154              : 
     155              :       end subroutine do1_alt_dlnT_dm_eqn
     156              : 
     157              : 
     158            0 :       subroutine do1_gradT_eqn(s, k, nvar, ierr)
     159            0 :          use eos_def
     160              :          use star_utils, only: save_eqn_residual_info
     161              :          type (star_info), pointer :: s
     162              :          integer, intent(in) :: k, nvar
     163              :          integer, intent(out) :: ierr
     164              : 
     165              :          type(auto_diff_real_star_order1) :: &
     166              :             resid, gradT, dlnT, dlnP
     167              :          integer :: i_equL
     168              :          logical :: test_partials
     169              : 
     170              :          include 'formats'
     171            0 :          ierr = 0
     172              : 
     173              :          !test_partials = (k == s% solver_test_partials_k)
     174            0 :          test_partials = .false.
     175              : 
     176            0 :          i_equL = s% i_equL
     177            0 :          if (i_equL == 0) return
     178              : 
     179            0 :          gradT = s% gradT_ad(k)
     180            0 :          dlnT = wrap_lnT_m1(s,k) - wrap_lnT_00(s,k)
     181            0 :          dlnP = wrap_lnPeos_m1(s,k) - wrap_lnPeos_00(s,k)
     182              : 
     183            0 :          resid = gradT*dlnP - dlnT
     184            0 :          s% equ(i_equL, k) = resid%val
     185              : 
     186            0 :          if (is_bad(s% equ(i_equL, k))) then
     187            0 :             ierr = -1
     188            0 :             if (s% report_ierr) write(*,2) 'equ(i_equL, k)', k, s% equ(i_equL, k)
     189            0 :             if (s% stop_for_bad_nums) call mesa_error(__FILE__,__LINE__,'do1_gradT_eqn')
     190            0 :             return
     191              :             write(*,2) 'equ(i_equL, k)', k, s% equ(i_equL, k)
     192              :             write(*,2) 'gradT', k, gradT
     193              :             write(*,2) 'dlnT', k, dlnT
     194              :             write(*,2) 'dlnP', k, dlnP
     195              :             call mesa_error(__FILE__,__LINE__,'do1_gradT_eqn')
     196              :          end if
     197              : 
     198              :          if (test_partials) then
     199              :             s% solver_test_partials_val = s% equ(i_equL,k)
     200              :          end if
     201              : 
     202              :          call save_eqn_residual_info( &
     203            0 :             s, k, nvar, i_equL, resid, 'do1_gradT_eqn', ierr)
     204              : 
     205              :          !call set_xtras
     206              : 
     207              :          contains
     208              : 
     209              :          subroutine set_xtras
     210            0 :             use auto_diff_support
     211              :             use star_utils, only: get_Lrad
     212              :             type(auto_diff_real_star_order1) :: &
     213              :                T4m1, T400, kap_m1, kap_00, alfa, beta, kap_face, &
     214              :                diff_T4_div_kap
     215              :             T4m1 = pow4(wrap_T_m1(s,k))
     216              :             T400 = pow4(wrap_T_00(s,k))
     217              :             kap_m1 = wrap_kap_m1(s,k)
     218              :             kap_00 = wrap_kap_00(s,k)
     219              :             alfa = s% dq(k-1)/(s% dq(k-1) + s% dq(k))
     220              :             beta = 1d0 - alfa
     221              :             kap_face = alfa*kap_00 + beta*kap_m1
     222              :             diff_T4_div_kap = (T4m1 - T400)/kap_face
     223              :             s% xtra1_array(k) = s% T_start(k)
     224              :             s% xtra2_array(k) = T4m1%val - T400%val
     225              :             s% xtra3_array(k) = kap_face%val
     226              :             s% xtra4_array(k) = diff_T4_div_kap%val
     227              :             s% xtra5_array(k) = get_Lrad(s,k)
     228              :             s% xtra6_array(k) = 1
     229              :          end subroutine set_xtras
     230              : 
     231              :       end subroutine do1_gradT_eqn
     232              : 
     233              : 
     234        52304 :       subroutine do1_dlnT_dm_eqn(s, k, nvar, ierr)
     235              :          use eos_def
     236              :          use star_utils, only: save_eqn_residual_info
     237              :          type (star_info), pointer :: s
     238              :          integer, intent(in) :: k, nvar
     239              :          integer, intent(out) :: ierr
     240              : 
     241              :          type(auto_diff_real_star_order1) :: resid, &
     242              :             dlnPdm, Ppoint, gradT, dlnTdm, T00, Tm1, dT, Tpoint, lnTdiff
     243        52304 :          real(dp) :: delm, alfa
     244              :          integer :: i_equL
     245              :          logical :: test_partials
     246              : 
     247              :          include 'formats'
     248        52304 :          ierr = 0
     249              : 
     250              :          !test_partials = (k == s% solver_test_partials_k)
     251        52304 :          test_partials = .false.
     252              : 
     253        52304 :          i_equL = s% i_equL
     254        52304 :          if (i_equL == 0) return
     255              : 
     256        52304 :          if (s% use_gradT_actual_vs_gradT_MLT_for_T_gradient_eqn) then
     257            0 :             call do1_gradT_eqn(s, k, nvar, ierr)
     258            0 :             return
     259              :          end if
     260              : 
     261        52304 :          if (s% use_dPrad_dm_form_of_T_gradient_eqn) then
     262            0 :             call do1_alt_dlnT_dm_eqn(s, k, nvar, ierr)
     263            0 :             return
     264              :          end if
     265              : 
     266              :          ! dT/dm = dP/dm * T/P * grad_T, grad_T = dlnT/dlnP from MLT.
     267              :          ! but use hydrostatic value for dP/dm in this.
     268              :          ! this is because of limitations of MLT for calculating grad_T.
     269              :          ! (MLT assumes hydrostatic equilibrium)
     270              :          ! see comment in K&W chpt 9.1.
     271              : 
     272        52304 :          call eval_dlnPdm_qhse(s, k, dlnPdm, Ppoint, ierr)
     273        52304 :          if (ierr /= 0) return
     274              : 
     275        52304 :          gradT = s% gradT_ad(k)
     276        52304 :          dlnTdm = dlnPdm*gradT
     277              : 
     278        52304 :          Tm1 = wrap_T_m1(s,k)
     279        52304 :          T00 = wrap_T_00(s,k)
     280        52304 :          dT = Tm1 - T00
     281        52304 :          alfa = s% dm(k-1)/(s% dm(k-1) + s% dm(k))
     282        52304 :          Tpoint = alfa*T00 + (1d0 - alfa)*Tm1
     283        52304 :          lnTdiff = dT/Tpoint  ! use this in place of lnT(k-1)-lnT(k)
     284        52304 :          delm = (s% dm(k) + s% dm(k-1))/2
     285              : 
     286        52304 :          resid = delm*dlnTdm - lnTdiff
     287        52304 :          s% equ(i_equL, k) = resid%val
     288              : 
     289        52304 :          if (is_bad(s% equ(i_equL, k))) then
     290            0 :             ierr = -1
     291            0 :             if (s% report_ierr) write(*,2) 'equ(i_equL, k)', k, s% equ(i_equL, k)
     292            0 :             if (s% stop_for_bad_nums) call mesa_error(__FILE__,__LINE__,'hydro eqns')
     293            0 :             return
     294              :             write(*,2) 'equ(i_equL, k)', k, s% equ(i_equL, k)
     295              :             write(*,2) 'lnTdiff', k, lnTdiff
     296              :             write(*,2) 'delm', k, delm
     297              :             write(*,2) 'dlnPdm', k, dlnPdm
     298              :             write(*,2) 'gradT', k, gradT
     299              :             call mesa_error(__FILE__,__LINE__,'i_equL')
     300              :          end if
     301              : 
     302              :          if (test_partials) then
     303              :             s% solver_test_partials_val = s% equ(i_equL,k)
     304              :          end if
     305              : 
     306              :          call save_eqn_residual_info( &
     307        52304 :             s, k, nvar, i_equL, resid, 'do1_dlnT_dm_eqn', ierr)
     308              : 
     309        52304 :       end subroutine do1_dlnT_dm_eqn
     310              : 
     311              : 
     312              : 
     313              :       ! only used for dlnT_dm equation
     314        52304 :       subroutine eval_dlnPdm_qhse(s, k, &  ! calculate the expected dlnPdm for HSE
     315              :             dlnPdm_qhse, Ppoint, ierr)
     316        52304 :          use hydro_momentum, only: expected_HSE_grav_term
     317              :          type (star_info), pointer :: s
     318              :          integer, intent(in) :: k
     319              :          type(auto_diff_real_star_order1), intent(out) :: dlnPdm_qhse, Ppoint
     320              :          integer, intent(out) :: ierr
     321              : 
     322        52304 :          real(dp) :: alfa
     323              :          type(auto_diff_real_star_order1) :: grav, area, P00, Pm1
     324              :          include 'formats'
     325              : 
     326              :          ierr = 0
     327              : 
     328              :          ! basic eqn is dP/dm = -G m / (4 pi r^4)
     329              :          ! divide by Ppoint to make it unitless
     330              : 
     331              :          ! for rotation, multiply gravity by factor fp.  MESA 2, eqn 22.
     332              : 
     333        52304 :          call expected_HSE_grav_term(s, k, grav, area, ierr)
     334        52304 :          if (ierr /= 0) return
     335              : 
     336        52304 :          P00 = wrap_Peos_00(s,k)
     337        52304 :          if (s% using_velocity_time_centering) P00 = 0.5d0*(P00 + s% Peos_start(k))
     338              : 
     339        52304 :          if (k == 1) then
     340            0 :             Pm1 = 0d0
     341            0 :             Ppoint = P00
     342              :          else
     343        52304 :             Pm1 = wrap_Peos_m1(s,k)
     344        52304 :             alfa = s% dq(k-1)/(s% dq(k-1) + s% dq(k))
     345        52304 :             Ppoint = alfa*P00 + (1d0-alfa)*Pm1
     346              :          end if
     347              : 
     348        52304 :          dlnPdm_qhse = grav/(area*Ppoint)  ! note that expected_HSE_grav_term is negative
     349              : 
     350        52304 :          if (is_bad(dlnPdm_qhse%val)) then
     351            0 :             ierr = -1
     352            0 :             s% retry_message = 'eval_dlnPdm_qhse: is_bad(dlnPdm_qhse)'
     353            0 :             if (s% report_ierr) then
     354            0 : !$OMP critical (hydro_vars_crit1)
     355            0 :                write(*,*) 'eval_dlnPdm_qhse: is_bad(dlnPdm_qhse)'
     356            0 :                stop
     357              : !$OMP end critical (hydro_vars_crit1)
     358              :             end if
     359            0 :             if (s% stop_for_bad_nums) then
     360            0 :                write(*,2) 'dlnPdm_qhse', k, dlnPdm_qhse
     361            0 :                call mesa_error(__FILE__,__LINE__,'eval_dlnPdm_qhse')
     362              :             end if
     363            0 :             return
     364              :          end if
     365              : 
     366        52304 :       end subroutine eval_dlnPdm_qhse
     367              : 
     368              :       end module hydro_temperature
        

Generated by: LCOV version 2.0-1