LCOV - code coverage report
Current view: top level - star/private - pulse_fgong.f90 (source / functions) Coverage Total Hit
Test: coverage.info Lines: 0.0 % 269 0
Test Date: 2025-05-08 18:23:42 Functions: 0.0 % 5 0

            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 pulse_fgong
      21              : 
      22              :   use star_private_def
      23              :   use const_def, only: dp, pi, rsun, four_thirds, no_mixing, standard_cgrav
      24              :   use utils_lib
      25              :   use chem_def
      26              :   use atm_def
      27              :   use eos_def, only: i_Gamma1, i_lnPgas, i_chiRho, i_chiT
      28              :   use eos_def, only: num_eos_basic_results, num_eos_d_dxa_results
      29              :   use atm_support
      30              :   use eos_support
      31              :   use pulse_utils
      32              : 
      33              :   implicit none
      34              : 
      35              :   ! Parameter definitions (these values are for FGONG format versions
      36              :   ! 300 & 1300)
      37              : 
      38              :   integer, parameter :: ICONST = 15
      39              :   integer, parameter :: IVAR = 40
      40              : 
      41              :   private
      42              :   public :: get_fgong_data
      43              :   public :: write_fgong_data
      44              : 
      45              : contains
      46              : 
      47            0 :   subroutine get_fgong_data (id, &
      48              :        add_center_point, keep_surface_point, add_atmosphere, global_data, point_data, ierr)
      49              : 
      50              :     integer, intent(in)                :: id
      51              :     logical, intent(in)                :: add_center_point
      52              :     logical, intent(in)                :: keep_surface_point
      53              :     logical, intent(in)                :: add_atmosphere
      54              :     real(dp), allocatable, intent(out) :: global_data(:)
      55              :     real(dp), allocatable, intent(out) :: point_data(:,:)
      56              :     integer, intent(out)               :: ierr
      57              : 
      58              :     type(star_info), pointer :: s
      59            0 :     integer, allocatable     :: k_a(:)
      60            0 :     integer, allocatable     :: k_b(:)
      61              :     integer                  :: n_sg
      62              :     integer                  :: h1
      63              :     integer                  :: h2
      64              :     integer                  :: he3
      65              :     integer                  :: he4
      66              :     integer                  :: li7
      67              :     integer                  :: be7
      68              :     integer                  :: c12
      69              :     integer                  :: c13
      70              :     integer                  :: n14
      71              :     integer                  :: n15
      72              :     integer                  :: o16
      73              :     integer                  :: o17
      74              :     integer                  :: o18
      75              :     integer                  :: ne20
      76              :     integer                  :: n_atm
      77              :     integer                  :: nn_atm
      78              :     integer                  :: n_env
      79              :     integer                  :: nn_env
      80              :     integer                  :: nn
      81            0 :     real(dp)                 :: r_outer
      82            0 :     real(dp)                 :: m_outer
      83            0 :     real(dp)                 :: P_c
      84            0 :     real(dp)                 :: rho_c
      85            0 :     real(dp)                 :: d2P_dr2_c
      86              :     integer                  :: j
      87              :     integer                  :: k
      88              :     integer                  :: sg
      89              : 
      90              :     real(dp), dimension(num_eos_basic_results) :: &
      91            0 :        res, res_loX, res_hiX, dres_dlnRho, dres_dlnT
      92              : 
      93              :     ! Rather than allocating these arrays before use in each region,
      94              :     ! allocate them in outer calling subroutine.
      95              :     ! ∂lnΓ₁/∂… blocks in each region can probably be refactored.
      96            0 :     real(dp), allocatable :: dres_dxa(:,:)
      97            0 :     real(dp), allocatable :: xa(:)
      98              :     real(dp), parameter :: dxa = 1d-3  ! perturbation of abundances for ∂lnΓ₁/∂Y
      99              : 
     100              :     ! Get FGONG data
     101              : 
     102            0 :     call get_star_ptr(id, s, ierr)
     103            0 :     if (ierr /= 0) then
     104            0 :        write(*,*) 'bad star id for get_fgong_data'
     105            0 :        return
     106              :     end if
     107              : 
     108              :     ! Set up segment indices
     109              : 
     110              :     call set_segment_indices(s, k_a, k_b, add_center_point)
     111              : 
     112            0 :     n_sg = SIZE(k_a)
     113              : 
     114              :     ! Set up specicies indices
     115              : 
     116            0 :     h1 = s%net_iso(ih1)
     117            0 :     h2 = s%net_iso(ih2)
     118            0 :     he3 = s%net_iso(ihe3)
     119            0 :     he4 = s%net_iso(ihe4)
     120            0 :     li7 = s%net_iso(ili7)
     121            0 :     be7 = s%net_iso(ibe7)
     122            0 :     c12 = s%net_iso(ic12)
     123            0 :     c13 = s%net_iso(ic13)
     124            0 :     n14 = s%net_iso(in14)
     125            0 :     n15 = s%net_iso(in15)
     126            0 :     o16 = s%net_iso(io16)
     127            0 :     o17 = s%net_iso(io17)
     128            0 :     o18 = s%net_iso(io18)
     129            0 :     ne20 = s%net_iso(ine20)
     130              : 
     131              :     ! Determine data dimensions
     132              : 
     133            0 :     allocate(dres_dxa(num_eos_basic_results, s% species))
     134            0 :     allocate(xa(s% species))
     135              : 
     136            0 :     if (add_atmosphere) then
     137            0 :        call build_atm(s, s%L(1), s%r(1), s%Teff, s%m_grav(1), s%cgrav(1), ierr)
     138            0 :        if (ierr /= 0) then
     139            0 :           write(*,*) 'failed in build_atm'
     140            0 :           return
     141              :        end if
     142            0 :        n_atm = s%atm_structure_num_pts
     143            0 :        nn_atm = n_atm - 1
     144              :     else
     145              :        n_atm = 0
     146              :        nn_atm = 0
     147              :     end if
     148              : 
     149            0 :     n_env = s%nz
     150              : 
     151            0 :     if (keep_surface_point) then
     152            0 :        nn_env = n_env + n_sg - 1
     153              :     else
     154            0 :        nn_env = n_env - 1 + n_sg - 1
     155              :     end if
     156              : 
     157            0 :     if (add_center_point) then
     158            0 :        nn = nn_env + nn_atm + 1
     159              :     else
     160            0 :        nn = nn_env + nn_atm
     161              :     end if
     162              : 
     163              :     ! Store global data
     164              : 
     165            0 :     allocate(global_data(ICONST))
     166            0 :     global_data = 0d0
     167              : 
     168            0 :     r_outer = Rsun*s%photosphere_r
     169            0 :     m_outer = s%m_grav(1)
     170              : 
     171            0 :     global_data(1) = m_outer
     172            0 :     global_data(2) = r_outer
     173            0 :     global_data(3) = s%L(1)
     174            0 :     global_data(4) = s%initial_z
     175            0 :     global_data(5) = 1d0 - (s%initial_y + s%initial_z)
     176            0 :     global_data(6) = s%mixing_length_alpha
     177              : 
     178              :     ! global_data(7)-global_data(10) are not used
     179              : 
     180            0 :     if (s%interpolate_rho_for_pulse_data) then
     181            0 :        rho_c = eval_center_rho(s, k_b(n_sg))
     182              :     else
     183            0 :        rho_c = eval_center(s%rmid, s%rho, k_a(n_sg), k_b(n_sg))
     184              :     end if
     185              : 
     186              :     ! at the centre d²P/dr² = -4πGρ²/3
     187            0 :     d2P_dr2_c = -four_thirds*pi*s% cgrav(s% nz)*rho_c**2
     188            0 :     P_c = s%Peos(s% nz) - 0.5d0*d2P_dr2_c*s% rmid(s% nz)**2
     189            0 :     global_data(11) = r_outer**2*d2P_dr2_c/P_c
     190            0 :     global_data(12) = r_outer**2*eval_center_d2(s%rmid, s%rho, k_a(n_sg), k_b(n_sg)) / rho_c
     191            0 :     global_data(13) = s%star_age
     192            0 :     global_data(14) = s%Teff
     193            0 :     global_data(15) = standard_cgrav
     194              : 
     195              :     ! Store point data
     196              : 
     197            0 :     allocate(point_data(IVAR,nn))
     198            0 :     point_data = 0d0
     199              : 
     200            0 :     j = 1
     201              : 
     202              :     ! Atmosphere (we skip the point at the base of the atm to smooth
     203              :     ! the transition)
     204              : 
     205            0 :     atm_loop : do k = 1, n_atm-1
     206            0 :        call store_point_data_atm(j, k, k_a(1), k_b(1))
     207            0 :        j = j + 1
     208              :     end do atm_loop
     209              : 
     210              :     ! Envelope
     211              : 
     212            0 :     sg = 1
     213              : 
     214            0 :     env_loop : do k = 1, n_env
     215              : 
     216            0 :        if (k == 1 .AND. .NOT. keep_surface_point) cycle env_loop
     217              : 
     218            0 :        call store_point_data_env(j, k, k_a(sg), k_b(sg))
     219            0 :        j = j + 1
     220              : 
     221            0 :        if (k == k_b(sg)+1) then
     222              : 
     223            0 :           sg = sg + 1
     224              : 
     225            0 :           call store_point_data_env(j, k, k_a(sg), k_b(sg))
     226            0 :           j = j + 1
     227              : 
     228              :        end if
     229              : 
     230              :     end do env_loop
     231              : 
     232              :     ! Center
     233              : 
     234            0 :     if (add_center_point) then
     235            0 :        call store_point_data_ctr(j, k_a(n_sg), k_b(n_sg))
     236            0 :        j = j + 1
     237              :     end if
     238              : 
     239              :     ! Tidy up
     240              : 
     241            0 :     if (ASSOCIATED(s%atm_structure)) then
     242            0 :        deallocate(s%atm_structure)
     243              :     end if
     244              : 
     245            0 :     deallocate(dres_dxa)
     246            0 :     deallocate(xa)
     247              : 
     248            0 :     return
     249              : 
     250              :   contains
     251              : 
     252            0 :     subroutine store_point_data_atm (j, k, k_a, k_b)
     253              : 
     254              :       integer, intent(in) :: j
     255              :       integer, intent(in) :: k
     256              :       integer, intent(in) :: k_a
     257              :       integer, intent(in) :: k_b
     258              : 
     259            0 :       real(dp) :: grav
     260            0 :       real(dp) :: N2
     261              : 
     262              :       ! Store data associated with atmosphere point k into the
     263              :       ! point_data array at position j
     264              : 
     265              :       associate ( &
     266              :            r => point_data(1,j), &
     267              :            lnq => point_data(2,j), &
     268              :            T => point_data(3,j), &
     269              :            P => point_data(4,j), &
     270              :            rho => point_data(5,j), &
     271              :            X => point_data(6,j), &
     272              :            L => point_data(7,j), &
     273              :            kap => point_data(8,j), &
     274              :            eps => point_data(9,j), &
     275              :            Gamma_1 => point_data(10,j), &
     276              :            nabla_ad => point_data(11,j), &
     277              :            delta => point_data(12,j), &
     278              :            c_P => point_data(13,j), &
     279              :            rec_mu_e => point_data(14,j), &
     280              :            A_ast => point_data(15,j), &
     281              :            r_X => point_data(16,j), &
     282              :            Z => point_data(17,j), &
     283              :            R_r => point_data(18,j), &
     284              :            eps_grav => point_data(19,j), &
     285              :            X_He3 => point_data(21,j), &
     286              :            X_C12 => point_data(22,j), &
     287              :            X_C13 => point_data(23,j), &
     288              :            X_N14 => point_data(24,j), &
     289              :            X_O16 => point_data(25,j), &
     290              :            dlnGamma1_dlnrho => point_data(26,j), &
     291              :            dlnGamma1_dlnP => point_data(27,j), &
     292              :            dlnGamma1_dY => point_data(28,j), &
     293              :            X_H2 => point_data(29,j), &
     294              :            X_He4 => point_data(30,j), &
     295              :            X_Li7 => point_data(31,j), &
     296              :            X_Be7 => point_data(32,j), &
     297              :            X_N15 => point_data(33,j), &
     298              :            X_O17 => point_data(34,j), &
     299              :            X_O18 => point_data(35,j), &
     300              :            X_Ne20 => point_data(36,j))
     301              : 
     302            0 :         r = s%r(1) + s%atm_structure(atm_delta_r,k)
     303            0 :         lnq = log(s%m_grav(1)/m_outer)
     304            0 :         T = exp(s%atm_structure(atm_lnT,k))
     305            0 :         P = exp(s%atm_structure(atm_lnP,k))
     306            0 :         rho = exp(s%atm_structure(atm_lnd,k))
     307            0 :         X = eval_face(s%dq, s%X, 1, k_a, k_b, v_lo=0d0, v_hi=1d0)
     308            0 :         L = s%L(1)
     309            0 :         kap = s%atm_structure(atm_kap,k)
     310            0 :         eps = 0d0
     311            0 :         Gamma_1 = s%atm_structure(atm_gamma1,k)
     312            0 :         nabla_ad = s%atm_structure(atm_grada,k)
     313            0 :         delta = s%atm_structure(atm_chiT,k)/s%atm_structure(atm_chiRho,k)
     314            0 :         c_P = s%atm_structure(atm_cp,k)
     315            0 :         rec_mu_e = exp(s%atm_structure(atm_lnfree_e,k))  ! check
     316              : 
     317            0 :         grav = s%cgrav(1)*s%m_grav(1)/(r*r)
     318            0 :         N2 = grav*grav*(rho/P)*delta*(nabla_ad - s%atm_structure(atm_gradT,k))
     319            0 :         A_ast = N2*r/grav
     320              : 
     321            0 :         r_X = 0d0  ! dxdt_nuc_h1
     322              :         Z = MIN(1d0, MAX(0d0, 1d0 - &
     323              :              eval_face(s%dq, s%X, 1, k_a, k_b) - &
     324            0 :              eval_face(s%dq, s%Y, 1, k_a, k_b)))
     325            0 :         R_r = r_outer - r
     326            0 :         eps_grav = 0d0
     327              : 
     328            0 :         X_He3 = eval_face_X(s, he3, 1, k_a, k_b)
     329            0 :         X_C12 = eval_face_X(s, c12, 1, k_a, k_b)
     330            0 :         X_C13 = eval_face_X(s, c13, 1, k_a, k_b)
     331            0 :         X_N14 = eval_face_X(s, n14, 1, k_a, k_b)
     332            0 :         X_O16 = eval_face_X(s, o16, 1, k_a, k_b)
     333            0 :         X_H2 = eval_face_X(s, h2, 1, k_a, k_b)
     334            0 :         X_He4 = eval_face_X(s, he4, 1, k_a, k_b)
     335            0 :         X_Li7 = eval_face_X(s, li7, 1, k_a, k_b)
     336            0 :         X_Be7 = eval_face_X(s, be7, 1, k_a, k_b)
     337            0 :         X_N15 = eval_face_X(s, n15, 1, k_a, k_b)
     338            0 :         X_O17 = eval_face_X(s, o17, 1, k_a, k_b)
     339            0 :         X_O18 = eval_face_X(s, o18, 1, k_a, k_b)
     340            0 :         X_Ne20 = eval_face_X(s, ne20, 1, k_a, k_b)
     341              : 
     342              :         ! Γ₁ derivatives
     343            0 :         xa(:) = s% xa(:,1)
     344              : 
     345              :         ! evaluate EoS at low X
     346            0 :         xa(h1) = s% xa(h1,1) - dxa
     347            0 :         xa(he4) = s% xa(he4,1) + dxa
     348              :         call get_eos(s, k, xa(:), rho, log10(rho), T, log10(T), &
     349            0 :            res_loX, dres_dlnRho, dres_dlnT, dres_dxa, ierr)
     350              : 
     351              :         ! evaluate EoS at high X
     352            0 :         xa(h1) = s% xa(h1,1) + dxa
     353            0 :         xa(he4) = s% xa(he4,1) - dxa
     354              :         call get_eos(s, k, xa(:), rho, log10(rho), T, log10(T), &
     355            0 :            res_hiX, dres_dlnRho, dres_dlnT, dres_dxa, ierr)
     356              : 
     357              :         ! evaluate EoS at  actual X
     358              :         call get_eos(s, k, s% xa(:,1), rho, log10(rho), T, log10(T), &
     359            0 :            res, dres_dlnRho, dres_dlnT, dres_dxa, ierr)
     360              : 
     361              :         ! use dres_dxa(:,1) to store finite difference,
     362              :         ! which is evaluated at constant (ρ,T)
     363            0 :         dres_dxa(:,1) = (res_hiX-res_loX)/2/dxa
     364              : 
     365              :         dlnGamma1_dlnRho = dres_dlnRho(i_Gamma1) &
     366            0 :            - dres_dlnT(i_Gamma1)*res(i_chiRho)/res(i_chiT)
     367            0 :         dlnGamma1_dlnRho = dlnGamma1_dlnRho/res(i_Gamma1)
     368              : 
     369            0 :         dlnGamma1_dlnP = dres_dlnT(i_Gamma1)/res(i_chiT)/res(i_Gamma1)
     370              : 
     371              :         dlnGamma1_dY = dres_dxa(i_Gamma1,1) &
     372            0 :            - dres_dlnT(i_Gamma1)*dres_dxa(i_lnPgas,1)/res(i_chiT)
     373            0 :         dlnGamma1_dY = -dlnGamma1_dY/res(i_Gamma1)  ! d/dY ~ -d/dX
     374              : 
     375              :       end associate
     376              : 
     377            0 :       return
     378              : 
     379              :     end subroutine store_point_data_atm
     380              : 
     381              : 
     382            0 :     subroutine store_point_data_env (j, k, k_a, k_b)
     383              : 
     384              :       integer, intent(in) :: j
     385              :       integer, intent(in) :: k
     386              :       integer, intent(in) :: k_a
     387              :       integer, intent(in) :: k_b
     388              : 
     389              :       ! Store data for envelope face k into the point_data array at
     390              :       ! position j
     391              : 
     392              :       associate ( &
     393              :            r => point_data(1,j), &
     394              :            lnq => point_data(2,j), &
     395              :            T => point_data(3,j), &
     396              :            P => point_data(4,j), &
     397              :            rho => point_data(5,j), &
     398              :            X => point_data(6,j), &
     399              :            L => point_data(7,j), &
     400              :            kap => point_data(8,j), &
     401              :            eps => point_data(9,j), &
     402              :            Gamma_1 => point_data(10,j), &
     403              :            nabla_ad => point_data(11,j), &
     404              :            delta => point_data(12,j), &
     405              :            c_P => point_data(13,j), &
     406              :            rec_mu_e => point_data(14,j), &
     407              :            A_ast => point_data(15,j), &
     408              :            r_X => point_data(16,j), &
     409              :            Z => point_data(17,j), &
     410              :            R_r => point_data(18,j), &
     411              :            eps_grav => point_data(19,j), &
     412              :            X_He3 => point_data(21,j), &
     413              :            X_C12 => point_data(22,j), &
     414              :            X_C13 => point_data(23,j), &
     415              :            X_N14 => point_data(24,j), &
     416              :            X_O16 => point_data(25,j), &
     417              :            dlnGamma1_dlnrho => point_data(26,j), &
     418              :            dlnGamma1_dlnP => point_data(27,j), &
     419              :            dlnGamma1_dY => point_data(28,j), &
     420              :            X_H2 => point_data(29,j), &
     421              :            X_He4 => point_data(30,j), &
     422              :            X_Li7 => point_data(31,j), &
     423              :            X_Be7 => point_data(32,j), &
     424              :            X_N15 => point_data(33,j), &
     425              :            X_O17 => point_data(34,j), &
     426              :            X_O18 => point_data(35,j), &
     427              :            X_Ne20 => point_data(36,j))
     428              : 
     429            0 :         r = s%r(k)
     430            0 :         lnq = log(s%m_grav(k)/m_outer)
     431            0 :         T = eval_face(s%dq, s%T, k, 1, s%nz)
     432            0 :         P = eval_face(s%dq, s%Peos, k, 1, s%nz)
     433            0 :         if (s%interpolate_rho_for_pulse_data) then
     434            0 :            rho = eval_face(s%dq, s%rho, k, k_a, k_b)
     435              :         else
     436            0 :            rho = eval_face_rho(s, k, k_a, k_b)
     437              :         end if
     438            0 :         X = eval_face(s%dq, s%X, k, k_a, k_b, v_lo=0d0, v_hi=1d0)
     439            0 :         L = s%L(k)
     440            0 :         kap = eval_face(s%dq, s%opacity, k, k_a, k_b)
     441            0 :         eps = eval_face(s%dq, s%eps_nuc, k, k_a, k_b) + eval_face(s%dq, s%eps_grav_ad%val, k, k_a, k_b)
     442            0 :         Gamma_1 = eval_face(s%dq, s%gamma1, k, k_a, k_b)
     443            0 :         nabla_ad = eval_face(s%dq, s%grada, k, k_a, k_b)
     444            0 :         delta = eval_face(s%dq, s%chiT, k, k_a, k_b)/eval_face(s%dq, s%chiRho, k, k_a, k_b)
     445            0 :         c_P = eval_face(s%dq, s%cp, k, k_a, k_b)
     446            0 :         rec_mu_e = exp(eval_face(s%dq, s%lnfree_e, k, k_a, k_b))
     447            0 :         if (r <= s%fgong_zero_A_inside_r*Rsun .AND. s%mixing_type(k) /= no_mixing) then
     448            0 :            A_ast = 0d0
     449              :         else
     450            0 :            A_ast = eval_face_A_ast(s, k, k_a, k_b)
     451              :         end if
     452            0 :         r_X = eval_face(s%dq, s%dxdt_nuc(h1,:), k, k_a, k_b)
     453              :         Z = MIN(1d0, MAX(0d0, 1d0 - &
     454              :              eval_face(s%dq, s%X, k, k_a, k_b) - &
     455            0 :              eval_face(s%dq, s%Y, k, k_a, k_b)))
     456            0 :         R_r = r_outer - s%r(k)
     457            0 :         eps_grav = eval_face(s%dq, s%eps_grav_ad%val, k, k_a, k_b)
     458            0 :         X_He3 = eval_face_X(s, he3, k, k_a, k_b)
     459            0 :         X_C12 = eval_face_X(s, c12, k, k_a, k_b)
     460            0 :         X_C13 = eval_face_X(s, c13, k, k_a, k_b)
     461            0 :         X_N14 = eval_face_X(s, n14, k, k_a, k_b)
     462            0 :         X_O16 = eval_face_X(s, o16, k, k_a, k_b)
     463            0 :         X_H2 = eval_face_X(s, h2, k, k_a, k_b)
     464            0 :         X_He4 = eval_face_X(s, he4, k, k_a, k_b)
     465            0 :         X_Li7 = eval_face_X(s, li7, k, k_a, k_b)
     466            0 :         X_Be7 = eval_face_X(s, be7, k, k_a, k_b)
     467            0 :         X_N15 = eval_face_X(s, n15, k, k_a, k_b)
     468            0 :         X_O17 = eval_face_X(s, o17, k, k_a, k_b)
     469            0 :         X_O18 = eval_face_X(s, o18, k, k_a, k_b)
     470            0 :         X_Ne20 = eval_face_X(s, ne20, k, k_a, k_b)
     471              : 
     472              :         ! Γ₁ derivatives
     473            0 :         xa(:) = s% xa(:,k)
     474              : 
     475              :         ! evaluate EoS at low X
     476            0 :         xa(h1) = s% xa(h1,k) - dxa
     477            0 :         xa(he4) = s% xa(he4,k) + dxa
     478              :         call get_eos(s, k, xa(:), rho, log10(rho), T, log10(T), &
     479            0 :            res_loX, dres_dlnRho, dres_dlnT, dres_dxa, ierr)
     480              : 
     481              :         ! evaluate EoS at high X
     482            0 :         xa(h1) = s% xa(h1,k) + dxa
     483            0 :         xa(he4) = s% xa(he4,k) - dxa
     484              :         call get_eos(s, k, xa(:), rho, log10(rho), T, log10(T), &
     485            0 :            res_hiX, dres_dlnRho, dres_dlnT, dres_dxa, ierr)
     486              : 
     487              :         ! evaluate EoS at  actual X
     488              :         call get_eos(s, k, s% xa(:,k), rho, log10(rho), T, log10(T), &
     489            0 :            res, dres_dlnRho, dres_dlnT, dres_dxa, ierr)
     490              : 
     491              :         ! use dres_dxa(:,1) to store finite difference,
     492              :         ! which is evaluated at constant (ρ,T)
     493            0 :         dres_dxa(:,1) = (res_hiX-res_loX)/2/dxa
     494              : 
     495              :         dlnGamma1_dlnRho = dres_dlnRho(i_Gamma1) &
     496            0 :            - dres_dlnT(i_Gamma1)*res(i_chiRho)/res(i_chiT)
     497            0 :         dlnGamma1_dlnRho = dlnGamma1_dlnRho/res(i_Gamma1)
     498              : 
     499            0 :         dlnGamma1_dlnP = dres_dlnT(i_Gamma1)/res(i_chiT)/res(i_Gamma1)
     500              : 
     501              :         dlnGamma1_dY = dres_dxa(i_Gamma1,1) &
     502            0 :            - dres_dlnT(i_Gamma1)*dres_dxa(i_lnPgas,1)/res(i_chiT)
     503            0 :         dlnGamma1_dY = -dlnGamma1_dY/res(i_Gamma1)  ! d/dY ~ -d/dX
     504              : 
     505              :       end associate
     506              : 
     507            0 :       return
     508              : 
     509              :     end subroutine store_point_data_env
     510              : 
     511              : 
     512            0 :     subroutine store_point_data_ctr (j, k_a, k_b)
     513              : 
     514              :       integer, intent(in) :: j
     515              :       integer, intent(in) :: k_a
     516              :       integer, intent(in) :: k_b
     517              : 
     518              :       ! Store data for the center into the point_data array at position j
     519              : 
     520              :       associate ( &
     521              :            r => point_data(1,j), &
     522              :            lnq => point_data(2,j), &
     523              :            T => point_data(3,j), &
     524              :            P => point_data(4,j), &
     525              :            rho => point_data(5,j), &
     526              :            X => point_data(6,j), &
     527              :            L => point_data(7,j), &
     528              :            kap => point_data(8,j), &
     529              :            eps => point_data(9,j), &
     530              :            Gamma_1 => point_data(10,j), &
     531              :            nabla_ad => point_data(11,j), &
     532              :            delta => point_data(12,j), &
     533              :            c_P => point_data(13,j), &
     534              :            rec_mu_e => point_data(14,j), &
     535              :            A_ast => point_data(15,j), &
     536              :            r_X => point_data(16,j), &
     537              :            Z => point_data(17,j), &
     538              :            R_r => point_data(18,j), &
     539              :            eps_grav => point_data(19,j), &
     540              :            X_He3 => point_data(21,j), &
     541              :            X_C12 => point_data(22,j), &
     542              :            X_C13 => point_data(23,j), &
     543              :            X_N14 => point_data(24,j), &
     544              :            X_O16 => point_data(25,j), &
     545              :            dlnGamma1_dlnrho => point_data(26,j), &
     546              :            dlnGamma1_dlnP => point_data(27,j), &
     547              :            dlnGamma1_dY => point_data(28,j), &
     548              :            X_H2 => point_data(29,j), &
     549              :            X_He4 => point_data(30,j), &
     550              :            X_Li7 => point_data(31,j), &
     551              :            X_Be7 => point_data(32,j), &
     552              :            X_N15 => point_data(33,j), &
     553              :            X_O17 => point_data(34,j), &
     554              :            X_O18 => point_data(35,j), &
     555              :            X_Ne20 => point_data(36,j))
     556              : 
     557            0 :         r = 0d0
     558            0 :         lnq = log(TINY(0d0))
     559            0 :         T = eval_center(s%rmid, s%T, 1, s%nz)
     560            0 :         P = P_c
     561            0 :         rho = rho_c
     562            0 :         X = eval_center(s%rmid, s%X, k_a, k_b, v_lo=0d0, v_hi=1d0)
     563            0 :         L = 0d0
     564            0 :         kap = eval_center(s%rmid, s%opacity, k_a, k_b)
     565            0 :         eps = eval_center(s%rmid, s%eps_nuc, k_a, k_b) + eval_center(s%rmid, s%eps_grav_ad%val, k_a, k_b)
     566            0 :         Gamma_1 = eval_center(s%rmid, s%gamma1, k_a, k_b)
     567            0 :         nabla_ad = eval_center(s%rmid, s%grada, k_a, k_b)
     568            0 :         delta = eval_center(s%rmid, s%chiT, k_a, k_b)/eval_center(s%rmid, s%chiRho, k_a, k_b)
     569            0 :         c_P = eval_center(s%rmid, s%cp, k_a, k_b)
     570            0 :         rec_mu_e = exp(eval_center(s%rmid, s%lnfree_e, k_a, k_b))
     571            0 :         A_ast = 0d0
     572            0 :         r_X = eval_center(s%rmid, s%dxdt_nuc(h1,:), k_a, k_b)
     573              :         Z = MIN(1d0, MAX(0d0, 1d0 - &
     574              :              eval_center(s%rmid, s%X, k_a, k_b) - &
     575            0 :              eval_center(s%rmid, s%Y, k_a, k_b)))
     576            0 :         R_r = r_outer
     577            0 :         eps_grav = eval_center(s%rmid, s%eps_grav_ad%val, k_a, k_b)
     578            0 :         X_He3 = eval_center_X(s, he3, k_a, k_b)
     579            0 :         X_C12 = eval_center_X(s, c12, k_a, k_b)
     580            0 :         X_C13 = eval_center_X(s, c13, k_a, k_b)
     581            0 :         X_N14 = eval_center_X(s, n14, k_a, k_b)
     582            0 :         X_O16 = eval_center_X(s, o16, k_a, k_b)
     583            0 :         X_H2 = eval_center_X(s, h2, k_a, k_b)
     584            0 :         X_He4 = eval_center_X(s, he4, k_a, k_b)
     585            0 :         X_Li7 = eval_center_X(s, li7, k_a, k_b)
     586            0 :         X_Be7 = eval_center_X(s, be7, k_a, k_b)
     587            0 :         X_N15 = eval_center_X(s, n15, k_a, k_b)
     588            0 :         X_O17 = eval_center_X(s, o17, k_a, k_b)
     589            0 :         X_O18 = eval_center_X(s, o18, k_a, k_b)
     590            0 :         X_Ne20 = eval_center_X(s, ne20, k_a, k_b)
     591              : 
     592              :         ! Γ₁ derivatives
     593              :         ! I assume the abundances at r=0 are the same as in the innermost cell
     594              :         ! This could be improved using eval_center_X
     595            0 :         xa(:) = s% xa(:, s% nz)
     596              : 
     597              :         ! evaluate EoS at low X
     598            0 :         xa(h1) = s% xa(h1, s% nz) - dxa
     599            0 :         xa(he4) = s% xa(he4, s% nz) + dxa
     600              :         call get_eos(s, k, xa(:), rho, log10(rho), T, log10(T), &
     601            0 :            res_loX, dres_dlnRho, dres_dlnT, dres_dxa, ierr)
     602              : 
     603              :         ! evaluate EoS at high X
     604            0 :         xa(h1) = s% xa(h1, s% nz) + dxa
     605            0 :         xa(he4) = s% xa(he4, s% nz) - dxa
     606              :         call get_eos(s, k, xa(:), rho, log10(rho), T, log10(T), &
     607            0 :            res_hiX, dres_dlnRho, dres_dlnT, dres_dxa, ierr)
     608              : 
     609              :         ! evaluate EoS at  actual X
     610              :         call get_eos(s, k, s% xa(:, s% nz), rho, log10(rho), T, log10(T), &
     611            0 :            res, dres_dlnRho, dres_dlnT, dres_dxa, ierr)
     612              : 
     613              :         ! use dres_dxa(:,1) to store finite difference,
     614              :         ! which is evaluated at constant (ρ,T)
     615            0 :         dres_dxa(:,1) = (res_hiX-res_loX)/2/dxa
     616              : 
     617              :         dlnGamma1_dlnRho = dres_dlnRho(i_Gamma1) &
     618            0 :            - dres_dlnT(i_Gamma1)*res(i_chiRho)/res(i_chiT)
     619            0 :         dlnGamma1_dlnRho = dlnGamma1_dlnRho/res(i_Gamma1)
     620              : 
     621            0 :         dlnGamma1_dlnP = dres_dlnT(i_Gamma1)/res(i_chiT)/res(i_Gamma1)
     622              : 
     623              :         dlnGamma1_dY = dres_dxa(i_Gamma1,1) &
     624            0 :            - dres_dlnT(i_Gamma1)*dres_dxa(i_lnPgas,1)/res(i_chiT)
     625            0 :         dlnGamma1_dY = -dlnGamma1_dY/res(i_Gamma1)  ! d/dY ~ -d/dX
     626              : 
     627              :       end associate
     628              : 
     629            0 :       return
     630              : 
     631              :     end subroutine store_point_data_ctr
     632              : 
     633              :   end subroutine get_fgong_data
     634              : 
     635              : 
     636            0 :   subroutine write_fgong_data (id, filename, global_data, point_data, ierr)
     637              : 
     638              :     integer, intent(in)      :: id
     639              :     character(*), intent(in) :: filename
     640              :     real(dp), intent(in)     :: global_data(:)
     641              :     real(dp), intent(in)     :: point_data(:,:)
     642              :     integer, intent(out)     :: ierr
     643              : 
     644              :     type(star_info), pointer :: s
     645              :     integer                  :: iounit
     646              :     integer                  :: n_global
     647              :     integer                  :: n_point
     648              :     integer                  :: nn
     649              :     integer                  :: i
     650              :     integer                  :: j
     651              :     integer                  :: k
     652              :     character(len=strlen)    :: format_for_fgong_data
     653              : 
     654              :     ! Write FGONG data to file
     655              : 
     656            0 :     call get_star_ptr(id, s, ierr)
     657            0 :     if (ierr /= 0) then
     658            0 :        write(*,*) 'bad star id for write_fgong_info'
     659            0 :        return
     660              :     end if
     661              : 
     662              :     ! Set float format from version number (ivers)
     663              : 
     664            0 :     if (s% fgong_ivers == 300) then
     665            0 :        format_for_fgong_data = '(1P5E16.9,x)'
     666            0 :     else if (s% fgong_ivers == 1300) then
     667            0 :        format_for_fgong_data = '(1P,5(X,E26.18E3))'
     668              :     else
     669            0 :        write(*,*) ''
     670            0 :        write(*,'(a,i4)') 'bad fgong_ivers: must be 300 or 1300, not ', s% fgong_ivers
     671            0 :        ierr = 1
     672            0 :        return
     673              :     end if
     674              : 
     675              :     ! Open the file
     676              : 
     677            0 :     open(newunit=iounit, file=TRIM(filename), status='REPLACE', iostat=ierr)
     678            0 :     if (ierr /= 0) then
     679            0 :        write(*,*) 'failed to open '//TRIM(filename)
     680            0 :        return
     681              :     end if
     682              : 
     683              :     ! Write the data
     684              : 
     685            0 :     n_global = SIZE(global_data)
     686            0 :     n_point = SIZE(point_data, 1)
     687              : 
     688            0 :     nn = SIZE(point_data, 2)
     689              : 
     690            0 :     do k = 1, 4
     691            0 :        write(iounit, *) trim(s% fgong_header(k))
     692              :     end do
     693              : 
     694            0 :     write(iounit,'(4I10)') nn, ICONST, IVAR, s% fgong_ivers
     695              : 
     696            0 :     write(iounit, format_for_fgong_data) (global_data(i), i=1,n_global)
     697              : 
     698            0 :     do k = 1, nn
     699            0 :        write(iounit, format_for_fgong_data) (point_data(j,k), j=1,n_point)
     700              :     end do
     701              : 
     702              :     ! Close the file
     703              : 
     704            0 :     close(iounit)
     705              : 
     706            0 :     return
     707              : 
     708              :   end subroutine write_fgong_data
     709              : 
     710              : end module pulse_fgong
        

Generated by: LCOV version 2.0-1