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

            Line data    Source code
       1              : ! ***********************************************************************
       2              : !
       3              : !   Copyright (C) 2013-2019  The MESA Team
       4              : !
       5              : !   This program is free software: you can redistribute it and/or modify
       6              : !   it under the terms of the GNU Lesser General Public License
       7              : !   as published by the Free Software Foundation,
       8              : !   either version 3 of the License, or (at your option) any later version.
       9              : !
      10              : !   This program is distributed in the hope that it will be useful,
      11              : !   but WITHOUT ANY WARRANTY; without even the implied warranty of
      12              : !   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
      13              : !   See the GNU Lesser General Public License for more details.
      14              : !
      15              : !   You should have received a copy of the GNU Lesser General Public License
      16              : !   along with this program. If not, see <https://www.gnu.org/licenses/>.
      17              : !
      18              : ! ***********************************************************************
      19              : 
      20              :       module op_eval_mombarg
      21              : 
      22              :       use const_def, only: dp, pi
      23              : 
      24              :       implicit none
      25              : 
      26              :       private
      27              :       public :: compute_grad
      28              :       public :: compute_grad_fast
      29              :       public :: compute_gamma_grid
      30              :       public :: compute_kappa
      31              :       public :: compute_kappa_fast
      32              :       public :: interpolate_kappa
      33              :       public :: compute_kappa_grid
      34              : 
      35              :       real(dp), parameter :: log_c = 10.476820702927927d0  !log10_cr(dble(299792458e2)) c = speed of light
      36              :       real(dp), parameter :: log10_bohr_radius_sqr = -16.55280d0
      37              :       real(dp), parameter :: logNa = 23.779750912481397d0  !log10_cr(6.0221409d23) Avogadro's number
      38              : 
      39              :       real(dp), parameter :: diff_v = (1.0552976117319748d0 - 0.00010565516589892675d0)   !v(u(1)) - v(u(nptot))
      40              : 
      41              :       contains
      42              : 
      43              : 
      44              :       !!! Compute g_rad for a single cell. (Currently not used.)
      45            0 :       subroutine compute_grad(k, fk, logT_face, logRho_face,l, r,lkap_ross_cell, lgrad_cell, ierr,ite,jne,epatom,amamu,sig,eumesh)
      46              :         ! OP mono data for: H, C, N, O, Ne, Na, Mg, Al, Si, S, Ar, Ca, Cr, Mn, Fe, and Ni.
      47              :       use chem_def, only: chem_isos, ih1, ihe3, ihe4, ic12, in14, io16, ine20, ina23, &
      48              :                           img24, ial27, isi28, is32, iar40, ica40, icr52, imn55, ife56, ini58
      49              :       use interp_2d_lib_sg
      50              :       use cubic_interpolator, only: interpolator
      51              : 
      52              :       integer, intent(inout) :: ierr
      53              :       integer, intent(in) :: k
      54              :       real(dp), intent(in) :: fk(:), logT_face, logRho_face, l, r
      55              :       integer :: nel, nptot
      56              :       parameter(nel = 17, nptot = 10000)  !number of elements and number of u-mesh points.
      57              :       real(dp), intent(out) :: lkap_ross_cell, lgrad_cell(nel)
      58              : 
      59              :       integer , pointer :: ite(:),jne(:)
      60              :       real(dp), pointer :: sig(:,:,:)
      61              :       real(dp), pointer  :: epatom(:,:),amamu(:),eumesh(:,:,:)
      62              : 
      63              : 
      64              :       ! ite: temperature index, logT = 0.025*ite, (1648)
      65              :       ! jne: electron density index, logNe = 0.25*jne, (1648)
      66              :       ! epatom: electrons per atom, (nel,nptot).
      67              :       ! amamu: mu = mean atomic weight (nel)
      68              :       ! sig: monochromatic cross sections in (a0^2), (nel,1648,nptot)
      69              :       ! eumesh: sigma_i*(1 - exp(-u(v))) - a_k,i, where u=h*nu/(kT). OP mono grid is equally spaced in variable v. a_k,i are the correction factors. (nel,1648,nptot)
      70              : 
      71              : 
      72              :       integer :: ke, id, m, ik, i
      73              : 
      74            0 :       real(dp):: epa_mix_cell(1648), amu_mix_cell, logRho(1648),logT(1648)  ! Number of electrons per atom, mean molecular weight, density and temperature as a function of ite (temp index) and jne (density index) from the OP mono data.
      75            0 :       real(dp) :: delta(1648)
      76            0 :       real(dp) :: lgamm_cell(nel)  !interpolated log kappa Rossland and log gamma_k in each cell (k = element index).
      77              :       real(dp), parameter :: dv = diff_v/nptot  !v(u(1)) - v(u(nptot))/nptot
      78            0 :       real(dp) :: mH
      79              : 
      80              :       integer ::  delta_min_idx
      81            0 :       real(dp) :: lkap_Ross(4,4),gamma_k(4,4,nel),lgamm(4,4,nel),sig_Ross(4,4)  ! Rossland cross section, log kappa, gamma_k, log gamma_k for interpolation.
      82            0 :       real(dp) :: sf, flux  !'scale factor' for g_rad, local flux.
      83            0 :       real, allocatable :: sig_mix_cell(:,:,:),sig_int(:)
      84              :       integer :: ii, jj, ite_min, jne_min, ii_min, jj_min, ite_step, jne_step
      85              :       integer :: ite_i, jne_i, dite, djne, i_grid(4,4)
      86            0 :       real(dp) :: logT_min, logRho_min, logT_grid(4,4), logRho_grid(4,4)
      87              :       integer :: offset1, offset2, tries, missing_point(4,4)
      88            0 :       real(dp) :: log_amu_mix_cell, gam
      89              :       integer :: imin, imax
      90              :       logical :: retry
      91              : 
      92              :       type(interpolator) :: rossl_interpolator
      93              :       type(interpolator) :: gaml_interpolators(nel)
      94              : 
      95            0 :       ierr = 0
      96              : 
      97              : 
      98            0 :       imin = 1  !-1
      99            0 :       imax = 1648  !-1
     100            0 :       ite_step = 2
     101            0 :       jne_step = 2
     102              : 
     103              :       !!! Compute the number of electrons per atom for the local mixture.
     104            0 :       epa_mix_cell = 0d0
     105            0 :         do i=imin,imax
     106            0 :           epa_mix_cell(i) = dot_product(fk,epatom(1:nel,i))
     107              :         end do
     108              : 
     109            0 :       amu_mix_cell = dot_product(fk,amamu)
     110              : 
     111            0 :       mH = chem_isos% W(ih1) * 1.660538782d-24
     112            0 :       log_amu_mix_cell = log10(amu_mix_cell * mH)
     113              :       !logRho = 0.25d0*jne + log_amu_mix_cell - log10(epa_mix_cell)
     114            0 :       logRho = 0.25d0*jne + log10(amu_mix_cell) - log10(epa_mix_cell) -logNa
     115            0 :       logT   = 0.025d0*ite
     116              :       !write(*,*) 'rho computed'
     117              : 
     118              :       !!! Select nearest points in logT,logRho for interpolation.
     119              :       !!! First, find the nearest OP data point, and check which of the four possible positionings this minimum has wrt to (T,Rho)_cell.
     120              :       !!! Acquire the remaining 15 points of the 4x4 grid, where (T,Rho)_cell is located in the inner square.
     121              : 
     122            0 :       delta = sqrt((logRho - logRho_face)*(logRho - logRho_face)/0.25d0 + (logT-logT_face)*(logT-logT_face)/0.025d0)
     123              : 
     124            0 :       delta_min_idx = MINLOC(delta, DIM=1)
     125            0 :       ite_min   = ite(delta_min_idx)
     126            0 :       jne_min   = jne(delta_min_idx)
     127            0 :       logT_min   = logT(delta_min_idx)
     128            0 :       logRho_min = logRho(delta_min_idx)
     129            0 :       if (logT_min <= logT_face .and. logRho_min <= logRho_face) then
     130            0 :         ii_min = 2
     131            0 :         jj_min = 2
     132            0 :       else if (logT_min < logT_face .and. logRho_min > logRho_face) then
     133            0 :         ii_min = 2  !3
     134            0 :         jj_min = 3  !2
     135            0 :       else if (logT_min > logT_face .and. logRho_min < logRho_face) then
     136            0 :         ii_min = 3
     137            0 :         jj_min = 2
     138            0 :       else if (logT_min > logT_face .and. logRho_min > logRho_face) then
     139            0 :         ii_min = 3
     140            0 :         jj_min = 3
     141              :       end if
     142              :       !write(*,*) 'ii, jj min', ii_min, jj_min, logT_min, XC, logRho_min, logRho_cell
     143              : 
     144            0 :       offset1 = 0
     145            0 :       offset2 = 0
     146            0 :       missing_point = 1
     147              :       tries = 0
     148              :       retry = .true.
     149              :       !do while (point_not_found .ne. 0) !If (T,Rho)_cell lies to close to the edge of the OP mono grid (in Rho), shift the 4x4 grid up/down by 1 in jne.
     150            0 :       do while (retry)  !If (T,Rho)_cell lies to close to the edge of the OP mono grid (in Rho), shift the 4x4 grid up/down by 1 in jne.
     151            0 :       missing_point = 1
     152            0 :       retry = .false.
     153            0 :       do jj=1,4
     154            0 :             do ii=1,4
     155            0 :               dite = (ii - ii_min + offset1)*ite_step  !(ii - ii_min)*ite_step + offset2
     156            0 :               djne = (jj - jj_min + offset2)*jne_step  !(jj - jj_min)*jne_step + offset1
     157            0 :              do i =imin,imax
     158            0 :                ite_i = ite(i)
     159            0 :                jne_i = jne(i)
     160              : 
     161            0 :                 if (ite_i == ite_min +  dite .and. jne_i == jne_min + djne) THEN
     162            0 :                   logT_grid(ii,jj) = logT(i)
     163            0 :                   logRho_grid(ii,jj) = logRho(i)
     164            0 :                   i_grid(ii,jj) = i
     165              :                   !write(*,*) ite_i, jne_i, ii, jj, i_grid(ii,jj), ',',logT_grid(ii,jj),&
     166              :                   !',', logRho_grid(ii,jj)
     167            0 :                   missing_point(ii,jj) = 0
     168              :                 end if
     169              :               end do
     170              :             end do
     171              :       end do
     172            0 :       if (SUM(missing_point) > 0) then
     173            0 :         retry = .true.
     174            0 :         if (SUM(missing_point(2:4,1:3)) == 0) then
     175            0 :           offset1 = offset1 + 1
     176            0 :           offset2 = offset2 - 1
     177            0 :         else if (SUM(missing_point(1:3,1:3)) == 0) then
     178            0 :           offset1 = offset1 - 1
     179            0 :           offset2 = offset2 - 1
     180            0 :         else if (SUM(missing_point(2:4,2:4)) == 0) then
     181            0 :           offset1 = offset1 + 1
     182            0 :           offset2 = offset2 + 1
     183            0 :         else if (SUM(missing_point(1:3,2:4)) == 0) then
     184            0 :           offset1 = offset1 - 1
     185            0 :           offset2 = offset2 + 1
     186              :         else
     187              :           !write(*,*) 'warning interpolation quality in cell grad', k,ite_min,jne_min, &
     188              :           !logT_face, logRho_face, ii_min, jj_min
     189            0 :           if (ii_min == 3 .and. jj_min == 2) then
     190            0 :             offset1 = offset1 + 2
     191            0 :             offset2 = offset2 - 2
     192            0 :           else if (ii_min == 2 .and. jj_min == 3) then
     193            0 :             offset1 = offset1 - 2
     194            0 :             offset2 = offset2 + 2
     195            0 :           else if (ii_min == 2 .and. jj_min == 2) then
     196            0 :             offset1 = offset1 - 2
     197            0 :             offset2 = offset2 - 2
     198            0 :           else if (ii_min == 3 .and. jj_min == 3) then
     199            0 :             offset1 = offset1 + 2
     200            0 :             offset2 = offset2 - 1
     201              :           end if
     202              :         end if
     203              :       end if
     204              : 
     205              : 
     206            0 :       if (tries > 2) THEN  ! To prevent loop from getting stuck.
     207            0 :         write(*,*) 'Cannot find points for interpolation compute_grad', &
     208            0 :                     k, ite_min, jne_min, logT_min, logRho_min, logT_face, &
     209            0 :                     logRho_face, missing_point, ii_min, jj_min, offset1, offset2, &
     210            0 :                     imin, imax, log_amu_mix_cell
     211            0 :         ierr = 1
     212              :         return
     213              :       end if
     214            0 :       tries = tries + 1
     215              :       end do
     216              :       !write(*,*) 'Points for interpolation selected', k
     217              : 
     218              :       !!! Compute the monochromatic cross-section for the local mixture.
     219            0 :       allocate(sig_mix_cell(4,4,nptot),sig_int(nptot-1), stat=ierr)
     220            0 :       sig_mix_cell = 0d0
     221            0 :       do jj=1,4
     222            0 :           do ii=1,4
     223            0 :             ik = i_grid(ii,jj)  !+ 1648*(ke-1)
     224            0 :             do m=1,nptot
     225            0 :               sig_mix_cell(ii,jj,m) = dot_product(fk,sig(:,ik,m))
     226              :             end do
     227              :           end do
     228              :       end do
     229              : 
     230              :       !!! Compute the Rossland mean cross-section by integrating over variable v (mesh equally spaced in v).
     231            0 :       sig_Ross = 0d0
     232            0 :       do jj=1,4
     233            0 :         do ii=1,4
     234            0 :            sig_int(1:nptot-1) = (1/sig_mix_cell(ii,jj,1:nptot-1) + 1/sig_mix_cell(ii,jj,2:nptot))/2.0d0 * dv
     235            0 :            do m=1, nptot-1
     236              :                 !sig_Ross(ii,jj) = sig_Ross(ii,jj) + (1/sig_mix_cell(ii,jj,m) + 1/sig_mix_cell(ii,jj,m+1))/2.0d0 * dv
     237            0 :                 sig_Ross(ii,jj) = sig_Ross(ii,jj) + sig_int(m)
     238              :            end do
     239              :         end do
     240              :       end do
     241              : 
     242            0 :       lkap_Ross =  log10_bohr_radius_sqr - log_amu_mix_cell - log10(sig_Ross)
     243              : 
     244            0 :       call rossl_interpolator% initialize()
     245            0 :       do jj = 1, 4
     246            0 :          do ii = 1, 4
     247            0 :             call rossl_interpolator% add_point(logT_grid(ii,jj), logRho_grid(ii,jj), lkap_Ross(ii,jj))
     248              :          end do
     249              :       end do
     250              : 
     251            0 :       lkap_ross_cell  = rossl_interpolator% evaluate(logT_face,logRho_face)
     252              : 
     253              : 
     254              :       !!! Compute gamma for each element for interpolation.
     255            0 :       gamma_k = 0d0
     256              : 
     257            0 :       do jj=1,4
     258            0 :         do ii=1,4
     259            0 :           ik = i_grid(ii,jj)  ! + 1648*(ke-1)
     260            0 :           do ke=3,nel
     261              :             gam = 0
     262            0 :             do m=1, nptot-1
     263            0 :             gam = gam + ((eumesh(ke,ik,m)/ sig_mix_cell(ii,jj,m)) +(eumesh(ke,ik,m+1)/ sig_mix_cell(ii,jj,m+1)))
     264              :             end do
     265            0 :            gamma_k(ii,jj,ke) = gam/2.0d0 * dv
     266              :           end do
     267              :         end do
     268              :       end do
     269              : 
     270            0 :       deallocate(sig_mix_cell,sig_int)
     271              : 
     272            0 :       where (gamma_k < 0.0d0)
     273              :         gamma_k = 10d-30
     274              :       endwhere
     275            0 :       lgamm = log10(gamma_k)
     276              : 
     277            0 :       do ke = 3, nel
     278            0 :          call gaml_interpolators(ke)% initialize()
     279            0 :          do jj = 1, 4
     280            0 :             do ii = 1, 4
     281            0 :                call gaml_interpolators(ke)% add_point(logT_grid(ii,jj), logRho_grid(ii,jj), lgamm(ii,jj,ke))
     282              :             end do
     283              :          end do
     284              : 
     285            0 :         lgamm_cell(ke) = gaml_interpolators(ke)% evaluate(logT_face, logRho_face)  !cell
     286              :       end do
     287            0 :       lgamm_cell(1) = -30.
     288            0 :       lgamm_cell(2) = -30.
     289              :       !write(*,*) 'lgamm_cell computed'!, ke, lgamm_cell(ke)
     290              : 
     291              :       ! Compute log g_rad.
     292            0 :         flux  = l / (4d0*pi*r*r)
     293            0 :         sf = lkap_ross_cell  - log_c + log10(flux) + log10(amu_mix_cell)
     294            0 :         lgrad_cell = sf + lgamm_cell - log10(amamu)
     295            0 :       lgrad_cell(1) = -30.
     296            0 :       lgrad_cell(2) = -30.
     297              :       !write(*,*) 'log kappa + log g_rad Fe cell', k, lkap_ross_cell, lgrad_cell(16)
     298              :       !write(*,*) 'compute_grad done', k
     299              : 
     300            0 :       end subroutine compute_grad
     301              : 
     302              : 
     303              :       !!! Compute gamma factors and kappa_Ross for all OP mono data points for a given mixture.
     304            0 :       subroutine compute_gamma_grid(ngp, fk_all,lgamm_pcg, lkap_face_pcg, &
     305              :                                     logT_pcg, logRho_pcg, ierr,ite,jne,epatom,amamu,sig,eumesh)
     306              :         ! OP mono data for: H, C, N, O, Ne, Na, Mg, Al, Si, S, Ar, Ca, Cr, Mn, Fe, and Ni.
     307            0 :       use chem_def, only: chem_isos, ih1, ihe3, ihe4, ic12, in14, io16, ine20, ina23, &
     308              :                           img24, ial27, isi28, is32, iar40, ica40, icr52, imn55, ife56, ini58
     309              :       use interp_2d_lib_sg
     310              :       use cubic_interpolator, only: interpolator
     311              : 
     312              :       integer, intent(inout) :: ierr
     313              :       integer, intent(in) :: ngp
     314              :       real(dp), intent(in) :: fk_all(:)
     315              :       integer :: nel, nptot
     316              :       parameter(nel = 17, nptot = 10000)  !number of elements and number of u-mesh points.
     317              :       !real(dp), pointer, intent(out)::lgamm_pcg(:,:,:),lkap_face_pcg(:,:)
     318              :       real(dp), intent(out)::lgamm_pcg(nel,1648),lkap_face_pcg(1648)
     319              : 
     320              :       real(dp), intent(out) :: logT_pcg(1648), logRho_pcg(1648)
     321              : 
     322              :       integer , pointer :: ite(:),jne(:)
     323              :       real(dp), pointer :: sig(:,:,:)  !, ak_f(:,:)
     324              :       real(dp), pointer :: epatom(:,:),amamu(:),eumesh(:,:,:)
     325              :       integer :: imin, imax
     326              : 
     327              :       integer :: n, ke, nz, id, m, ik, i, j
     328              : 
     329              :       !real(dp) :: fk_norm_fac !Local fractional abundance per element and normalization factor.
     330            0 :       real(dp):: epa_mix_cell(1648), amu_mix_cell, fk(nel) ! Number of electrons per atom, mean molecular weight, density and temperature as a function of ite (temp index) and jne (density index) from the OP mono data.
     331              :       !integer ::  eid(nel)
     332              :       real(dp), parameter :: dv = diff_v/nptot  !v(u(1)) - v(u(nptot))/nptot
     333            0 :       real(dp) :: mH
     334              : 
     335              :       !!!! For interpolator.
     336              : 
     337              : 
     338            0 :       real(dp) :: sig_Ross(1648), gamma_k(nel,1648)  !, lgamm(nel,1648) ! Rossland cross section, log kappa, gamma_k, log gamma_k for interpolation.
     339              : 
     340              : 
     341            0 :       real, allocatable :: sig_mix_cell(:,:),sig_int(:)
     342            0 :       real(dp) :: log_amu_mix_cell, gam
     343              : 
     344              : 
     345            0 :       ierr = 0
     346              : 
     347              :       !!! Compute an estimated temperature range.
     348            0 :       imin = 1  !-1
     349            0 :       imax = 1648  !-1
     350              : 
     351            0 :       fk = fk_all  !(j,:)
     352              :       !!! Compute the number of electrons per atom for the local mixture.
     353            0 :       epa_mix_cell = 0d0
     354            0 :         do i=imin,imax
     355            0 :           epa_mix_cell(i) = dot_product(fk,epatom(1:nel,i))
     356              :         end do
     357              : 
     358            0 :       amu_mix_cell = dot_product(fk,amamu)
     359              : 
     360            0 :       mH = chem_isos% W(ih1) * 1.660538782d-24
     361            0 :       log_amu_mix_cell = log10(amu_mix_cell * mH)
     362              : 
     363              : 
     364              :       !!! Compute the monochromatic cross-section for the local mixture.
     365            0 :       allocate(sig_mix_cell(1648,nptot),sig_int(nptot-1), stat=ierr)
     366            0 :       sig_mix_cell = 0d0
     367            0 : !$OMP PARALLEL DO PRIVATE(i,m) SCHEDULE(guided)
     368              :           do i=1,1648
     369              :               do m=1,nptot
     370              :               sig_mix_cell(i,m) = dot_product(fk,sig(:,i,m))
     371              :               end do
     372              :           end do
     373              : !$OMP END PARALLEL DO
     374              : 
     375              :       !!! Compute the Rossland mean cross-section by integrating over variable v (mesh equally spaced in v).
     376            0 :       sig_Ross = 0d0
     377            0 : !$OMP PARALLEL DO PRIVATE(i,m,sig_int) SCHEDULE(guided)
     378              :         do i=1,1648
     379              :               sig_int(1:nptot-1) = (1/sig_mix_cell(i,1:nptot-1) + 1/sig_mix_cell(i,2:nptot))/2.0d0 * dv  !inv_sig_mix_cell(ii,jj,1:nptot-1) + inv_sig_mix_cell(ii,jj,2:nptot)
     380              :               do m=1, nptot-1
     381              :                 sig_Ross(i) = sig_Ross(i) + sig_int(m)
     382              :               end do
     383              :         end do
     384              : !$OMP END PARALLEL DO
     385              : 
     386              : 
     387            0 :       logT_pcg   = 0.025d0*ite
     388            0 :       logRho_pcg = 0.25d0*jne + log10(amu_mix_cell) - log10(epa_mix_cell) - logNa
     389              :       !if (j==1) allocate(lkap_face_pcg(ngp,1648),stat=ierr)
     390            0 :       lkap_face_pcg =  log10_bohr_radius_sqr - log_amu_mix_cell - log10(sig_Ross)
     391            0 : !$OMP PARALLEL DO PRIVATE(i,ke,m,gam) SCHEDULE(guided)
     392              :         do i=imin,imax
     393              :           do ke=3,nel
     394              :             gam = 0d0
     395              :             do m=1, nptot-1
     396              :             gam = gam + ((eumesh(ke,i,m)/ sig_mix_cell(i,m))+(eumesh(ke,i,m+1)/ sig_mix_cell(i,m+1)))
     397              :             end do
     398              :            gamma_k(ke,i) = gam/2.0d0 * dv
     399              :           end do
     400              :         end do
     401              : !$OMP END PARALLEL DO
     402              : 
     403            0 :         where (gamma_k < 0.0d0)
     404              :           gamma_k = 10d-30
     405              :         endwhere
     406              : 
     407            0 :         deallocate(sig_mix_cell,sig_int)
     408              : 
     409            0 :         lgamm_pcg = log10(gamma_k)
     410            0 :       end subroutine compute_gamma_grid
     411              : 
     412              : 
     413              :       !!! Compute g_rad from precomputeds for grid for gamma and kappa_Ross for the entire OP mono data.
     414            0 :       subroutine compute_grad_fast(k, fk, logT_face, logRho_face, l, r,lgrad_cell, &
     415              :                                    ierr,ite,jne,epatom,amamu,logT_pcg,logRho_pcg,lgamm_pcg,lkap_face_pcg)
     416              : 
     417            0 :       use cubic_interpolator, only: interpolator
     418              : 
     419              :       integer, intent(inout) :: ierr
     420              :       integer, intent(in) :: k
     421              :       real(dp), intent(in) :: fk(:), logT_face, logRho_face, l, r
     422              :       real(dp), intent(in) :: logT_pcg(1648), logRho_pcg(1648)  !, lgamm_pcg(:,:), lkap_face_pcg(:)
     423              :       integer :: nel, nptot
     424              :       parameter(nel = 17, nptot = 10000)  !number of elements and number of u-mesh points.
     425              :       real(dp), intent(in) :: lgamm_pcg(nel,1648), lkap_face_pcg(1648)
     426              :       real(dp), intent(out) :: lgrad_cell(nel)
     427              : 
     428              :       integer , pointer :: ite(:),jne(:)
     429              :       real(dp), pointer :: epatom(:,:),amamu(:)
     430              : 
     431              :       integer :: n, ke, nz, id, m, ik, i
     432              : 
     433            0 :       real(dp):: epa_mix_cell(1648), amu_mix_cell  ! Number of electrons per atom, mean molecular weight, density and temperature as a function of ite (temp index) and jne (density index) from the OP mono data.
     434            0 :       real(dp) :: delta(1648)
     435              :       integer ::  eid(nel)
     436            0 :       real(dp) :: lgamm_cell(nel)  !interpolated log kappa Rossland and log gamma_k in each cell (k = element index).
     437              :       real(dp), parameter :: dv = diff_v/nptot  !v(u(1)) - v(u(nptot))/nptot
     438              :       real(dp) :: mH
     439              : 
     440              :       !!!! For interpolator.
     441              :       integer ::  delta_min_idx
     442            0 :       real(dp) :: lkap_Ross(4,4),sig_Ross(4,4)  ! Rossland cross section, log kappa, gamma_k, log gamma_k for interpolation.
     443            0 :       real(dp) :: sf, flux  !'scale factor' for g_rad, local flux.
     444              : 
     445              :       integer :: ii, jj, ite_min, jne_min, ii_min, jj_min, ite_step, jne_step
     446              :       integer :: ite_i, jne_i, dite, djne, i_grid(4,4)
     447            0 :       real(dp) :: logT_min, logRho_min, logT_grid(4,4),logRho_grid(4,4),lgamm(4,4,nel)
     448              :       integer ::  offset1, offset2, tries, missing_point(4,4)
     449            0 :       real(dp) :: log_amu_mix_cell, lkap_ross_cell
     450              :       integer :: imin, imax
     451            0 :       real(dp) :: logT(1648), logRho(1648)  !, ite_grid(4,4), jne_grid(4,4)
     452              :       logical :: retry, do_difficult_point
     453              :       type(interpolator) :: rossl_interpolator
     454              :       type(interpolator) :: gaml_interpolators(nel)
     455              : 
     456            0 :       ierr = 0
     457              : 
     458            0 :       imin = 1
     459            0 :       imax = 1648
     460              : 
     461              : 
     462              : 
     463            0 :       amu_mix_cell = dot_product(fk,amamu)
     464              : 
     465            0 :       logT   = logT_pcg  !0.025d0*ite
     466            0 :       logRho = logRho_pcg  !0.25d0*jne + log10_cr(amu_mix_cell) - log10(epa_mix_cell) - logNa
     467              : 
     468              :       !!! Compute an estimated temperature range.
     469              :       imin = 1
     470              :       imax = 1648
     471            0 :       ite_step = 2
     472            0 :       jne_step = 2
     473              : 
     474            0 :       delta = sqrt((logRho - logRho_face)*(logRho - logRho_face)/0.25d0 +(logT-logT_face)*(logT-logT_face)/0.025d0)
     475              : 
     476            0 :       delta_min_idx = MINLOC(delta, DIM=1)
     477            0 :       ite_min   = ite(delta_min_idx)
     478            0 :       jne_min   = jne(delta_min_idx)
     479            0 :       logT_min   = logT(delta_min_idx)
     480            0 :       logRho_min = logRho(delta_min_idx)
     481            0 :       if (logT_min <= logT_face .and. logRho_min <= logRho_face) then
     482            0 :         ii_min = 2
     483            0 :         jj_min = 2
     484            0 :       else if (logT_min < logT_face .and. logRho_min > logRho_face) then
     485            0 :         ii_min = 2
     486            0 :         jj_min = 3
     487            0 :       else if (logT_min > logT_face .and. logRho_min < logRho_face) then
     488            0 :         ii_min = 3
     489            0 :         jj_min = 2
     490            0 :       else if (logT_min > logT_face .and. logRho_min > logRho_face) then
     491            0 :         ii_min = 3
     492            0 :         jj_min = 3
     493              :       end if
     494              : 
     495              : 
     496            0 :       offset1 = 0
     497            0 :       offset2 = 0
     498            0 :       missing_point = 1
     499              :       tries = 0
     500              :       retry = .true.
     501            0 :       do while (retry)  !If (T,Rho)_cell lies to close to the edge of the OP mono grid (in Rho), shift the 4x4 grid up/down by 1 in jne.
     502            0 :       missing_point = 1
     503            0 :       retry = .false.
     504            0 :       do jj=1,4
     505            0 :             do ii=1,4
     506            0 :               dite = (ii - ii_min + offset1)*ite_step
     507            0 :               djne = (jj - jj_min + offset2)*jne_step
     508            0 :              do i =imin,imax
     509            0 :                ite_i = ite(i)
     510            0 :                jne_i = jne(i)
     511              : 
     512            0 :                 if (ite_i == ite_min +  dite .and. jne_i == jne_min + djne) THEN
     513            0 :                   logT_grid(ii,jj) = logT(i)
     514            0 :                   logRho_grid(ii,jj) = logRho(i)
     515            0 :                   i_grid(ii,jj) = i
     516            0 :                   missing_point(ii,jj) = 0
     517              : 
     518              :                 end if
     519              :               end do
     520              :             end do
     521              :       end do
     522              : 
     523            0 :       if (SUM(missing_point) > 0) then
     524            0 :         retry = .true.
     525            0 :         if (SUM(missing_point(2:4,1:3)) == 0) then
     526            0 :           offset1 = offset1 + 1
     527            0 :           offset2 = offset2 - 1
     528            0 :         else if (SUM(missing_point(1:3,1:3)) == 0) then
     529            0 :           offset1 = offset1 - 1
     530            0 :           offset2 = offset2 - 1
     531            0 :         else if (SUM(missing_point(2:4,2:4)) == 0) then
     532            0 :           offset1 = offset1 + 1
     533            0 :           offset2 = offset2 + 1
     534            0 :         else if (SUM(missing_point(1:3,2:4)) == 0) then
     535            0 :           offset1 = offset1 - 1
     536            0 :           offset2 = offset2 + 1
     537              :         else
     538            0 :           if (ii_min == 3 .and. jj_min == 2) then
     539            0 :             offset1 = offset1 + 2
     540            0 :             offset2 = offset2 - 2
     541            0 :           else if (ii_min == 2 .and. jj_min == 3) then
     542            0 :             offset1 = offset1 - 2
     543            0 :             offset2 = offset2 + 2
     544            0 :           else if (ii_min == 2 .and. jj_min == 2) then
     545            0 :             offset1 = offset1 - 2
     546            0 :             offset2 = offset2 - 2
     547            0 :           else if (ii_min == 3 .and. jj_min == 3) then
     548            0 :             offset1 = offset1 + 2
     549            0 :             offset2 = offset2 - 1
     550              :           end if
     551              :         end if
     552              :       end if
     553              : 
     554            0 :       if (tries > 2) THEN  ! To prevent loop from getting stuck.
     555            0 :        do_difficult_point = .false.
     556            0 :        if (ite_min == 226 .and. jne_min == 90 .and. ii_min == 2 .and. jj_min == 3) do_difficult_point = .true.
     557            0 :        if (ite_min == 226 .and. jne_min == 88 .and. ii_min == 2 .and. jj_min == 2) do_difficult_point = .true.
     558            0 :        if (ite_min == 230 .and. jne_min == 88 .and. ii_min == 3 .and. jj_min == 2) do_difficult_point = .true.
     559            0 :        if (ite_min == 230 .and. jne_min == 90 .and. ii_min == 3 .and. jj_min == 3) do_difficult_point = .true.
     560              : 
     561            0 :        if (do_difficult_point) then
     562            0 :           do jj=1,4
     563            0 :             do ii =1,4
     564            0 :               dite = (ii - ii_min)*2*ite_step
     565            0 :               djne = (jj - jj_min - 1)*jne_step
     566            0 :               do i=imin,imax
     567            0 :                 ite_i = ite(i)
     568            0 :                 jne_i = jne(i)
     569            0 :                 if (ite_i == ite_min + dite .and. jne_i == jne_min + djne) then
     570            0 :                   logT_grid(ii,jj) = logT(i)
     571            0 :                   logRho_grid(ii,jj) = logRho(i)
     572            0 :                   i_grid(ii,jj) = i
     573              : 
     574              :                 end if
     575              :               end do
     576              :              end do
     577              :             end do
     578              :             retry = .false.
     579              :         else
     580              : 
     581            0 :         write(*,*) 'Cannot find points for interpolation compute_grad_fast', &
     582            0 :                     k, ite_min, jne_min, logT_min, logRho_min, logT_face, logRho_face, &
     583            0 :                     missing_point, ii_min, jj_min, offset1, offset2,imin, imax
     584            0 :         ierr = 1
     585            0 :         return
     586              :         end if
     587              :       end if
     588            0 :       tries = tries + 1
     589              :       end do
     590              : 
     591            0 :       do jj=1,4
     592            0 :         do ii=1,4
     593            0 :           ik = i_grid(ii,jj)
     594            0 :           do ke=3,nel
     595            0 :             lgamm(ii,jj,ke) = lgamm_pcg(ke,ik)
     596              :           end do
     597            0 :           lkap_Ross(ii,jj) = lkap_face_pcg(ik)
     598              :         end do
     599              :       end do
     600              : 
     601              : 
     602            0 :       call rossl_interpolator% initialize()
     603            0 :       do jj = 1, 4
     604            0 :          do ii = 1, 4
     605            0 :             call rossl_interpolator% add_point(logT_grid(ii,jj), logRho_grid(ii,jj), lkap_Ross(ii,jj))
     606              :          end do
     607              :       end do
     608              : 
     609            0 :       lkap_ross_cell  = rossl_interpolator% evaluate(logT_face,logRho_face)
     610              : 
     611            0 :       do ke = 3, nel
     612            0 :          call gaml_interpolators(ke)% initialize()
     613            0 :          do jj = 1, 4
     614            0 :             do ii = 1, 4
     615            0 :                call gaml_interpolators(ke)% add_point(logT_grid(ii,jj), logRho_grid(ii,jj), lgamm(ii,jj,ke))
     616              :             end do
     617              :          end do
     618              : 
     619            0 :         lgamm_cell(ke) = gaml_interpolators(ke)% evaluate(logT_face, logRho_face)  !cell
     620              :       end do
     621            0 :       lgamm_cell(1) = -30d0
     622            0 :       lgamm_cell(2) = -30d0
     623              : 
     624            0 :       flux  = l / (4d0*pi*r*r)
     625            0 :       sf = lkap_ross_cell  - log_c + log10(flux) + log10(amu_mix_cell)
     626            0 :       lgrad_cell = sf + lgamm_cell - log10(amamu)
     627            0 :       lgrad_cell(1) = -30.
     628            0 :       lgrad_cell(2) = -30.
     629              : 
     630              :       end subroutine compute_grad_fast
     631              : 
     632              : 
     633              :       !!! Compute Rossland opacity and derivatives for a single cell.
     634            0 :       subroutine compute_kappa(k,fk,logT_cntr,logRho_cntr,lkap_ross_cell, &
     635              :                                dlnkap_rad_dlnT,dlnkap_rad_dlnRho,ierr,ite,jne,epatom,amamu,sig,logT_grid,logRho_grid,lkap_Ross)
     636              :         ! OP mono data for: H, C, N, O, Ne, Na, Mg, Al, Si, S, Ar, Ca, Cr, Mn, Fe, and Ni.
     637              :       use chem_def, only: chem_isos, ih1, ihe3, ihe4, ic12, in14, io16, ine20, ina23, &
     638              :                           img24, ial27, isi28, is32, iar40, ica40, icr52, imn55, ife56, ini58
     639              :       use interp_2d_lib_sg
     640              :       use cubic_interpolator, only: interpolator
     641              : 
     642              :       integer, intent(inout) :: ierr
     643              :       integer, intent(in) :: k
     644              :       real(dp), intent(in) :: fk(:), logT_cntr, logRho_cntr
     645              :       integer :: nel, nptot
     646              :       parameter(nel = 17, nptot = 10000)  !number of elements and number of u-mesh points.
     647              :       real(dp), intent(out) :: lkap_ross_cell, dlnkap_rad_dlnT, dlnkap_rad_dlnRho
     648              :       real(dp), intent(out), dimension(4,4) :: logT_grid, logRho_grid, lkap_Ross
     649              : 
     650              : 
     651              :       integer , pointer :: ite(:),jne(:)
     652              :       real(dp), pointer :: sig(:,:,:)
     653              :       real(dp), pointer :: epatom(:,:),amamu(:)
     654              : 
     655              :       integer :: n, ke, nz, id, m, ik, i
     656              : 
     657            0 :       real(dp):: epa_mix_cell(1648), amu_mix_cell, logRho(1648), logT(1648)  ! Number of electrons per atom, mean molecular weight, density and temperature as a function of ite (temp index) and jne (density index) from the OP mono data.
     658            0 :       real(dp) :: delta(1648)
     659              :       real(dp) :: lgamm_cell(nel)  !interpolated log kappa Rossland and log gamma_k in each cell (k = element index).
     660              :       real(dp), parameter :: dv = diff_v/nptot  !v(u(1)) - v(u(nptot))/nptot
     661            0 :       real(dp) :: mH
     662              : 
     663              : 
     664              :       integer ::  delta_min_idx
     665            0 :       real(dp) :: sig_Ross(4,4)  !,lkap_Ross(4,4), ! Rossland cross section, log kappa, gamma_k, log gamma_k for interpolation.
     666              :       real(dp) :: sf, flux  !'scale factor' for g_rad, local flux.
     667              : 
     668            0 :       real, allocatable :: sig_mix_cell(:,:,:),sig_int(:)
     669              :       integer :: ii, jj, ite_min, jne_min, ii_min, jj_min, ite_step, jne_step
     670              :       integer :: ite_i, jne_i, dite, djne, i_grid(4,4)
     671              :       real(dp) :: logT_min, logRho_min  !, logT_grid(4,4), logRho_grid(4,4)
     672              :       integer :: offset1, offset2, tries, missing_point(4,4)
     673              :       real(dp) :: log_amu_mix_cell
     674              :       integer :: imin, imax
     675              :       real(dp) :: sig_grid(nel,4,4,nptot)
     676              :       logical :: retry
     677              : 
     678              :       type(interpolator) :: rossl_interpolator
     679              : 
     680            0 :       ierr = 0
     681              : 
     682            0 :       imin = 1  !-1
     683            0 :       imax = 1648  !-1
     684            0 :       ite_step = 2
     685            0 :       jne_step = 2
     686              : 
     687              :       !!! Compute the number of electrons per atom for the local mixture.
     688            0 :       epa_mix_cell = 0d0
     689            0 :         do i=imin,imax
     690            0 :           epa_mix_cell(i) = dot_product(fk,epatom(1:nel,i))
     691              :         end do
     692              : 
     693              : 
     694            0 :       amu_mix_cell = dot_product(fk,amamu)
     695              : 
     696            0 :       mH = chem_isos% W(ih1) * 1.660538782d-24
     697            0 :       log_amu_mix_cell = log10(amu_mix_cell * mH)
     698              :       !logRho = 0.25d0*jne + log_amu_mix_cell - log10(epa_mix_cell)
     699            0 :       logRho = 0.25d0*jne + log10(amu_mix_cell) - log10(epa_mix_cell) -logNa
     700              : 
     701            0 :       logT   = 0.025d0*ite
     702              : 
     703              :       !!! Select nearest points in logT,logRho for interpolation.
     704              :       !!! First, find the nearest OP data point, and check which of the four possible positionings this minimum has wrt to (T,Rho)_cell.
     705              :       !!! Acquire the remaining 15 points of the 4x4 grid, where (T,Rho)_cell is located in the inner square.
     706              : 
     707              : 
     708            0 :       delta = sqrt((logRho - logRho_cntr)*(logRho - logRho_cntr)/0.25d0 +(logT-logT_cntr)*(logT-logT_cntr)/0.025d0)
     709              : 
     710            0 :       delta_min_idx = MINLOC(delta, DIM=1)
     711            0 :       ite_min   = ite(delta_min_idx)
     712            0 :       jne_min   = jne(delta_min_idx)
     713            0 :       logT_min   = logT(delta_min_idx)
     714            0 :       logRho_min = logRho(delta_min_idx)
     715            0 :       if (logT_min <= logT_cntr .and. logRho_min <= logRho_cntr) then
     716            0 :         ii_min = 2
     717            0 :         jj_min = 2
     718            0 :       else if (logT_min < logT_cntr .and. logRho_min > logRho_cntr) then
     719            0 :         ii_min = 2  !3
     720            0 :         jj_min = 3  !2
     721            0 :       else if (logT_min > logT_cntr .and. logRho_min < logRho_cntr) then
     722            0 :         ii_min = 3
     723            0 :         jj_min = 2
     724            0 :       else if (logT_min > logT_cntr .and. logRho_min > logRho_cntr) then
     725            0 :         ii_min = 3
     726            0 :         jj_min = 3
     727              :       end if
     728              : 
     729            0 :       offset1 = 0
     730            0 :       offset2 = 0
     731            0 :       missing_point = 1
     732              :       tries = 0
     733              :       retry = .true.
     734            0 :       do while (retry)  !If (T,Rho)_cell lies to close to the edge of the OP mono grid (in Rho), shift the 4x4 grid up/down by 1 in jne.
     735            0 :       missing_point = 1
     736            0 :       retry = .false.
     737            0 :       do jj=1,4
     738            0 :             do ii=1,4
     739            0 :               dite = (ii - ii_min + offset1)*ite_step
     740            0 :               djne = (jj - jj_min + offset2)*jne_step
     741            0 :              do i =imin,imax
     742            0 :                ite_i = ite(i)
     743            0 :                jne_i = jne(i)
     744              : 
     745            0 :                 if (ite_i == ite_min +  dite .and. jne_i == jne_min + djne) THEN
     746            0 :                   logT_grid(ii,jj) = logT(i)
     747            0 :                   logRho_grid(ii,jj) = logRho(i)
     748            0 :                   i_grid(ii,jj) = i
     749              : 
     750            0 :                   missing_point(ii,jj) = 0
     751              :                 end if
     752              :               end do
     753              :             end do
     754              :       end do
     755              : 
     756            0 :       if (SUM(missing_point) > 0) then
     757            0 :         retry = .true.
     758            0 :         if (SUM(missing_point(2:4,1:3)) == 0) then
     759            0 :           offset1 = offset1 + 1
     760            0 :           offset2 = offset2 - 1
     761            0 :         else if (SUM(missing_point(1:3,1:3)) == 0) then
     762            0 :           offset1 = offset1 - 1
     763            0 :           offset2 = offset2 - 1
     764            0 :         else if (SUM(missing_point(2:4,2:4)) == 0) then
     765            0 :           offset1 = offset1 + 1
     766            0 :           offset2 = offset2 + 1
     767            0 :         else if (SUM(missing_point(1:3,2:4)) == 0) then
     768            0 :           offset1 = offset1 - 1
     769            0 :           offset2 = offset2 + 1
     770              :         else
     771            0 :           if (ii_min == 3 .and. jj_min == 2) then
     772            0 :             offset1 = offset1 + 2
     773            0 :             offset2 = offset2 - 2
     774            0 :           else if (ii_min == 2 .and. jj_min == 3) then
     775            0 :             offset1 = offset1 - 2
     776            0 :             offset2 = offset2 + 2
     777            0 :           else if (ii_min == 2 .and. jj_min == 2) then
     778            0 :             offset1 = offset1 - 2
     779            0 :             offset2 = offset2 - 2
     780            0 :           else if (ii_min == 3 .and. jj_min == 3) then
     781            0 :             offset1 = offset1 + 2
     782            0 :             offset2 = offset2 - 1
     783              :           end if
     784              :         end if
     785              :       end if
     786              : 
     787              : 
     788              : 
     789            0 :       if (tries > 4) THEN  ! To prevent loop from getting stuck.
     790            0 :         write(*,*) 'Cannot find points for interpolation compute_kappa', &
     791            0 :                     k, ite_min, jne_min, logT_min, logRho_min,logT_cntr, logRho_cntr, &
     792            0 :                     missing_point, ii_min, jj_min, offset1, offset2,imin, imax, log_amu_mix_cell
     793            0 :         ierr = 1
     794              :         return
     795              :       end if
     796            0 :       tries = tries + 1
     797              :       end do
     798              : 
     799              : 
     800              :       !!! Compute the monochromatic cross-section for the local mixture.
     801            0 :       allocate(sig_mix_cell(4,4,nptot),sig_int(nptot-1), stat=ierr)
     802              : 
     803              : 
     804            0 :       sig_mix_cell = 0d0
     805            0 :       do jj=1,4
     806            0 :         do ii=1,4
     807            0 :               ik = i_grid(ii,jj)
     808            0 :               do m=1,nptot
     809            0 :                  sig_mix_cell(ii,jj,m) = dot_product(fk,sig(:,ik,m))
     810              :               end do
     811              :         end do
     812              :       end do
     813              : 
     814              :       !!! Compute the Rossland mean cross-section by integrating over variable v (mesh equally spaced in v).
     815            0 :       sig_Ross = 0d0
     816            0 :       do jj=1,4
     817            0 :         do ii=1,4
     818            0 :               sig_int = (1/sig_mix_cell(ii,jj,1:nptot-1) + 1/sig_mix_cell(ii,jj,2:nptot))/2.0d0 * dv  !(1:nptot-1) inv_sig_mix_cell(ii,jj,1:nptot-1) + inv_sig_mix_cell(ii,jj,2:nptot)
     819            0 :               do m=1, nptot-1
     820            0 :                 sig_Ross(ii,jj) = sig_Ross(ii,jj) + sig_int(m)
     821              :               end do
     822              :         end do
     823              :       end do
     824              : 
     825            0 :       lkap_Ross =  log10_bohr_radius_sqr - log_amu_mix_cell - log10(sig_Ross)
     826              : 
     827              : 
     828            0 :       call rossl_interpolator% initialize()
     829            0 :       do jj = 1, 4
     830            0 :          do ii = 1, 4
     831            0 :             call rossl_interpolator% add_point(logT_grid(ii,jj), logRho_grid(ii,jj), lkap_Ross(ii,jj))
     832              :          end do
     833              :       end do
     834              : 
     835            0 :       lkap_ross_cell  = rossl_interpolator% evaluate(logT_cntr,logRho_cntr)
     836            0 :       dlnkap_rad_dlnT = rossl_interpolator% evaluate_deriv(logT_cntr,logRho_cntr, .true., .false.)
     837            0 :       dlnkap_rad_dlnRho = rossl_interpolator% evaluate_deriv(logT_cntr, logRho_cntr, .false., .true.)
     838              : 
     839              : 
     840            0 :       deallocate(sig_mix_cell,sig_int)
     841              : 
     842            0 :       end subroutine compute_kappa
     843              : 
     844              : 
     845              : 
     846              :       !!! Compute the Rossland opacity for the entire OP mono data set given a mixture.
     847            0 :       subroutine compute_kappa_grid(fk,lkap_ross_pcg, ierr,ite,jne,epatom,amamu,sig)
     848              :         ! OP mono data for: H, C, N, O, Ne, Na, Mg, Al, Si, S, Ar, Ca, Cr, Mn, Fe, and Ni.
     849            0 :       use chem_def, only: chem_isos, ih1, ihe3, ihe4, ic12, in14, io16, ine20, ina23, &
     850              :                           img24, ial27, isi28, is32, iar40, ica40, icr52, imn55, ife56, ini58
     851              :       use interp_2d_lib_sg
     852              :       use cubic_interpolator, only: interpolator
     853              : 
     854              :       integer, intent(inout) :: ierr
     855              :       real(dp), intent(in) :: fk(:)
     856              :       integer :: nel, nptot
     857              :       parameter(nel = 17, nptot = 10000)  !number of elements and number of u-mesh points.
     858              :       real(dp), pointer, intent(out) :: lkap_ross_pcg(:)  !, fk_pcg(:)
     859              :       real(dp) :: logT_pcg(1648), logRho_pcg(1648)
     860              : 
     861              :       integer , pointer :: ite(:),jne(:)
     862              :       real(dp), pointer :: sig(:,:,:)  !, ak_f(:,:)
     863              :       real(dp), pointer :: epatom(:,:),amamu(:)
     864              :       integer :: imin, imax
     865              : 
     866              :       integer :: n, ke, nz, id, m, ik, i
     867              : 
     868            0 :       real(dp):: epa_mix_cell(1648), amu_mix_cell  ! Number of electrons per atom, mean molecular weight, density and temperature as a function of ite (temp index) and jne (density index) from the OP mono data.
     869              :       real(dp) :: lgamm_cell(nel)  !interpolated log kappa Rossland and log gamma_k in each cell (k = element index).
     870              :       real(dp), parameter :: dv = diff_v/nptot  !v(u(1)) - v(u(nptot))/nptot
     871            0 :       real(dp) :: mH
     872              : 
     873              :       !!!! For interpolator.
     874              :       integer ::  delta_min_idx
     875              : 
     876            0 :       real(dp) :: sig_Ross(1648)  ! Rossland cross section, log kappa, gamma_k, log gamma_k for interpolation.
     877              : 
     878            0 :       real, allocatable :: sig_mix_cell(:,:),sig_int(:)
     879            0 :       real(dp) :: log_amu_mix_cell
     880              : 
     881              :       type(interpolator) :: rossl_interpolator
     882              : 
     883            0 :       ierr = 0
     884              : 
     885              :       !!! Compute an estimated temperature range.
     886            0 :       imin = 1
     887            0 :       imax = 1648
     888              : 
     889              :       !!! Compute the number of electrons per atom for the local mixture.
     890              :       epa_mix_cell = 0d0
     891            0 :       do i=imin,imax
     892              :           epa_mix_cell(i) = dot_product(fk,epatom(1:nel,i))
     893              :       end do
     894              : 
     895            0 :       amu_mix_cell = dot_product(fk,amamu)
     896              : 
     897            0 :       mH = chem_isos% W(ih1) * 1.660538782d-24
     898            0 :       log_amu_mix_cell = log10(amu_mix_cell * mH)
     899              : 
     900              :       !!! Compute the monochromatic cross-section for the local mixture.
     901            0 :       allocate(sig_mix_cell(1648,nptot),sig_int(nptot-1), stat=ierr)
     902            0 :       sig_mix_cell = 0d0
     903            0 : !$OMP PARALLEL DO PRIVATE(i,m) SCHEDULE(guided)
     904              : 
     905              :           do i=1,1648
     906              :               do m=1,nptot
     907              :               sig_mix_cell(i,m) = dot_product(fk,sig(:,i,m))
     908              :               end do
     909              :           end do
     910              : !$OMP END PARALLEL DO
     911              : 
     912              :       !!! Compute the Rossland mean cross-section by integrating over variable v (mesh equally spaced in v).
     913            0 :       sig_Ross = 0
     914            0 : !$OMP PARALLEL DO PRIVATE(i,m,sig_int) SCHEDULE(guided)
     915              :         do i=1,1648
     916              :               sig_int(1:nptot-1) = (1/sig_mix_cell(i,1:nptot-1) + 1/sig_mix_cell(i,2:nptot))/2.0d0 * dv
     917              :               ! inv_sig_mix_cell(ii,jj,1:nptot-1) + inv_sig_mix_cell(ii,jj,2:nptot)
     918              :               do m=1, nptot-1
     919              :                 sig_Ross(i) = sig_Ross(i) + sig_int(m)
     920              :               end do
     921              :         end do
     922              : !$OMP END PARALLEL DO
     923              : 
     924            0 :       deallocate(sig_mix_cell,sig_int)
     925              : 
     926              :       logT_pcg   = 0.025d0*ite
     927              :       logRho_pcg = 0.25d0*jne + log10(amu_mix_cell) - log10(epa_mix_cell) - logNa
     928            0 :       allocate(lkap_ross_pcg(1648),stat=ierr)
     929            0 :       lkap_ross_pcg =  log10_bohr_radius_sqr - log_amu_mix_cell - log10(sig_Ross)
     930              : 
     931            0 :       end subroutine compute_kappa_grid
     932              : 
     933              : 
     934              :       !!! Routine to compute Rossland opacity from a precomputed grid of the entire OP mono data.
     935            0 :       subroutine compute_kappa_fast(k, fk, logT_cntr, logRho_cntr, lkap_ross_cell, dlnkap_rad_dlnT, dlnkap_rad_dlnRho, &
     936              :                                     ierr,ite,jne,epatom,amamu,sig,lkap_ross_pcg)
     937              :         ! OP mono data for: H, C, N, O, Ne, Na, Mg, Al, Si, S, Ar, Ca, Cr, Mn, Fe, and Ni.
     938            0 :       use chem_def, only: chem_isos, ih1, ihe3, ihe4, ic12, in14, io16, ine20, ina23, &
     939              :                           img24, ial27, isi28, is32, iar40, ica40, icr52, imn55, ife56, ini58
     940              :       use cubic_interpolator, only: interpolator
     941              : 
     942              :       integer, intent(inout) :: ierr
     943              :       integer, intent(in) :: k
     944              :       real(dp), intent(in) :: fk(:), logT_cntr, logRho_cntr
     945              :       real(dp), pointer, intent(in) :: lkap_ross_pcg(:)
     946              :       integer :: nel, nptot
     947              :       parameter(nel = 17, nptot = 10000)  !number of elements and number of u-mesh points.
     948              :       real(dp), intent(out) :: lkap_ross_cell, dlnkap_rad_dlnT, dlnkap_rad_dlnRho
     949              :       integer , pointer :: ite(:),jne(:)
     950              :       real(dp), pointer :: sig(:,:,:)
     951              :       real(dp), pointer :: epatom(:,:),amamu(:)
     952              : 
     953              :       integer :: n, ke, nz, id, m, ik, i
     954              : 
     955            0 :       real(dp):: epa_mix_cell(1648), amu_mix_cell  ! Number of electrons per atom, mean molecular weight, density and temperature as a function of ite (temp index) and jne (density index) from the OP mono data.
     956            0 :       real(dp) :: delta(1648)
     957              :       real(dp) :: lgamm_cell(nel)  !interpolated log kappa Rossland and log gamma_k in each cell (k = element index).
     958              :       real(dp), parameter :: dv = diff_v/nptot  !v(u(1)) - v(u(nptot))/nptot
     959              :       real(dp) :: mH
     960              : 
     961              :       !!!! For interpolator.
     962              :       integer ::  delta_min_idx
     963            0 :       real(dp) :: lkap_Ross(4,4),sig_Ross(4,4)  ! Rossland cross section, log kappa, gamma_k, log gamma_k for interpolation.
     964              :       real(dp) :: sf, flux  !'scale factor' for g_rad, local flux.
     965              : 
     966              :       integer :: ii, jj, ite_min, jne_min, ii_min, jj_min, ite_step, jne_step
     967              :       integer :: ite_i, jne_i, dite, djne, i_grid(4,4)
     968            0 :       real(dp) :: logT_min, logRho_min, logT_grid(4,4), logRho_grid(4,4)
     969              :       integer ::  offset1, offset2, tries, missing_point(4,4)
     970              :       real(dp) :: log_amu_mix_cell
     971              :       integer :: imin, imax
     972            0 :       real(dp) :: logT(1648), logRho(1648)  !, ite_grid(4,4), jne_grid(4,4)
     973              :       logical :: retry, do_difficult_point
     974              : 
     975              :       type(interpolator) :: rossl_interpolator
     976              : 
     977            0 :       ierr = 0
     978              : 
     979            0 :       imin = 1
     980            0 :       imax = 1648
     981              : 
     982              :       !!! Compute the number of electrons per atom for the local mixture.
     983            0 :       epa_mix_cell = 0d0
     984            0 :         do i=imin,imax
     985            0 :           epa_mix_cell(i) = dot_product(fk,epatom(:,i))
     986              :         end do
     987              : 
     988            0 :       amu_mix_cell = dot_product(fk,amamu)
     989              : 
     990            0 :       logT   = 0.025d0*ite
     991            0 :       logRho = 0.25d0*jne + log10(amu_mix_cell) - log10(epa_mix_cell) - logNa
     992              : 
     993              :       imin = 1
     994              :       imax = 1648
     995            0 :       ite_step = 2
     996            0 :       jne_step = 2
     997              : 
     998              :       !!! Select nearest points in logT,logRho for interpolation.
     999              :       !!! First, find the nearest OP data point, and check which of the four possible positionings this minimum has wrt to (T,Rho)_cell.
    1000              :       !!! Acquire the remaining 15 points of the 4x4 grid, where (T,Rho)_cell is located in the inner square.
    1001              : 
    1002            0 :       delta = sqrt((logRho - logRho_cntr)*(logRho - logRho_cntr)/0.25d0 +(logT-logT_cntr)*(logT-logT_cntr)/0.025d0)
    1003              : 
    1004            0 :       delta_min_idx = MINLOC(delta, DIM=1)
    1005              :       !delta_min(1)     = MINVAL(delta)(1)
    1006            0 :       ite_min   = ite(delta_min_idx)
    1007            0 :       jne_min   = jne(delta_min_idx)
    1008            0 :       logT_min   = logT(delta_min_idx)
    1009            0 :       logRho_min = logRho(delta_min_idx)
    1010            0 :       if (logT_min <= logT_cntr .and. logRho_min <= logRho_cntr) then
    1011            0 :         ii_min = 2
    1012            0 :         jj_min = 2
    1013            0 :       else if (logT_min < logT_cntr .and. logRho_min > logRho_cntr) then
    1014            0 :         ii_min = 2  !3
    1015            0 :         jj_min = 3  !2
    1016            0 :       else if (logT_min > logT_cntr .and. logRho_min < logRho_cntr) then
    1017            0 :         ii_min = 3
    1018            0 :         jj_min = 2
    1019            0 :       else if (logT_min > logT_cntr .and. logRho_min > logRho_cntr) then
    1020            0 :         ii_min = 3
    1021            0 :         jj_min = 3
    1022              :       end if
    1023              : 
    1024              : 
    1025            0 :       offset1 = 0
    1026            0 :       offset2 = 0
    1027            0 :       missing_point = 1
    1028              :       tries = 0
    1029              :       retry = .true.
    1030            0 :       do while (retry)  !If (T,Rho)_cell lies to close to the edge of the OP mono grid (in Rho), shift the 4x4 grid up/down by 1 in jne.
    1031            0 :       missing_point = 1
    1032            0 :       retry = .false.
    1033            0 :       do jj=1,4
    1034            0 :             do ii=1,4
    1035            0 :               dite = (ii - ii_min + offset1)*ite_step  !(ii - ii_min)*ite_step + offset2
    1036            0 :               djne = (jj - jj_min + offset2)*jne_step  !(jj - jj_min)*jne_step + offset1
    1037            0 :              do i =imin,imax
    1038            0 :                ite_i = ite(i)
    1039            0 :                jne_i = jne(i)
    1040              : 
    1041            0 :                 if (ite_i == ite_min +  dite .and. jne_i == jne_min + djne) THEN
    1042            0 :                   logT_grid(ii,jj) = logT(i)
    1043            0 :                   logRho_grid(ii,jj) = logRho(i)
    1044            0 :                   i_grid(ii,jj) = i
    1045            0 :                   missing_point(ii,jj) = 0
    1046              : 
    1047              :                 end if
    1048              :               end do
    1049              :             end do
    1050              :       end do
    1051              : 
    1052            0 :       if (SUM(missing_point) > 0) then
    1053            0 :         retry = .true.
    1054            0 :         if (SUM(missing_point(2:4,1:3)) == 0) then
    1055            0 :           offset1 = offset1 + 1
    1056            0 :           offset2 = offset2 - 1
    1057            0 :         else if (SUM(missing_point(1:3,1:3)) == 0) then
    1058            0 :           offset1 = offset1 - 1
    1059            0 :           offset2 = offset2 - 1
    1060            0 :         else if (SUM(missing_point(2:4,2:4)) == 0) then
    1061            0 :           offset1 = offset1 + 1
    1062            0 :           offset2 = offset2 + 1
    1063            0 :         else if (SUM(missing_point(1:3,2:4)) == 0) then
    1064            0 :           offset1 = offset1 - 1
    1065            0 :           offset2 = offset2 + 1
    1066              :         else
    1067            0 :           if (ii_min == 3 .and. jj_min == 2) then
    1068            0 :             offset1 = offset1 + 2
    1069            0 :             offset2 = offset2 - 2
    1070            0 :           else if (ii_min == 2 .and. jj_min == 3) then
    1071            0 :             offset1 = offset1 - 2
    1072            0 :             offset2 = offset2 + 2
    1073            0 :           else if (ii_min == 2 .and. jj_min == 2) then
    1074            0 :             offset1 = offset1 - 2
    1075            0 :             offset2 = offset2 - 2
    1076            0 :           else if (ii_min == 3 .and. jj_min == 3) then
    1077            0 :             offset1 = offset1 + 2
    1078            0 :             offset2 = offset2 - 1
    1079              :           end if
    1080              : 
    1081              :         end if
    1082              :       end if
    1083              : 
    1084            0 :       if (tries > 2) THEN  ! To prevent loop from getting stuck.
    1085            0 :         do_difficult_point = .false.
    1086            0 :         if (ite_min == 226 .and. jne_min == 90 .and. ii_min == 2 .and. jj_min == 3) do_difficult_point = .true.
    1087            0 :         if (ite_min == 226 .and. jne_min == 88 .and. ii_min == 2 .and. jj_min == 2) do_difficult_point = .true.
    1088            0 :         if (ite_min == 230 .and. jne_min == 88 .and. ii_min == 3 .and. jj_min == 2) do_difficult_point = .true.
    1089            0 :         if (ite_min == 230 .and. jne_min == 90 .and. ii_min == 3 .and. jj_min == 3) do_difficult_point = .true.
    1090              : 
    1091            0 :         if (do_difficult_point) then
    1092            0 :            do jj=1,4
    1093            0 :              do ii =1,4
    1094            0 :                dite = (ii - ii_min)*2*ite_step
    1095            0 :                djne = (jj - jj_min - 1)*jne_step
    1096            0 :                do i=imin,imax
    1097            0 :                  ite_i = ite(i)
    1098            0 :                  jne_i = jne(i)
    1099            0 :                  if (ite_i == ite_min + dite .and. jne_i == jne_min + djne) then
    1100            0 :                    logT_grid(ii,jj) = logT(i)
    1101            0 :                    logRho_grid(ii,jj) = logRho(i)
    1102            0 :                    i_grid(ii,jj) = i
    1103              :                  end if
    1104              :                end do
    1105              :               end do
    1106              :              end do
    1107              :              retry = .false.
    1108              :          else
    1109            0 :         write(*,*) 'Cannot find points for interpolation compute_kappa_fast', &
    1110            0 :                     k, ite_min, jne_min, logT_min, logRho_min,logT_cntr, logRho_cntr, &
    1111            0 :                     missing_point, ii_min, jj_min, offset1, offset2,imin, imax
    1112            0 :         ierr = 1
    1113              :         return
    1114              :         !stop
    1115              :         end if
    1116              :       end if
    1117            0 :       tries = tries + 1
    1118              :       end do
    1119              : 
    1120            0 :       do jj=1,4
    1121            0 :         do ii=1,4
    1122            0 :           ik = i_grid(ii,jj)
    1123            0 :           lkap_Ross(ii,jj) = lkap_ross_pcg(ik)
    1124              :         end do
    1125              :       end do
    1126              : 
    1127            0 :       call rossl_interpolator% initialize()
    1128            0 :       do jj = 1, 4
    1129            0 :          do ii = 1, 4
    1130            0 :             call rossl_interpolator% add_point(logT_grid(ii,jj), logRho_grid(ii,jj), lkap_Ross(ii,jj))
    1131              :          end do
    1132              :       end do
    1133              : 
    1134            0 :       lkap_ross_cell  = rossl_interpolator% evaluate(logT_cntr,logRho_cntr)
    1135            0 :       dlnkap_rad_dlnT = rossl_interpolator% evaluate_deriv(logT_cntr, logRho_cntr, .true., .false.)
    1136            0 :       dlnkap_rad_dlnRho = rossl_interpolator% evaluate_deriv(logT_cntr, logRho_cntr, .false., .true.)
    1137              : 
    1138            0 :       end subroutine compute_kappa_fast
    1139              : 
    1140              : 
    1141              :       !!! Interpolate Rossland opacity and derivatives from a 4x4 grid computed last time step.
    1142            0 :       subroutine interpolate_kappa(k, logT_cntr, logRho_cntr,lkap_ross_cell, dlnkap_rad_dlnT, dlnkap_rad_dlnRho, &
    1143              :                                    ierr,logT_grid, logRho_grid, lkap_grid)
    1144              : 
    1145            0 :       use cubic_interpolator, only: interpolator
    1146              : 
    1147              :       integer, intent(inout) :: ierr
    1148              :       integer, intent(in) :: k
    1149              :       real(dp), intent(in) :: logT_cntr, logRho_cntr
    1150              :       real(dp), intent(in) :: logT_grid(4,4), logRho_grid(4,4), lkap_grid(4,4)
    1151              :       real(dp), intent(out) :: lkap_ross_cell, dlnkap_rad_dlnT, dlnkap_rad_dlnRho
    1152              : 
    1153              :       integer :: ii,jj
    1154              : 
    1155              :       type(interpolator) :: rossl_interpolator
    1156              : 
    1157            0 :       ierr = 0
    1158              : 
    1159            0 :       call rossl_interpolator% initialize()
    1160            0 :       do jj = 1, 4
    1161            0 :          do ii = 1, 4
    1162            0 :             call rossl_interpolator% add_point(logT_grid(ii,jj), logRho_grid(ii,jj), lkap_grid(ii,jj))
    1163              :          end do
    1164              :       end do
    1165              : 
    1166            0 :       lkap_ross_cell  = rossl_interpolator% evaluate(logT_cntr,logRho_cntr)
    1167            0 :       dlnkap_rad_dlnT = rossl_interpolator% evaluate_deriv(logT_cntr,logRho_cntr, .true., .false.)
    1168            0 :       dlnkap_rad_dlnRho = rossl_interpolator% evaluate_deriv(logT_cntr,logRho_cntr, .false., .true.)
    1169              : 
    1170            0 :       end subroutine interpolate_kappa
    1171              :       end module op_eval_mombarg
        

Generated by: LCOV version 2.0-1