LCOV - code coverage report
Current view: top level - atm/private - atm_t_tau_varying.f90 (source / functions) Coverage Total Hit
Test: coverage.info Lines: 37.4 % 273 102
Test Date: 2025-06-06 17:08:43 Functions: 44.4 % 9 4

            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_T_tau_varying
      21              : 
      22              :   use const_def, only: dp, ln10, cgas
      23              :   use math_lib
      24              :   use utils_lib, only: mesa_error
      25              : 
      26              :   implicit none
      27              : 
      28              :   private
      29              :   public :: eval_T_tau_varying
      30              :   public :: build_T_tau_varying
      31              : 
      32              : contains
      33              : 
      34              :   ! Evaluate atmosphere data from T-tau relation with varying opacity
      35              : 
      36           10 :   subroutine eval_T_tau_varying( &
      37              :        tau_surf, L, R, M, cgrav, &
      38              :        T_tau_id, eos_proc, kap_proc, &
      39              :        errtol, max_steps, skip_partials, &
      40              :        Teff, &
      41              :        lnT, dlnT_dL, dlnT_dlnR, dlnT_dlnM, dlnT_dlnkap, &
      42              :        lnP, dlnP_dL, dlnP_dlnR, dlnP_dlnM, dlnP_dlnkap, &
      43              :        ierr)
      44              : 
      45              :     use atm_def, only: atm_eos_iface, atm_kap_iface
      46              : 
      47              :     real(dp), intent(in)       :: tau_surf
      48              :     real(dp), intent(in)       :: L
      49              :     real(dp), intent(in)       :: R
      50              :     real(dp), intent(in)       :: M
      51              :     real(dp), intent(in)       :: cgrav
      52              :     integer, intent(in)        :: T_tau_id
      53              :     procedure(atm_eos_iface)   :: eos_proc
      54              :     procedure(atm_kap_iface)   :: kap_proc
      55              :     real(dp), intent(in)       :: errtol
      56              :     integer, intent(in)        :: max_steps
      57              :     logical, intent(in)        :: skip_partials
      58              :     real(dp), intent(in)       :: Teff
      59              :     real(dp), intent(out)      :: lnT
      60              :     real(dp), intent(out)      :: dlnT_dL
      61              :     real(dp), intent(out)      :: dlnT_dlnR
      62              :     real(dp), intent(out)      :: dlnT_dlnM
      63              :     real(dp), intent(out)      :: dlnT_dlnkap
      64              :     real(dp), intent(out)      :: lnP
      65              :     real(dp), intent(out)      :: dlnP_dL
      66              :     real(dp), intent(out)      :: dlnP_dlnR
      67              :     real(dp), intent(out)      :: dlnP_dlnM
      68              :     real(dp), intent(out)      :: dlnP_dlnkap
      69              :     integer, intent(out)       :: ierr
      70              : 
      71              :     real(dp), parameter :: DLNTEFF = 1.E-4_dp
      72              : 
      73              :     real(dp) :: g
      74           10 :     real(dp) :: lnTeff
      75           10 :     real(dp) :: lnTeff_p
      76           10 :     real(dp) :: lnTeff_m
      77           10 :     real(dp) :: lnT_p
      78           10 :     real(dp) :: lnT_m
      79           10 :     real(dp) :: lnP_p
      80           10 :     real(dp) :: lnP_m
      81              :     integer  :: ierr_p
      82              :     integer  :: ierr_m
      83           10 :     real(dp) :: dlnTeff_dlnR
      84           10 :     real(dp) :: dlnTeff_dL
      85           10 :     real(dp) :: dlnT_dlnTeff
      86           10 :     real(dp) :: dlnP_dlnTeff
      87              : 
      88           10 :     ierr = 0
      89              : 
      90              :     ! Sanity checks
      91              : 
      92           10 :     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 gravity
      98              : 
      99           10 :     g = cgrav*M/(R*R)
     100              : 
     101              :     ! Perform the necessary evaluations
     102              : 
     103           10 :     if (skip_partials) then
     104              : 
     105              :        ! No partial evaluation required
     106              : 
     107              :        call eval_data( &
     108              :             tau_surf, Teff, g, &
     109              :             T_tau_id, eos_proc, kap_proc, errtol, max_steps, &
     110           10 :             lnT, lnP, ierr)
     111              : 
     112           10 :        if (ierr /= 0) then
     113            0 :           write(*,*) 'atm: Call to eval_data failed in atm_t_tau_varying'
     114            0 :           return
     115              :        end if
     116              : 
     117           10 :        dlnT_dL = 0._dp
     118           10 :        dlnT_dlnR = 0._dp
     119           10 :        dlnT_dlnM = 0._dp
     120           10 :        dlnT_dlnkap = 0._dp
     121              : 
     122           10 :        dlnP_dL = 0._dp
     123           10 :        dlnP_dlnR = 0._dp
     124           10 :        dlnP_dlnM = 0._dp
     125           10 :        dlnP_dlnkap = 0._dp
     126              : 
     127              :     else
     128              : 
     129              :        ! Partials required, use finite differencing in Teff (we could
     130              :        ! in principle get dlnT_dlnTeff from the T-tau relation, but
     131              :        ! for consistency with dln_dlnTeff we use the same finite
     132              :        ! differencing)
     133              : 
     134            0 :        lnTeff = log(Teff)
     135              : 
     136            0 :        lnTeff_p = lnTeff + DLNTEFF
     137            0 :        lnTeff_m = lnTeff - DLNTEFF
     138              : 
     139              :        !$OMP SECTIONS
     140              : 
     141              :        !$OMP SECTION
     142              : 
     143              :        call eval_data( &
     144              :             tau_surf, exp(lnTeff), g, &
     145              :             T_tau_id, eos_proc, kap_proc, errtol, max_steps, &
     146            0 :             lnT, lnP, ierr)
     147              : 
     148              :        !$OMP SECTION
     149              : 
     150              :        call eval_data( &
     151              :             tau_surf, exp(lnTeff_p), g, &
     152              :             T_tau_id, eos_proc, kap_proc, errtol, max_steps, &
     153            0 :             lnT_p, lnP_p, ierr_p)
     154              : 
     155              :        !$OMP SECTION
     156              : 
     157              :        call eval_data( &
     158              :             tau_surf, exp(lnTeff_m), g, &
     159              :             T_tau_id, eos_proc, kap_proc, errtol, max_steps, &
     160            0 :             lnT_m, lnP_m, ierr_m)
     161              : 
     162              :        !$OMP END SECTIONS
     163              : 
     164            0 :        if (ierr_p /= 0) ierr = ierr_p
     165            0 :        if (ierr_m /= 0) ierr = ierr_m
     166            0 :        if (ierr /= 0) then
     167            0 :           write(*,*) 'Call to eval_data failed in atm_t_tau_varying_opacity'
     168            0 :           return
     169              :        end if
     170              : 
     171              :        ! Set up the partials
     172              : 
     173            0 :        dlnTeff_dlnR = -0.5_dp
     174            0 :        dlnTeff_dL = 0.25_dp/L
     175              : 
     176            0 :        dlnT_dlnTeff = (lnT_p - lnT_m) / (lnTeff_p - lnTeff_m)
     177            0 :        dlnT_dL = dlnT_dlnTeff*dlnTeff_dL
     178            0 :        dlnT_dlnR = dlnT_dlnTeff*dlnTeff_dlnR
     179            0 :        dlnT_dlnM = 0._dp
     180            0 :        dlnT_dlnkap = 0._dp
     181              : 
     182            0 :        dlnP_dlnTeff = (lnP_p - lnP_m) / (lnTeff_p - lnTeff_m)
     183            0 :        dlnP_dL = dlnP_dlnTeff*dlnTeff_dL
     184            0 :        dlnP_dlnR = dlnP_dlnTeff*dlnTeff_dlnR
     185            0 :        dlnP_dlnM = 0._dp
     186            0 :        dlnP_dlnkap = 0._dp
     187              : 
     188              :     end if
     189              : 
     190              :     return
     191              : 
     192              :   end subroutine eval_T_tau_varying
     193              : 
     194              : 
     195              :   ! Evaluate atmosphere data from T-tau relation with varying opacity
     196              : 
     197           10 :   subroutine eval_data( &
     198              :        tau_surf, Teff, g, &
     199              :        T_tau_id, eos_proc, kap_proc, errtol, max_steps, &
     200              :        lnT, lnP, ierr)
     201              : 
     202              :     use atm_def, only: atm_eos_iface, atm_kap_iface
     203              : 
     204              :     real(dp), intent(in)       :: tau_surf
     205              :     real(dp), intent(in)       :: Teff
     206              :     real(dp), intent(in)       :: g
     207              :     integer, intent(in)        :: T_tau_id
     208              :     procedure(atm_eos_iface)   :: eos_proc
     209              :     procedure(atm_kap_iface)   :: kap_proc
     210              :     real(dp), intent(in)       :: errtol
     211              :     integer, intent(in)        :: max_steps
     212              :     real(dp), intent(out)      :: lnT
     213              :     real(dp), intent(out)      :: lnP
     214              :     integer, intent(out)       :: ierr
     215              : 
     216              :     real(dp), parameter :: TAU_OUTER_FACTOR = 1.E-5_dp
     217              :     integer, parameter  :: MAX_TRIES = 3
     218              :     real(dp), parameter :: TRY_SCALE = 10._dp
     219              : 
     220              :     real(dp) :: tau_outer_curr
     221              :     real(dp) :: errtol_curr
     222              :     integer  :: try
     223              : 
     224              :     ! Try doing the integration, relaxing tau_outer and errtol if failures occur
     225              : 
     226           10 :     tau_outer_curr = tau_surf*TAU_OUTER_FACTOR
     227           10 :     errtol_curr = errtol
     228              : 
     229           10 :     try_loop : do try = 1, MAX_TRIES
     230              : 
     231              :        call eval_data_try( &
     232              :             tau_surf, Teff, g, tau_outer_curr, &
     233              :             T_tau_id, eos_proc, kap_proc, errtol_curr, max_steps, &
     234           10 :             lnT, lnP, ierr)
     235           10 :        if (ierr == 0) exit try_loop
     236              : 
     237            0 :        tau_outer_curr = tau_outer_curr*TRY_SCALE
     238           20 :        errtol_curr = errtol*TRY_SCALE
     239              : 
     240              :     end do try_loop
     241              : 
     242           10 :     return
     243              : 
     244              :   end subroutine eval_data
     245              : 
     246              : 
     247           10 :   subroutine eval_data_try( &
     248              :        tau_surf, Teff, g, tau_outer, &
     249              :        T_tau_id, eos_proc, kap_proc, errtol, max_steps, &
     250              :        lnT, lnP, ierr)
     251              : 
     252              :     use eos_lib, only: radiation_pressure
     253              :     use atm_def, only: atm_eos_iface, atm_kap_iface
     254              :     use atm_T_tau_relations, only: eval_T_tau
     255              :     use num_lib, only: dopri5_work_sizes, dopri5
     256              : 
     257              :     real(dp), intent(in)       :: tau_surf
     258              :     real(dp), intent(in)       :: Teff
     259              :     real(dp), intent(in)       :: g
     260              :     real(dp), intent(in)       :: tau_outer
     261              :     integer, intent(in)        :: T_tau_id
     262              :     procedure(atm_eos_iface)   :: eos_proc
     263              :     procedure(atm_kap_iface)   :: kap_proc
     264              :     real(dp), intent(in)       :: errtol
     265              :     integer, intent(in)        :: max_steps
     266              :     real(dp), intent(out)      :: lnT
     267              :     real(dp), intent(out)      :: lnP
     268              :     integer, intent(out)       :: ierr
     269              : 
     270              :     integer, parameter :: NUM_VARS = 1
     271              :     integer, parameter :: NRDENS = 0
     272              :     integer, parameter :: LRPAR = 0
     273              :     integer, parameter :: LIPAR = 0
     274              :     integer, parameter :: IOUT = 0
     275              :     integer, parameter :: LOUT = 0
     276              : 
     277              :     real(dp), parameter :: RHO_OUTER = 1.E-10_dp
     278              :     real(dp), parameter :: DLNTAU_SURF = 1.E-3_dp
     279              :     real(dp), parameter :: DLNTAU_MAX = 0._dp
     280              : 
     281              :     integer           :: liwork
     282              :     integer           :: lwork
     283           10 :     real(dp), pointer :: work(:)
     284           10 :     integer, pointer  :: iwork(:)
     285              :     real(dp), target  :: rpar_ary(LRPAR)
     286              :     integer, target   :: ipar_ary(LIPAR)
     287           20 :     real(dp), target  :: y_ary(NUM_VARS)
     288           10 :     real(dp), pointer :: rpar(:)
     289           10 :     integer, pointer  :: ipar(:)
     290           10 :     real(dp), pointer :: y(:)
     291           10 :     real(dp)          :: lnTeff
     292           10 :     real(dp)          :: T_outer
     293           10 :     real(dp)          :: Pgas_outer
     294           10 :     real(dp)          :: P_outer
     295           10 :     real(dp)          :: lntau_outer
     296           10 :     real(dp)          :: lntau_surf
     297           10 :     real(dp)          :: dlntau
     298           20 :     real(dp)          :: rtol(NUM_VARS)
     299           20 :     real(dp)          :: atol(NUM_VARS)
     300              :     integer           :: idid
     301              : 
     302           10 :     ierr = 0
     303              : 
     304              :     ! Allocate work arrays for the integrator
     305              : 
     306           10 :     call dopri5_work_sizes(NUM_VARS, NRDENS, liwork, lwork)
     307           10 :     allocate(work(lwork), iwork(liwork), stat=ierr)
     308           10 :     if (ierr /= 0) then
     309            0 :        write(*,*) 'allocate failed in eval_data_try'
     310            0 :        return
     311              :     end if
     312              : 
     313          330 :     work = 0._dp
     314          220 :     iwork = 0
     315              : 
     316              :     ! Set pointers (simply because dopri5 wants pointer args)
     317              : 
     318           10 :     rpar => rpar_ary
     319           10 :     ipar => ipar_ary
     320              : 
     321           10 :     y => y_ary
     322              : 
     323              :     ! Set values at the outer boundary (y(1) = lnP; estimate
     324              :     ! Pgas from low-density ideal gas law)
     325              : 
     326           10 :     lnTeff = log(Teff)
     327              : 
     328           10 :     call eval_T_tau(T_tau_id, tau_outer, Teff, lnT, ierr)
     329           10 :     if (ierr /= 0) then
     330            0 :        write(*,*) 'atm: Call to eval_T_tau failed in eval_data_try'
     331            0 :        return
     332              :     end if
     333              : 
     334           10 :     T_outer = exp(lnT)
     335           10 :     Pgas_outer = cgas*RHO_OUTER*T_outer
     336           10 :     P_outer = Pgas_outer + radiation_pressure(T_outer)
     337           10 :     lnP = log(P_outer)
     338              : 
     339           10 :     y(1) = lnP
     340              : 
     341              :     ! Integrate inward from tau_outer to tau_surf
     342              : 
     343           10 :     lntau_outer = log(tau_outer)
     344           10 :     lntau_surf = log(tau_surf)
     345              : 
     346           10 :     dlntau = DLNTAU_SURF
     347              : 
     348           20 :     rtol = errtol
     349           20 :     atol = errtol
     350              : 
     351              :     call dopri5( &
     352              :          NUM_VARS, eval_fcn, lntau_outer, y, lntau_surf, &
     353              :          dlntau, DLNTAU_MAX, max_steps, &
     354              :          rtol, atol, 1, &
     355              :          eval_solout, IOUT, &
     356              :          work, lwork, iwork, liwork, &
     357              :          LRPAR, rpar, LIPAR, ipar, &
     358           10 :          LOUT, idid)
     359           10 :     if (idid < 0) then
     360            0 :        write(*,*) 'Call to dopri5 failed in eval_data_try: idid=', idid
     361            0 :        ierr = -1
     362            0 :        return
     363              :     end if
     364              : 
     365              :     ! Store the final pressure and temperature
     366              : 
     367           10 :     lnP = y(1)
     368              : 
     369           10 :     call eval_T_tau(T_tau_id, tau_surf, Teff, lnT, ierr)
     370           10 :     if (ierr /= 0) then
     371            0 :        write(*,*) 'atm: Call to eval_T_tau failed in eval_data_try'
     372            0 :        return
     373              :     end if
     374              : 
     375              :     ! Deallocate arrays
     376              : 
     377           10 :     deallocate(work, iwork)
     378              : 
     379           40 :     return
     380              : 
     381              :   contains
     382              : 
     383         6178 :     subroutine eval_fcn(n, x, h, y, f, lr, rpar, li, ipar, ierr)
     384              : 
     385           10 :       use eos_def, only: num_eos_basic_results
     386              :       use atm_T_tau_relations, only: eval_T_tau
     387              : 
     388              :       integer, intent(in) :: n, lr, li
     389              :       real(dp), intent(in) :: x, h
     390              :       real(dp), intent(inout) :: y(:)
     391              :       real(dp), intent(inout) :: f(:)
     392              :       integer, intent(inout), pointer :: ipar(:)
     393              :       real(dp), intent(inout), pointer :: rpar(:)
     394              :       integer, intent(out) :: ierr
     395              : 
     396              :       real(dp) :: tau
     397         6178 :       real(dp) :: lnP
     398              :       real(dp) :: lnT
     399         6178 :       real(dp) :: lnRho
     400       166806 :       real(dp) :: res(num_eos_basic_results)
     401       166806 :       real(dp) :: dres_dlnRho(num_eos_basic_results)
     402       166806 :       real(dp) :: dres_dlnT(num_eos_basic_results)
     403         6178 :       real(dp) :: kap
     404         6178 :       real(dp) :: dlnkap_dlnRho
     405         6178 :       real(dp) :: dlnkap_dlnT
     406              : 
     407         6178 :       ierr = 0
     408              : 
     409              :       ! Calculate the temperature
     410              : 
     411         6178 :       tau = exp(x)
     412              : 
     413         6178 :       lnP = y(1)
     414              : 
     415         6178 :       call eval_T_tau(T_tau_id, tau, Teff, lnT, ierr)
     416         6178 :       if (ierr /= 0) then
     417            0 :          write(*,*) 'atm: Call to eval_T_tau failed in eval_fcn'
     418            0 :          return
     419              :       end if
     420              : 
     421              :       ! Calculate the density and eos results
     422              : 
     423              :       call eos_proc( &
     424              :            lnP, lnT, &
     425              :            lnRho, res, dres_dlnRho, dres_dlnT, &
     426         6178 :            ierr)
     427         6178 :       if (ierr /= 0) then
     428            0 :          write(*,*) 'atm: Call to eos_proc failed in eval_fcn'
     429            0 :          return
     430              :       end if
     431              : 
     432              :       ! Calculate the opacity
     433              : 
     434              :        call kap_proc( &
     435              :             lnRho, lnT, res, dres_dlnRho, dres_dlnT, &
     436              :             kap, dlnkap_dlnRho, dlnkap_dlnT, &
     437         6178 :             ierr)
     438         6178 :        if (ierr /= 0) then
     439            0 :           write(*,*) 'atm: Call to kap_proc failed in eval_fcn'
     440            0 :           return
     441              :        end if
     442              : 
     443              :       ! Set up the rhs for the hydrostatic eqm equation
     444              :        ! dlnP/dlntau = tau*g/P*kappa
     445              : 
     446         6178 :        f(1) = tau*g/(kap*exp(lnP))
     447              : 
     448         6178 :       return
     449              : 
     450         6178 :     end subroutine eval_fcn
     451              : 
     452              : 
     453            0 :     subroutine eval_solout( &
     454              :          nr, xold, x, n, y, rwork_y, iwork_y, interp_y, lrpar, rpar, lipar, ipar, irtrn)
     455              : 
     456              :       integer, intent(in) :: nr, n, lrpar, lipar
     457              :       real(dp), intent(in) :: xold, x
     458              :       real(dp), intent(inout) :: y(:)
     459              :       real(dp), intent(inout), target :: rwork_y(*)
     460              :       integer, intent(inout), target :: iwork_y(*)
     461              :       integer, intent(inout), pointer :: ipar(:)
     462              :       real(dp), intent(inout), pointer :: rpar(:)
     463              :       interface
     464              :          real(dp) function interp_y(i, s, rwork_y, iwork_y, ierr)
     465              :            use const_def, only: dp
     466              :            implicit none
     467              :            integer, intent(in) :: i
     468              :            real(dp), intent(in) :: s
     469              :            real(dp), intent(inout), target :: rwork_y(*)
     470              :            integer, intent(inout), target :: iwork_y(*)
     471              :            integer, intent(out) :: ierr
     472              :          end function interp_y
     473              :       end interface
     474              :       integer, intent(out) :: irtrn  ! < 0 causes solver to return to calling program.
     475              : 
     476            0 :       irtrn = 0  ! for ifort
     477              : 
     478              :       ! Dummy routine that's never called
     479              : 
     480            0 :       call mesa_error(__FILE__,__LINE__,'Bogus call to eval_solout')
     481              : 
     482         6178 :     end subroutine eval_solout
     483              : 
     484              :   end subroutine eval_data_try
     485              : 
     486              : 
     487              :   ! Build atmosphere structure data from T-tau relation with varying
     488              :   ! opacity
     489              : 
     490            0 :   subroutine build_T_tau_varying( &
     491              :        tau_surf, L, R, Teff, M, cgrav, lnP_surf, tau_outer, &
     492              :        T_tau_id, eos_proc, kap_proc, errtol, dlogtau, &
     493              :        atm_structure_num_pts, atm_structure, &
     494              :        ierr)
     495              : 
     496              :     use atm_def
     497              :     use atm_utils, only: eval_Teff_g
     498              :     use num_lib, only: dopri5_work_sizes, dopri5
     499              : 
     500              :     real(dp), intent(in)      :: tau_surf
     501              :     real(dp), intent(in)      :: L
     502              :     real(dp), intent(in)      :: R
     503              :     real(dp), intent(in)      :: Teff
     504              :     real(dp), intent(in)      :: M
     505              :     real(dp), intent(in)      :: cgrav
     506              :     real(dp), intent(in)      :: lnP_surf
     507              :     real(dp), intent(in)      :: tau_outer
     508              :     integer, intent(in)       :: T_tau_id
     509              :     procedure(atm_eos_iface)  :: eos_proc
     510              :     procedure(atm_kap_iface)  :: kap_proc
     511              :     real(dp), intent(in)      :: errtol
     512              :     real(dp), intent(in)      :: dlogtau
     513              :     integer, intent(out)      :: atm_structure_num_pts
     514              :     real(dp), pointer         :: atm_structure(:,:)
     515              :     integer, intent(out)      :: ierr
     516              : 
     517              :     integer, parameter :: INIT_NUM_PTS = 100
     518              :     integer, parameter :: NUM_VARS = 2
     519              :     integer, parameter :: NRDENS = 0
     520              :     integer, parameter :: MAX_STEPS = 0
     521              :     integer, parameter :: LRPAR = 0
     522              :     integer, parameter :: LIPAR = 0
     523              :     integer, parameter :: IOUT = 1
     524              :     integer, parameter :: LOUT = 0
     525              : 
     526            0 :     real(dp)          :: g
     527              :     integer           :: liwork
     528              :     integer           :: lwork
     529            0 :     real(dp), pointer :: work(:)
     530            0 :     integer, pointer  :: iwork(:)
     531              :     real(dp), target  :: rpar_ary(LRPAR)
     532              :     integer, target   :: ipar_ary(LIPAR)
     533            0 :     real(dp), target  :: y_ary(NUM_VARS)
     534            0 :     real(dp), pointer :: rpar(:)
     535            0 :     integer, pointer  :: ipar(:)
     536            0 :     real(dp), pointer :: y(:)
     537            0 :     real(dp)          :: lntau_surf
     538            0 :     real(dp)          :: lntau_outer
     539            0 :     real(dp)          :: rtol(NUM_VARS)
     540            0 :     real(dp)          :: atol(NUM_VARS)
     541            0 :     real(dp)          :: dlntau
     542            0 :     real(dp)          :: dlntau_max
     543              :     integer           :: idid
     544              : 
     545            0 :     ierr = 0
     546              : 
     547              :     ! Sanity checks
     548              : 
     549            0 :     if (L <= 0._dp .OR. R <= 0._dp .OR. M <= 0._dp) then
     550            0 :        ierr = -1
     551            0 :        return
     552              :     end if
     553              : 
     554            0 :     if (dlntau <= 0._dp) then
     555            0 :        write(*,*) 'Invalid dlntau in build_atm_uniform:', dlntau
     556            0 :        call mesa_error(__FILE__,__LINE__)
     557              :     end if
     558              : 
     559              :     ! Evaluate the gravity
     560              : 
     561            0 :     g = cgrav*M/(R*R)
     562              : 
     563              :     ! Allocate atm_structure at its initial size
     564              : 
     565            0 :     allocate(atm_structure(num_results_for_build_atm,INIT_NUM_PTS))
     566              : 
     567            0 :     atm_structure_num_pts = 0
     568              : 
     569            0 :     if (tau_outer > tau_surf) return
     570              : 
     571              :     ! Allocate work rrays for the integrator
     572              : 
     573            0 :     call dopri5_work_sizes(NUM_VARS, NRDENS, liwork, lwork)
     574            0 :     allocate(work(lwork), iwork(liwork), stat=ierr)
     575            0 :     if (ierr /= 0) then
     576            0 :        write(*,*) 'atm: allocate failed in build_T_tau_varying'
     577            0 :        deallocate(atm_structure)
     578            0 :        return
     579              :     end if
     580              : 
     581            0 :     work = 0._dp
     582            0 :     iwork = 0
     583              : 
     584              :     ! Set pointers (simply because dopri5 wants pointer args)
     585              : 
     586            0 :     rpar => rpar_ary
     587            0 :     ipar => ipar_ary
     588              : 
     589            0 :     y => y_ary
     590              : 
     591              :     ! Set starting values for the integrator (y(1) = delta_r; y(2) = lnP)
     592              : 
     593            0 :     y(1) = 0._dp
     594            0 :     y(2) = lnP_surf
     595              : 
     596              :     ! Integrate from the atmosphere base outward
     597              : 
     598            0 :     lntau_outer = log(tau_outer)
     599            0 :     lntau_surf = log(tau_surf)
     600              : 
     601            0 :     dlntau_max = -dlogtau*ln10
     602            0 :     dlntau = 0.5_dp*dlntau_max
     603              : 
     604            0 :     rtol = errtol
     605            0 :     atol = errtol
     606              : 
     607              :     call dopri5( &
     608              :          NUM_VARS, build_fcn, lntau_surf, y, lntau_outer, &
     609              :          dlntau, dlntau_max, MAX_STEPS, &
     610              :          rtol, atol, 1, &
     611              :          build_solout, IOUT, &
     612              :          work, lwork, iwork, liwork, &
     613              :          LRPAR, rpar, LIPAR, ipar, &
     614            0 :          LOUT, idid)
     615            0 :     if (idid < 0) then
     616            0 :        write(*,*) 'atm: Call to dopri5 failed in build_T_tau_varying: idid=', idid
     617            0 :        ierr = -1
     618              :     end if
     619              : 
     620              :     ! Reverse the data ordering (since by convention data in atm_structure
     621              :     ! should be ordered outward-in)
     622              : 
     623              :     atm_structure(:,:atm_structure_num_pts) = &
     624            0 :          atm_structure(:,atm_structure_num_pts:1:-1)
     625              : 
     626              :     ! Deallocate arrays
     627              : 
     628            0 :     deallocate(work, iwork)
     629              : 
     630              :   contains
     631              : 
     632            0 :     subroutine build_fcn(n, x, h, y, f, lr, rpar, li, ipar, ierr)
     633              : 
     634              :       integer, intent(in) :: n, lr, li
     635              :       real(dp), intent(in) :: x, h
     636              :       real(dp), intent(inout) :: y(:)
     637              :       real(dp), intent(inout) :: f(:)
     638              :       integer, intent(inout), pointer :: ipar(:)
     639              :       real(dp), intent(inout), pointer :: rpar(:)
     640              :       integer, intent(out) :: ierr
     641              : 
     642            0 :       real(dp) :: tau
     643            0 :       real(dp) :: P
     644            0 :       real(dp) :: rho
     645            0 :       real(dp) :: kap
     646              : 
     647            0 :       real(dp) :: atm_structure_sgl(num_results_for_build_atm)
     648              : 
     649              :       ierr = 0
     650              : 
     651              :       ! Evaluate structure data
     652              : 
     653            0 :       call build_data(x, y(1), y(2), atm_structure_sgl, ierr)
     654            0 :       if (ierr /= 0) then
     655              :          ! Non-zero ierr signals we must use a smaller stepsize;
     656              :          ! whereas in fact we want to terminate the integration.
     657              :          ! Needs fixing!
     658            0 :          return
     659              :       end if
     660              : 
     661              :       ! Set up the rhs for the optical depth and hydrostatic
     662              :       ! equilibrium equations
     663              :       ! dr/dlntau = -tau/(kappa*rho)
     664              :       !
     665              : 
     666            0 :       tau = exp(x)
     667            0 :       P = exp(y(2))
     668            0 :       rho = exp(atm_structure_sgl(atm_lnd))
     669            0 :       kap = atm_structure_sgl(atm_kap)
     670              : 
     671            0 :       f(1) = -tau/(kap*rho)
     672            0 :       f(2) = tau*g/(kap*P)
     673              : 
     674            0 :     end subroutine build_fcn
     675              : 
     676              : 
     677            0 :     subroutine build_solout( &
     678            0 :          nr, xold, x, n, y, rwork_y, iwork_y, interp_y, lrpar, rpar, lipar, ipar, irtrn)
     679              : 
     680              :       use utils_lib, only: realloc_double2
     681              : 
     682              :       integer, intent(in) :: nr, n, lrpar, lipar
     683              :       real(dp), intent(in) :: xold, x
     684              :       real(dp), intent(inout) :: y(:)
     685              :       real(dp), intent(inout), target :: rwork_y(*)
     686              :       integer, intent(inout), target :: iwork_y(*)
     687              :       integer, intent(inout), pointer :: ipar(:)
     688              :       real(dp), intent(inout), pointer :: rpar(:)
     689              :       interface
     690              :          real(dp) function interp_y(i, s, rwork_y, iwork_y, ierr)
     691              :            use const_def, only: dp
     692              :            implicit none
     693              :            integer, intent(in) :: i
     694              :            real(dp), intent(in) :: s
     695              :            real(dp), intent(inout), target :: rwork_y(*)
     696              :            integer, intent(inout), target :: iwork_y(*)
     697              :            integer, intent(out) :: ierr
     698              :          end function interp_y
     699              :       end interface
     700              :       integer, intent(out) :: irtrn
     701              : 
     702              :       integer :: ierr
     703              :       integer :: sz
     704            0 :       real(dp) :: atm_structure_sgl(num_results_for_build_atm)
     705              : 
     706              :       ierr = 0
     707              : 
     708              :       ! Evaluate structure data
     709              : 
     710            0 :       call build_data(x, y(1), y(2), atm_structure_sgl, ierr)
     711            0 :       if (ierr /= 0) then
     712            0 :          irtrn = -1
     713            0 :          return
     714              :       end if
     715              : 
     716              :       ! If necessary, expand arrays
     717              : 
     718            0 :       atm_structure_num_pts = atm_structure_num_pts + 1
     719            0 :       sz = size(atm_structure, dim=2)
     720              : 
     721            0 :       if (atm_structure_num_pts > sz) then
     722            0 :          sz = 2*sz + 100
     723              :          call realloc_double2( &
     724            0 :               atm_structure,num_results_for_build_atm,sz,ierr)
     725              :       end if
     726              : 
     727              :       ! Store data
     728              : 
     729            0 :       atm_structure(:,atm_structure_num_pts) = atm_structure_sgl
     730              : 
     731              :       return
     732              : 
     733              :     end subroutine build_solout
     734              : 
     735              : 
     736            0 :     subroutine build_data(lntau, delta_r, lnP, atm_structure_sgl, ierr)
     737              : 
     738              :       use eos_def
     739              :       use eos_lib, only: radiation_pressure
     740              :       use atm_T_tau_relations, only: eval_T_tau
     741              :       use atm_utils, only: eval_Paczynski_gradr
     742              : 
     743              :       real(dp), intent(in)  :: lntau
     744              :       real(dp), intent(in)  :: delta_r
     745              :       real(dp), intent(in)  :: lnP
     746              :       real(dp), intent(out) :: atm_structure_sgl(:)
     747              :       integer, intent(out)  :: ierr
     748              : 
     749            0 :       real(dp) :: tau
     750            0 :       real(dp) :: lnT
     751            0 :       real(dp) :: lnRho
     752            0 :       real(dp) :: res(num_eos_basic_results)
     753            0 :       real(dp) :: dres_dlnRho(num_eos_basic_results)
     754            0 :       real(dp) :: dres_dlnT(num_eos_basic_results)
     755            0 :       real(dp) :: kap
     756            0 :       real(dp) :: dlnkap_dlnRho
     757            0 :       real(dp) :: dlnkap_dlnT
     758            0 :       real(dp) :: gradr
     759              : 
     760            0 :       ierr = 0
     761              : 
     762              :       ! Calculate the temperature
     763              : 
     764            0 :       tau = exp(lntau)
     765              : 
     766            0 :       call eval_T_tau(T_tau_id, tau, Teff, lnT, ierr)
     767            0 :       if (ierr /= 0) then
     768            0 :          write(*,*) 'atm: Call to eval_T_tau failed in build_data'
     769            0 :          return
     770              :       end if
     771              : 
     772              :       ! Calculate the density and eos results
     773              : 
     774              :       call eos_proc( &
     775              :            lnP, lnT, &
     776              :            lnRho, res, dres_dlnRho, dres_dlnT, &
     777            0 :            ierr)
     778            0 :       if (ierr /= 0) then
     779            0 :          write(*,*) 'atm: Call to eos_proc failed in build_data'
     780            0 :          return
     781              :       end if
     782              : 
     783              :       ! Calculate the opacity
     784              : 
     785              :        call kap_proc( &
     786              :             lnRho, lnT, res, dres_dlnRho, dres_dlnT, &
     787              :             kap, dlnkap_dlnRho, dlnkap_dlnT, &
     788            0 :            ierr)
     789            0 :        if (ierr /= 0) then
     790            0 :           write(*,*) 'atm: Call to kap_proc failed in build_data'
     791            0 :           return
     792              :        end if
     793              : 
     794              :       ! Evaluate radiative temperature gradient
     795              : 
     796            0 :       gradr = eval_Paczynski_gradr(exp(lnT), exp(lnP), exp(lnRho), tau, kap, L, M, R, cgrav)
     797              : 
     798              :       ! Store data
     799              : 
     800            0 :       atm_structure_sgl(atm_xm) = 0._dp  ! We assume negligible mass in the atmosphere
     801            0 :       atm_structure_sgl(atm_delta_r) = delta_r
     802            0 :       atm_structure_sgl(atm_lnP) = lnP
     803            0 :       atm_structure_sgl(atm_lnd) = lnRho
     804            0 :       atm_structure_sgl(atm_lnT) = lnT
     805            0 :       atm_structure_sgl(atm_gradT) = gradr  ! by assumption, atm is radiative
     806            0 :       atm_structure_sgl(atm_kap) = kap
     807            0 :       atm_structure_sgl(atm_gamma1) = res(i_gamma1)
     808            0 :       atm_structure_sgl(atm_grada) = res(i_grad_ad)
     809            0 :       atm_structure_sgl(atm_chiT) = res(i_chiT)
     810            0 :       atm_structure_sgl(atm_chiRho) = res(i_chiRho)
     811            0 :       atm_structure_sgl(atm_cp) = res(i_Cp)
     812            0 :       atm_structure_sgl(atm_cv) = res(i_Cv)
     813            0 :       atm_structure_sgl(atm_tau) = tau
     814            0 :       atm_structure_sgl(atm_lnfree_e) = res(i_lnfree_e)
     815            0 :       atm_structure_sgl(atm_dlnkap_dlnT) = dlnkap_dlnT
     816            0 :       atm_structure_sgl(atm_dlnkap_dlnd) = dlnkap_dlnRho
     817            0 :       atm_structure_sgl(atm_lnPgas) = res(i_lnPgas)
     818            0 :       atm_structure_sgl(atm_gradr) = gradr
     819              : 
     820            0 :     end subroutine build_data
     821              : 
     822              :   end subroutine build_T_tau_varying
     823              : 
     824              : end module atm_T_tau_varying
        

Generated by: LCOV version 2.0-1