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

            Line data    Source code
       1              : ! ***********************************************************************
       2              : !
       3              : !   Copyright (C) 2015-2022  Evan Bauer & 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 diffusion_support
      21              : 
      22              :       use const_def, only: dp, pi, pi4, me, mp, qe, amu, fine, boltzm, hbar, msun, rsun, secyer, one_third, four_thirds_pi
      23              :       use chem_def
      24              :       use utils_lib, only: is_bad_num
      25              :       use star_private_def
      26              : 
      27              :       implicit none
      28              : 
      29              :       private
      30              :       public :: tiny_mass
      31              :       public :: smallx
      32              :       public :: get_matrix_coeffs
      33              : 
      34              :       real(dp), parameter :: Xlim = 1d-14
      35              :       real(dp), parameter :: tiny_mass = 1d3  ! a kilogram
      36              :       real(dp), parameter :: tinyX = 1d-50
      37              :       real(dp), parameter :: smallX = 1d-20
      38              : 
      39              :       contains
      40              : 
      41            0 :       subroutine get_matrix_coeffs( &
      42              :             s, nz, nc, m, nzlo, nzhi, ih1, ihe4, pure_Coulomb, &
      43            0 :             dt, v_advection_max, tiny_C, diffusion_factor, &
      44            0 :             A, X, Z, rho_face, T_face, four_pi_r2_rho_face, &
      45            0 :             xm_face, cell_dm, dm_bar, dlnP_dr_face, dlnT_dr_face, dlnRho_dr_face, &
      46            0 :             r_face, r_mid, gamma_T_limit_coeffs_face, alfa_face, &
      47            0 :             rad_accel_face, log10_g_rad, g_rad, &
      48              :             min_T_for_radaccel, max_T_for_radaccel, &
      49            0 :             X_init, X_face, C, C_div_X, C_div_X_face, &
      50            0 :             e_ap, e_at, e_ar, e_ax, E_field_face, &
      51            0 :             g_ap, g_at, g_ar, g_ax, g_field_face, &
      52            0 :             v_advection_face, v_total_face, vlnP_face, vlnT_face, v_rad_face, &
      53            0 :             GT_face, D_self_face, AD_face, SIG_face, sigma_lnC, ierr)
      54              : 
      55              :          type (star_info), pointer :: s
      56              :          integer, intent(in) :: &
      57              :             nz, nc, m, nzlo, nzhi, ih1, ihe4
      58              :          logical, intent(in) :: pure_Coulomb
      59              :          real(dp), intent(in) :: &
      60              :             dt, v_advection_max, tiny_C, min_T_for_radaccel, max_T_for_radaccel
      61              :          real(dp), dimension(:), intent(in) :: &
      62              :             diffusion_factor, A, rho_face, T_face, four_pi_r2_rho_face, &
      63              :             xm_face, cell_dm, dm_bar, dlnP_dr_face, dlnT_dr_face, dlnRho_dr_face, &
      64              :             r_face, r_mid, gamma_T_limit_coeffs_face, alfa_face
      65              :          real(dp), dimension(:,:), intent(in) :: &
      66              :             Z, X_init, rad_accel_face, log10_g_rad, g_rad
      67              :          real(dp), dimension(:,:), intent(inout) :: X
      68              : 
      69              :          real(dp), dimension(:), intent(out) :: AD_face, &
      70              :             e_ap, e_at, e_ar, E_field_face, &
      71              :             g_ap, g_at, g_ar, g_field_face
      72              :          real(dp), dimension(:,:), intent(out) :: &
      73              :             X_face, C, C_div_X, C_div_X_face, v_advection_face, v_total_face, &
      74              :             vlnP_face, vlnT_face, v_rad_face, GT_face, e_ax, g_ax, D_self_face
      75              :          real(dp), dimension(:,:,:), intent(out) :: SIG_face, sigma_lnC
      76              :          integer, intent(out) :: ierr
      77              : 
      78              :          integer :: i, j, k, op_err
      79            0 :          real(dp) :: tmp, tinyX, dlamch, sfmin, &
      80            0 :             AD_dm_full_on, AD_dm_full_off, AD_boost_factor, sum_dm, &
      81            0 :             Vlimit_dm_full_on, Vlimit_dm_full_off, Vlimit, sigmax, &
      82            0 :             SIG_factor, GT_factor
      83            0 :          real(dp), dimension(m) :: C_face, Z_face, dC_dr_face
      84            0 :          real(dp), dimension(nc) :: total_diffusion_factor
      85            0 :          real(dp) :: dlnne_dr_face
      86              : 
      87              :          include 'formats'
      88              : 
      89            0 :          ierr = 0
      90            0 :          sfmin = dlamch('S')
      91              : 
      92            0 :          tinyX = 1d-50
      93            0 :          do k=nzlo,nzhi
      94            0 :             do j=1,nc
      95            0 :                X(j,k) = max(X(j,k),tinyX)
      96              :             end do
      97            0 :             tmp = sum(Z(1:nc,k)*X(1:nc,k)/A(1:nc))
      98            0 :             do j=1,nc
      99            0 :                C_div_X(j,k) = 1d0/(A(j)*tmp)
     100            0 :                C(j,k) = X(j,k)*C_div_X(j,k)
     101              :             end do
     102            0 :             C(m,k) = 1d0
     103            0 :             X(m,k) = A(m)/dot_product(A(1:nc),C(1:nc,k))
     104              :          end do
     105              : 
     106            0 :          Vlimit_dm_full_on = s% diffusion_Vlimit_dm_full_on*Msun
     107            0 :          Vlimit_dm_full_off = s% diffusion_Vlimit_dm_full_off*Msun
     108            0 :          Vlimit = s% diffusion_Vlimit
     109              : 
     110              : 
     111            0 : !$OMP PARALLEL DO PRIVATE(k, j, i, total_diffusion_factor, op_err, C_face, Z_face, dC_dr_face, dlnne_dr_face, tmp) SCHEDULE(dynamic,2)
     112              :          do k = nzlo+1, nzhi
     113              : 
     114              :             ! Total diffusion scaling factor is product of
     115              :             ! diffusion_class_factor (const throughout the star), and
     116              :             ! extra_diffusion_factor (profile set in other_diffusion_factor)
     117              :             if(s% use_other_diffusion_factor) then
     118              :                do j=1,nc
     119              :                   total_diffusion_factor(j) = diffusion_factor(j)*s% extra_diffusion_factor(j,k)
     120              :                end do
     121              :             else
     122              :                total_diffusion_factor(1:nc) = diffusion_factor(1:nc)
     123              :             end if
     124              : 
     125              :             call get1_CXZn_face( &
     126              :                k, nz, nc, m, nzlo, nzhi, C, X, Z, A, alfa_face, tiny_C, &
     127              :                four_pi_r2_rho_face(k)/dm_bar(k), dlnRho_dr_face(k), &
     128              :                C_face, X_face, Z_face, C_div_X_face, dC_dr_face, dlnne_dr_face)
     129              : 
     130              :             op_err = 0
     131              :             call get1_coeffs_face( &
     132              :                s, k, nz, nc, m, nzlo, nzhi, ih1, ihe4, pure_Coulomb, &
     133              :                rho_face(k), T_face(k), gamma_T_limit_coeffs_face(k), &
     134              :                four_pi_r2_rho_face(k), dm_bar(k), v_advection_max, tiny_C, sfmin, &
     135              :                dlnP_dr_face(k), dlnT_dr_face(k), dlnRho_dr_face(k), &
     136              :                s% grav(k), dlnne_dr_face, &
     137              :                Vlimit_dm_full_on, Vlimit_dm_full_off, Vlimit, xm_face(k), r_mid, dt, &
     138              :                A, X_face(:,k), Z_face, C_face, C_div_X_face(:,k), &
     139              :                total_diffusion_factor, rad_accel_face(:,k), &
     140              :                s% diffusion_use_cgs_solver, s% eta(k), &
     141              :                s% cgs_thermal_diffusion_eta_full_on, s% cgs_thermal_diffusion_eta_full_off, &
     142              :                (T_face(k) <= max_T_for_radaccel .and. T_face(k) >= min_T_for_radaccel), &
     143              :                v_advection_face(:,k), vlnP_face(:,k), vlnT_face(:,k), v_rad_face(:,k), &
     144              :                e_ap(k), e_at(k), e_ar(k), e_ax(:,k), &
     145              :                g_ap(k), g_at(k), g_ar(k), g_ax(:,k), &
     146              :                sigma_lnC(:,:,k), op_err)
     147              :             if (op_err /= 0) ierr = op_err
     148              : 
     149              :             if(s% diffusion_use_cgs_solver) then
     150              :                ! Electric Field from Iben & MacDonald solve.
     151              :                E_field_face(k) = &
     152              :                     boltzm*T_face(k)*dlnT_dr_face(k)*e_at(k) + &
     153              :                     amu*(s% grav(k))*e_ap(k)  ! + e_ar(k) should be the radiation term, skipping for now
     154              :                do j=1,nc
     155              :                   E_field_face(k) = E_field_face(k) + &
     156              :                        boltzm*T_face(k)*e_ax(j,k)*(dC_dr_face(j)&
     157              :                        &/C_face(j) + dlnne_dr_face)
     158              :                end do
     159              :                ! Because we solved for eE as the unknown rather than E in the vector containing diffusion velocities.
     160              :                E_field_face(k) = E_field_face(k)/qe
     161              :                g_field_face(k) = s% grav(k)
     162              :             else
     163              :                ! Electric and gravitational field from Thoul solve.
     164              :                E_field_face(k) = &
     165              :                     e_ap(k)*dlnP_dr_face(k) + &
     166              :                     e_at(k)*dlnT_dr_face(k)  ! + e_ar(k)*......  skipping the radiation term for now
     167              :                g_field_face(k) = &
     168              :                     g_ap(k)*dlnP_dr_face(k) + &
     169              :                     g_at(k)*dlnT_dr_face(k)  ! + g_ar(k)*......  skipping the radiation term for now
     170              :                do j=1,nc
     171              :                   if (C_face(j) < 1d-20) cycle
     172              :                   E_field_face(k) = E_field_face(k) + &
     173              :                        e_ax(j,k)*dC_dr_face(j)/C_face(j)
     174              :                   g_field_face(k) = g_field_face(k) + &
     175              :                        g_ax(j,k)*dC_dr_face(j)/C_face(j)
     176              :                end do
     177              :                ! Convert to cgs units
     178              :                tmp = sum(Z_face(1:nc)*X_face(1:nc,k)/A(1:nc))
     179              :                g_field_face(k) = g_field_face(k)*(1.144d-40)*T_face(k)*tmp/(amu*amu)
     180              :                e_field_face(k) = e_field_face(k)*(1.144d-40)*T_face(k)*tmp/(qe*amu)
     181              :             end if
     182              : 
     183              :             do i = 1,nc
     184              :                v_total_face(i,k) = v_advection_face(i,k)
     185              :                do j = 1,nc
     186              :                   v_total_face(i,k) = v_total_face(i,k) - sigma_lnC(i,j,k)*dC_dr_face(j)/C_face(j)
     187              :                end do
     188              :             end do
     189              : 
     190              :          end do
     191              : !$OMP END PARALLEL DO
     192              : 
     193            0 :          if (ierr /= 0) return
     194            0 :          sum_dm = cell_dm(nzlo)
     195              : 
     196            0 :          AD_dm_full_on = s% diffusion_AD_dm_full_on*Msun
     197            0 :          AD_dm_full_off = s% diffusion_AD_dm_full_off*Msun
     198            0 :          AD_boost_factor = s% diffusion_AD_boost_factor
     199              : 
     200            0 :          SIG_factor = s% diffusion_SIG_factor
     201            0 :          GT_factor = s% diffusion_GT_factor
     202              : 
     203              :          !write(*,1) 'GT_factor SIG_factor', GT_factor, SIG_factor
     204              : 
     205            0 :          do k = nzlo+1, nzhi
     206              :             call get1_flow_coeffs( &
     207              :                k, nc, m, v_advection_face(:,k), v_advection_max, &
     208              :                SIG_factor, GT_factor, sigma_lnC(:,:,k), &
     209              :                four_pi_r2_rho_face(k), dm_bar(k), &
     210            0 :                C_div_X_face(:,k), GT_face(:,k), D_self_face(:,k), SIG_face(:,:,k))
     211            0 :             if (sum_dm >= AD_dm_full_off) then
     212            0 :                AD_face(k) = 0d0
     213              :             else
     214              :                sigmax = 0d0
     215            0 :                do j=1,nc
     216            0 :                   if (SIG_face(j,j,k) > sigmax) sigmax = SIG_face(j,j,k)
     217              :                end do
     218            0 :                AD_face(k) = AD_boost_factor*sigmax
     219            0 :                if (sum_dm > AD_dm_full_on) &
     220              :                   AD_face(k) = AD_face(k) * &
     221              :                      (sum_dm - AD_dm_full_off)/&
     222            0 :                         (AD_dm_full_on - AD_dm_full_off)
     223              :                !write(*,2) 'boost factor AD_face', k, AD_face(k)/sigmax, AD_face(k)
     224              :             end if
     225            0 :             sum_dm = sum_dm + cell_dm(k)
     226              :          end do
     227              : 
     228            0 :          do j=1,nc  ! not used, but copy just for sake of plotting
     229            0 :             D_self_face(j,nzlo) = D_self_face(j,nzlo+1)
     230            0 :             v_advection_face(j,nzlo) = v_advection_face(j,nzlo+1)
     231            0 :             v_total_face(j,nzlo) = v_total_face(j,nzlo+1)
     232            0 :             vlnP_face(j,nzlo) = vlnP_face(j,nzlo+1)
     233            0 :             vlnT_face(j,nzlo) = vlnT_face(j,nzlo+1)
     234            0 :             v_rad_face(j,nzlo) = v_rad_face(j,nzlo+1)
     235            0 :             GT_face(j,nzlo) = GT_face(j,nzlo+1)
     236            0 :             do i=1,nc
     237            0 :                SIG_face(i,j,nzlo) = SIG_face(i,j,nzlo+1)
     238              :             end do
     239              :          end do
     240              : 
     241              :       end subroutine get_matrix_coeffs
     242              : 
     243              : 
     244            0 :       subroutine get1_coeffs_face( &
     245              :             s, k, nz, nc, m, nzlo, nzhi, ih1, ihe4, pure_Coulomb, &
     246              :             rho_face, T_face, gamma_T_limit_coeff_face, &
     247              :             four_pi_r2_rho_face, dm_bar, &
     248              :             v_advection_max, tiny_C, sfmin, &
     249              :             dlnP_dr_face, dlnT_dr_face, dlnRho_dr_face, grav, dlnne_dr_face, &
     250            0 :             Vlimit_dm_full_on, Vlimit_dm_full_off, Vlimit, xm_face, r_mid, dt, &
     251            0 :             A, X_face, Z_face, C_face, C_div_X_face, &
     252            0 :             diffusion_factor, rad_accel_face, &
     253              :             use_cgs_solver, eta, eta_on, eta_off, rad, &
     254            0 :             v_advection_face, vlnP_face, vlnT_face, v_rad_face, &
     255            0 :             e_ap, e_at, e_ar, e_ax, &
     256            0 :             g_ap, g_at, g_ar, g_ax, &
     257            0 :             sigma_lnC, ierr)
     258              : 
     259              :          type (star_info), pointer :: s
     260              :          integer, intent(in) :: k, nz, nc, m, nzlo, nzhi, ih1, ihe4
     261              :          logical, intent(in) :: pure_Coulomb
     262              :          real(dp), intent(in) :: rho_face, T_face, gamma_T_limit_coeff_face, &
     263              :             xm_face, r_mid(:), Vlimit_dm_full_on, Vlimit_dm_full_off, Vlimit, dt
     264              :          real(dp), intent(in) :: four_pi_r2_rho_face, dm_bar
     265              :          real(dp), intent(in) :: v_advection_max, tiny_C, sfmin
     266              :          real(dp), intent(in) :: dlnP_dr_face, dlnT_dr_face, &
     267              :               dlnRho_dr_face, grav, dlnne_dr_face
     268              :          real(dp), intent(in), dimension(:) :: &
     269              :             A, X_face, Z_face, C_face, C_div_X_face, &
     270              :             rad_accel_face, diffusion_factor
     271              :          logical, intent(in) :: use_cgs_solver, rad
     272              :          real(dp), intent(in) :: eta, eta_on, eta_off
     273              :          real(dp), intent(inout), dimension(:) :: &
     274              :             v_advection_face, vlnP_face, vlnT_face, v_rad_face  ! (nc)
     275              :          real(dp), intent(out) :: e_ap, e_at, e_ar, g_ap, g_at, g_ar
     276              :          real(dp), intent(inout) :: e_ax(:), g_ax(:)  ! (m)
     277              :          real(dp), intent(inout) :: sigma_lnC(:,:)  ! (nc,nc)
     278              :          integer, intent(out) :: ierr
     279              : 
     280            0 :          real(dp), dimension(m) :: AP, AT, AR
     281            0 :          real(dp), dimension(m,m) :: kappa_st, Zdiff, Zdiff1, Zdiff2, AX
     282              : 
     283              :          include 'formats'
     284              : 
     285            0 :          ierr = 0
     286              : 
     287              :          call get1_burgers_coeffs( &
     288              :             s, k, nc, m, A, Z_face, X_face, C_face, &
     289              :             rho_face, T_face, pure_Coulomb, &
     290            0 :             kappa_st, Zdiff, Zdiff1, Zdiff2)
     291              : 
     292              :          call get1_gradient_coeffs( &
     293              :             k, m, sfmin, A, Z_face, X_face, C_face, rho_face, T_face, &
     294              :             use_cgs_solver, eta, eta_on, eta_off, &
     295              :             rad, rad_accel_face, kappa_st, Zdiff, Zdiff1, Zdiff2, &
     296              :             AP, AT, AR, AX, &
     297              :             e_ap, e_at, e_ar, e_ax, &
     298              :             g_ap, g_at, g_ar, g_ax, &
     299            0 :             ierr)
     300            0 :          if (ierr /= 0) return
     301              : 
     302              :          call get1_diffusion_velocities( &
     303              :             k, nc, m, nzlo, nzhi, AP, AT, AR, AX, rho_face, T_face, &
     304              :             dlnP_dr_face, dlnT_dr_face, dlnRho_dr_face, &
     305              :             grav, dlnne_dr_face, X_face, &
     306              :             Vlimit_dm_full_on, Vlimit_dm_full_off, Vlimit, xm_face, r_mid, s% dt, &
     307              :             gamma_T_limit_coeff_face, v_advection_max, diffusion_factor, &
     308              :             use_cgs_solver, &
     309            0 :             v_advection_face, vlnP_face, vlnT_face, v_rad_face, sigma_lnC)
     310              : 
     311            0 :       end subroutine get1_coeffs_face
     312              : 
     313              : 
     314            0 :       subroutine get1_CXZn_face( &
     315            0 :             k, nz, nc, m, nzlo, nzhi, C, X, Z, A, alfa_face, tiny_C, &
     316            0 :             d_dr_factor, dlnRho_dr_face, C_face, X_face, Z_face, C_div_X_face, &
     317            0 :             dC_dr_face, dlnne_dr_face)
     318              :          integer, intent(in) :: k, nc, m, nz, nzlo, nzhi
     319              :          real(dp), dimension(:,:), intent(in) :: C, X, Z  ! (m,nz)
     320              :          real(dp), intent(in) :: A(:)  ! (m) atomic number
     321              :          real(dp), intent(in) :: alfa_face(:), d_dr_factor, dlnRho_dr_face
     322              :          real(dp), intent(in) :: tiny_C
     323              :          real(dp), dimension(:), intent(out) :: C_face, Z_face, dC_dr_face  ! (m)
     324              :          real(dp), intent(out) :: dlnne_dr_face
     325              :          real(dp), dimension(:,:), intent(out) :: X_face, C_div_X_face  ! (m,nz)
     326              :          integer :: j
     327            0 :          real(dp) :: tmp, tmp1, tmp2, dlntmp_dr_face, alfa, beta
     328              : 
     329            0 :          alfa = alfa_face(k)
     330            0 :          beta = 1d0 - alfa
     331            0 :          do j = 1, m
     332            0 :             X_face(j,k) = alfa*X(j,k) + beta*X(j,k-1)
     333            0 :             Z_face(j) = alfa*Z(j,k) + beta*Z(j,k-1)
     334              :          end do
     335              : 
     336              :          ! "tmp" at the face of the zone
     337            0 :          tmp = sum(Z_face(1:nc)*X_face(1:nc,k)/A(1:nc))
     338            0 :          do j = 1, m
     339            0 :             C_div_X_face(j,k) = 1/(A(j)*tmp)
     340            0 :             C_face(j) = X_face(j,k)*C_div_X_face(j,k)
     341              : 
     342              :             ! Old way of calculating the derivative. Fixed below.
     343              :             ! dC_dr_face(j) = (X(j,k-1) - X(j,k))*C_div_X_face(j,k)*d_dr_factor
     344              : 
     345            0 :             dC_dr_face(j) = (C(j,k-1) - C(j,k))*d_dr_factor
     346              :          end do
     347              : 
     348              :          ! Calculate the electron number density ln gradient used in
     349              :          ! converting between the Thoul and Iben/MacDonald notations.
     350              :          ! This is accomplished by adding two logarithmic derivatives
     351              :          ! evaluated at the face of the zone, one of which we already
     352              :          ! know, and one of which must be calculated.
     353              : 
     354              :          ! "tmp" averaged over zone k
     355            0 :          tmp1 = sum(Z(1:nc,k)*X(1:nc,k)/A(1:nc))
     356              :          ! "tmp" averaged over zone k-1
     357            0 :          tmp2 = sum(Z(1:nc,k-1)*X(1:nc,k-1)/A(1:nc))
     358            0 :          dlntmp_dr_face = ((tmp2-tmp1)/tmp)*d_dr_factor
     359              :          ! ne = rho*tmp/amu, so...
     360            0 :          dlnne_dr_face = dlnRho_dr_face + dlntmp_dr_face
     361              : 
     362            0 :       end subroutine get1_CXZn_face
     363              : 
     364              : 
     365            0 :       subroutine get1_burgers_coeffs( &
     366            0 :             s, k, nc, m, A, Z, X, C, rho, T, pure_Coulomb, &
     367            0 :             kappa_st, Zdiff, Zdiff1, Zdiff2)
     368              : 
     369              :          use paquette_coeffs, only: paquette_coefficients
     370              : 
     371              :          type (star_info), pointer :: s
     372              :          integer, intent(in) :: k, nc, m
     373              :          real(dp), intent(in) :: rho, T
     374              :          logical, intent(in) :: pure_Coulomb
     375              :          real(dp), intent(in), dimension(:) :: A, X, Z, C  ! (m)
     376              :          real(dp), intent(inout), dimension(:,:) :: &
     377              :             kappa_st, Zdiff, Zdiff1, Zdiff2  ! (m,m)
     378              : 
     379              :          integer :: i, j
     380            0 :          real(dp) :: ac, ni, cz, xij, ne, ao, lambdad, lambda, alfa, Gamlo, Gamhi
     381            0 :          real(dp), dimension(m) :: charge, na
     382            0 :          real(dp), dimension(m,m) :: cl, Ath, Ddiff, Kdiff, Kdiff2
     383            0 :          real(dp) :: Gamma, kappa_SM
     384            0 :          real(dp) :: Ddiff_Caplan(nc)
     385              : 
     386            0 :          do i = 1, nc
     387            0 :             charge(i) = max(1d0, Z(i))  ! assume some ionization
     388              :          end do
     389            0 :          charge(m) = Z(m)
     390              : 
     391            0 :          if (.not. pure_Coulomb) then  ! use Paquette coeffs
     392              :             ! Get number densities (per cm^3)
     393            0 :             do i = 1, nc
     394            0 :                na(i) = rho*X(i)/(A(i)*amu)
     395              :             end do
     396            0 :             na(m) = 0.d0
     397            0 :             do i = 1, nc
     398            0 :                na(m) = na(m) + charge(i)*na(i)
     399              :             end do
     400              :             ! Compute resistance coefficients from Paquette&al (1986)
     401              :             call paquette_coefficients( &
     402            0 :                rho, T, m, A, charge, na, Ddiff, Kdiff, Zdiff, Zdiff1, Zdiff2, Ath)
     403              : 
     404            0 :             if(.not. s% diffusion_use_paquette .and. .not. s% use_other_diffusion_coefficients) then
     405            0 :                Gamma = s% gam(k)
     406            0 :                Gamlo = 3d0
     407            0 :                Gamhi = 10d0  ! for blending over from Stanton & Murillo coeffs to CBF coeffs at high Gamma
     408            0 :                if(Gamma < Gamlo .or. .not. s% diffusion_use_caplan) then
     409            0 :                   call get_SM_coeffs(nc,m,rho,T,A,charge,na,Kdiff,Zdiff,Zdiff1,Zdiff2,kappa_SM)
     410              :                   ! This must get called after Paquette because it doesn't calculate
     411              :                   ! the electron entries (m). It leaves them untouched while calculating
     412              :                   ! and changing all the ion-ion terms (1:nc), so after calling this
     413              :                   ! routine we have all ion-ion coefficients from Stanton&Murillo and
     414              :                   ! all ion-electron coefficients from Paquette&al.
     415            0 :                else if(Gamma >= Gamlo .and. Gamma <= Gamhi) then  ! blend
     416            0 :                   alfa = (Gamhi - Gamma)/(Gamhi - Gamlo)
     417            0 :                   Kdiff2(:,:) = Kdiff(:,:)  ! need to initialize so that (m,m) entries are set
     418            0 :                   call get_SM_coeffs(nc,m,rho,T,A,charge,na,Kdiff,Zdiff,Zdiff1,Zdiff2,kappa_SM)  ! alfa = 1
     419            0 :                   call get_CBF_coeffs(nc,m,rho,T,A,charge,na,Gamma,Ddiff_Caplan,Kdiff2)  ! alfa = 0
     420            0 :                   Kdiff(:,:) = alfa*Kdiff(:,:) + (1d0-alfa)*Kdiff2(:,:)
     421              :                else
     422              :                   ! use Caplan, Bauer, & Freeman coefficients at moderate to strong coupling
     423            0 :                   call get_CBF_coeffs(nc,m,rho,T,A,charge,na,Gamma,Ddiff_Caplan,Kdiff)
     424              :                end if
     425              :             end if
     426              : 
     427            0 :             if(s% use_other_diffusion_coefficients) then
     428              :                call s% other_diffusion_coefficients( &
     429              :                   s% id, k, nc, m, rho, T,  A, X, Z, C, charge, na, &
     430            0 :                   Ddiff, Kdiff, Zdiff, Zdiff1, Zdiff2, Ath)
     431              :             end if
     432              : 
     433              :             ! Unit conversion conveniently applies to both Paquette and Stanton&Murillo
     434            0 :             kappa_st(:,:) = Kdiff(:,:)/(1.41D-25*pow(T,-1.5D0)*na(m)*na(m))
     435              :                ! = kappa_st of eq 37, Thoul&al 1994
     436              :             return
     437              :          end if
     438              : 
     439              :          ! calculate density of electrons (ne) from mass density (rho):
     440              :          ac=0.d0
     441            0 :          do i=1, m
     442            0 :             ac=ac+a(i)*c(i)
     443              :          end do
     444            0 :          ne=rho/(mp*ac)
     445              :          ! calculate interionic distance (ao):
     446            0 :          ni=0.d0
     447            0 :          do i=1, nc
     448            0 :             ni=ni+c(i)*ne
     449              :          end do
     450            0 :          ao=pow(0.23873d0/ni,one_third)
     451              :          ! calculate debye length (lambdad):
     452            0 :          cz=0.d0
     453            0 :          do i=1, m
     454            0 :             cz=cz+c(i)*charge(i)*charge(i)
     455              :          end do
     456            0 :          lambdad=6.9010d0*sqrt(t/(ne*cz))
     457              :          ! calculate lambda to use in coulomb logarithm:
     458            0 :          lambda=max(lambdad, ao)
     459              :          ! calculate coulomb logarithms:
     460            0 :          do i=1, m
     461            0 :             do j=1, m
     462            0 :                xij=2.3939d3*t*lambda/abs(charge(i)*charge(j))
     463            0 :                cl(i,j)=0.81245d0*log1p(0.18769d0*pow(xij,1.2d0))
     464              :             end do
     465              :          end do
     466              : 
     467              :          ! set coeffs for pure Coulomb potential
     468            0 :          do i=1, m
     469            0 :             do j=1, m
     470            0 :                Zdiff(i,j) = 0.6d0
     471            0 :                Zdiff1(i,j) = 1.3d0
     472            0 :                Zdiff2(i,j) = 2d0
     473              :                kappa_st(i,j) = &
     474              :                   cl(i,j)*sqrt(a(i)*a(j)/(a(i)+a(j)))* &
     475            0 :                      c(i)*c(j)*charge(i)*charge(i)*charge(j)*charge(j)
     476              :             end do
     477              :          end do
     478              : 
     479            0 :       end subroutine get1_burgers_coeffs
     480              : 
     481              : 
     482            0 :       subroutine get1_gradient_coeffs( &
     483            0 :             k, m, sfmin, A, Z, X, C, rho, T, use_cgs_solver, eta, eta_on, eta_off, &
     484            0 :             rad, rad_accel, kappa_st, Zdiff, Zdiff1, Zdiff2, &
     485            0 :             AP, AT, AR, AX, &
     486            0 :             e_ap, e_at, e_ar, e_ax, &
     487            0 :             g_ap, g_at, g_ar, g_ax, &
     488              :             ierr)
     489              :          integer, intent(in) :: k, m
     490              :          real(dp), intent(in) :: sfmin, rho, T
     491              :          real(dp), intent(in) :: eta, eta_on, eta_off
     492              :          real(dp), intent(in), dimension(:) :: A, X, Z, C, rad_accel  ! (m)
     493              :          logical, intent(in) :: use_cgs_solver, rad
     494              :          real(dp), dimension(:,:), intent(in) :: &
     495              :             kappa_st, Zdiff, Zdiff1, Zdiff2  ! (m,m)
     496              :          real(dp), dimension(:), intent(out) :: AP, AT, AR  ! (m)
     497              :          real(dp), intent(inout) :: AX(:,:)  ! (m,m)
     498              :          real(dp), intent(inout) :: e_ap, e_at, e_ar, e_ax(:)  ! (m)
     499              :          real(dp), intent(inout) :: g_ap, g_at, g_ar, g_ax(:)  ! (m)
     500              :          integer, intent(out) :: ierr
     501              : 
     502              :          integer :: i, j
     503            0 :          real(dp) :: charge(m), nd(m), Kdiff(m,m), alfa, beta
     504              : 
     505              :          ! For blending solves with and without thermal diffusion.
     506            0 :          real(dp) :: AP1(m), AT1(m), AR1(m), AX1(m,m)
     507            0 :          real(dp) :: e_ap1, e_at1, e_ar1, e_ax1(m)
     508            0 :          real(dp) :: AP2(m), AT2(m), AR2(m), AX2(m,m)
     509            0 :          real(dp) :: e_ap2, e_at2, e_ar2, e_ax2(m)
     510              : 
     511              :          include 'formats'
     512              : 
     513            0 :          ierr = 0
     514              : 
     515            0 :          do i=1,m-1
     516            0 :             charge(i) = max(1d0, Z(i))
     517              :          end do
     518            0 :          charge(m) = Z(m)
     519              : 
     520            0 :          if(use_cgs_solver) then  ! Use the cgs solver
     521              :             ! Get number densities using info contained in X,A,Z,rho
     522            0 :             nd(1:m) = 0d0
     523            0 :             do i=1,m-1
     524            0 :                nd(i) = rho*X(i)/(A(i)*amu)
     525            0 :                nd(m) = nd(m) + nd(i)*charge(i)  ! Electron Number Density satisfies charge neutrality
     526              :             end do
     527              : 
     528            0 :             Kdiff(:,:) = kappa_st(:,:)*(1.41D-25*pow(T,-1.5D0)*nd(m)*nd(m))
     529              : 
     530            0 :             if(eta < eta_on) then
     531              :                call solve_burgers_cgs_with_thermal(2*m+1,m,A,charge,nd,rad_accel,rad, &
     532              :                     Kdiff, Zdiff, Zdiff1, Zdiff2, &
     533              :                     AP,AT,AR,AX, &
     534            0 :                     e_ap,e_at,e_ar,e_ax,ierr)
     535            0 :             else if(eta > eta_off) then
     536              :                call solve_burgers_cgs_no_thermal(m+1,m,A,charge,nd,rad_accel,rad, &
     537              :                     Kdiff,AP,AT,AR,AX, &
     538            0 :                     e_ap,e_at,e_ar,e_ax,ierr)
     539              :             else
     540              :                ! Call both and do a linear blend of all coefficients.
     541            0 :                alfa = (eta - eta_on)/(eta_off - eta_on)  ! alfa = 1 means no thermal diffusion.
     542            0 :                beta = 1d0 - alfa  ! beta = 1 means full thermal diffusion.
     543              : 
     544              :                call solve_burgers_cgs_no_thermal(m+1,m,A,charge,nd,rad_accel,rad, &
     545              :                     Kdiff,AP1,AT1,AR1,AX1, &
     546            0 :                     e_ap1,e_at1,e_ar1,e_ax1,ierr)
     547              : 
     548            0 :                if (ierr /= 0) then
     549              :                   !return
     550            0 :                   write(*,2) 'solve_burgers_cgs_no_thermal failed', k
     551            0 :                   do i=1,m-1
     552            0 :                      write(*,2) 'A X Z C', i, A(i), X(i), Z(i), C(i)
     553              :                   end do
     554            0 :                   call mesa_error(__FILE__,__LINE__,'get1_gradient_coeffs')
     555              :                end if
     556              : 
     557              :                call solve_burgers_cgs_with_thermal(2*m+1,m,A,charge,nd,rad_accel,rad, &
     558              :                     Kdiff, Zdiff, Zdiff1, Zdiff2, &
     559              :                     AP2,AT2,AR2,AX2, &
     560            0 :                     e_ap2,e_at2,e_ar2,e_ax2,ierr)
     561              : 
     562              :                ! Check how much different the two solutions are.
     563              :                ! if( abs((AT1(3) - AT2(3))/AT1(3)) > 2d0 ) then ! 3 is index for Helium in basic.net
     564              :                !    print *, "Thermal diffusion changing temperature coefficient by more than factor of two."
     565              :                !    print *, "Relative difference: ", abs((AT1(3) - AT2(3))/AT1(3))
     566              :                ! end if
     567              : 
     568              :                ! Blending between the two solutions.
     569            0 :                do i = 1,m
     570            0 :                   AP(i) = alfa*AP1(i) + beta*AP2(i)
     571            0 :                   AT(i) = alfa*AT1(i) + beta*AT2(i)
     572            0 :                   AR(i) = alfa*AR1(i) + beta*AR2(i)
     573            0 :                   do j = 1,m
     574            0 :                      AX(i,j) = alfa*AX1(i,j) + beta*AX2(i,j)
     575              :                   end do
     576            0 :                   e_ax(i) = alfa*e_ax1(i) + beta*e_ax2(i)
     577              :                end do
     578            0 :                e_ap = alfa*e_ap1 + beta*e_ap2
     579            0 :                e_at = alfa*e_at1 + beta*e_at2
     580            0 :                e_ar = alfa*e_ar1 + beta*e_ar2
     581              : 
     582              :             end if
     583              :             ! Gravity isn't being calculated by this version of the
     584              :             ! diffusion routine, so set the coefficients to zero.
     585            0 :             g_ap = 0d0
     586            0 :             g_at = 0d0
     587            0 :             g_ar = 0d0
     588            0 :             g_ax(1:m) = 0d0
     589              : 
     590            0 :             if (ierr /= 0) then
     591              :                !return
     592            0 :                write(*,2) 'solve_burgers_cgs failed', k
     593            0 :                do i=1,m-1
     594            0 :                   write(*,2) 'A X Z C', i, A(i), X(i), Z(i), C(i)
     595              :                end do
     596            0 :                call mesa_error(__FILE__,__LINE__,'get1_gradient_coeffs')
     597              :             end if
     598              :          else  ! Use the Thoul solver
     599              :             call do1_solve_thoul_hu( &
     600              :                2*m+2, m, sfmin, A, charge, X, C, rad_accel, rad, &
     601              :                kappa_st, Zdiff, Zdiff1, Zdiff2, &
     602              :                AP, AT, AR, AX, &
     603              :                e_ap, e_at, e_ar, e_ax, &
     604              :                g_ap, g_at, g_ar, g_ax, &
     605            0 :                ierr)
     606              : 
     607            0 :             if (ierr /= 0) then
     608              :                !return
     609            0 :                write(*,2) 'do1_solve_thoul_hu failed', k
     610            0 :                do i=1,m-1
     611            0 :                   write(*,2) 'A X Z C', i, A(i), X(i), Z(i), C(i)
     612              :                end do
     613            0 :                call mesa_error(__FILE__,__LINE__,'get1_gradient_coeffs')
     614              :             end if
     615              :          end if
     616              : 
     617              : 
     618            0 :       end subroutine get1_gradient_coeffs
     619              : 
     620              : 
     621            0 :       subroutine get1_diffusion_velocities( &
     622            0 :             k, nc, m, nzlo, nzhi, AP, AT, AR, AX, rho, T, &
     623            0 :             dlnP_dr, dlnT_dr, dlnRho_dr, grav, dlnne_dr, X_face, &
     624            0 :             Vlimit_dm_full_on, Vlimit_dm_full_off, Vlimit, xm_face, r_mid, dt, &
     625            0 :             limit_coeff, v_advection_max, diffusion_factor, use_cgs_solver, &
     626            0 :             vgt, vlnP, vlnT, vrad, sigma_lnC)
     627              :          integer, intent(in) :: k, nc, m, nzlo, nzhi
     628              :          real(dp), intent(in), dimension(:) :: AP, AT, AR, r_mid
     629              :          real(dp), intent(in) :: AX(:,:)  ! (m,m)
     630              :          real(dp), intent(in) :: rho, T, limit_coeff, v_advection_max, &
     631              :             Vlimit_dm_full_on, Vlimit_dm_full_off, Vlimit, xm_face, dt
     632              :          real(dp), intent(in) :: dlnP_dr, dlnT_dr, dlnRho_dr, grav, dlnne_dr
     633              :          real(dp), intent(in) :: X_face(:)
     634              :          real(dp), intent(in) :: diffusion_factor(:)
     635              :          logical, intent(in) :: use_cgs_solver
     636              :          real(dp), intent(inout), dimension(:) :: vgt, vlnP, vlnT, vrad
     637              :          real(dp), intent(inout) :: sigma_lnC(:,:)  ! (nc,nc)
     638              : 
     639              :          integer :: i, j, im
     640            0 :          real(dp) :: coef, coef_vrad, dv_im, dr, T2pt5, &
     641            0 :             vcross, vmax, vmax_limit, frac, alfa, beta
     642            0 :          real(dp) :: tau0  ! = 6d13*secyer, solar diffusion time (seconds)
     643              :          real(dp), parameter :: rho_unit = 1d2
     644              :          real(dp), parameter :: T_unit = 1d7
     645              : 
     646              :          include 'formats'
     647              : 
     648            0 :          if (limit_coeff <= 0) then
     649            0 :             vgt(:) = 0
     650            0 :             sigma_lnC(:,:) = 0
     651              :             return
     652              :          end if
     653              : 
     654            0 :          dr = r_mid(k-1) - r_mid(k)
     655            0 :          vcross = dr/dt
     656            0 :          if (xm_face >= Vlimit_dm_full_off .or. Vlimit <= 0d0) then
     657              :             vmax_limit = 1d99
     658              :             alfa = 0d0
     659            0 :             beta = 1d0
     660            0 :          else if (xm_face <= Vlimit_dm_full_on) then
     661            0 :             vmax_limit = vcross*Vlimit
     662            0 :             alfa = 1d0
     663            0 :             beta = 0d0
     664              :          else  ! combine
     665              :             alfa = (xm_face - Vlimit_dm_full_off)/&
     666            0 :                         (Vlimit_dm_full_on - Vlimit_dm_full_off)
     667            0 :             beta = 1d0 - alfa  ! fraction of normal v when it is > vmax
     668            0 :             vmax_limit = vcross*Vlimit/alfa  ! Want to scale to no limit at alfa = 0
     669              :          end if
     670              : 
     671            0 :          if(use_cgs_solver) then  ! Converts coefficients to velocities
     672              :             ! assuming cgs routine.
     673            0 :             do i=1,nc
     674            0 :                do j=1,nc
     675            0 :                   sigma_lnC(j,i) = -limit_coeff*diffusion_factor(i)*boltzm*T*AX(j,i)
     676              :                end do
     677            0 :                vlnP(i) = AP(i)*amu*grav*diffusion_factor(i)*limit_coeff
     678            0 :                vlnT(i) = AT(i)*boltzm*T*dlnT_dr*diffusion_factor(i)*limit_coeff
     679            0 :                vrad(i) = AR(i)*diffusion_factor(i)*limit_coeff  ! AR already contains all constants.
     680            0 :                vgt(i) = vlnP(i) + vlnT(i) + vrad(i)
     681              :             end do
     682              : 
     683            0 :             do i = 1,nc
     684              :                ! Converting from Iben/MacDonald notation to Thoul
     685              :                ! notation using electron number density gradient.
     686            0 :                vgt(i) = vgt(i) - dlnne_dr*sum(sigma_lnC(i,1:nc))
     687            0 :                if (X_face(i) < 1d-15) vgt(i) = 0d0
     688              :             end do
     689              : 
     690              :          else  ! converts coefficients to velocities assuming Thoul.
     691            0 :             tau0 = 6d13*secyer
     692            0 :             T2pt5 = pow(T/T_unit,2.5d0)
     693            0 :             coef = limit_coeff*Rsun*T2pt5/(rho/rho_unit)*(Rsun/tau0)
     694            0 :             coef_vrad = (limit_coeff/T)*Rsun*Rsun*T2pt5/(rho/rho_unit)/tau0
     695              :             ! converts to cgs units
     696              :             ! T^(5/2)/rho takes care of the last part from Thoul equations
     697              :             ! (21) and (28). Rsun/tau0 converts the velocity from units of
     698              :             ! Rsun/tau0 to cm/s. The extra Rsun accounts for the fact that
     699              :             ! MESA's gradients (e.g. dlnP_dr) have units of cm^-1, whereas
     700              :             ! Thoul's gradients in eqn (21) are Rsun^-1.
     701              : 
     702            0 :             do i=1,nc
     703            0 :                do j=1,nc
     704            0 :                   sigma_lnC(j,i) = -diffusion_factor(i)*coef*AX(j,i)
     705              :                end do
     706            0 :                vlnP(i) = AP(i)*dlnP_dr*diffusion_factor(i)*coef
     707            0 :                vlnT(i) = AT(i)*dlnT_dr*diffusion_factor(i)*coef
     708            0 :                vrad(i) = AR(i)*diffusion_factor(i)*coef_vrad
     709            0 :                vgt(i) = vlnP(i) + vlnT(i) + vrad(i)
     710            0 :                if (X_face(i) < 1d-15) vgt(i) = 0d0
     711              :             end do
     712              :          end if
     713              : 
     714              :          ! final fixup for vgt of most abundant so it gives baryon conservation.
     715            0 :          im = maxloc(X_face(1:nc),dim=1)
     716            0 :          dv_im = -dot_product(X_face(1:nc), vgt(1:nc))/X_face(im)
     717            0 :          vgt(im) = vgt(im) + dv_im
     718              : 
     719            0 :          vmax = maxval(abs(vgt(1:nc)))
     720            0 :          if (vmax > v_advection_max) then
     721            0 :             frac = v_advection_max/vmax
     722            0 :             do i=1,nc
     723            0 :                vgt(i) = vgt(i)*frac
     724              :                ! Need to rescale the sigma terms by the same factor
     725              :                ! or diffusive equilibrium can break in WDs.
     726            0 :                do j=1,nc
     727            0 :                   sigma_lnC(j,i) = sigma_lnC(j,i)*frac
     728              :                end do
     729              :             end do
     730              :             vmax = v_advection_max
     731              :             !write(*,3) 'vmax > v_advection_max', im, k, vmax, v_advection_max
     732              :             !call mesa_error(__FILE__,__LINE__,'get1_diffusion_velocities')
     733              :          end if
     734              : 
     735            0 :          if (alfa > 0d0 .and. vmax > vmax_limit) then
     736            0 :             frac = vmax_limit/vmax
     737            0 :             do i=1,nc
     738            0 :                vgt(i) = vgt(i)*frac
     739              :                ! Need to rescale the sigma terms by the same factor
     740              :                ! or diffusive equilibrium can break in WDs.
     741            0 :                do j=1,nc
     742            0 :                   sigma_lnC(j,i) = sigma_lnC(j,i)*frac
     743              :                end do
     744              :             end do
     745              :          end if
     746              : 
     747              :       end subroutine get1_diffusion_velocities
     748              : 
     749              : 
     750            0 :       subroutine get1_flow_coeffs( &
     751              :             k, nc, m, &
     752            0 :             v_advection_face, v_advection_max, SIG_factor, GT_factor, &
     753            0 :             sigma_lnC_face, four_pi_r2_rho_face, &
     754            0 :             dm_bar, C_div_X_face, GT_face, D_self_face, SIG_face)
     755              :          integer, intent(in) :: k, nc, m
     756              :          real(dp), intent(in) :: &
     757              :             v_advection_max, SIG_factor, GT_factor, v_advection_face(:)  ! (nc)
     758              :          real(dp), intent(in) :: sigma_lnC_face(:,:)  ! (nc,nc)
     759              :          real(dp), intent(in) :: four_pi_r2_rho_face, dm_bar
     760              :          real(dp), intent(in), dimension(:) :: C_div_X_face  ! (m)
     761              :          real(dp), intent(inout) :: GT_face(:)  ! (nc)
     762              :          real(dp), intent(inout) :: D_self_face(:)  ! (nc)
     763              :          real(dp), intent(inout) :: SIG_face(:,:)  ! (nc,nc)
     764              : 
     765              :          integer :: i, j
     766            0 :          real(dp) :: c
     767              : 
     768              :          include 'formats'
     769              : 
     770            0 :          c = SIG_factor*four_pi_r2_rho_face*four_pi_r2_rho_face/dm_bar
     771            0 :          do i = 1, nc
     772            0 :             GT_face(i) = GT_factor*four_pi_r2_rho_face*v_advection_face(i)
     773            0 :             D_self_face(i) = sigma_lnC_face(i,i)
     774            0 :             do j = 1, nc
     775            0 :                SIG_face(i,j) = c*sigma_lnC_face(i,j)/C_div_X_face(j)
     776              :             end do
     777              :          end do
     778              : 
     779            0 :       end subroutine get1_flow_coeffs
     780              : 
     781              : 
     782              : ! *************************************************************
     783              : ! Original of this routine was written by Anne A. Thoul, at the Institute
     784              : ! for Advanced Study, Princeton, NJ 08540.
     785              : ! See Thoul et al., Ap.J. 421, p. 828 (1994)
     786              : 
     787              : ! With modifications by Hali Hu for non Coulomb and rad levitation.
     788              : ! *************************************************************
     789              : ! This routine inverses the burgers equations.
     790              : !
     791              : ! The system contains N equations with N unknowns.
     792              : ! The equations are: the M momentum equations,
     793              : !                    the M energy equations,
     794              : !                    two constraints: the current neutrality
     795              : !                                     the zero fluid velocity.
     796              : ! The unknowns are: the M diffusion velocities,
     797              : !                   the M heat fluxes,
     798              : !                   the electric field E
     799              : !                   the gravitational force g.
     800              : !
     801              : ! **************************************************
     802              : 
     803              : 
     804              : ! comments from Anne's original version
     805              :    ! Inverse the system for each possible right-hand-side, i.e.,
     806              :    ! if alpha is the r.h.s., we obtain the coefficient A_p
     807              :    ! if nu    ---------------------------------------- A_T
     808              :    ! if gamma(i,j) ----------------------------------- A_Cj
     809              :    !
     810              :    ! If I=1, we obtain the hydrogen diffusion velocity
     811              :    ! If I=2, ------------- helium   ------------------
     812              :    ! If I=3,M-1, --------- heavy element -------------
     813              :    ! If I=M, ------------- electrons -----------------
     814              :    ! For I=M,2M, we get the heat fluxes
     815              :    ! For I=N-1, we get the electric field
     816              :    ! For I=N, we get the gravitational force g
     817              : 
     818              : 
     819            0 :       subroutine do1_solve_thoul_hu( &
     820            0 :             n, m, sfmin, a, z, x, c, rad_accel, rad, &
     821            0 :             kappa_st, Zdiff, Zdiff1, Zdiff2, &
     822            0 :             ap, at, ar, ax, &
     823            0 :             e_ap, e_at, e_ar, e_ax, &
     824            0 :             g_ap, g_at, g_ar, g_ax, &
     825              :             ierr)
     826              : 
     827              :          ! the parameter m is the number of fluids considered (ions+electrons)
     828              :          ! the parameter n is the number of equations (2*m+2).
     829              :          !
     830              :          ! the vectors a,z and x contain the atomic mass numbers,
     831              :          ! the charges (ionization), and the mass fractions, of the elements.
     832              :          ! note: since m is the electron fluid, its mass and charge must be
     833              :          !      a(m)=m_e/m_u
     834              :          !      z(m)=-1.
     835              :          !
     836              :          ! the array cl contains the values of the coulomb logarithms.
     837              :          ! the vector ap, at, and array ax contains the results for the diffusion
     838              :          ! coefficients.
     839              : 
     840              :          integer, intent(in) :: m,n
     841              :          real(dp), intent(in) :: sfmin
     842              :          real(dp), intent(in), dimension(:) :: A, Z, X, C, rad_accel  ! (m)
     843              :          logical, intent(in) :: rad
     844              :          real(dp), intent(in), dimension(:,:) :: &
     845              :             kappa_st, Zdiff, Zdiff1, Zdiff2  ! (m,m)
     846              : !           kappa_st from the resistance coefficient Kdiff with eq (37) Thoul&al.
     847              : !           Zdiff, Zdiff1, Zdiff2 = arrays of resistance coefficients,
     848              :          real(dp), intent(inout), dimension(:) :: ap, at, ar  ! (m)
     849              :          real(dp), intent(inout) :: ax(:,:)  ! (m,m)
     850              :          real(dp), intent(inout) :: e_ap, e_at, e_ar, e_ax(:)  ! (m)
     851              :          real(dp), intent(inout) :: g_ap, g_at, g_ar, g_ax(:)  ! (m)
     852              :          integer, intent(out) :: ierr
     853              : 
     854            0 :          integer :: i, j, l, indx(n)
     855            0 :          real(dp) :: cc, ac, ko, f
     856            0 :          real(dp), dimension(m,m) :: xx, y, yy, k
     857            0 :          real(dp), dimension(n) :: alpha, nu, ga, beta
     858            0 :          real(dp), dimension(n,n) :: delta, gamma
     859              : 
     860              :          ! the vector c contains the concentrations
     861              :          ! cc is the total concentration: cc=sum(c_s)
     862              :          ! ac is proportional to the mass density: ac=sum(a_s c_s)
     863              :          ! the arrays xx,y,yy and k are various parameters which appear in
     864              :          ! burgers equations.
     865              :          ! the vectors and arrays alpha, nu, gamma, delta, and ga represent
     866              :          ! the "right- and left-hand-sides" of burgers equations, and later
     867              :          ! the diffusion coefficients.
     868              : 
     869              :          ! initialize:
     870              : 
     871            0 :          ierr = 0
     872            0 :          ko = 2d0
     873            0 :          indx(1:n) = 0
     874              : 
     875              :          ! calculate cc and ac:
     876              : 
     877            0 :          cc=sum(c(1:m))
     878            0 :          ac=dot_product(a(1:m),c(1:m))
     879              : 
     880              :          ! calculate the coefficients of the burgers equations
     881              : 
     882            0 :          do i=1,m
     883            0 :             do j=1,m
     884            0 :                xx(i,j)=a(j)/(a(i)+a(j))
     885            0 :                y(i,j)=a(i)/(a(i)+a(j))
     886            0 :                yy(i,j) = 3D0*y(i,j) + Zdiff1(i,j)*xx(i,j)*a(j)/a(i)
     887            0 :                k(i,j) = kappa_st(i,j)
     888              :             end do
     889              :          end do
     890              : 
     891              :          ! write the burgers equations and the two constraints as
     892              :          ! alpha_s dp + nu_s dt + sum_t(not ihe or m) gamma_st dc_t
     893              :          !                     = sum_t delta_st w_t
     894              : 
     895            0 :          do i=1,m
     896            0 :             alpha(i)=c(i)/cc
     897            0 :             nu(i)=0d0
     898            0 :             gamma(i,1:n)=0d0
     899            0 :             if (rad) then
     900            0 :                beta(i) = -(amu/boltzm)*alpha(i)*a(i)*rad_accel(i)
     901              :             else
     902            0 :                beta(i) = 0d0
     903              :             end if
     904            0 :             do j=1,m
     905            0 :                if (j /= m) then  ! HH: Include He gradient
     906            0 :                   gamma(i,j) = -c(j)/cc
     907            0 :                   if (j == i) gamma(i,j) = gamma(i,j) + 1d0
     908            0 :                   gamma(i,j) = gamma(i,j)*c(i)/cc
     909              :                end if
     910              :             end do
     911              :          end do
     912              : 
     913            0 :          do i=m+1,n-2
     914            0 :             alpha(i)=0d0
     915            0 :             nu(i)=2.5d0*c(i-m)/cc
     916            0 :             beta(i) = 0d0
     917            0 :             gamma(i,1:n)=0d0
     918              :          end do
     919              : 
     920            0 :          alpha(n-1)=0d0
     921            0 :          nu(n-1)=0d0
     922            0 :          beta(n-1)=0d0
     923            0 :          gamma(n-1,1:n)=0d0
     924              : 
     925            0 :          alpha(n)=0d0
     926            0 :          nu(n)=0d0
     927            0 :          beta(n)=0d0
     928            0 :          gamma(n,1:n)=0d0
     929              : 
     930            0 :          delta(1:n,1:n) = 0d0
     931              : 
     932            0 :          do i=1,m
     933              : 
     934            0 :             do j=1,m
     935            0 :                if (j == i) then
     936            0 :                   do l=1,m
     937            0 :                      if (l /= i) then
     938            0 :                         delta(i,j)=delta(i,j)-k(i,l)
     939              :                      end if
     940              :                   end do
     941              :                else
     942            0 :                   delta(i,j)=k(i,j)
     943              :                end if
     944              :             end do
     945              : 
     946            0 :             do j=m+1,n-2
     947            0 :                if (j-m == i) then
     948            0 :                   do l=1,m
     949            0 :                      if (l /= i) &
     950            0 :                         delta(i,j) = delta(i,j) + Zdiff(i,l)*xx(i,l)*k(i,l)
     951              :                   end do
     952              :                else
     953            0 :                   delta(i,j) = -Zdiff(i,j-m)*y(i,j-m)*k(i,j-m)
     954              :                end if
     955              :             end do
     956              : 
     957            0 :             delta(i,n-1)=c(i)*z(i)
     958              : 
     959            0 :             delta(i,n)=-c(i)*a(i)
     960              : 
     961              :          end do
     962              : 
     963            0 :          do i=m+1,n-2
     964              : 
     965            0 :             do j=1,m
     966            0 :                if (j == i-m) then
     967            0 :                   do l=1,m
     968            0 :                      if (l /= i-m) delta(i,j) = &
     969            0 :                         delta(i,j) + 2.5D0*Zdiff(i-m,l)*xx(i-m,l)*k(i-m,l)
     970              :                   end do
     971              :                else
     972            0 :                   delta(i,j) = -(2.5d0*Zdiff(i-m,j))*xx(i-m,j)*k(i-m,j)
     973              :                end if
     974              :             end do
     975              : 
     976            0 :             do j=m+1,n-2
     977            0 :                if (j-m == i-m) then
     978            0 :                   do l=1,m
     979            0 :                      if (l /= i-m) delta(i,j) = delta(i,j) - &
     980            0 :                            y(i-m,l)*k(i-m,l)*(0.8D0*Zdiff2(i-m,l)*xx(i-m,l)+yy(i-m,l))
     981              :                   end do
     982            0 :                   delta(i,j) = delta(i,j) - 0.4D0*Zdiff2(i-m,i-m)*k(i-m,i-m)
     983              :                else
     984              :                   delta(i,j) = k(i-m,j-m)*xx(i-m,j-m)*y(i-m,j-m) * &
     985            0 :                         (3D0 + Zdiff1(i-m,j-m) - 0.8D0*Zdiff2(i-m,j-m))
     986              :                end if
     987              :             end do
     988              : 
     989            0 :             delta(i,n-1:n)=0d0
     990              : 
     991              :          end do
     992              : 
     993            0 :          do j=1,m
     994            0 :             delta(n-1,j) = c(j)*z(j)
     995              :          end do
     996            0 :          delta(n-1,m+1:n) = 0d0
     997              : 
     998            0 :          do j=1,m
     999            0 :             delta(n,j) = c(j)*a(j)
    1000              :          end do
    1001            0 :          delta(n,m+1:n) = 0d0
    1002              : 
    1003            0 :          call dgetrf(n, n, delta, n, indx, ierr)
    1004            0 :          if (ierr /= 0) return
    1005              : 
    1006            0 :          call dgetrs( 'n', n, 1, delta, n, indx, alpha, n, ierr )
    1007            0 :          if (ierr /= 0) return
    1008              : 
    1009            0 :          call dgetrs( 'n', n, 1, delta, n, indx, nu, n, ierr )
    1010            0 :          if (ierr /= 0) return
    1011              : 
    1012            0 :          if (rad) then
    1013            0 :             call dgetrs( 'n', n, 1, delta, n, indx, beta, n, ierr )
    1014            0 :             if (ierr /= 0) return
    1015              :          end if
    1016              : 
    1017            0 :          do j=1,n
    1018            0 :             do i=1,n
    1019            0 :                ga(i)=gamma(i,j)
    1020              :             end do
    1021            0 :             call dgetrs( 'n', n, 1, delta, n, indx, ga, n, ierr )
    1022            0 :             if (ierr /= 0) return
    1023            0 :             do i=1,n
    1024            0 :                gamma(i,j)=ga(i)
    1025              :             end do
    1026              :          end do
    1027              : 
    1028            0 :          f = ko*ac*cc
    1029            0 :          do j=1,m
    1030            0 :             ap(j)=alpha(j)*f
    1031            0 :             at(j)=nu(j)*f
    1032            0 :             ar(j)=beta(j)*f
    1033            0 :             do i=1,m
    1034            0 :                ax(i,j)=gamma(i,j)*f
    1035              :             end do
    1036              :          end do
    1037              : 
    1038            0 :          e_ap=alpha(n-1)*f
    1039            0 :          g_ap=alpha(n)*f
    1040              : 
    1041            0 :          e_at=nu(n-1)*f
    1042            0 :          g_at=nu(n)*f
    1043              : 
    1044            0 :          e_ar=beta(n-1)*f
    1045            0 :          g_ar=beta(n)*f
    1046              : 
    1047            0 :          do i=1,m
    1048            0 :             e_ax(i)=gamma(n-1,i)*f
    1049            0 :             g_ax(i)=gamma(n,i)*f
    1050              :          end do
    1051              : 
    1052            0 :       end subroutine do1_solve_thoul_hu
    1053              : 
    1054              : 
    1055            0 :       subroutine solve_burgers_cgs_no_thermal( &
    1056            0 :            n, m, A, Z, nd, rad_accel, rad, &
    1057            0 :            Kdiff, ap, at, ar, ax, &
    1058            0 :            e_ap, e_at, e_ar, e_ax, ierr)
    1059              : 
    1060              :         ! nd = array of number densities
    1061              :         ! m = # of species including electrons
    1062              :         ! n = m+1 without thermal diffusion
    1063              :         !   is the number of equations and unknowns
    1064              :         !   Thermal diffusion off: (m-1) diffusion equations,
    1065              :         !                          2 conservation equations.
    1066              :         !   Thermal diffusion  on: 2m diffusion equations (maybe 2*m-1)
    1067              :         !                          2 conservation equations.
    1068              : 
    1069              :         integer, intent(in) :: m,n
    1070              :         real(dp), intent(in), dimension(:) :: A, Z, nd, rad_accel  ! (m)
    1071              :         logical, intent(in) :: rad
    1072              :         real(dp), intent(in), dimension(:,:) :: Kdiff  ! (m,m)
    1073              :         real(dp), intent(inout), dimension(:) :: ap, at, ar  ! (m)
    1074              :         real(dp), intent(inout) :: ax(:,:)  ! (m,m)
    1075              :         real(dp), intent(inout) :: e_ap, e_at, e_ar, e_ax(:)
    1076              :         integer, intent(out) :: ierr
    1077              : 
    1078            0 :         integer :: i,j,l,indx(n)
    1079            0 :         real(dp), dimension(n) :: alpha, beta, nu, ga
    1080              :         ! Add in beta later for rad lev. ga is the temp holder for the
    1081              :         ! columns of gamm when doing matrix solve one column at a time.
    1082            0 :         real(dp), dimension(n,n) :: delta, gamm
    1083              : 
    1084              :         ! initialize
    1085            0 :         ierr = 0
    1086            0 :         indx(1:n) = 0
    1087            0 :         delta(1:n,1:n) = 0d0
    1088            0 :         alpha(1:n) = 0d0
    1089            0 :         beta(1:n) = 0d0
    1090            0 :         nu(1:n) = 0d0
    1091            0 :         ga(1:n) = 0d0
    1092            0 :         gamm(1:n,1:n) = 0d0
    1093              : 
    1094            0 :         e_ap = 0d0
    1095            0 :         e_at = 0d0
    1096            0 :         e_ar = 0d0
    1097            0 :         e_ax(1:m) = 0d0
    1098              : 
    1099              :         ! Assign the RHS Matrix multiplying the unknown quantities.
    1100              :         ! Right now this is for thermal diffusion off, assuming gravity
    1101              :         ! is a known, so there are m unknown diffusion velocities and
    1102              :         ! one unknown electric field, corresponding to (m-1) ion equaitions
    1103              :         ! (no electron equation) and 2 conservation equations.
    1104            0 :         do i = 1,(m-1)
    1105              : 
    1106            0 :            do j = 1,m
    1107            0 :               if (j == i) then
    1108            0 :                  do l = 1,m
    1109            0 :                     if (l /= j) then
    1110            0 :                        delta(i,j) = delta(i,j) - Kdiff(i,l)
    1111              :                     end if
    1112              :                  end do
    1113              :               else
    1114            0 :                  delta(i,j) = Kdiff(i,j)
    1115              :               end if
    1116              :            end do
    1117              : 
    1118            0 :            delta(i,n) = nd(i)*Z(i)
    1119              : 
    1120              :         end do
    1121              : 
    1122            0 :         do j = 1,m
    1123            0 :            delta(m,j) = A(j)*nd(j)
    1124            0 :            delta(n,j) = Z(j)*nd(j)
    1125              :         end do
    1126              :         ! Delta assignment finished.
    1127              : 
    1128              :         ! Assign LHS quantities. (Everything not assigned here stays zero thanks to earlier initialization)
    1129            0 :         do i = 1,(m-1)
    1130            0 :            alpha(i) = nd(i)*A(i)
    1131            0 :            nu(i) = nd(i)
    1132            0 :            gamm(i,i) = nd(i)
    1133            0 :            if (rad) then
    1134            0 :               beta(i) = -1d0*alpha(i)*amu*rad_accel(i)
    1135              :            end if
    1136              :         end do
    1137              : 
    1138              :         ! alpha,nu,gamm assignment finished
    1139              : 
    1140              : 
    1141              :         ! Invert the matrix and solve to get the contribution of each
    1142              :         ! vector/column on the LHS. This takes alpha, nu, ga from being
    1143              :         ! the knowns on the LHS to vectors containing information on
    1144              :         ! contributions for the unknowns. These then get assigned to the
    1145              :         ! output arrays ap, at, ax, which will then be multiplied by
    1146              :         ! gravity, k_b*T, and number density gradients to provide the
    1147              :         ! full solution for diffusion velocities.
    1148              : 
    1149            0 :         call dgetrf(n,n,delta,n,indx,ierr)
    1150              : 
    1151            0 :         if( ierr /= 0 ) then
    1152              :            ! print *, "Factoring failed!"
    1153              :            return
    1154              :         end if
    1155              : 
    1156            0 :         call dgetrs('N',n,1,delta,n,indx,alpha,n,ierr)
    1157            0 :         if( ierr /= 0 ) then
    1158              :            ! print *, "solve failed on alpha"
    1159              :            return
    1160              :         end if
    1161              : 
    1162            0 :         call dgetrs('N',n,1,delta,n,indx,nu,n,ierr)
    1163            0 :         if( ierr /= 0 ) then
    1164              :            ! print *, "solve failed on nu"
    1165              :            return
    1166              :         end if
    1167              : 
    1168            0 :         if (rad) then
    1169            0 :            call dgetrs('N',n,1,delta,n,indx,beta,n,ierr)
    1170            0 :            if( ierr /= 0 ) then
    1171              :               ! print *, "solve failed on beta"
    1172              :               return
    1173              :            end if
    1174              :         else
    1175            0 :            beta(1:n) = 0d0
    1176              :         end if
    1177              : 
    1178            0 :         do j=1,n
    1179            0 :            do i=1,n
    1180            0 :               ga(i) = gamm(i,j)
    1181              :            end do
    1182            0 :            call dgetrs('N',n,1,delta,n,indx,ga,n,ierr)
    1183            0 :            if( ierr /= 0 ) then
    1184              :               ! print *, "solve failed on gamma"
    1185              :               return
    1186              :            end if
    1187            0 :            do i=1,n
    1188            0 :               gamm(i,j) = ga(i)
    1189              :            end do
    1190              :         end do
    1191              : 
    1192              :         ! Assign the results of the matrix solve to the output
    1193              :         ! arrays/matrix.
    1194              : 
    1195            0 :         do j = 1,m
    1196            0 :            ap(j) = alpha(j)
    1197            0 :            at(j) = nu(j)
    1198            0 :            ar(j) = beta(j)
    1199            0 :            do i=1,m
    1200            0 :               ax(i,j) = gamm(i,j)
    1201              :            end do
    1202              :         end do
    1203              : 
    1204            0 :         e_ap = alpha(n)
    1205            0 :         e_at = nu(n)
    1206            0 :         e_ar = beta(n)
    1207            0 :         do i=1,m
    1208            0 :            e_ax(i) = gamm(n,i)
    1209              :         end do
    1210              : 
    1211            0 :       end subroutine solve_burgers_cgs_no_thermal
    1212              : 
    1213              : 
    1214            0 :       subroutine solve_burgers_cgs_with_thermal( &
    1215            0 :            n, m, A, Z, nd, rad_accel, rad, &
    1216            0 :            Kdiff, zdiff, zdiff1, zdiff2, &
    1217            0 :            ap, at, ar, ax, &
    1218            0 :            e_ap, e_at, e_ar, e_ax, ierr)
    1219              : 
    1220              :         ! nd = array of number densities
    1221              :         ! m = # of species including electrons
    1222              :         ! n = 2*m+1 with thermal diffusion
    1223              :         !   is the number of equations and unknowns
    1224              :         !   Thermal diffusion on: 2m-1 diffusion equations (m-1 momentum + m energy)
    1225              :         !                         2 conservation equations.
    1226              :         ! There is one less momentum equation because we are neglecting the electron
    1227              :         ! equation (which is wrong when electrons are degenerate),
    1228              :         ! and making up for losing that equation by treating grav as known.
    1229              :         ! We can't do the same with the energy equation because there are no more
    1230              :         ! unknowns that can be dropped, so this solver shouldn't really be used when
    1231              :         ! there is degeneracy. Having it in this form makes it easier to transition
    1232              :         ! between ideal gas (where this solver is valid) and solve_burgers_cgs
    1233              :         ! (which is much better when things are degenerate).
    1234              : 
    1235              :         integer, intent(in) :: m,n
    1236              :         real(dp), intent(in), dimension(:) :: A, Z, nd, rad_accel  ! (m)
    1237              :         logical, intent(in) :: rad
    1238              :         real(dp), intent(in), dimension(:,:) :: Kdiff  ! (m,m)
    1239              :         real(dp), intent(in), dimension(:,:) :: zdiff, zdiff1, zdiff2  ! (m,m)
    1240              :         real(dp), intent(inout), dimension(:) :: ap, at, ar  ! (m)
    1241              :         real(dp), intent(inout) :: ax(:,:)  ! (m,m)
    1242              :         real(dp), intent(inout) :: e_ap, e_at, e_ar, e_ax(:)
    1243              :         integer, intent(out) :: ierr
    1244              : 
    1245            0 :         integer :: i,j,l,indx(n), rightshift, downshift
    1246            0 :         real(dp), dimension(n) :: alpha, beta, nu, ga
    1247              :         ! Add in beta later for rad lev. ga is the temp holder for the
    1248              :         ! columns of gamm when doing matrix solve one column at a time.
    1249            0 :         real(dp), dimension(n,n) :: delta, gamm
    1250              : 
    1251              :         ! initialize
    1252            0 :         ierr = 0
    1253            0 :         indx(1:n) = 0
    1254            0 :         delta(1:n,1:n) = 0d0
    1255            0 :         alpha(1:n) = 0d0
    1256            0 :         beta(1:n) = 0d0
    1257            0 :         nu(1:n) = 0d0
    1258            0 :         ga(1:n) = 0d0
    1259            0 :         gamm(1:n,1:n) = 0d0
    1260              : 
    1261            0 :         e_ap = 0d0
    1262            0 :         e_at = 0d0
    1263            0 :         e_ar = 0d0
    1264            0 :         e_ax(1:m) = 0d0
    1265              :         ! Just a way to make it clear what's going on with the thermal terms in delta
    1266              :         ! by making block matrices and then shifting them into the proper position.
    1267              :         ! This makes the comparisons for checking the subdiagonals easier, as well
    1268              :         ! as indexing of the coefficients.
    1269            0 :         rightshift = m
    1270            0 :         downshift = m-1  ! Because electron momentum equation dropped.
    1271              : 
    1272              :         ! Assign the RHS Matrix multiplying the unknown quantities.
    1273              :         ! Assuming gravity is a known, so there are m unknown
    1274              :         ! diffusion velocities, m unknown heat flow vectors, and
    1275              :         ! one unknown electric field, corresponding to (m-1) momentum equations
    1276              :         ! (no electron equation), m energy equations, and 2 conservation equations.
    1277              : 
    1278              :         ! Terms corresponding to the momentum equations.
    1279            0 :         do i = 1,(m-1)
    1280              : 
    1281              :            ! Terms that multiply the diffusion velocities.
    1282            0 :            do j = 1,m
    1283            0 :               if (j == i) then
    1284            0 :                  do l = 1,m
    1285            0 :                     if (l /= j) then
    1286            0 :                        delta(i,j) = delta(i,j) - Kdiff(i,l)
    1287              :                     end if
    1288              :                  end do
    1289              :               else
    1290            0 :                  delta(i,j) = Kdiff(i,j)
    1291              :               end if
    1292              :            end do
    1293              : 
    1294              :            ! Terms that multiply the heat flow vectors.
    1295            0 :            do j = 1,m
    1296            0 :               if (j == i) then
    1297            0 :                  do l = 1,m
    1298            0 :                     if (l /= j) then
    1299            0 :                        delta(i,j+rightshift) = delta(i,j+rightshift) + Kdiff(i,l)*zdiff(i,l)*A(l)/(A(i)+A(l))
    1300              :                     end if
    1301              :                  end do
    1302              :               else
    1303            0 :                  delta(i,j+rightshift) = -1d0*Kdiff(i,j)*zdiff(i,j)*A(i)/(A(i) + A(j))
    1304              :               end if
    1305              :            end do
    1306              : 
    1307              :            ! Term multiplying the electric field.
    1308            0 :            delta(i,n) = nd(i)*Z(i)
    1309              : 
    1310              :         end do
    1311              : 
    1312              :         ! Terms corresponding to the energy equations.
    1313            0 :         do i = 1,m  ! All these entries get shifted lower into the i+downshift position.
    1314              : 
    1315              :            ! Terms that multiply the diffusion velocities.
    1316            0 :            do j = 1,m
    1317            0 :               if (j == i) then
    1318            0 :                  do l = 1,m
    1319            0 :                     if (l /= j) then
    1320            0 :                        delta(i+downshift,j) = delta(i+downshift,j) + 2.5d0*Kdiff(i,l)*zdiff(i,l)*A(l)/(A(i) + A(l))
    1321              :                     end if
    1322              :                  end do
    1323              :               else
    1324            0 :                  delta(i+downshift,j) = -2.5d0*Kdiff(i,j)*zdiff(i,j)*A(j)/(A(i) + A(j))
    1325              :               end if
    1326              :            end do
    1327              : 
    1328              :            ! Terms that multiply the heat flow vectors.
    1329            0 :            do j = 1,m
    1330              :               ! Shift these entries to be in the lower-right half of the matrix.
    1331            0 :               if (j == i) then
    1332            0 :                  delta(i+downshift,j+rightshift) = -0.4d0*Kdiff(i,j)*zdiff2(i,j)  ! 1st term on RHS of eqn (90) in MESA3
    1333            0 :                  do l=1,m  ! second line of eqn (90) in MESA3
    1334            0 :                     if (l /= j) then
    1335              :                        delta(i+downshift,j+rightshift) = delta(i+downshift,j+rightshift) - &
    1336              :                             Kdiff(i,l)* &
    1337              :                             ( &
    1338              :                             (3d0*pow2(A(i)) + pow2(A(l))*zdiff1(i,l))/pow2(A(i)+A(l)) + &
    1339              :                             0.8d0*zdiff2(i,l)*A(i)*A(l)/pow2(A(i) + A(l)) &
    1340            0 :                             )
    1341              :                     end if
    1342              :                  end do
    1343              :               else  ! third line of eqn (90) in MESA3
    1344              :                  delta(i+downshift,j+rightshift) = Kdiff(i,j)* &
    1345              :                       ( 3d0 + zdiff1(i,j) - 0.8d0*zdiff2(i,j) )* &
    1346            0 :                       A(i)*A(j)/pow2(A(i)+A(j))
    1347              :               end if
    1348              :            end do
    1349              : 
    1350              :            ! Term multiplying the electric field. (doesn't appear in energy equations)
    1351            0 :            delta(i+downshift,n) = 0d0
    1352              :         end do
    1353              : 
    1354              :         ! Terms from the mass and charge conservation laws, the last two rows of the matrix.
    1355              :         ! These only involve the diffusion velocities, not heat flow or e-field.
    1356            0 :         do j = 1,m
    1357            0 :            delta(n-1,j) = A(j)*nd(j)
    1358            0 :            delta(n,j) = Z(j)*nd(j)
    1359              :         end do
    1360              :         ! Delta assignment finished.
    1361              : 
    1362              :         ! Assign LHS quantities. (Everything not assigned here stays zero thanks to earlier initialization)
    1363              :         ! LHS of momentum equations.
    1364            0 :         do i = 1,(m-1)
    1365            0 :            alpha(i) = nd(i)*A(i)
    1366            0 :            nu(i) = nd(i)
    1367            0 :            gamm(i,i) = nd(i)
    1368            0 :            if (rad) then
    1369            0 :               beta(i) = -1d0*alpha(i)*amu*rad_accel(i)
    1370              :            end if
    1371              :         end do
    1372              :         ! LHS of energy equations.
    1373            0 :         do i = 1,m
    1374            0 :            nu(i+downshift) = 2.5d0*nd(i)
    1375              :         end do
    1376              : 
    1377              :         ! alpha,nu,gamm assignment finished
    1378              : 
    1379              : 
    1380              :         ! Invert the matrix and solve to get the contribution of each
    1381              :         ! vector/column on the LHS. This takes alpha, nu, ga from being
    1382              :         ! the knowns on the LHS to vectors containing information on
    1383              :         ! contributions for the unknowns. These then get assigned to the
    1384              :         ! output arrays ap, at, ax, which will then be multiplied by
    1385              :         ! gravity, k_b*T, and number density gradients to provide the
    1386              :         ! full solution for diffusion velocities.
    1387              : 
    1388            0 :         call dgetrf(n,n,delta,n,indx,ierr)
    1389              : 
    1390            0 :         if( ierr /= 0 ) then
    1391              :            ! print *, "Factoring failed!"
    1392              :            return
    1393              :         end if
    1394              : 
    1395            0 :         call dgetrs('N',n,1,delta,n,indx,alpha,n,ierr)
    1396            0 :         if( ierr /= 0 ) then
    1397              :            ! print *, "solve failed on alpha"
    1398              :            return
    1399              :         end if
    1400              : 
    1401            0 :         call dgetrs('N',n,1,delta,n,indx,nu,n,ierr)
    1402            0 :         if( ierr /= 0 ) then
    1403              :            ! print *, "solve failed on nu"
    1404              :            return
    1405              :         end if
    1406              : 
    1407            0 :         if (rad) then
    1408            0 :            call dgetrs('N',n,1,delta,n,indx,beta,n,ierr)
    1409            0 :            if( ierr /= 0 ) then
    1410              :               ! print *, "solve failed on beta"
    1411              :               return
    1412              :            end if
    1413              :         else
    1414            0 :            beta(1:n) = 0d0
    1415              :         end if
    1416              : 
    1417            0 :         do j=1,n
    1418            0 :            do i=1,n
    1419            0 :               ga(i) = gamm(i,j)
    1420              :            end do
    1421            0 :            call dgetrs('N',n,1,delta,n,indx,ga,n,ierr)
    1422            0 :            if( ierr /= 0 ) then
    1423              :               ! print *, "solve failed on gamma"
    1424              :               return
    1425              :            end if
    1426            0 :            do i=1,n
    1427            0 :               gamm(i,j) = ga(i)
    1428              :            end do
    1429              :         end do
    1430              : 
    1431              : 
    1432              :         ! Assign the results of the matrix solve from the diffusion
    1433              :         ! velocity part of the arrays to the solution vectors.
    1434              : 
    1435            0 :         do j = 1,m
    1436            0 :            ap(j) = alpha(j)
    1437            0 :            at(j) = nu(j)
    1438            0 :            ar(j) = beta(j)
    1439            0 :            do i=1,m
    1440            0 :               ax(i,j) = gamm(i,j)
    1441              :            end do
    1442              :         end do
    1443              : 
    1444              :         ! Entries m+1-2m are heat flow vectors, so those don't get output.
    1445              :         ! Skip to final entry (n) for electric field.
    1446            0 :         e_ap = alpha(n)
    1447            0 :         e_at = nu(n)
    1448            0 :         e_ar = beta(n)
    1449            0 :         do i=1,m
    1450            0 :            e_ax(i) = gamm(n,i)
    1451              :         end do
    1452              : 
    1453            0 :       end subroutine solve_burgers_cgs_with_thermal
    1454              : 
    1455              : 
    1456              :       ! Calculate coefficients given in Appendix C.3 of Stanton & Murillo, PR E 93, 043203 (2016)
    1457            0 :       subroutine get_SM_coeffs(nc,m,rho,T,A,Z,nd,Kdiff,zdiff,zdiff1,zdiff2,kappa)
    1458              :         integer, intent(in) :: nc, m
    1459              :         real(dp), intent(in) :: rho, T
    1460              :         real(dp), dimension(:), intent(in) :: A, Z, nd  ! m
    1461              :         real(dp), intent(out) :: kappa  ! ion separation relative to electron screening length.
    1462              :         real(dp), dimension(:,:), intent(inout) :: Kdiff,zdiff,zdiff1,zdiff2  ! (m,m) but electron entries shouldn't be used.
    1463              :         ! Only the ion terms are modified by this routine right now.
    1464              : 
    1465            0 :         real(dp), dimension(nc,nc) :: g_plasma, mu
    1466            0 :         real(dp), dimension(nc,nc,2,3) :: Keff, Omega  ! Indexed by all species and different orders
    1467              :         ! Fitting coefficients from Stanton & Murillo
    1468            0 :         real(dp), dimension(2,3) :: a1,a2,a3,a4,a5,b0,b1,b2,b3,b4
    1469            0 :         real(dp) :: lambda  ! The screening length
    1470              :         integer :: i,j,facmo,no,mo  ! Last two are used for different orders of collisions.
    1471              : 
    1472            0 :         real(dp) :: lgp, gp1, gp2, gp3, gp4, gp5, kbT32, tmp
    1473              : 
    1474              :         ! Initialize all to 0, since some entries never get set or used.
    1475            0 :         a1(:,:) = 0d0
    1476            0 :         a2(:,:) = 0d0
    1477            0 :         a3(:,:) = 0d0
    1478            0 :         a4(:,:) = 0d0
    1479            0 :         a5(:,:) = 0d0
    1480            0 :         b0(:,:) = 0d0
    1481            0 :         b1(:,:) = 0d0
    1482            0 :         b2(:,:) = 0d0
    1483            0 :         b3(:,:) = 0d0
    1484            0 :         b4(:,:) = 0d0
    1485              : 
    1486              :         ! Table IV, coefficients for fits (C23)-(C24)
    1487            0 :         a1(1,1) = 1.4660d0
    1488            0 :         a1(1,2) = 0.52094d0
    1489            0 :         a1(1,3) = 0.30346d0
    1490            0 :         a1(2,2) = 0.85401d0
    1491              : 
    1492            0 :         a2(1,1) = -1.7836d0
    1493            0 :         a2(1,2) = 0.25153d0
    1494            0 :         a2(1,3) = 0.23739d0
    1495            0 :         a2(2,2) = -0.22898d0
    1496              : 
    1497            0 :         a3(1,1) = 1.4313d0
    1498            0 :         a3(1,2) = -1.1337d0
    1499            0 :         a3(1,3) = -0.62167d0
    1500            0 :         a3(2,2) = -0.60059d0
    1501              : 
    1502            0 :         a4(1,1) = -0.55833d0
    1503            0 :         a4(1,2) = 1.2155d0
    1504            0 :         a4(1,3) = 0.56110d0
    1505            0 :         a4(2,2) = 0.80591d0
    1506              : 
    1507            0 :         a5(1,1) = 0.061162d0
    1508            0 :         a5(1,2) = -0.43784d0
    1509            0 :         a5(1,3) = -0.18046d0
    1510            0 :         a5(2,2) = -0.30555d0
    1511              : 
    1512            0 :         b0(1,1) = 0.081033d0
    1513            0 :         b0(1,2) = 0.20572d0
    1514            0 :         b0(1,3) = 0.68375d0
    1515            0 :         b0(2,2) = 0.43475d0
    1516              : 
    1517            0 :         b1(1,1) = -0.091336d0
    1518            0 :         b1(1,2) = -0.16536d0
    1519            0 :         b1(1,3) = -0.38459d0
    1520            0 :         b1(2,2) = -0.21147d0
    1521              : 
    1522            0 :         b2(1,1) = 0.051760d0
    1523            0 :         b2(1,2) = 0.061572d0
    1524            0 :         b2(1,3) = 0.10711d0
    1525            0 :         b2(2,2) = 0.11116d0
    1526              : 
    1527            0 :         b3(1,1) = -0.50026d0
    1528            0 :         b3(1,2) = -0.12770d0
    1529            0 :         b3(1,3) = 0.10649d0
    1530            0 :         b3(2,2) = 0.19665d0
    1531              : 
    1532            0 :         b4(1,1) = 0.17044d0
    1533            0 :         b4(1,2) = 0.066993d0
    1534            0 :         b4(1,3) = 0.028760d0
    1535            0 :         b4(2,2) = 0.15195d0
    1536              : 
    1537              :         ! Get the screening length
    1538            0 :         call lam_SM(nc,m,rho,T,Z,nd,lambda,kappa)
    1539              : 
    1540              :         ! Calculate g_plasma
    1541            0 :         do i=1,nc
    1542            0 :            do j=1,nc
    1543            0 :               g_plasma(i,j) = Z(i)*Z(j)*qe*qe/(lambda*boltzm*T)
    1544              :            end do
    1545              :         end do
    1546              : 
    1547              :         ! Calculate Keff using Eqns (C22-C24)
    1548            0 :         do i=1,nc
    1549            0 :            do j=1,nc
    1550              :               ! cache g powers
    1551            0 :               lgp = safe_log(g_plasma(i,j))
    1552            0 :               gp1 = g_plasma(i,j)
    1553            0 :               gp2 = pow2(gp1)
    1554            0 :               gp3 = pow3(gp1)
    1555            0 :               gp4 = pow4(gp1)
    1556            0 :               gp5 = pow5(gp1)
    1557            0 :               if( g_plasma(i,j) < 0d0) then  ! Don't calculate for attractive potentials, set to 0
    1558            0 :                  Keff(i,j,:,:) = 0d0
    1559            0 :               else if( g_plasma(i,j) < 1d0) then  ! Use eqn C23 for weakly coupled
    1560            0 :                  do no=1,2
    1561            0 :                     do mo=1,3  ! Implementing the (m-1)! term with a simple if statement.
    1562            0 :                        if(mo == 3) then
    1563              :                           facmo = 2  ! (3-1)!
    1564              :                        else
    1565            0 :                           facmo = 1  ! (1-1)! and (2-1)!
    1566              :                        end if
    1567              :                        Keff(i,j,no,mo) = (-1d0*no/4d0)*facmo*safe_log( &
    1568              :                             a1(no,mo)*gp1 &
    1569              :                             + a2(no,mo)*gp2 &
    1570              :                             + a3(no,mo)*gp3 &
    1571              :                             + a4(no,mo)*gp4 &
    1572            0 :                             + a5(no,mo)*gp5)
    1573              :                     end do
    1574              :                  end do
    1575              :               else  ! Use eqn C24 for strongly coupled
    1576            0 :                  do no=1,2
    1577            0 :                     do mo=1,3
    1578              :                        Keff(i,j,no,mo) = &
    1579              :                             (b0(no,mo) + b1(no,mo)*lgp + b2(no,mo)*pow2(lgp) ) / &
    1580            0 :                             (1d0 + b3(no,mo)*gp1 + b4(no,mo)*gp2 )
    1581              :                     end do
    1582              :                  end do
    1583              :               end if
    1584              :            end do
    1585              :         end do
    1586              : 
    1587              :         ! Calculate the collision integrals using (C19)
    1588            0 :         kBT32 = pow(boltzm*T,1.5d0)
    1589            0 :         do i=1,nc
    1590            0 :            do j=1,nc
    1591            0 :               mu(i,j) = amu*A(i)*A(j)/(A(i) + A(j))  ! Reduced mass for collision
    1592            0 :               tmp = sqrt(2d0*pi/(mu(i,j))) * (pow2(Z(i)*Z(j)*qe*qe)/kBT32)
    1593            0 :               do no=1,2
    1594            0 :                  do mo=1,3
    1595            0 :                     Omega(i,j,no,mo) = tmp * Keff(i,j,no,mo)
    1596              :                  end do
    1597              :               end do
    1598              :            end do
    1599              :         end do
    1600              : 
    1601              :         ! Resistance coefficient is (16/3) ni nj mu Omega11
    1602              :         ! (compare Paquette eqn 22 with SM eq B8)
    1603              :         ! The zdiffs are given in terms of collision integrals in Paquette eqns (14-16), (23-25)
    1604            0 :         do i=1,nc
    1605            0 :            do j=1,nc
    1606            0 :               Kdiff(i,j) = (16d0/3d0)*nd(i)*nd(j)*mu(i,j)*Omega(i,j,1,1)
    1607            0 :               zdiff(i,j) = 1d0 - 2d0*Omega(i,j,1,2)/(5d0*Omega(i,j,1,1))
    1608            0 :               zdiff1(i,j) = 2.5d0 + (2d0*Omega(i,j,1,3) - 10d0*Omega(i,j,1,2))/(5d0*Omega(i,j,1,1))
    1609            0 :               zdiff2(i,j) = Omega(i,j,2,2)/Omega(i,j,1,1)
    1610              :            end do
    1611              :         end do
    1612              : 
    1613              :         ! Note that SM don't give fits for attractive potentials, so we haven't
    1614              :         ! touched the electron entries. They exit this routine unchanged, so they
    1615              :         ! either need to be initialized before this routine is called or somehow
    1616              :         ! calculated later.
    1617              : 
    1618            0 :       end subroutine get_SM_coeffs
    1619              : 
    1620              :       ! Screening Length according to Stanton & Murillo
    1621            0 :       subroutine lam_SM(nc,m,rho,T,Z,nd,lam_eff,kappa)
    1622              :         integer, intent(in) :: nc, m
    1623              :         real(dp), intent(in) :: rho, T
    1624              :         real(dp), dimension(:), intent(in) :: Z, nd  ! m. charges, number densities of all species
    1625              :         real(dp), intent(out) :: lam_eff
    1626              :         real(dp), intent(out) :: kappa  ! ion separation relative to electron screening length.
    1627              : 
    1628            0 :         real(dp) :: tiny_n, ne, EF, lam_e, lam_sum, rhotot, ni_tot
    1629            0 :         real(dp), dimension(nc) :: ai, gam_is, lam_i  ! ion sphere radius, coupling, screening for each type of ion
    1630              :         integer :: i
    1631              : 
    1632            0 :         tiny_n = 1d-20  ! g/cc
    1633            0 :         ne = nd(m)
    1634              :         ! Electron Fermi energy
    1635            0 :         EF = (hbar*hbar*pow(3d0*pi*pi*ne,2d0/3d0))/(2d0*me)
    1636              :         ! Electron screening length accounting for degeneracy correction
    1637            0 :         lam_e = pow(pi4*qe*qe*ne/sqrt(pow2(boltzm*T) + pow2((2d0/3d0)*EF)),-0.5d0)
    1638              : 
    1639              :         ! Compute kappa
    1640            0 :         ni_tot = 0d0
    1641            0 :         do i = 1,nc
    1642            0 :            ni_tot = ni_tot + nd(i)
    1643              :         end do
    1644            0 :         kappa = pow(3d0/(pi4*ni_tot),one_third)/lam_e
    1645              : 
    1646            0 :         rhotot = 0d0
    1647            0 :         do i = 1,nc
    1648              :            ! rhotot is a CHARGE density. Just trying to follow the notation of SM eq (34)
    1649            0 :            rhotot = rhotot + Z(i)*qe*nd(i)  ! = qe*ne?
    1650              :         end do
    1651            0 :         do i = 1,nc
    1652            0 :            ai(i) = pow(Z(i)*qe/(four_thirds_pi*rhotot), one_third)
    1653            0 :            gam_is(i) = Z(i)*Z(i)*qe*qe/(ai(i)*boltzm*T)
    1654              :            ! Number densities that are 0 or tiny cause screening length to diverge.
    1655              :            ! This is physical; nothing is there to screen anything.
    1656              :            ! But numerically, I don't want to rely on fortran to handle division by zero and infinity,
    1657              :            ! so just set these screening lengths to be huge and they won't
    1658              :            ! contribute anything to overall screening length.
    1659            0 :            if(nd(i) < tiny_n) then
    1660            0 :               lam_i(i) = 1d99  ! cm. This won't contribute to any screening.
    1661              :            else
    1662            0 :               lam_i(i) = sqrt(boltzm*T/( pi4*pow2(Z(i)*qe)*nd(i) ))
    1663              :            end if
    1664              :         end do
    1665              : 
    1666            0 :         lam_sum = 1d0/pow2(lam_e)  ! The electron part of the screening length.
    1667            0 :         do i = 1,nc  ! Sum over all the ions.
    1668            0 :            lam_sum = lam_sum + pow( pow2(lam_i(i))*(1d0+3d0*gam_is(i)), -1d0)
    1669              :         end do
    1670            0 :         lam_eff = pow(lam_sum,-0.5d0)
    1671            0 :       end subroutine lam_SM
    1672              : 
    1673              :       ! Calculate coefficients given in Section 4 of Caplan, Bauer, & Freeman 2022
    1674            0 :       subroutine get_CBF_coeffs(nc,m,rho,T,A,Z,nd,Gamma,Ddiff,Kdiff)
    1675              :         integer, intent(in) :: nc, m
    1676              :         real(dp), intent(in) :: rho, T, Gamma
    1677              :         real(dp), dimension(:), intent(in) :: A, Z, nd  ! m
    1678              :         real(dp), dimension(:), intent(out) :: Ddiff  ! nc
    1679              :         real(dp), dimension(:,:), intent(inout) :: Kdiff  ! (m,m), but only touch (nc,nc)
    1680              : 
    1681            0 :         real(dp) :: kappa, DstarOCP, omegap, ai, lam_e, Docp
    1682            0 :         real(dp) :: Abar, Zbar, ni_sum, Zp6bar, Kfac
    1683              :         integer :: i, j
    1684              : 
    1685            0 :         ni_sum = sum(nd(1:nc))  ! total ion number density (excludes electron entry m)
    1686            0 :         Abar = sum(A(1:nc)*nd(1:nc))/ni_sum
    1687            0 :         Zbar = sum(Z(1:nc)*nd(1:nc))/ni_sum
    1688            0 :         Zp6bar = 0d0  ! average of Z^0.6, needed for constructing Kij
    1689            0 :         do j = 1,nc
    1690            0 :            Zp6bar = Zp6bar + pow(Z(j),0.6d0)*nd(j)/ni_sum
    1691              :         end do
    1692              : 
    1693              :         ! Set kappa as input for Dstar calculation,
    1694              :         ! also sets omegap, ai, lam_e for converting to cgs units later.
    1695            0 :         call kappa_CBF(nc,m,rho,T,Abar,Zbar,nd,omegap,ai,lam_e,kappa)
    1696              : 
    1697              :         ! Calculate Dstar using fit of Eqn (5)
    1698            0 :         call get_Dstar_OCP(Gamma,kappa,DstarOCP)
    1699            0 :         Docp = DstarOCP*ai*ai*omegap  ! convert from dimensionless to cgs units
    1700              : 
    1701              :         ! Eqn (11)
    1702            0 :         do j = 1,nc
    1703            0 :            Ddiff(j) = Docp*pow(Z(j)/Zbar,-0.6d0)
    1704              :         end do
    1705              : 
    1706              :         ! Translate into Kij coefficients for Burgers equations
    1707            0 :         Kfac = boltzm*T/(ni_sum*Zp6bar*pow(Zbar,0.6d0)*Docp)
    1708            0 :         do i = 1,nc
    1709            0 :            do j = 1,nc
    1710            0 :               Kdiff(i,j) = nd(i)*nd(j)*pow(Z(i)*Z(j),0.6d0)*Kfac
    1711              :            end do
    1712              :         end do
    1713              : 
    1714            0 :       end subroutine get_CBF_coeffs
    1715              : 
    1716            0 :       subroutine get_Dstar_OCP(Gamma,kappa,DstarOCP)
    1717              :         real(dp), intent(in) :: Gamma, kappa
    1718              :         real(dp), intent(out) :: DstarOCP
    1719              : 
    1720            0 :         real(dp) :: a0, a1, a2, b0, b1, b2, c0, c1, c2, c3
    1721            0 :         real(dp) :: Ak, Bk, Ck
    1722              : 
    1723            0 :         a0 = 1.55973d0
    1724            0 :         a1 = 1.10941d0
    1725            0 :         a2 = 1.36909d0
    1726              : 
    1727            0 :         b0 = 0.0070782d0
    1728            0 :         b1 = 0.80499d0
    1729            0 :         b2 = 4.53523d0
    1730              : 
    1731            0 :         c0 = 2.20689d0
    1732            0 :         c1 = 1.351594d0
    1733            0 :         c2 = 1.57138d0
    1734            0 :         c3 = 3.34187d0
    1735              : 
    1736            0 :         Ak = sqrt(pi/3d0)*(a0 + a1*pow(kappa,a2))
    1737            0 :         Bk = b0*exp(-b1*pow(kappa,b2))
    1738            0 :         Ck = c0 + c1*bitsafe_erf_fit(c2*pow(kappa,c3))
    1739              : 
    1740              :         ! Eqn (5)
    1741            0 :         DstarOCP = sqrt(pi/3d0)*Ak*pow(Gamma,-2.5d0)*exp(-Bk*Gamma)/log(1d0 + Ck*pow(Gamma,-1.5d0)/sqrt(3d0))
    1742              : 
    1743            0 :       end subroutine get_Dstar_OCP
    1744              : 
    1745              :       ! Screening Length for CBF diffusion coefficients.
    1746              :       ! Only electron screening, accounts for potentially relativistic electron degeneracy.
    1747            0 :       subroutine kappa_CBF(nc,m,rho,T,Abar,Zbar,nd,omegap,ai,lam_e,kappa)
    1748              :         integer, intent(in) :: nc, m
    1749              :         real(dp), intent(in) :: rho, T, Abar, Zbar
    1750              :         real(dp), dimension(:), intent(in) :: nd  ! m. number densities of all species
    1751              :         real(dp), intent(out) :: omegap, ai, lam_e
    1752              :         real(dp), intent(out) :: kappa  ! ion separation relative to electron screening length.
    1753              : 
    1754            0 :         real(dp) :: tiny_n, ne, EF, kF, lam_e_SM, lam_e_rel, ni_tot
    1755              :         integer :: i
    1756              : 
    1757            0 :         tiny_n = 1d-20  ! g/cc
    1758            0 :         ne = nd(m)  ! electron number density
    1759              :         ! Electron Fermi energy
    1760            0 :         EF = (hbar*hbar*pow(3d0*pi*pi*ne,2d0/3d0))/(2d0*me)
    1761              :         ! Electron screening length accounting for degeneracy correction
    1762            0 :         lam_e_SM = pow(pi4*qe*qe*ne/sqrt(pow2(boltzm*T) + pow2((2d0/3d0)*EF)),-0.5d0)
    1763              : 
    1764            0 :         if (rho < 1d6) then
    1765            0 :            lam_e = lam_e_SM
    1766              :         else  ! calculate and use relativistic screening length if rho > 1d6
    1767            0 :            kF = pow(3d0*pi*pi*ne,one_third)  ! electron Fermi momentum
    1768            0 :            lam_e_rel = 1d0/(2d0*kF*sqrt(fine/pi))  ! fine = fine structure constant ~1/137
    1769            0 :            lam_e = min(lam_e_SM,lam_e_rel)  ! min for continuity
    1770              :         end if
    1771              : 
    1772              :         ! Compute kappa
    1773            0 :         ni_tot = 0d0
    1774            0 :         do i = 1,nc
    1775            0 :            ni_tot = ni_tot + nd(i)
    1776              :         end do
    1777            0 :         omegap = sqrt(pi4*ni_tot*Zbar*Zbar*qe*qe/(Abar*amu))  ! plasma frequency
    1778            0 :         ai = pow(3d0/(pi4*ni_tot),one_third)
    1779            0 :         kappa = ai/lam_e
    1780              : 
    1781            0 :       end subroutine kappa_CBF
    1782              : 
    1783              :       ! crlibm does not include error function, so implement an
    1784              :       ! erf fit good to 2.5e-5 (Abramowitz and Stegun 1964)
    1785              :       ! in terms of other bitsafe functions.
    1786            0 :       real(dp) function bitsafe_erf_fit(x)
    1787              :         real(dp) :: x
    1788            0 :         real(dp) :: t, p, a1, a2, a3
    1789              : 
    1790            0 :         p = 0.47047d0
    1791            0 :         a1 = 0.3480242d0
    1792            0 :         a2 = -0.0958798d0
    1793            0 :         a3 = 0.7478556d0
    1794              : 
    1795            0 :         t = 1d0/(1d0 + p*x)
    1796              : 
    1797            0 :         bitsafe_erf_fit = 1d0 - (a1*t + a2*t*t + a3*t*t*t)*exp(-x*x)
    1798            0 :       end function bitsafe_erf_fit
    1799              : 
    1800              :       end module diffusion_support
        

Generated by: LCOV version 2.0-1