LCOV - code coverage report
Current view: top level - atm/private - table_atm.f90 (source / functions) Coverage Total Hit
Test: coverage.info Lines: 65.6 % 366 240
Test Date: 2025-05-08 18:23:42 Functions: 100.0 % 8 8

            Line data    Source code
       1              : ! ***********************************************************************
       2              : !
       3              : !   Copyright (C) 2010-2019  The MESA Team
       4              : !
       5              : !   This program is free software: you can redistribute it and/or modify
       6              : !   it under the terms of the GNU Lesser General Public License
       7              : !   as published by the Free Software Foundation,
       8              : !   either version 3 of the License, or (at your option) any later version.
       9              : !
      10              : !   This program is distributed in the hope that it will be useful,
      11              : !   but WITHOUT ANY WARRANTY; without even the implied warranty of
      12              : !   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
      13              : !   See the GNU Lesser General Public License for more details.
      14              : !
      15              : !   You should have received a copy of the GNU Lesser General Public License
      16              : !   along with this program. If not, see <https://www.gnu.org/licenses/>.
      17              : !
      18              : ! ***********************************************************************
      19              : 
      20              :       module table_atm
      21              :       use atm_def
      22              :       use const_def, only: dp
      23              :       use math_lib
      24              :       use utils_lib, only: mesa_error
      25              : 
      26              :       implicit none
      27              : 
      28              :       logical, parameter :: dbg = .false.
      29              : 
      30              :       contains
      31              : 
      32              :       !reads in table_summary file from atm_data, initializes logZ, Teff_array,
      33              :       ! logg_array, and Teff_bound arrays; sets some flags
      34            3 :       subroutine table_atm_init(use_cache, ierr)
      35              :          logical, intent(in) :: use_cache
      36              :          integer, intent(out) :: ierr
      37              : 
      38              :          integer :: nZ, ng, nT, i, j, iounit
      39            3 :          integer, pointer :: ibound(:,:), tmp_version(:)
      40              :          character(len=256) :: filename
      41              : 
      42            3 :          if (table_atm_is_initialized) call table_atm_shutdown()
      43              : 
      44              :          ierr = 0
      45              : 
      46            3 :          call load_table_summary(ATM_TABLE_PHOTOSPHERE, 'table_summary.txt', ai_two_thirds, ierr)
      47            3 :          if (ierr /= 0) return
      48            3 :          call load_table_summary(ATM_TABLE_TAU_100, 'table100_summary.txt', ai_100, ierr)
      49            3 :          if (ierr /= 0) return
      50            3 :          call load_table_summary(ATM_TABLE_TAU_10, 'table10_summary.txt', ai_10, ierr)
      51            3 :          if (ierr /= 0) return
      52            3 :          call load_table_summary(ATM_TABLE_TAU_1, 'table1_summary.txt', ai_1, ierr)
      53            3 :          if (ierr /= 0) return
      54            3 :          call load_table_summary(ATM_TABLE_TAU_1M1, 'table1m1_summary.txt', ai_1m1, ierr)
      55            3 :          if (ierr /= 0) return
      56            3 :          call load_table_summary(ATM_TABLE_WD_TAU_25, 'table_wd_25_summary.txt', ai_wd_25, ierr)
      57            3 :          if (ierr /= 0) return
      58            3 :          call load_table_summary(ATM_TABLE_DB_WD_TAU_25, 'table_db_wd_25_summary.txt', ai_db_wd_25, ierr)
      59            3 :          if (ierr /= 0) return
      60              : 
      61            3 :          table_atm_is_initialized = .true.
      62              : 
      63              : 
      64              :          contains
      65              : 
      66              : 
      67           21 :          subroutine load_table_summary(id, fname, ai, ierr)
      68              :             use const_def, only: mesa_data_dir
      69              :             integer, intent(in) :: id
      70              :             character(len=*), intent(in) :: fname
      71              :             type(atm_info), intent(inout) :: ai
      72              :             integer, intent(out) :: ierr
      73              : 
      74          441 :             real(dp), target :: vec_ary(20)
      75           21 :             real(dp), pointer :: vec(:)
      76              : 
      77           21 :             vec => vec_ary
      78              : 
      79           21 :             filename = trim(mesa_data_dir)//'/atm_data/' // trim(fname)
      80              : 
      81              :             if (dbg) write(*,*) 'read ' // trim(filename)
      82              : 
      83           21 :             open(newunit=iounit,file=trim(filename),action='read',status='old',iostat=ierr)
      84           21 :             if (ierr/= 0) then
      85            0 :                write(*,*) 'table_atm_init: missing atm data'
      86            0 :                write(*,*) trim(filename)
      87            0 :                write(*,'(A)')
      88            0 :                write(*,'(A)')
      89            0 :                write(*,'(A)')
      90            0 :                write(*,'(A)')
      91            0 :                write(*,'(A)')
      92            0 :                write(*,*) 'FATAL ERROR: missing or bad atm data.'
      93            0 :                write(*,*) 'Please update by removing the directory mesa/data/atm_data,'
      94            0 :                write(*,*) 'and rerunning the mesa ./install script.'
      95            0 :                write(*,'(A)')
      96            0 :                call mesa_error(__FILE__,__LINE__)
      97              :             end if
      98              : 
      99              :             !read first line and (nZ, nT, ng)
     100           21 :             read(iounit,*)            !first line is text, skip it
     101           21 :             read(iounit,*) nZ, nT, ng
     102              : 
     103           21 :             ai% nZ = nZ
     104           21 :             ai% nT = nT
     105           21 :             ai% ng = ng
     106           21 :             ai% id = id
     107              : 
     108              :             allocate( &
     109              :                ai% Teff_array(nT), ai% logg_array(ng), ai% Teff_bound(ng), &
     110              :                ai% logZ(nZ), ai% alphaFe(nZ), &
     111              :                ai% Pgas_interp1(4*ng*nT*nZ), ai% T_interp1(4*ng*nT*nZ), &
     112           21 :                ai% have_atm_table(nZ), ai% atm_mix(nZ), ai% table_atm_files(nZ))
     113              : 
     114           21 :             ai% Pgas_interp(1:4,1:ng,1:nT,1:nZ) => ai% Pgas_interp1(1:4*ng*nT*nZ)
     115           21 :             ai% T_interp(1:4,1:ng,1:nT,1:nZ) => ai% T_interp1(1:4*ng*nT*nZ)
     116              : 
     117           21 :             allocate(ibound(ng,nZ), tmp_version(nZ))
     118              : 
     119           63 :             ai% have_atm_table(:) = .false.
     120              : 
     121              :             !read filenames and headers
     122           21 :             read(iounit,*)            !text
     123           63 :             do i=1,nZ
     124           42 :                read(iounit,'(a)') ai% table_atm_files(i)
     125           42 :                read(iounit,'(14x,i4)') tmp_version(i)
     126           63 :                read(iounit,1) ai% logZ(i), ai% alphaFe(i), ai% atm_mix(i), ibound(1:ng,i)
     127              :             end do
     128              : 
     129              :             !read Teff_array
     130           21 :             read(iounit,*)            !text
     131           21 :             read(iounit,2) ai% Teff_array(:)
     132              : 
     133              :             !read logg_array
     134           21 :             read(iounit,*)            !text
     135           21 :             read(iounit,3) ai% logg_array(:)
     136              : 
     137           21 :             close(iounit)
     138              : 
     139              :  1          format(13x,f5.2,8x,f4.1,1x,a8,1x,15x,99i4)
     140              :  2          format(13f7.0)
     141              :  3          format(13f7.2)
     142              : 
     143              :             !determine table boundaries
     144          393 :             do i=1,ng                 ! -- for each logg, smallest Teff at which Pgas->0
     145          372 :                ai% Teff_bound(i) = ai% Teff_array(ibound(i,1))
     146          666 :                do j=2,nZ
     147          645 :                   ai% Teff_bound(i) = min( ai% Teff_bound(i) , ai% Teff_array(ibound(i,j)) )
     148              :                end do
     149              :             end do
     150              : 
     151              : 
     152              :             if (dbg) write(*,*) 'ai% logg_array(:)', ai% logg_array(:)
     153              : 
     154              : 
     155           21 :             deallocate(ibound, tmp_version)
     156              : 
     157           21 :          end subroutine load_table_summary
     158              : 
     159              : 
     160              :       end subroutine table_atm_init
     161              : 
     162              : 
     163            1 :       subroutine table_atm_shutdown()
     164              : 
     165            1 :          if (.NOT. table_atm_is_initialized) return
     166              : 
     167            1 :          call free_table_summary(ai_two_thirds)
     168            1 :          call free_table_summary(ai_100)
     169            1 :          call free_table_summary(ai_10)
     170            1 :          call free_table_summary(ai_1)
     171            1 :          call free_table_summary(ai_1m1)
     172            1 :          call free_table_summary(ai_wd_25)
     173            1 :          call free_table_summary(ai_db_wd_25)
     174              : 
     175            1 :          table_atm_is_initialized = .false.
     176              : 
     177              :        contains
     178              : 
     179            7 :          subroutine free_table_summary(ai)
     180              : 
     181              :             type(atm_info), intent(inout) :: ai
     182              : 
     183            0 :             deallocate( &
     184            0 :                ai% Teff_array, ai% logg_array, ai% Teff_bound, &
     185            0 :                ai% logZ, ai% alphaFe, &
     186            0 :                ai% Pgas_interp1, ai% T_interp1, &
     187            7 :                ai% have_atm_table, ai% atm_mix, ai% table_atm_files)
     188              : 
     189            7 :           end subroutine free_table_summary
     190              : 
     191              :       end subroutine table_atm_shutdown
     192              : 
     193              : 
     194              :       !interpolate in Z, logg, & Teff: 4pt in Z; bicubic spline in Teff,logg
     195           14 :       subroutine get_table_values( &
     196              :             id, newZ, newlogg_in, newTeff_in, &
     197              :             newPgas, dPgas_dTeff, dPgas_dlogg, &
     198              :             newT, dT_dTeff, dT_dlogg, &
     199              :             ierr)
     200              :          use chem_def,only:GN93_Zsol
     201              :          use interp_1d_lib, only: interp_pm, interp_values
     202              :          use interp_1d_def
     203              :          use interp_2d_lib_db, only: interp_evbicub_db
     204              :          use utils_lib, only: is_bad
     205              : 
     206              : 
     207              :          integer, intent(in) :: id
     208              :          real(dp), intent(in) :: newZ, newlogg_in, newTeff_in
     209              :          real(dp), intent(out) :: newPgas, dPgas_dTeff, dPgas_dlogg
     210              :          real(dp), intent(out) :: newT, dT_dTeff, dT_dlogg
     211              :          integer, intent(out) :: ierr
     212              :          integer :: i, j, numZs, nZ, ng, nT, ict(6), Zindex, Zlo, Zhi
     213              :          integer, parameter :: num_res = 3  !number of results (Pgas, dPgas_dTeff, dPgas_dlogg)
     214           42 :          real(dp) :: newlogg, newTeff, newlogZ(1), result_Z(1)
     215          238 :          real(dp), target :: fZ1_ary(4*4)
     216              :          real(dp), pointer :: fZ1(:), fZ(:,:)
     217          798 :          real(dp), target :: work_ary(4*mp_work_size)
     218           14 :          real(dp), pointer :: result_2D(:,:), work(:)
     219              :          character(len=256) :: filename
     220              :          logical :: clip_Teff, clip_logg, gtv_dbg
     221              : 
     222              :          type (Atm_Info), pointer :: ai
     223              : 
     224              :          include 'formats'
     225              : 
     226           14 :          gtv_dbg = dbg
     227              : 
     228           14 :          fZ1 => fZ1_ary
     229           14 :          fZ(1:4,1:4) => fZ1(1:4*4)
     230              : 
     231           14 :          ierr = 0
     232           14 :          work => work_ary
     233              : 
     234              :          ! ensure data have been initialized
     235           14 :          if (.not.table_atm_is_initialized) then
     236            0 :             write(*,*) 'get_table_values: table_atm_init required to proceed'
     237            0 :             ierr=-1
     238            0 :             return
     239              :          end if
     240              : 
     241           14 :          newlogZ(1) = safe_log10(newZ/GN93_Zsol)
     242              : 
     243           16 :          select case (id)
     244              :          case (ATM_TABLE_PHOTOSPHERE)
     245            2 :             ai => ai_two_thirds
     246              :          case (ATM_TABLE_TAU_100)
     247            2 :             ai => ai_100
     248              :          case (ATM_TABLE_TAU_10)
     249            2 :             ai => ai_10
     250              :          case (ATM_TABLE_TAU_1)
     251            2 :             ai => ai_1
     252              :          case (ATM_TABLE_TAU_1M1)
     253            2 :             ai => ai_1m1
     254              :          case (ATM_TABLE_WD_TAU_25)
     255            2 :             ai => ai_wd_25
     256              :          case (ATM_TABLE_DB_WD_TAU_25)
     257            2 :             ai => ai_db_wd_25
     258              :          case default
     259            0 :             write(*,*) 'Invalid id in get_table_values:', id
     260            0 :             ierr = -1
     261           14 :             return
     262              :          end select
     263              : 
     264           14 :          nZ = ai% nZ
     265           14 :          nT = ai% nT
     266           14 :          ng = ai% ng
     267              : 
     268           14 :          clip_Teff = .false.
     269           14 :          if (newTeff_in < ai% Teff_array(1)) then
     270            0 :             newTeff = ai% Teff_array(1)  ! clip to table in T
     271            0 :             clip_Teff = .true.
     272           14 :          else if (newTeff_in > ai% Teff_array(nT)) then
     273            0 :             newTeff = ai% Teff_array(nT)  ! clip to table in T
     274            0 :             clip_Teff = .true.
     275              :          else
     276           14 :             newTeff = newTeff_in
     277              :          end if
     278              : 
     279           14 :          clip_logg = .false.
     280           14 :          if (newlogg_in < ai% logg_array(1)) then
     281            0 :             newlogg = ai% logg_array(1)  ! clip to table in logg
     282            0 :             clip_logg = .true.
     283           14 :          else if (newlogg_in > ai% logg_array(ng)) then
     284            0 :             newlogg = ai% logg_array(ng)  ! clip to table in logg
     285            0 :             clip_logg = .true.
     286              :          else
     287           14 :             newlogg = newlogg_in
     288              :          end if
     289              : 
     290           14 :          allocate(result_2D(6,nZ))
     291              : 
     292           14 :          if (gtv_dbg) write(*,*) 'loaded tables: ', ai% have_atm_table(:)
     293              : 
     294              :          if (.false.) then  !check for Z within range of tables
     295              :             if (nz > 1 .and. (newlogZ(1) < ai% logZ(1) .or. newlogZ(1) > ai% logZ(nZ))) then
     296              :                write(*,*) 'get_table_values: Z outside range of atm tables'
     297              :                ierr=-1
     298              :                return
     299              :             end if
     300           14 :          else if (newlogZ(1) < ai% logZ(1)) then
     301            0 :             newlogZ(1) = ai% logZ(1)
     302           14 :          else if (newlogZ(1) > ai% logZ(nZ)) then
     303           12 :             newlogZ(1) = ai% logZ(nZ)
     304              :          end if
     305              : 
     306              :          !identify surrounding Z values and initialize interpolation
     307           14 :          if (newlogZ(1) <= ai% logZ(1)) then
     308           12 :             Zindex = 1
     309            2 :          else if (newlogZ(1) >= ai% logZ(nz)) then
     310            0 :             Zindex = nz
     311              :          else
     312            2 :             Zindex = nz
     313           16 :             do j=1,nz-1
     314           16 :                if (ai% logZ(j) <= newlogZ(1)) then
     315           14 :                   Zindex = j
     316              :                end if
     317              :             end do
     318              :          end if
     319              : 
     320              :          !identify upper (Zhi) and lower (Zlo) bounds on Z
     321           14 :          Zlo = max( 1,Zindex-1)
     322           14 :          Zhi = min(nZ,Zindex+2)
     323           14 :          if (Zhi-Zlo /= 3) Zlo=max( 1,Zlo-1)
     324           14 :          if (Zhi-Zlo /= 3) Zhi=min(nZ,Zhi+1)
     325           14 :          if (gtv_dbg) write(*,*) 'Zlo, Zindex, Zhi = ', Zlo, Zindex, Zhi
     326           14 :          numZs = Zhi - Zlo + 1
     327              : 
     328              :          !do 2D Teff,logg interpolation on each of 4 Z tables (Zlo-Zhi)
     329              :                  !  P(g,T) dP_dg, dP_dT, d2P_dg2, d2P_dT2, d2P_dg_dT
     330              :                  !    1      2      3       4        5         6
     331           14 :          ict(:) = [  1,     1,     1,      0,       0,        0  ]
     332              : 
     333           14 :          if (gtv_dbg) write(*,*) 'do_interp for Pgas', id
     334           14 :          call do_interp(ai% Pgas_interp1, newPgas, dPgas_dlogg, dPgas_dTeff, ierr)
     335           14 :          if (ierr /= 0) then
     336            0 :             if (gtv_dbg) write(*,*) 'do_interp failed'
     337            0 :             return
     338              :          end if
     339           14 :          if (clip_logg) dPgas_dlogg = 0
     340           14 :          if (clip_Teff) dPgas_dTeff = 0
     341              : 
     342           14 :          if (id == ATM_TABLE_PHOTOSPHERE) then
     343            2 :             newT = newTeff
     344            2 :             if (clip_Teff) then
     345            0 :                dT_dTeff = 0
     346              :             else
     347            2 :                dT_dTeff = 1
     348              :             end if
     349            2 :             dT_dlogg = 0
     350            2 :             return
     351              :          end if
     352              : 
     353           12 :          if (gtv_dbg) write(*,*) 'do_interp for Temp', id
     354           12 :          call do_interp(ai% T_interp1, newT, dT_dlogg, dT_dTeff, ierr)
     355           12 :          if (ierr /= 0) then
     356            0 :             if (gtv_dbg) write(*,*) 'do_interp failed'
     357            0 :             return
     358              :          end if
     359           12 :          if (clip_logg) dT_dlogg = 0
     360           12 :          if (clip_Teff) dT_dTeff = 0
     361              : 
     362           12 :          if (dbg .or. is_bad(newPgas) .or. is_bad(newT)) then
     363            0 :             write(*,1) 'newPgas', newPgas
     364            0 :             write(*,1) 'dPgas_dTeff', dPgas_dTeff
     365            0 :             write(*,1) 'dPgas_dlogg', dPgas_dlogg
     366            0 :             write(*,'(A)')
     367            0 :             write(*,1) 'newT', newT
     368            0 :             write(*,1) 'dT_dTeff', dT_dTeff
     369            0 :             write(*,1) 'dT_dlogg', dT_dlogg
     370            0 :             write(*,'(A)')
     371            0 :             ierr = -1
     372            0 :             return
     373              :             !if (is_bad(newPgas) .or. is_bad(newT)) call mesa_error(__FILE__,__LINE__,'get_table_values')
     374              :          end if
     375              : 
     376              :          !if (dbg) write(*,*) 'loaded tables: ', ai% have_atm_table(:)
     377              : 
     378           40 :          deallocate(result_2D)
     379              : 
     380              :          contains
     381              : 
     382           26 :          subroutine do_interp(f1, newval, dval_dlogg, dval_dTeff, ierr)
     383              :             real(dp), dimension(:), pointer :: f1
     384              :             real(dp), intent(out) :: newval, dval_dlogg, dval_dTeff
     385              :             integer, intent(out) :: ierr
     386              : 
     387          182 :             real(dp) :: res(6)
     388              :             integer :: j
     389           26 :             real(dp), pointer :: f(:)
     390              : 
     391              :             include 'formats'
     392              : 
     393           26 :             ierr = 0
     394              : 
     395           58 :             do i = Zlo, Zhi
     396           32 :                if (.not. ai% have_atm_table(i)) then
     397           20 :                   call load_atm_table(i,ierr)  !<-load on demand
     398              :                end if
     399           32 :                if (ierr /= 0) then
     400            0 :                   if (gtv_dbg) write(*,*) 'load_atm_table failed'
     401            0 :                   return
     402              :                end if
     403              : 
     404           32 :                f(1:4*ng*nT) => f1(1+4*ng*nT*(i-1):4*ng*nT*i)
     405              :                call interp_evbicub_db(newlogg, newTeff, ai% logg_array, ng, ai% Teff_array, nT, &
     406           32 :                   ai% iling, ai% ilinT, f, ng, ict, res, ierr)
     407          224 :                do j=1,6
     408          224 :                   result_2D(j,i) = res(j)
     409              :                end do
     410           90 :                if (ierr /= 0) then
     411            0 :                   if (gtv_dbg) write(*,*) 'interp_evbicub_db failed'
     412            0 :                   if (newlogg < ai% logg_array(1)) then
     413            0 :                      write(*,1) 'logg too small for atm table', newlogg, ai% logg_array(1)
     414              :                   end if
     415            0 :                   if (newlogg > ai% logg_array(ng)) then
     416            0 :                      write(*,1) 'logg too large for atm table', newlogg, ai% logg_array(ng)
     417              :                   end if
     418            0 :                   if (newTeff < ai% Teff_array(1)) then
     419            0 :                      write(*,1) 'Teff too small for atm table', newTeff, ai% Teff_array(1)
     420              :                   end if
     421            0 :                   if (newTeff > ai% Teff_array(ng)) then
     422            0 :                      write(*,1) 'Teff too large for atm table', newTeff, ai% Teff_array(ng)
     423              :                   end if
     424            0 :                   return
     425              :                end if
     426              :             end do
     427              : 
     428              :             ! now we have val, dval_dTeff, and dval_dlogg in result_2D for each Z
     429              : 
     430           26 :             if (numZs == 1) then
     431              : 
     432           24 :                newval = result_2D(1,Zlo)
     433           24 :                dval_dlogg = result_2D(2,Zlo)
     434           24 :                dval_dTeff = result_2D(3,Zlo)
     435              : 
     436              :             else  ! Z interpolation
     437              : 
     438           18 :                fZ(1,1:numZs) = result_2D(1,Zlo:Zhi)
     439            2 :                call interp_pm(ai% logZ(Zlo:Zhi),numZs,fZ1,mp_work_size,work,'atm',ierr)
     440            2 :                if (ierr /= 0) then
     441            0 :                   if (gtv_dbg) write(*,*) 'interp_pm failed for Z interpolation'
     442            0 :                   return
     443              :                end if
     444            2 :                call interp_values(ai% logZ(Zlo:Zhi),numZs,fZ1,1,newlogZ,result_Z(1:1),ierr)
     445            2 :                if (ierr /= 0) then
     446            0 :                   if (gtv_dbg) write(*,*) 'interp_values failed for Z interpolation'
     447            0 :                   return
     448              :                end if
     449            2 :                newval = result_Z(1)
     450              : 
     451           18 :                fZ(1,1:numZs) = result_2D(2,Zlo:Zhi)
     452            2 :                call interp_pm(ai% logZ(Zlo:Zhi),numZs,fZ1,mp_work_size,work,'atm',ierr)
     453            2 :                if (ierr /= 0) then
     454            0 :                   if (gtv_dbg) write(*,*) 'interp_pm failed for Z interpolation of d_dlogg'
     455            0 :                   return
     456              :                end if
     457            2 :                call interp_values(ai% logZ(Zlo:Zhi),numZs,fZ1,1,newlogZ,result_Z(1:1),ierr)
     458            2 :                if (ierr /= 0) then
     459            0 :                   if (gtv_dbg) write(*,*) 'interp_values failed for Z interpolation of d_dlogg'
     460            0 :                   return
     461              :                end if
     462            2 :                dval_dlogg = result_Z(1)
     463              : 
     464           18 :                fZ(1,1:numZs) = result_2D(3,Zlo:Zhi)
     465            2 :                call interp_pm(ai% logZ(Zlo:Zhi),numZs,fZ1,mp_work_size,work,'atm',ierr)
     466            2 :                if (ierr /= 0) then
     467            0 :                   if (gtv_dbg) write(*,*) 'interp_pm failed for Z interpolation of d_dTeff'
     468            0 :                   return
     469              :                end if
     470            2 :                call interp_values(ai% logZ(Zlo:Zhi),numZs,fZ1,1,newlogZ,result_Z(1:1),ierr)
     471            2 :                if (ierr /= 0) then
     472            0 :                   if (gtv_dbg) write(*,*) 'interp_values failed for Z interpolation of d_dTeff'
     473            0 :                   return
     474              :                end if
     475            2 :                dval_dTeff = result_Z(1)
     476              : 
     477              :             end if
     478              : 
     479           40 :          end subroutine do_interp
     480              : 
     481              : 
     482              : 
     483              :          !reads in the iZth atm pressure table and pre-processes it for 2D spline interpolation
     484              :          !optional: reads or writes binary version of the spline table to atm_data/cache
     485           20 :          subroutine load_atm_table(iZ,ierr)
     486              :             use utils_lib
     487              :             use interp_2D_lib_db, only: interp_mkbicub_db
     488              :             use const_def, only: mesa_data_dir
     489              :             integer, intent(in)  :: iZ  !index of Z table to be loaded
     490              :             integer, intent(out) :: ierr
     491           40 :             integer :: iounit, i, j, ibound_tmp(ng), ibcTmin, ibcTmax, ibcgmin, ibcgmax
     492              :             integer :: text_file_version, nvec
     493         2996 :             real(dp) :: Teff_tmp(nT), logg_tmp(ng)
     494        63844 :             real(dp) :: bcTmin(nT), bcTmax(ng), bcgmin(ng), bcgmax(ng), data_tmp(ng,nT)
     495         2020 :             real(dp), target :: vec_ary(100)
     496           20 :             real(dp), pointer :: f1(:), vec(:)
     497              :             character(len=2000) :: buf
     498              : 
     499           20 :             ierr = 0
     500           20 :             vec => vec_ary
     501              : 
     502              :             !read in and process the text files
     503           20 :             filename = trim(mesa_data_dir) // '/atm_data/' // trim(ai% table_atm_files(iZ))
     504           20 :             open(newunit=iounit,file=trim(filename),action='read',status='old',iostat=ierr)
     505           20 :             if (ierr/= 0) then
     506            0 :                write(*,*) 'load_atm_table: missing atm data:'
     507            0 :                write(*,*) trim(filename)
     508            0 :                write(*,'(A)')
     509            0 :                write(*,'(A)')
     510            0 :                write(*,'(A)')
     511            0 :                write(*,'(A)')
     512            0 :                write(*,'(A)')
     513            0 :                write(*,*) 'FATAL ERROR: missing or bad atm data.'
     514            0 :                write(*,*) 'Please update by removing the directory mesa/data/atm_data,'
     515            0 :                write(*,*) 'and rerunning the mesa ./install script.'
     516            0 :                write(*,'(A)')
     517            0 :                call mesa_error(__FILE__,__LINE__)
     518              :             end if
     519              : 
     520           20 :             read(iounit,'(14x,i4)',iostat=ierr) text_file_version
     521           20 :             if (failed(1)) return
     522           20 :             if (text_file_version /= table_atm_version) then
     523            0 :                write(*,*) 'load_atm_table: mismatch in table versions'
     524            0 :                write(*,*) 'expected version ', table_atm_version
     525            0 :                write(*,*) 'received version ', text_file_version
     526            0 :                write(*,'(A)')
     527            0 :                write(*,'(A)')
     528            0 :                write(*,'(A)')
     529            0 :                write(*,'(A)')
     530            0 :                write(*,'(A)')
     531            0 :                write(*,'(A)')
     532            0 :                write(*,*) 'FATAL ERROR: out-of-date version of atm data.'
     533            0 :                write(*,*) 'Please update by removing the directory mesa/data/atm_data,'
     534            0 :                write(*,*) 'and rerunning the mesa ./install script.'
     535            0 :                write(*,'(A)')
     536            0 :                write(*,'(A)')
     537            0 :                call mesa_error(__FILE__,__LINE__)
     538              :             end if
     539              : 
     540          346 :             ibound_tmp = -1
     541           20 :             read(iounit,1,iostat=ierr) ai% logZ(iZ), ai% alphaFe(iZ), ai% atm_mix(iZ), ibound_tmp(1:ng)
     542           20 :             if (ierr /= 0) then
     543            0 :                write(*,*) 'iZ', iZ
     544            0 :                write(*,*) 'ai% logZ(iZ)', ai% logZ(iZ)
     545            0 :                write(*,*) 'ai% alphaFe(iZ)', ai% alphaFe(iZ)
     546            0 :                write(*,*) 'ai% atm_mix(iZ)', ai% atm_mix(iZ)
     547            0 :                do j=1,ng
     548            0 :                   write(*,*) j, ibound_tmp(j)
     549              :                end do
     550            0 :                write(*,'(A)')
     551              :             end if
     552           20 :             if (failed(2)) return
     553           20 :             read(iounit,2,iostat=ierr) logg_tmp(:)
     554           20 :             if (failed(3)) return
     555        60216 :             data_tmp(:,:) = -1
     556         2670 :             do j=1,nT
     557         2650 :                read(iounit,'(a)',iostat=ierr) buf
     558              :                !write(*,*) 'read ierr', ierr
     559         2650 :                if (ierr == 0) then
     560         2650 :                   call str_to_vector(buf, vec, nvec, ierr)
     561              :                   !write(*,*) 'str_to_vector ierr', ierr
     562         2650 :                   if (nvec < ng + 1) ierr = -1
     563              :                   !write(*,*) 'nvec ierr', ierr
     564              :                end if
     565         2650 :                if (ierr /= 0) then
     566            0 :                   write(*,*) 'failed reading Pgas Teff', ai% Teff_array(j)
     567            0 :                   write(*,'(a)') 'buf "' // trim(buf) // '"'
     568            0 :                   write(*,*) 'len_trim(buf)', len_trim(buf)
     569            0 :                   write(*,*) 'nvec', nvec
     570            0 :                   write(*,*) 'ng', ng
     571            0 :                   return
     572              :                   !stop
     573              :                end if
     574         2650 :                if (failed(4)) return
     575         2650 :                Teff_tmp(j) = vec(1)
     576        60216 :                do i=1,ng
     577        60196 :                   data_tmp(i,j) = vec(i+1)
     578              :                end do
     579              :             end do
     580        60216 :             ai% Pgas_interp(1,:,:,iZ) = data_tmp(:,:)
     581              : 
     582           20 :             if (ai% id /= ATM_TABLE_PHOTOSPHERE) then  ! read T
     583           12 :                read(iounit,2,iostat=ierr)  ! skip line
     584           12 :                if (failed(5)) return
     585         2006 :                do j=1,nT
     586         1994 :                   read(iounit,'(a)',iostat=ierr) buf
     587         1994 :                   if (ierr == 0) then
     588         1994 :                      call str_to_vector(buf, vec, nvec, ierr)
     589         1994 :                      if (nvec < ng + 1) ierr = -1
     590              :                   end if
     591         1994 :                   if (ierr /= 0) then
     592            0 :                      write(*,*) 'failed reading T Teff', ai% Teff_array(j)
     593              :                   end if
     594         1994 :                   if (failed(6)) return
     595         1994 :                   Teff_tmp(j) = vec(1)
     596        51024 :                   do i=1,ng
     597        51012 :                      data_tmp(i,j) = vec(i+1)
     598              :                   end do
     599              :                end do
     600        51024 :                ai% T_interp(1,:,:,iZ) = data_tmp(:,:)
     601              :             end if
     602              : 
     603           20 :             close(iounit)
     604              : 
     605              :  1          format(13x,f5.2,8x,f4.1,1x,a8,1x,15x,99i4)
     606              :  2          format(15x,99(9x,f5.2,1x))
     607              :  3          format(99e15.7)
     608              : 
     609              :             !verify that Teff and logg arrays are the same as globals
     610         2670 :             do i=1,nT
     611         2670 :                if (abs(Teff_tmp(i) - ai% Teff_array(i)) > 1d-10*Teff_tmp(i)) then
     612            0 :                   ierr = -1
     613            0 :                   if (gtv_dbg) then
     614            0 :                      write(*,'(a30,i6,e24.12)') 'Teff_tmp(i)', i, Teff_tmp(i)
     615            0 :                      write(*,'(a30,i6,e24.12)') 'ai% Teff_array(i)', i, ai% Teff_array(i)
     616              :                   end if
     617            0 :                   return
     618              :                end if
     619              :             end do
     620              : 
     621          346 :             do i=1,ng
     622              :                !write(*,*) 'logg', i, logg_tmp(i), ai% logg_array(i)
     623          346 :                if (abs(logg_tmp(i) - ai% logg_array(i)) > 1d-10*abs(logg_tmp(i)) ) then
     624            0 :                   ierr=-1
     625            0 :                   if (gtv_dbg) then
     626            0 :                      write(*,'(a30,i6,e24.12)') 'logg_tmp(i)', i, logg_tmp(i)
     627            0 :                      write(*,'(a30,i6,e24.12)') 'ai% logg_array(i)', i, ai% logg_array(i)
     628              :                   end if
     629            0 :                   return
     630              :                end if
     631              :             end do
     632              :             !stop
     633              : 
     634              :             !make sure boundaries set earlier are still valid
     635          346 :             do i=1,ng
     636          346 :                ai% Teff_bound(i) = min( ai% Teff_bound(i), Teff_tmp(ibound_tmp(i)) )
     637              :             end do
     638              : 
     639              :             ! use "not a knot" bc's
     640         2670 :             ibcTmin = 0; bcTmin(:) = 0d0
     641          346 :             ibcTmax = 0; bcTmax(:) = 0d0
     642          346 :             ibcgmin = 0; bcgmin(:) = 0d0
     643          346 :             ibcgmax = 0; bcgmax(:) = 0d0
     644              : 
     645              :             !generate Teff,logg 2D-interpolants
     646           20 :             f1(1:4*ng*nT) => ai% Pgas_interp1(1+4*ng*nT*(iZ-1):4*ng*nT*iZ)
     647              :             call interp_mkbicub_db(ai% logg_array, ng, ai% Teff_array, nT, &
     648              :                f1, ng, ibcgmin, bcgmin, ibcgmax, bcgmax, &
     649           20 :                ibcTmin, bcTmin, ibcTmax, bcTmax, ai% iling, ai% ilinT, ierr )
     650           20 :             if (ierr /= 0) then
     651            0 :                if (gtv_dbg) write(*,*) 'interp_mkbicub_db failed for Pgas_interp'
     652            0 :                return
     653              :             end if
     654              : 
     655           20 :             if (ai% id /= ATM_TABLE_PHOTOSPHERE) then
     656           12 :                f1(1:4*ng*nT) => ai% T_interp1(1+4*ng*nT*(iZ-1):4*ng*nT*iZ)
     657              :                call interp_mkbicub_db(ai% logg_array, ng, ai% Teff_array, nT, &
     658              :                   f1, ng, ibcgmin, bcgmin, ibcgmax, bcgmax, &
     659           12 :                   ibcTmin, bcTmin, ibcTmax, bcTmax, ai% iling, ai% ilinT, ierr )
     660           12 :                if (ierr /= 0) then
     661            0 :                   if (gtv_dbg) write(*,*) 'interp_mkbicub_db failed for T_interp'
     662            0 :                   return
     663              :                end if
     664              :             end if
     665              : 
     666              :             !this file has been loaded and processed
     667           20 :             ai% have_atm_table(iZ) = .true.
     668              : 
     669           20 :          end subroutine load_atm_table
     670              : 
     671              : 
     672         4716 :          logical function failed(i)
     673              :             integer, intent(in) :: i
     674         4716 :             failed = (ierr /= 0)
     675         4716 :             if (failed) then
     676              :                write(*,'(a,i6)') &
     677            0 :                   'failed in reading atm table ' // trim(filename), i
     678              :                !call mesa_error(__FILE__,__LINE__,'get_table_values')
     679              :             end if
     680         4716 :          end function failed
     681              : 
     682              :       end subroutine get_table_values
     683              : 
     684              :       end module table_atm
        

Generated by: LCOV version 2.0-1