LCOV - code coverage report
Current view: top level - atm/private - atm_irradiated.f90 (source / functions) Coverage Total Hit
Test: coverage.info Lines: 66.1 % 118 78
Test Date: 2025-05-08 18:23:42 Functions: 100.0 % 2 2

            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 atm_irradiated
      21              : 
      22              :   use const_def, only: dp
      23              :   use math_lib
      24              : 
      25              :   implicit none
      26              : 
      27              :   private
      28              : 
      29              :   public :: eval_irradiated
      30              : 
      31              : contains
      32              : 
      33              :   ! Evaluate irradiated atmosphere data with fixed, uniform opacity
      34              : 
      35           18 :   subroutine eval_irradiated( &
      36              :        L, R, M, cgrav, T_eq, P_surf, kap_guess, kap_v, gamma, &
      37              :        eos_proc, kap_proc, errtol, max_iters, skip_partials, &
      38              :        Teff, kap, tau, &
      39              :        lnT, dlnT_dL, dlnT_dlnR, dlnT_dlnM, dlnT_dlnkap, &
      40              :        ierr)
      41              : 
      42              :     use atm_def, only: atm_eos_iface, atm_kap_iface
      43              :     use atm_utils, only: eval_Teff_g
      44              :     use eos_def, only: num_eos_basic_results, i_chiRho, i_chiT
      45              : 
      46              :     real(dp), intent(in)     :: L
      47              :     real(dp), intent(in)     :: R
      48              :     real(dp), intent(in)     :: M
      49              :     real(dp), intent(in)     :: cgrav
      50              :     real(dp), intent(in)     :: T_eq
      51              :     real(dp), intent(in)     :: P_surf
      52              :     real(dp), intent(in)     :: kap_guess
      53              :     real(dp), intent(in)     :: kap_v
      54              :     real(dp), intent(in)     :: gamma
      55              :     procedure(atm_eos_iface) :: eos_proc
      56              :     procedure(atm_kap_iface) :: kap_proc
      57              :     real(dp), intent(in)     :: errtol
      58              :     integer, intent(in)      :: max_iters
      59              :     logical, intent(in)      :: skip_partials
      60              :     real(dp), intent(in)     :: Teff
      61              :     real(dp), intent(out)    :: kap
      62              :     real(dp), intent(out)    :: tau
      63              :     real(dp), intent(out)    :: lnT
      64              :     real(dp), intent(out)    :: dlnT_dL
      65              :     real(dp), intent(out)    :: dlnT_dlnR
      66              :     real(dp), intent(out)    :: dlnT_dlnM
      67              :     real(dp), intent(out)    :: dlnT_dlnkap
      68              :     integer, intent(out)     :: ierr
      69              : 
      70              :     real(dp) :: T_int
      71            2 :     real(dp) :: g
      72            2 :     real(dp) :: lnP
      73              :     integer  :: iters
      74            2 :     real(dp) :: lnRho
      75           54 :     real(dp) :: res(num_eos_basic_results)
      76           54 :     real(dp) :: dres_dlnRho(num_eos_basic_results)
      77           54 :     real(dp) :: dres_dlnT(num_eos_basic_results)
      78            2 :     real(dp) :: dlnkap_dlnRho
      79            2 :     real(dp) :: dlnkap_dlnT
      80            2 :     real(dp) :: kap_prev
      81            2 :     real(dp) :: err
      82            2 :     real(dp) :: chiRho
      83            2 :     real(dp) :: chiT
      84            2 :     real(dp) :: dlnkap_dlnT_P
      85              : 
      86              :     include 'formats'
      87              : 
      88            2 :     ierr = 0
      89              : 
      90              :     ! Sanity checks
      91              : 
      92            2 :     if (L <= 0._dp .OR. R <= 0._dp .OR. M <= 0._dp) then
      93            0 :        ierr = -1
      94            0 :        return
      95              :     end if
      96              : 
      97              :     ! Evaluate the 'interior' temperature & gravity
      98              : 
      99            2 :     call eval_Teff_g(L, R, M, cgrav, T_int, g)
     100              : 
     101              :     ! Evaluate atmosphere data using kap_guess as the opacity
     102              : 
     103            2 :     kap = kap_guess
     104              : 
     105              :     call eval_data( &
     106              :          T_int, g, L, T_eq, P_surf, kap, kap_v, gamma, skip_partials, &
     107              :          tau, lnT, dlnT_dL, dlnT_dlnR, dlnT_dlnM, dlnT_dlnkap, &
     108            2 :          ierr)
     109              : 
     110              :     ! Iterate to find a consistent opacity
     111              : 
     112            2 :     lnP = log(P_surf)
     113              : 
     114           16 :     iterate_loop : do iters = 1, max_iters
     115              : 
     116              :        ! Calculate the density & eos results
     117              : 
     118              :        call eos_proc( &
     119              :             lnP, lnT, &
     120              :             lnRho, res, dres_dlnRho, dres_dlnT, &
     121           16 :             ierr)
     122           16 :        if (ierr /= 0) then
     123            0 :           write(*,*) 'Call to eos_proc failed in eval_T_tau_uniform'
     124            0 :           return
     125              :        end if
     126              : 
     127              :        ! Update the opacity
     128              : 
     129           16 :        kap_prev = kap
     130              : 
     131              :        call kap_proc( &
     132              :             lnRho, lnT, res, dres_dlnRho, dres_dlnT, &
     133              :             kap, dlnkap_dlnRho, dlnkap_dlnT, &
     134           16 :             ierr)
     135           16 :        if (ierr /= 0) then
     136            0 :           write(*,*) 'Call to kap_proc failed in eval_T_tau_uniform'
     137            0 :           return
     138              :        end if
     139              : 
     140              :        ! Check for convergence
     141              : 
     142           16 :        err = abs(kap_prev - kap)/(errtol + errtol*kap)
     143              : 
     144           16 :        if (err < 1._dp) exit iterate_loop
     145              : 
     146           14 :        kap = kap_prev + 0.5_dp*(kap - kap_prev)  ! under correct
     147              : 
     148              :        ! Re-evaluate atmosphere data
     149              : 
     150              :        call eval_data( &
     151              :             T_int, g, L, T_eq, P_surf, kap, kap_v, gamma, skip_partials, &
     152              :             tau, lnT, dlnT_dL, dlnT_dlnR, dlnT_dlnM, dlnT_dlnkap, &
     153           16 :             ierr)
     154              : 
     155              :     end do iterate_loop
     156              : 
     157            2 :     if (max_iters > 0 .AND. iters > max_iters) then
     158            0 :        write(*,*) 'Exceeded max_iters iterations in eval_irradiated'
     159            0 :        ierr = -1
     160            0 :        return
     161              :     end if
     162              : 
     163              :     ! If necessary, fix up the partials to account for the implicit
     164              :     ! dependence of the opacity on the final T
     165              : 
     166            2 :     if (max_iters > 0 .AND. .NOT. skip_partials) then
     167              : 
     168            0 :        chiRho = res(i_chiRho)
     169            0 :        chiT = res(i_chiT)
     170              : 
     171            0 :        dlnkap_dlnT_P = dlnkap_dlnT - dlnkap_dlnRho*chiT/chiRho
     172              : 
     173            0 :        dlnT_dL = dlnT_dL/(1._dp - dlnkap_dlnT_P*dlnT_dlnkap)
     174            0 :        dlnT_dlnR = dlnT_dlnR/(1._dp - dlnkap_dlnT_P*dlnT_dlnkap)
     175            0 :        dlnT_dlnM = dlnT_dlnM/(1._dp - dlnkap_dlnT_P*dlnT_dlnkap)
     176              : 
     177            0 :        dlnT_dlnkap = 0._dp
     178              : 
     179              :     end if
     180              : 
     181              :     ! Set the effective temperature. This is equal to T_int, because
     182              :     ! irradiation has no effect on the *net* flux emerging from the
     183              :     ! atmosphere
     184              : 
     185              :     ! Teff = T_int
     186              : 
     187              :     return
     188              : 
     189            2 :   end subroutine eval_irradiated
     190              : 
     191              : 
     192              :   ! Evaluate atmosphere data
     193              : 
     194           16 :   subroutine eval_data( &
     195              :        T_int, g, L, T_eq, P_surf, kap, kap_v, gamma, skip_partials, &
     196              :        tau, lnT, dlnT_dL, dlnT_dlnR, dlnT_dlnM, dlnT_dlnkap, &
     197              :        ierr)
     198              : 
     199            2 :     use atm_utils, only: eval_E2
     200              : 
     201              :     real(dp), intent(in)  :: T_int
     202              :     real(dp), intent(in)  :: g
     203              :     real(dp), intent(in)  :: L
     204              :     real(dp), intent(in)  :: T_eq
     205              :     real(dp), intent(in)  :: P_surf
     206              :     real(dp), intent(in)  :: kap
     207              :     real(dp), intent(in)  :: kap_v
     208              :     real(dp), intent(in)  :: gamma
     209              :     logical, intent(in)   :: skip_partials
     210              :     real(dp), intent(out) :: tau
     211              :     real(dp), intent(out) :: lnT
     212              :     real(dp), intent(out) :: dlnT_dL
     213              :     real(dp), intent(out) :: dlnT_dlnR
     214              :     real(dp), intent(out) :: dlnT_dlnM
     215              :     real(dp), intent(out) :: dlnT_dlnkap
     216              :     integer, intent(out)  :: ierr
     217              : 
     218           16 :     real(dp) :: gamma_eff
     219              :     real(dp) :: x
     220              :     real(dp) :: E2
     221              :     real(dp) :: dE2_dx
     222           16 :     real(dp) :: f_1
     223           16 :     real(dp) :: f_2
     224           16 :     real(dp) :: T4_int
     225           16 :     real(dp) :: T4_eq
     226           16 :     real(dp) :: T4
     227           16 :     real(dp) :: df_1_dtau
     228           16 :     real(dp) :: df_2_dtau
     229           16 :     real(dp) :: df_1_dx
     230           16 :     real(dp) :: df_2_dx
     231           16 :     real(dp) :: dlnT_dlnT_int
     232           16 :     real(dp) :: dlnT_dlntau
     233           16 :     real(dp) :: dlnT_dlnx
     234           16 :     real(dp) :: dlnT_int_dlnL
     235           16 :     real(dp) :: dlnT_int_dlnR
     236           16 :     real(dp) :: dlnT_int_dlnM
     237           16 :     real(dp) :: dlnT_int_dlnkap
     238           16 :     real(dp) :: dlntau_dlnL
     239           16 :     real(dp) :: dlntau_dlnR
     240           16 :     real(dp) :: dlntau_dlnM
     241           16 :     real(dp) :: dlntau_dlnkap
     242           16 :     real(dp) :: dlnx_dlnL
     243           16 :     real(dp) :: dlnx_dlnR
     244           16 :     real(dp) :: dlnx_dlnM
     245           16 :     real(dp) :: dlnx_dlnkap
     246              : 
     247              :     ! Calculate the optical depth corresponding to P_surf
     248              : 
     249           16 :     tau = P_surf*kap/g
     250              : 
     251              :     ! Evaluate irradiation terms [cf. eq. 6 of Guillot & Havel (2011,
     252              :     ! A&A 527, A20)]
     253              : 
     254           16 :     if (gamma > 0._dp) then
     255              :        gamma_eff = gamma
     256              :     else
     257           16 :        gamma_eff = kap_v/kap
     258              :     end if
     259              : 
     260           16 :     x = gamma_eff*tau
     261              : 
     262           16 :     call eval_E2(x, E2, dE2_dx, ierr)
     263           16 :     if (ierr /= 0) return
     264              : 
     265           16 :     f_1 = 2._dp*(1._dp + (x/2._dp - 1._dp)*exp(-x))*tau/(3._dp*x)
     266           16 :     f_2 = 2._dp*x*(1 - tau*tau/2._dp)*E2/(3._dp*tau)
     267              : 
     268              :     ! Evaluate the temperature
     269              : 
     270           16 :     T4_int = T_int*T_int*T_int*T_int
     271           16 :     T4_eq = T_eq*T_eq*T_eq*T_eq
     272              : 
     273           16 :     T4 = 0.75_dp*(T4_int*(tau + 2._dp/3._dp) + T4_eq*(f_1 + f_2 + 2._dp/3._dp))
     274              : 
     275           16 :     lnT = 0.25_dp*log(T4)
     276              : 
     277              :     ! Set up partials
     278              : 
     279           16 :     if (.NOT. skip_partials) then
     280              : 
     281            0 :        df_1_dtau = (2._dp + (x - 2._dp)*exp(-x))/(3._dp*x)
     282            0 :        df_2_dtau = -x*(2._dp + tau*tau)*E2/(3._dp*tau*tau)
     283              : 
     284            0 :        df_1_dx = -(2._dp - (2._dp + (2._dp - x)*x)*exp(-x))*tau/(3._dp*x*x)
     285            0 :        df_2_dx = -(tau*tau - 2._dp)*(E2 + x*dE2_dx)/(3._dp*tau)
     286              : 
     287            0 :        dlnT_dlnT_int = 0.75_dp*(tau + 2._dp/3._dp)*T4_int/T4
     288            0 :        dlnT_dlntau = 0.75_dp*(T4_int + T4_eq*(df_1_dtau + df_2_dtau))*tau/(4._dp*T4)
     289            0 :        dlnT_dlnx = 0.75_dp*T4_eq*(df_1_dx + df_2_dx)*x/(4._dp*T4)
     290              : 
     291            0 :        dlnT_int_dlnL = 0.25_dp
     292            0 :        dlnT_int_dlnR = -0.5_dp
     293            0 :        dlnT_int_dlnM = 0._dp
     294            0 :        dlnT_int_dlnkap = 0._dp
     295              : 
     296            0 :        dlntau_dlnL = 0._dp
     297            0 :        dlntau_dlnR = 2._dp
     298            0 :        dlntau_dlnM = -1._dp
     299            0 :        dlntau_dlnkap = 1._dp
     300              : 
     301            0 :        dlnx_dlnL = 0._dp
     302            0 :        dlnx_dlnR = 2._dp
     303            0 :        dlnx_dlnM = -1._dp
     304            0 :        if (gamma > 0._dp) then
     305              :           dlnx_dlnkap = 1._dp
     306              :        else
     307            0 :           dlnx_dlnkap = 0._dp
     308              :        end if
     309              : 
     310              :        dlnT_dL = (dlnT_dlnT_int*dlnT_int_dlnL + &
     311              :                   dlnT_dlntau*dlntau_dlnL + &
     312            0 :                   dlnT_dlnx*dlnx_dlnL)/L
     313              :        dlnT_dlnR = dlnT_dlnT_int*dlnT_int_dlnR + &
     314              :                    dlnT_dlntau*dlntau_dlnR + &
     315            0 :                    dlnT_dlnx*dlnx_dlnR
     316              :        dlnT_dlnM = dlnT_dlnT_int*dlnT_int_dlnM + &
     317              :                    dlnT_dlntau*dlntau_dlnM + &
     318            0 :                    dlnT_dlnx*dlnx_dlnM
     319              :        dlnT_dlnkap = dlnT_dlnT_int*dlnT_int_dlnkap + &
     320              :                      dlnT_dlntau*dlntau_dlnkap + &
     321            0 :                      dlnT_dlnx*dlnx_dlnkap
     322              : 
     323              :     else
     324              : 
     325           16 :        dlnT_dL = 0._dp
     326           16 :        dlnT_dlnR = 0._dp
     327           16 :        dlnT_dlnM = 0._dp
     328           16 :        dlnT_dlnkap = 0._dp
     329              : 
     330              :     end if
     331              : 
     332           16 :   end subroutine eval_data
     333              : 
     334              : end module atm_irradiated
        

Generated by: LCOV version 2.0-1