LCOV - code coverage report
Current view: top level - star/private - star_solver.f90 (source / functions) Coverage Total Hit
Test: coverage.info Lines: 30.7 % 1007 309
Test Date: 2026-05-14 09:58:24 Functions: 40.0 % 35 14

            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              : 
      21              :       module star_solver
      22              : 
      23              :       use star_private_def
      24              :       use const_def, only: dp, i8
      25              :       use num_def
      26              :       use mtx_def
      27              :       use mtx_lib, only: block_multiply_xa
      28              :       use utils_lib, only: is_bad
      29              :       use solver_support
      30              : 
      31              :       implicit none
      32              : 
      33              :       private
      34              :       public :: solver
      35              : 
      36              :       contains
      37              : 
      38           22 :       subroutine solver( &
      39              :             s, nvar, skip_global_corr_coeff_limit, &
      40              :             gold_tolerances_level, tol_max_correction, tol_correction_norm, &
      41              :             convergence_failure, ierr)
      42              :          use alloc, only: non_crit_get_quad_array, non_crit_return_quad_array
      43              :          use utils_lib, only: realloc_if_needed_1, quad_realloc_if_needed_1, fill_with_NaNs
      44              : 
      45              :          type (star_info), pointer :: s
      46              :          ! the primary variables
      47              :          integer, intent(in) :: nvar  ! number of variables per zone
      48              :          logical, intent(in) :: skip_global_corr_coeff_limit
      49              : 
      50              :          ! convergence criteria
      51              :          integer, intent(in) :: gold_tolerances_level  ! 0, 1, or 2
      52              :          real(dp), intent(in) :: tol_max_correction, tol_correction_norm
      53              :             ! a trial solution is considered to have converged if
      54              :             ! max_correction <= tol_max_correction and
      55              :             !
      56              :             ! either
      57              :             !          (correction_norm <= tol_correction_norm)
      58              :             !    .and. (residual_norm <= tol_residual_norm)
      59              :             ! or
      60              :             !          (correction_norm*residual_norm <= tol_corr_resid_product)
      61              :             !    .and. (abs(slope) <= tol_abs_slope_min)
      62              :             !
      63              :             ! where "slope" is slope of the line for line search in the solver,
      64              :             ! and is analogous to the slope of df/ddx in a 1D solver root finder.
      65              : 
      66              :          ! output
      67              :          logical, intent(out) :: convergence_failure
      68              :          integer, intent(out) :: ierr  ! 0 means okay.
      69              : 
      70              :          integer :: ldAF, neqns
      71              : 
      72              :          include 'formats'
      73              : 
      74              :          ierr = 0
      75              : 
      76           11 :          neqns = nvar*s% nz
      77           11 :          ldAF = 3*nvar
      78              : 
      79           11 :          call realloc_if_needed_1(s% AF1,ldAF*neqns,(ldAF+2)*200,ierr)
      80           11 :          if (ierr /= 0) return
      81              : 
      82           11 :          if (s% fill_arrays_with_NaNs) call fill_with_NaNs(s% AF1)
      83              : 
      84              :          call do_solver( &
      85              :             s, nvar, s% AF1, ldAF, neqns, skip_global_corr_coeff_limit, &
      86              :             gold_tolerances_level, tol_max_correction, tol_correction_norm, &
      87           11 :             convergence_failure, ierr)
      88              : 
      89              :       end subroutine solver
      90              : 
      91              : 
      92           11 :       subroutine do_solver( &
      93              :             s, nvar, AF1, ldAF, neq, skip_global_corr_coeff_limit, &
      94              :             gold_tolerances_level, tol_max_correction, tol_correction_norm, &
      95              :             convergence_failure, ierr)
      96              : 
      97              :          type (star_info), pointer :: s
      98              : 
      99              :          integer, intent(in) :: nvar, ldAF, neq
     100              :          logical, intent(in) :: skip_global_corr_coeff_limit
     101              : 
     102              :          real(dp), pointer, dimension(:) :: AF1  ! =(ldAF, neq)
     103              : 
     104              :          ! controls
     105              :          integer, intent(in) :: gold_tolerances_level
     106              :          real(dp), intent(in) :: tol_max_correction, tol_correction_norm
     107              : 
     108              :          ! output
     109              :          logical, intent(out) :: convergence_failure
     110              :          integer, intent(out) :: ierr
     111              : 
     112              :          ! info saved in work arrays
     113              : 
     114              :          real(dp), dimension(:,:), pointer :: dxsave=>null(), ddxsave=>null(), B=>null(), grad_f=>null(), soln=>null()
     115              :          real(dp), dimension(:), pointer :: dxsave1=>null(), ddxsave1=>null(), B1=>null(), grad_f1=>null(), &
     116              :             row_scale_factors1=>null(), col_scale_factors1=>null(), soln1=>null(), &
     117              :             save_ublk1=>null(), save_dblk1=>null(), save_lblk1=>null(), band1=>null()
     118              :          real(dp), dimension(:,:), pointer :: rhs=>null()
     119              :          integer, dimension(:), pointer :: ipiv1=>null()
     120              :          real(dp), dimension(:,:), pointer :: ddx=>null(), xder=>null()
     121              : 
     122              :          integer, dimension(:), pointer :: ipiv_blk1=>null()
     123           11 :          character (len=s%nz) :: equed1
     124              : 
     125              :          real(dp), dimension(:), pointer :: lblk1=>null(), dblk1=>null(), ublk1=>null()
     126              :          real(dp), dimension(:), pointer :: lblkF1=>null(), dblkF1=>null(), ublkF1=>null()
     127              : 
     128              :          ! locals
     129              :          real(dp)  ::  &
     130              :             coeff, f, slope, residual_norm, max_residual, &
     131              :             corr_norm_min, resid_norm_min, correction_factor, temp_correction_factor, &
     132              :             correction_norm, max_correction, &
     133              :             tol_residual_norm, tol_max_residual, &
     134              :             tol_residual_norm2, tol_max_residual2, &
     135              :             tol_residual_norm3, tol_max_residual3, &
     136              :             tol_abs_slope_min, tol_corr_resid_product, &
     137              :             min_corr_coeff, max_corr_min, max_resid_min, max_abs_correction
     138              :          integer :: nz, iter, max_tries, tiny_corr_cnt, i, &
     139              :             force_iter_value, iter_for_resid_tol2, iter_for_resid_tol3, &
     140              :             max_corr_k, max_corr_j, max_resid_k, max_resid_j, &
     141              :             band_kl, band_ku, band_ldab, band_diag
     142              :          integer(i8) :: time0
     143              :          character (len=strlen) :: err_msg
     144              :          logical :: first_try, dbg_msg, passed_tol_tests, &
     145              :             doing_extra, disabled_resid_tests, pass_resid_tests, &
     146              :             pass_corr_tests_without_coeff, pass_corr_tests_with_coeff
     147              : 
     148              :          integer, parameter :: num_tol_msgs = 15
     149              :          character (len=32) :: tol_msg(num_tol_msgs)
     150              :          character (len=64) :: message
     151              : 
     152              :          real(dp), pointer, dimension(:) :: equ1=>null()
     153              :          real(dp), pointer, dimension(:,:) :: equ=>null()  ! (nvar,nz)
     154              :          real(dp), pointer, dimension(:,:) :: AF=>null()  ! (ldAF,neq)
     155              :          real(dp), pointer, dimension(:,:) :: band=>null()  ! (band_ldab,neq)
     156              :          real(dp), pointer, dimension(:,:,:) :: ublk=>null(), dblk=>null(), lblk=>null()  ! (nvar,nvar,nz)
     157              :          real(dp), dimension(:,:,:), pointer :: lblkF=>null(), dblkF=>null(), ublkF=>null()  ! (nvar,nvar,nz)
     158              : 
     159           11 :          call do_solver_work()
     160              :          ! Split it this way so we can guarantee cleanup() gets called once do_solver_work finishes
     161              :          ! Otherwise all the pointers will leak memory.
     162           11 :          call cleanup()
     163              : 
     164              :          contains
     165              : 
     166           55 :          subroutine do_solver_work
     167              :             include 'formats'
     168              : 
     169           11 :             err_msg = ''
     170              : 
     171           11 :             nz = s% nz
     172              : 
     173           11 :             AF(1:ldAF,1:neq) => AF1(1:ldAF*neq)
     174              : 
     175           11 :             tol_msg(1) = 'avg corr'
     176           11 :             tol_msg(2) = 'max corr '
     177           11 :             tol_msg(3) = 'avg+max corr'
     178           11 :             tol_msg(4) = 'avg resid'
     179           11 :             tol_msg(5) = 'avg corr+resid'
     180           11 :             tol_msg(6) = 'max corr, avg resid'
     181           11 :             tol_msg(7) = 'avg+max corr, avg resid'
     182           11 :             tol_msg(8) = 'max resid'
     183           11 :             tol_msg(9) = 'avg corr, max resid'
     184           11 :             tol_msg(10) = 'max corr+resid'
     185           11 :             tol_msg(11) = 'avg+max corr, max resid'
     186           11 :             tol_msg(12) = 'avg+max resid'
     187           11 :             tol_msg(13) = 'avg corr, avg+max resid'
     188           11 :             tol_msg(14) = 'max corr, avg+max resid'
     189           11 :             tol_msg(15) = 'avg+max corr+resid'
     190              : 
     191           11 :             ierr = 0
     192           11 :             iter = 0
     193           11 :             s% solver_iter = iter
     194              : 
     195           11 :             call set_param_defaults
     196           11 :             dbg_msg = s% report_solver_progress
     197              : 
     198           11 :             if (gold_tolerances_level == 2) then
     199            0 :                tol_residual_norm = s% gold2_tol_residual_norm1
     200            0 :                tol_max_residual = s% gold2_tol_max_residual1
     201            0 :                tol_residual_norm2 = s% gold2_tol_residual_norm2
     202            0 :                tol_max_residual2 = s% gold2_tol_max_residual2
     203            0 :                tol_residual_norm3 = s% gold2_tol_residual_norm3
     204            0 :                tol_max_residual3 = s% gold2_tol_max_residual3
     205           11 :             else if (gold_tolerances_level == 1) then
     206           11 :                tol_residual_norm = s% gold_tol_residual_norm1
     207           11 :                tol_max_residual = s% gold_tol_max_residual1
     208           11 :                tol_residual_norm2 = s% gold_tol_residual_norm2
     209           11 :                tol_max_residual2 = s% gold_tol_max_residual2
     210           11 :                tol_residual_norm3 = s% gold_tol_residual_norm3
     211           11 :                tol_max_residual3 = s% gold_tol_max_residual3
     212              :             else
     213            0 :                tol_residual_norm = s% tol_residual_norm1
     214            0 :                tol_max_residual = s% tol_max_residual1
     215            0 :                tol_residual_norm2 = s% tol_residual_norm2
     216            0 :                tol_max_residual2 = s% tol_max_residual2
     217            0 :                tol_residual_norm3 = s% tol_residual_norm3
     218            0 :                tol_max_residual3 = s% tol_max_residual3
     219              :             end if
     220              : 
     221           11 :             tol_abs_slope_min = -1  ! unused
     222           11 :             tol_corr_resid_product = -1  ! unused
     223           11 :             if (skip_global_corr_coeff_limit) then
     224           11 :                min_corr_coeff = 1
     225              :             else
     226            0 :                min_corr_coeff = s% corr_coeff_limit
     227              :             end if
     228              : 
     229           11 :             if (gold_tolerances_level == 2) then
     230            0 :                iter_for_resid_tol2 = s% gold2_iter_for_resid_tol2
     231            0 :                iter_for_resid_tol3 = s% gold2_iter_for_resid_tol3
     232           11 :             else if (gold_tolerances_level == 1) then
     233           11 :                iter_for_resid_tol2 = s% gold_iter_for_resid_tol2
     234           11 :                iter_for_resid_tol3 = s% gold_iter_for_resid_tol3
     235              :             else
     236            0 :                iter_for_resid_tol2 = s% iter_for_resid_tol2
     237            0 :                iter_for_resid_tol3 = s% iter_for_resid_tol3
     238              :             end if
     239              : 
     240           11 :             call pointers(ierr)
     241           11 :             if (ierr /= 0) then
     242              :                return
     243              :             end if
     244              : 
     245           11 :             doing_extra = .false.
     246           11 :             passed_tol_tests = .false.  ! goes true when pass the tests
     247           11 :             convergence_failure = .false.  ! goes true when time to give up
     248           11 :             coeff = 1.d0
     249              : 
     250           11 :             residual_norm=0
     251           11 :             max_residual=0
     252           11 :             corr_norm_min=1d99
     253           11 :             max_corr_min=1d99
     254           11 :             max_resid_min=1d99
     255           11 :             resid_norm_min=1d99
     256           11 :             correction_factor=0
     257           11 :             f=0d0
     258           11 :             slope=0d0
     259              : 
     260           11 :             call set_xscale_info(s, nvar, ierr)
     261           11 :             if (ierr /= 0) then
     262            0 :                if (dbg_msg) &
     263            0 :                   write(*, *) 'solver failure: set_xscale_info returned ierr', ierr
     264            0 :                convergence_failure = .true.
     265            0 :                return
     266              :             end if
     267              : 
     268           11 :             call do_equations(ierr)
     269           11 :             if (ierr /= 0) then
     270            0 :                if (dbg_msg) &
     271            0 :                   write(*, *) 'solver failure: eval_equations returned ierr', ierr
     272            0 :                convergence_failure = .true.
     273            0 :                return
     274              :             end if
     275              : 
     276           11 :             call sizequ(s, nvar, residual_norm, max_residual, max_resid_k, max_resid_j, ierr)
     277           11 :             if (ierr /= 0) then
     278            0 :                if (dbg_msg) &
     279            0 :                   write(*, *) 'solver failure: sizequ returned ierr', ierr
     280            0 :                convergence_failure = .true.
     281            0 :                return
     282              :             end if
     283              : 
     284           11 :             first_try = .true.
     285           11 :             iter = 1
     286           11 :             s% solver_iter = iter
     287           11 :             if (s% doing_first_model_of_run) then
     288            1 :                max_tries = s% max_tries1
     289           10 :             else if (s% retry_cnt > 20) then
     290            0 :                max_tries = s% max_tries_after_20_retries
     291           10 :             else if (s% retry_cnt > 10) then
     292            0 :                max_tries = s% max_tries_after_10_retries
     293           10 :             else if (s% retry_cnt > 5) then
     294            0 :                max_tries = s% max_tries_after_5_retries
     295           10 :             else if (s% retry_cnt > 0) then
     296            0 :                max_tries = s% max_tries_for_retry
     297              :             else
     298           10 :                max_tries = s% solver_max_tries_before_reject
     299              :             end if
     300           11 :             tiny_corr_cnt = 0
     301              : 
     302           11 :             s% num_solver_iterations = 0
     303              : 
     304           44 :          iter_loop: do while (.not. passed_tol_tests)
     305              : 
     306           33 :                if (dbg_msg .and. first_try) write(*, *)
     307              : 
     308           33 :                max_resid_j = -1
     309           33 :                max_corr_j = -1
     310              : 
     311           33 :                if (iter >= iter_for_resid_tol2) then
     312            0 :                   if (iter < iter_for_resid_tol3) then
     313            0 :                      tol_residual_norm = tol_residual_norm2
     314            0 :                      tol_max_residual = tol_max_residual2
     315            0 :                      if (dbg_msg .and. iter == iter_for_resid_tol2) &
     316            0 :                         write(*,1) 'tol2 residual tolerances: norm, max', &
     317            0 :                            tol_residual_norm, tol_max_residual
     318              :                   else
     319            0 :                      tol_residual_norm = tol_residual_norm3
     320            0 :                      tol_max_residual = tol_max_residual3
     321            0 :                      if (dbg_msg .and. iter == iter_for_resid_tol3) &
     322            0 :                         write(*,1) 'tol3 residual tolerances: norm, max', &
     323            0 :                            tol_residual_norm, tol_max_residual
     324              :                   end if
     325           33 :                else if (dbg_msg .and. iter == 1) then
     326            0 :                   write(*,2) 'solver_call_number', s% solver_call_number
     327            0 :                   write(*,2) 'gold tolerances level', gold_tolerances_level
     328            0 :                   write(*,1) 'correction tolerances: norm, max', &
     329            0 :                      tol_correction_norm, tol_max_correction
     330            0 :                   write(*,1) 'tol1 residual tolerances: norm, max', &
     331            0 :                      tol_residual_norm, tol_max_residual
     332              :                end if
     333              : 
     334           33 :                call solver_test_partials(nvar, xder, ierr)
     335           33 :                if (ierr /= 0) then
     336            0 :                   call write_msg('solver_test_partials returned ierr /= 0')
     337            0 :                   convergence_failure = .true.
     338            0 :                   exit iter_loop
     339              :                end if
     340              : 
     341           33 :                s% num_solver_iterations = s% num_solver_iterations + 1
     342              :                if (s% model_number == 1 .and. &
     343           33 :                   s% num_solver_iterations > 60 .and. &
     344              :                   mod(s% num_solver_iterations,10) == 0) &
     345            0 :                      write(*,*) 'first model is slow to converge: num tries', &
     346            0 :                         s% num_solver_iterations
     347              : 
     348           33 :                if (.not. solve_equ()) then  ! either singular or horribly ill-conditioned
     349            0 :                   write(err_msg, '(a, i5, 3x, a)') 'info', ierr, 'bad_matrix'
     350            0 :                   call oops(err_msg)
     351            0 :                   exit iter_loop
     352              :                end if
     353              : 
     354           33 :                call inspectB(s, nvar, soln, ierr)
     355           33 :                if (ierr /= 0) then
     356            0 :                   call oops('inspectB returned ierr')
     357            0 :                   exit iter_loop
     358              :                end if
     359              : 
     360              :                ! compute size of scaled correction B
     361              :                call sizeB(s, nvar, soln, &
     362           33 :                      max_correction, correction_norm, max_corr_k, max_corr_j, ierr)
     363           33 :                if (ierr /= 0) then
     364            0 :                   call oops('correction rejected by sizeB')
     365            0 :                   exit iter_loop
     366              :                end if
     367              : 
     368           33 :                correction_norm = abs(correction_norm)
     369           33 :                max_abs_correction = abs(max_correction)
     370           33 :                corr_norm_min = min(correction_norm, corr_norm_min)
     371           33 :                max_corr_min = min(max_abs_correction, max_corr_min)
     372              : 
     373           33 :                if (is_bad_num(correction_norm) .or. is_bad_num(max_abs_correction)) then
     374              :                   ! bad news -- bogus correction
     375            0 :                   call oops('bad result from sizeB -- correction info either NaN or Inf')
     376            0 :                   if (s% stop_for_bad_nums) then
     377            0 :                      write(*,1) 'correction_norm', correction_norm
     378            0 :                      write(*,1) 'max_correction', max_correction
     379            0 :                      call mesa_error(__FILE__,__LINE__,'solver')
     380              :                   end if
     381              :                   exit iter_loop
     382              :                end if
     383              : 
     384           33 :                if (.not. s% ignore_too_large_correction) then
     385           33 :                   if ((correction_norm > s% corr_param_factor*s% scale_correction_norm) .and. &
     386              :                         .not. s% doing_first_model_of_run) then
     387            0 :                      call oops('avg corr too large')
     388            0 :                      exit iter_loop
     389              :                   end if
     390              :                end if
     391              : 
     392              :                ! shrink the correction if it is too large
     393           33 :                correction_factor = 1d0
     394           33 :                temp_correction_factor = 1d0
     395              : 
     396           33 :                if (correction_norm*correction_factor > s% scale_correction_norm) then
     397            0 :                   correction_factor = min(correction_factor,s% scale_correction_norm/correction_norm)
     398              :                end if
     399              : 
     400           33 :                if (max_abs_correction*correction_factor > s% scale_max_correction) then
     401            0 :                   temp_correction_factor = s% scale_max_correction/max_abs_correction
     402              :                end if
     403              : 
     404           33 :                if (iter > s% solver_itermin_until_reduce_min_corr_coeff) then
     405            0 :                   if (min_corr_coeff == 1d0 .and. &
     406              :                      s% solver_reduced_min_corr_coeff < 1d0) then
     407            0 :                         min_corr_coeff = s% solver_reduced_min_corr_coeff
     408              :                   end if
     409              :                end if
     410              : 
     411           33 :                correction_factor = max(min_corr_coeff, correction_factor)
     412           33 :                if (.not. s% ignore_min_corr_coeff_for_scale_max_correction) then
     413           33 :                   temp_correction_factor = max(min_corr_coeff, temp_correction_factor)
     414              :                end if
     415           33 :                correction_factor = min(correction_factor, temp_correction_factor)
     416              : 
     417              :                ! fix B if out of definition domain
     418           33 :                call Bdomain(s, nvar, soln, correction_factor, ierr)
     419           33 :                if (ierr /= 0) then  ! correction cannot be fixed
     420            0 :                   call oops('correction rejected by Bdomain')
     421            0 :                   exit iter_loop
     422              :                end if
     423              : 
     424           33 :                if (min_corr_coeff < 1d0) then
     425              :                   ! compute gradient of f = equ<dot>jacobian
     426              :                   ! NOTE: NOT jacobian<dot>equ
     427            0 :                   call block_multiply_xa(nvar, nz, lblk1, dblk1, ublk1, equ1, grad_f1)
     428              : 
     429            0 :                   slope = eval_slope(nvar, nz, grad_f, soln)
     430            0 :                   if (is_bad_num(slope) .or. slope > 0d0) then  ! a very bad sign
     431            0 :                      if (is_bad_num(slope) .and. s% stop_for_bad_nums) then
     432            0 :                         write(*,1) 'slope', slope
     433            0 :                         call mesa_error(__FILE__,__LINE__,'solver')
     434              :                      end if
     435            0 :                      slope = 0d0
     436            0 :                      min_corr_coeff = 1d0
     437              :                   end if
     438              : 
     439              :                else
     440              : 
     441           33 :                   slope = 0d0
     442              : 
     443              :                end if
     444              : 
     445           33 :                f = 0d0
     446              :                call adjust_correction( &
     447           33 :                   min_corr_coeff, correction_factor, grad_f1, f, slope, coeff, err_msg, ierr)
     448           33 :                if (ierr /= 0) then
     449            0 :                   call oops(err_msg)
     450            0 :                   exit iter_loop
     451              :                end if
     452           33 :                s% solver_adjust_iter = 0
     453              : 
     454              :                ! coeff is factor by which adjust_correction rescaled the correction vector
     455           33 :                if (coeff > s% tiny_corr_factor*min_corr_coeff .or. min_corr_coeff >= 1d0) then
     456           33 :                   tiny_corr_cnt = 0
     457              :                else
     458            0 :                   tiny_corr_cnt = tiny_corr_cnt + 1
     459              :                end if
     460              : 
     461              :                ! check the residuals for the equations
     462              : 
     463           33 :                call sizequ(s, nvar, residual_norm, max_residual, max_resid_k, max_resid_j, ierr)
     464           33 :                if (ierr /= 0) then
     465            0 :                   call oops('sizequ returned ierr')
     466            0 :                   exit iter_loop
     467              :                end if
     468              : 
     469           33 :                if (is_bad_num(residual_norm)) then
     470            0 :                   call oops('residual_norm is a bad number (NaN or Infinity)')
     471            0 :                   if (s% stop_for_bad_nums) then
     472            0 :                      write(*,1) 'residual_norm', residual_norm
     473            0 :                      call mesa_error(__FILE__,__LINE__,'solver')
     474              :                   end if
     475              :                   exit iter_loop
     476              :                end if
     477              : 
     478           33 :                if (is_bad_num(max_residual)) then
     479            0 :                   call oops('max_residual is a bad number (NaN or Infinity)')
     480            0 :                   if (s% stop_for_bad_nums) then
     481            0 :                      write(*,1) 'max_residual', max_residual
     482            0 :                      call mesa_error(__FILE__,__LINE__,'solver')
     483              :                   end if
     484              :                   exit iter_loop
     485              :                end if
     486              : 
     487           33 :                residual_norm = abs(residual_norm)
     488           33 :                max_residual = abs(max_residual)
     489           33 :                s% residual_norm = residual_norm
     490           33 :                s% max_residual = max_residual
     491           33 :                resid_norm_min = min(residual_norm, resid_norm_min)
     492           33 :                max_resid_min = min(max_residual, max_resid_min)
     493              : 
     494              :                disabled_resid_tests = &
     495           33 :                   tol_max_residual > 1d2 .and. tol_residual_norm > 1d2
     496              :                pass_resid_tests = &
     497              :                   .not. disabled_resid_tests .and. &
     498              :                   max_residual <= tol_max_residual .and. &
     499           33 :                   residual_norm <= tol_residual_norm
     500              :                pass_corr_tests_without_coeff = &
     501              :                   max_abs_correction <= tol_max_correction .and. &
     502           33 :                   correction_norm <= tol_correction_norm
     503              :                pass_corr_tests_with_coeff = &
     504              :                   max_abs_correction <= tol_max_correction*coeff .and. &
     505           33 :                   correction_norm <= tol_correction_norm*coeff
     506              : 
     507              :                passed_tol_tests = &
     508              :                   (pass_resid_tests .and. pass_corr_tests_with_coeff) .or. &
     509           33 :                   (disabled_resid_tests .and. pass_corr_tests_without_coeff)
     510              : 
     511           33 :                if (.not. passed_tol_tests) then
     512              : 
     513           22 :                   if (iter >= max_tries) then
     514            0 :                      call get_message
     515            0 :                      message = trim(message) // ' -- give up'
     516            0 :                      if (len_trim(s% retry_message) == 0) &
     517            0 :                         s% retry_message = trim(message) // ' in solver'
     518            0 :                      if (dbg_msg) call write_msg(message)
     519            0 :                      if (.not. pass_resid_tests .and. .not. disabled_resid_tests) then
     520            0 :                         if (residual_norm > tol_residual_norm) &
     521            0 :                            write(*,2) 'residual_norm > tol_residual_norm', &
     522            0 :                               s% model_number, residual_norm, tol_residual_norm
     523            0 :                         if (max_residual > tol_max_residual) &
     524            0 :                            write(*,2) 'max_residual > tol_max_residual', &
     525            0 :                               s% model_number, max_residual, tol_max_residual
     526              :                      end if
     527            0 :                      if (disabled_resid_tests) then  ! no coeff for corrections
     528            0 :                         if (correction_norm > tol_correction_norm) &
     529            0 :                            write(*,2) 'correction_norm > tol_correction_norm', &
     530            0 :                               s% model_number, correction_norm, tol_correction_norm, coeff
     531            0 :                         if (max_abs_correction > tol_max_correction) &
     532            0 :                            write(*,2) 'max_abs_correction > tol_max_correction', &
     533            0 :                               s% model_number, max_abs_correction, tol_max_correction, coeff
     534              :                      else  ! include coeff for corrections
     535            0 :                         if (correction_norm > tol_correction_norm*coeff) &
     536            0 :                            write(*,2) 'correction_norm > tol_correction_norm*coeff', &
     537            0 :                               s% model_number, correction_norm, tol_correction_norm*coeff, coeff
     538            0 :                         if (max_abs_correction > tol_max_correction*coeff) &
     539            0 :                            write(*,2) 'max_abs_correction > tol_max_correction*coeff', &
     540            0 :                               s% model_number, max_abs_correction, tol_max_correction*coeff, coeff
     541              :                      end if
     542            0 :                      convergence_failure = .true.
     543            0 :                      exit iter_loop
     544           22 :                   else if (.not. first_try .and. .not. s% doing_first_model_of_run) then
     545           10 :                      if (correction_norm > s% corr_norm_jump_limit*corr_norm_min) then
     546            0 :                         call oops('avg correction jumped')
     547            0 :                         exit iter_loop
     548           10 :                      else if (residual_norm > s% resid_norm_jump_limit*resid_norm_min) then
     549            0 :                         call oops('avg residual jumped')
     550            0 :                         exit iter_loop
     551           10 :                      else if (max_abs_correction > s% max_corr_jump_limit*max_corr_min) then
     552            0 :                         call oops('max correction jumped')
     553            0 :                         exit iter_loop
     554           10 :                      else if (max_residual > s% max_resid_jump_limit*max_resid_min) then
     555            0 :                         call oops('max residual jumped')
     556            0 :                         exit iter_loop
     557              :                      else if (tiny_corr_cnt >= s% tiny_corr_coeff_limit &
     558           10 :                            .and. min_corr_coeff < 1) then
     559            0 :                         call oops('tiny corrections')
     560            0 :                         exit iter_loop
     561              :                      end if
     562           12 :                   else if (.not. s% doing_first_model_of_run) then
     563           10 :                      if (coeff < min(min_corr_coeff,correction_factor)) then
     564            0 :                         call oops('coeff too small')
     565            0 :                         exit iter_loop
     566              :                      end if
     567              :                   end if
     568              :                end if
     569              : 
     570           33 :                if (dbg_msg) then
     571            0 :                   if (.not. passed_tol_tests) then
     572            0 :                      call get_message
     573              :                   end if
     574            0 :                   if (.not. passed_tol_tests) then
     575            0 :                      call write_msg(message)
     576            0 :                   else if (iter < s% solver_itermin) then
     577            0 :                      call write_msg('iter < itermin')
     578              :                   else
     579            0 :                      call write_msg('okay!')
     580              :                   end if
     581              :                end if
     582              : 
     583           33 :                if (passed_tol_tests .and. (iter+1 < max_tries)) then
     584              :                   ! about to declare victory... but may want to do another iteration
     585           11 :                   force_iter_value = force_another_iteration(s, iter, s% solver_itermin)
     586           11 :                   if (force_iter_value > 0) then
     587            0 :                      passed_tol_tests = .false.  ! force another
     588            0 :                      tiny_corr_cnt = 0  ! reset the counter
     589            0 :                      corr_norm_min = 1d99
     590            0 :                      resid_norm_min = 1d99
     591            0 :                      max_corr_min = 1d99
     592            0 :                      max_resid_min = 1d99
     593           11 :                   else if (force_iter_value < 0) then  ! failure
     594            0 :                      call oops('force iter')
     595            0 :                      exit iter_loop
     596              :                   end if
     597              :                end if
     598              : 
     599           33 :                if (s% use_other_solver_monitor .and. &
     600              :                      associated(s% other_solver_monitor)) then
     601              :                   call s% other_solver_monitor( &
     602              :                      s% id, iter, passed_tol_tests, &
     603              :                      correction_norm, max_correction, &
     604            0 :                      residual_norm, max_residual, ierr)
     605            0 :                   if (ierr /= 0) then
     606            0 :                      call oops('other_solver_monitor')
     607            0 :                      exit iter_loop
     608              :                   end if
     609              :                end if
     610              : 
     611           33 :                iter=iter+1
     612           33 :                s% solver_iter = iter
     613           33 :                first_try = .false.
     614              : 
     615              :             end do iter_loop
     616              : 
     617           11 :             if (max_residual > s% warning_limit_for_max_residual .and. .not. convergence_failure) &
     618            0 :                write(*,2) 'WARNING: max_residual > warning_limit_for_max_residual', &
     619            0 :                   s% model_number, max_residual, s% warning_limit_for_max_residual
     620              : 
     621              :          end subroutine do_solver_work
     622              : 
     623              : 
     624           33 :          subroutine solver_test_partials(nvar, xder, ierr)
     625              :             ! create jacobian by using numerical differences for partial derivatives
     626              :             integer, intent(in) :: nvar
     627              :             real(dp), pointer, dimension(:,:) :: xder  ! (nvar, nz)
     628              :             integer, intent(out) :: ierr
     629              : 
     630              :             integer :: j, k, k_lo, k_hi
     631           33 :             real(dp), dimension(:,:), pointer :: save_equ, save_dx
     632              :             logical :: testing_partial
     633              : 
     634              :             include 'formats'
     635              : 
     636           33 :             ierr = 0
     637              :             testing_partial = &  ! check inlist parameters
     638              :                s% solver_test_partials_dx_0 > 0d0 .and. &
     639              :                s% solver_test_partials_k > 0 .and. &
     640              :                s% solver_call_number == s% solver_test_partials_call_number .and. &
     641           33 :                s% solver_test_partials_iter_number == iter
     642              :             if (.not. testing_partial) return
     643              : 
     644            0 :             call do_equations(ierr)
     645            0 :             if (ierr /= 0) return
     646              : 
     647            0 :             allocate(save_dx(nvar,nz), save_equ(nvar,nz))
     648              : 
     649            0 :             do k=1,nz
     650            0 :                do j=1,nvar
     651            0 :                   save_dx(j,k) = s% solver_dx(j,k)
     652            0 :                   save_equ(j,k) = equ(j,k)
     653              :                end do
     654              :             end do
     655              : 
     656            0 :             s% doing_check_partials = .true.  ! let set_vars_for_solver know
     657            0 :             k_lo = s% solver_test_partials_k_low
     658            0 :             if (k_lo > 0 .and. k_lo <= s% nz) then
     659            0 :                k_hi = s% solver_test_partials_k_high
     660            0 :                if (k_hi <= 0) then
     661              :                   k_hi = s% nz
     662              :                else
     663            0 :                   k_hi = min(k_hi,s% nz)
     664              :                end if
     665            0 :                do k = k_lo, k_hi
     666            0 :                   call test_cell_partials(s, k, save_dx, save_equ, ierr)
     667            0 :                   if (ierr /= 0) call mesa_error(__FILE__,__LINE__,'failed solver_test_partials')
     668              :                end do
     669              :             else
     670            0 :                k = s% solver_test_partials_k
     671            0 :                call test_cell_partials(s, k, save_dx, save_equ, ierr)
     672            0 :                if (ierr /= 0) call mesa_error(__FILE__,__LINE__,'failed solver_test_partials')
     673              :             end if
     674            0 :             deallocate(save_dx, save_equ)
     675            0 :             call mesa_error(__FILE__,__LINE__,'done solver_test_partials')
     676              : 
     677            0 :          end subroutine solver_test_partials
     678              : 
     679              : 
     680            0 :          subroutine get_message
     681              :             include 'formats'
     682            0 :             i = 0
     683            0 :             if (correction_norm > tol_correction_norm*coeff) i = i+1
     684            0 :             if (max_abs_correction > tol_max_correction*coeff) i = i+2
     685            0 :             if (residual_norm > tol_residual_norm*coeff) i = i+4
     686            0 :             if (max_residual > tol_max_residual*coeff) i = i+8
     687            0 :             if (i == 0) then
     688            0 :                message = 'out of tries'
     689              :             else
     690            0 :                message = tol_msg(i)
     691              :             end if
     692            0 :          end subroutine get_message
     693              : 
     694              : 
     695           11 :          subroutine set_param_defaults
     696           11 :             if (s% corr_param_factor == 0) s% corr_param_factor = 10d0
     697           11 :             if (s% scale_max_correction == 0) s% scale_max_correction = 1d99
     698           11 :             if (s% corr_norm_jump_limit == 0) s% corr_norm_jump_limit = 1d99
     699           11 :             if (s% max_corr_jump_limit == 0) s% max_corr_jump_limit = 1d99
     700           11 :          end subroutine set_param_defaults
     701              : 
     702              : 
     703            0 :          subroutine oops(msg)
     704              :             character (len=*), intent(in) :: msg
     705              :             character (len=strlen) :: full_msg
     706              :             include 'formats'
     707            0 :             full_msg = trim(msg) // ' -- give up'
     708            0 :             if (len_trim(s% retry_message) == 0) s% retry_message = trim(full_msg) // ' in solver'
     709            0 :             call write_msg(full_msg)
     710            0 :             convergence_failure = .true.
     711            0 :          end subroutine oops
     712              : 
     713              : 
     714          132 :          subroutine do_equations(ierr)
     715              :             integer, intent(out) :: ierr
     716           44 :             call prepare_solver_matrix(nvar, xder, ierr)
     717           44 :             if (ierr /= 0) return
     718           44 :             call eval_equations(s, nvar, ierr)
     719           44 :             if (ierr /= 0) return
     720           44 :             call s% other_after_solver_setmatrix(s% id, ierr)
     721              :          end subroutine do_equations
     722              : 
     723              : 
     724           44 :          subroutine prepare_solver_matrix(nvar, xder, ierr)
     725              :             integer, intent(in) :: nvar
     726              :             real(dp), pointer, dimension(:,:) :: xder  ! (nvar, nz)
     727              :             integer, intent(out) :: ierr
     728              :             integer :: nz, neqns
     729              :             include 'formats'
     730           44 :             ierr = 0
     731           44 :             nz = s% nz
     732           44 :             neqns = nvar*nz
     733           44 :             s% ublk(1:nvar,1:nvar,1:nz) => ublk1
     734           44 :             s% dblk(1:nvar,1:nvar,1:nz) => dblk1
     735           44 :             s% lblk(1:nvar,1:nvar,1:nz) => lblk1
     736           44 :          end subroutine prepare_solver_matrix
     737              : 
     738              : 
     739           33 :          subroutine adjust_correction( &
     740              :                min_corr_coeff_in, max_corr_coeff, grad_f, f, slope, coeff,  &
     741              :                err_msg, ierr)
     742              :             real(dp), intent(in) :: min_corr_coeff_in
     743              :             real(dp), intent(in) :: max_corr_coeff
     744              :             real(dp), intent(in) :: grad_f(:)  ! (neq) ! gradient df/ddx at xold
     745              :             real(dp), intent(out) :: f  ! 1/2 fvec^2. minimize this.
     746              :             real(dp), intent(in) :: slope
     747              :             real(dp), intent(out) :: coeff
     748              : 
     749              :             ! the new correction is coeff*xscale*soln
     750              :             ! with min_corr_coeff <= coeff <= max_corr_coeff
     751              :             ! if all goes well, the new x will give an improvement in f
     752              : 
     753              :             character (len=*), intent(out) :: err_msg
     754              :             integer, intent(out) :: ierr
     755              : 
     756              :             integer :: i, k, iter
     757              :             logical :: first_time
     758              :             real(dp) :: a1, alam, alam2, a2, disc, f2, &
     759              :                rhs1, rhs2, tmplam, fold, min_corr_coeff
     760              :             real(dp) :: f_target
     761              :             logical :: skip_eval_f, dbg_adjust
     762              : 
     763              :             real(dp), parameter :: alf = 1d-2  ! ensures sufficient decrease in f
     764              : 
     765              :             real(dp), parameter :: alam_factor = 0.2d0
     766              : 
     767              :             include 'formats'
     768              : 
     769           33 :             ierr = 0
     770           33 :             coeff = 0
     771           33 :             dbg_adjust = .false.
     772           33 :             err_msg = ''
     773              : 
     774           33 :             skip_eval_f = (min_corr_coeff_in == 1)
     775           33 :             if (skip_eval_f) then
     776           33 :                f = 0
     777              :             else
     778            0 :                do k=1,nz
     779            0 :                   do i=1,nvar
     780            0 :                      dxsave(i,k) = s% solver_dx(i,k)
     781            0 :                      ddxsave(i,k) = ddx(i,k)
     782              :                   end do
     783              :                end do
     784            0 :                f = eval_f(nvar,nz,equ)
     785            0 :                if (is_bad_num(f)) then
     786            0 :                   ierr = -1
     787            0 :                   write(err_msg,*) 'adjust_correction failed in eval_f'
     788            0 :                   if (dbg_msg) write(*,*) &
     789            0 :                      'adjust_correction: eval_f(nvar,nz,equ)', eval_f(nvar,nz,equ)
     790            0 :                   if (s% stop_for_bad_nums) then
     791            0 :                      write(*,1) 'f', f
     792            0 :                      call mesa_error(__FILE__,__LINE__,'solver adjust_correction')
     793              :                   end if
     794           33 :                   return
     795              :                end if
     796              :             end if
     797           33 :             fold = f
     798           33 :             min_corr_coeff = min(min_corr_coeff_in, max_corr_coeff)  ! make sure min <= max
     799           33 :             alam = max_corr_coeff
     800           33 :             first_time = .true.
     801           33 :             f2 = 0
     802           33 :             alam2 = 0
     803              :             if (dbg_adjust) then
     804              :                write(*,4) 'max_corr_coeff', k, s% solver_iter, &
     805              :                   s% model_number, max_corr_coeff
     806              :                write(*,4) 'slope', k, s% solver_iter, &
     807              :                   s% model_number, slope
     808              :                write(*,4) 'f', k, s% solver_iter, &
     809              :                   s% model_number, f
     810              :             end if
     811              : 
     812           33 :          search_loop: do iter = 1, 1000
     813              : 
     814           33 :                coeff = max(min_corr_coeff, alam)
     815           33 :                s% solver_adjust_iter = iter
     816              : 
     817           33 :                call apply_coeff(nvar, nz, dxsave, soln, coeff, skip_eval_f)
     818              : 
     819           33 :                call do_equations(ierr)
     820           33 :                if (ierr /= 0) then
     821            0 :                   if (alam > min_corr_coeff .and. s% model_number == 1) then
     822              :                      ! try again with smaller correction vector.
     823              :                      ! need this to rescue create pre-main-sequence model in some nasty cases.
     824            0 :                      alam = max(alam/10, min_corr_coeff)
     825            0 :                      ierr = 0
     826            0 :                      cycle search_loop
     827              :                   end if
     828            0 :                   write(err_msg,*) 'adjust_correction failed in eval_equations'
     829            0 :                   if (dbg_msg .or. dbg_adjust) &
     830            0 :                      write(*,2) 'adjust_correction: eval_equations returned ierr', &
     831            0 :                         ierr, min_corr_coeff, max_corr_coeff
     832              :                   exit search_loop
     833              :                end if
     834              : 
     835           33 :                if (min_corr_coeff == 1) return
     836              : 
     837              :                if (dbg_adjust) then
     838              :                   do k=1,nz
     839              :                      do i=1,nvar
     840              :                         write(*,5) trim(s% nameofequ(i)), k, iter, s% solver_iter, &
     841              :                            s% model_number, equ(i,k)
     842              :                      end do
     843              :                   end do
     844              :                end if
     845              : 
     846            0 :                f = eval_f(nvar,nz,equ)
     847            0 :                if (is_bad_num(f)) then
     848            0 :                   if (s% stop_for_bad_nums) then
     849            0 :                      write(*,1) 'f', f
     850            0 :                      call mesa_error(__FILE__,__LINE__,'solver adjust_correction eval_f')
     851              :                   end if
     852            0 :                   if (alam > min_corr_coeff) then
     853            0 :                      alam = max(alam/10, min_corr_coeff)
     854            0 :                      ierr = 0
     855            0 :                      cycle search_loop
     856              :                   end if
     857            0 :                   err_msg = 'equ norm is NaN or other bad num'
     858            0 :                   ierr = -1
     859            0 :                   exit search_loop
     860              :                end if
     861              : 
     862            0 :                f_target = max(fold/2, fold + alf*coeff*slope)
     863            0 :                if (f <= f_target) then
     864              :                   return  ! sufficient decrease in f
     865              :                end if
     866              : 
     867            0 :                if (alam <= min_corr_coeff) then
     868              :                   return  ! time to give up
     869              :                end if
     870              : 
     871              :                ! reduce alam and try again
     872            0 :                if (first_time) then
     873            0 :                   tmplam = -slope/(2*(f-fold-slope))
     874            0 :                   first_time = .false.
     875              :                   if (dbg_adjust) then
     876              :                      write(*,5) 'slope', k, iter, s% solver_iter, &
     877              :                         s% model_number, slope
     878              :                      write(*,5) 'f', k, iter, s% solver_iter, &
     879              :                         s% model_number, f
     880              :                      write(*,5) 'fold', k, iter, s% solver_iter, &
     881              :                         s% model_number, fold
     882              :                      write(*,5) '2*(f-fold-slope)', k, iter, s% solver_iter, &
     883              :                         s% model_number, 2*(f-fold-slope)
     884              :                   end if
     885              :                else  ! have two prior f values to work with
     886            0 :                   rhs1 = f - fold - alam*slope
     887            0 :                   rhs2 = f2 - fold - alam2*slope
     888            0 :                   a1 = (rhs1/(alam*alam) - rhs2/(alam2*alam2))/(alam - alam2)
     889            0 :                   a2 = (-alam2*rhs1/(alam*alam) + alam*rhs2/(alam2*alam2))/(alam - alam2)
     890              :                   if (dbg_adjust) then
     891              :                      write(*,5) 'slope', k, iter, s% solver_iter, &
     892              :                         s% model_number, slope
     893              :                      write(*,5) 'f', k, iter, s% solver_iter, &
     894              :                         s% model_number, f
     895              :                      write(*,5) 'f2', k, iter, s% solver_iter, &
     896              :                         s% model_number, f2
     897              :                      write(*,5) 'fold', k, iter, s% solver_iter, &
     898              :                         s% model_number, fold
     899              :                      write(*,5) 'alam', k, iter, s% solver_iter, &
     900              :                         s% model_number, alam
     901              :                      write(*,5) 'alam2', k, iter, s% solver_iter, &
     902              :                         s% model_number, alam2
     903              :                      write(*,5) 'rhs1', k, iter, s% solver_iter, &
     904              :                         s% model_number, rhs1
     905              :                      write(*,5) 'rhs2', k, iter, s% solver_iter, &
     906              :                         s% model_number, rhs2
     907              :                      write(*,5) 'a1', k, iter, s% solver_iter, &
     908              :                         s% model_number, a1
     909              :                      write(*,5) 'a2', k, iter, s% solver_iter, &
     910              :                         s% model_number, a2
     911              :                   end if
     912            0 :                   if (a1 == 0) then
     913            0 :                      tmplam = -slope/(2*a2)
     914              :                   else
     915            0 :                      disc = a2*a2-3*a1*slope
     916            0 :                      if (disc < 0) then
     917            0 :                         tmplam = alam*alam_factor
     918            0 :                      else if (a2 <= 0) then
     919            0 :                         tmplam = (-a2+sqrt(disc))/(3*a1)
     920              :                      else
     921            0 :                         tmplam = -slope/(a2+sqrt(disc))
     922              :                      end if
     923              :                      if (dbg_adjust) then
     924              :                         write(*,5) 'disc', k, iter, s% solver_iter, &
     925              :                            s% model_number, disc
     926              :                      end if
     927              :                   end if
     928            0 :                   if (tmplam > alam*alam_factor) tmplam = alam*alam_factor
     929              :                end if
     930              : 
     931            0 :                alam2 = alam
     932            0 :                f2 = f
     933            0 :                alam = max(tmplam, alam*alam_factor, min_corr_coeff)
     934              : 
     935           33 :                if (dbg_adjust) then
     936              :                   write(*,5) 'tmplam', k, iter, s% solver_iter, &
     937              :                      s% model_number, tmplam
     938              :                   write(*,5) 'min_corr_coeff', k, iter, s% solver_iter, &
     939              :                      s% model_number, min_corr_coeff
     940              :                   write(*,5) 'alam_factor', k, iter, s% solver_iter, &
     941              :                      s% model_number, alam_factor
     942              :                end if
     943              : 
     944              :             end do search_loop
     945              : 
     946            0 :             do k=1,nz
     947            0 :                do i=1,nvar
     948            0 :                   s% solver_dx(i,k) = dxsave(i,k)
     949            0 :                   ddx(i,k) = ddxsave(i,k)
     950              :                end do
     951              :             end do
     952              : 
     953           33 :          end subroutine adjust_correction
     954              : 
     955              : 
     956           33 :          subroutine apply_coeff(nvar, nz, dxsave, soln, coeff, just_use_dx)
     957              :             integer, intent(in) :: nvar, nz
     958              :             real(dp), intent(in), dimension(:,:) :: dxsave, soln
     959              :             real(dp), intent(in) :: coeff
     960              :             logical, intent(in) :: just_use_dx
     961              :             integer :: i, k
     962              :             include 'formats'
     963              : 
     964           33 :             if (just_use_dx) then
     965           33 :                if (coeff == 1d0) then
     966        39294 :                   do k=1,nz
     967       510426 :                      do i=1,nvar
     968       510393 :                         s% solver_dx(i,k) = s% solver_dx(i,k) + s% x_scale(i,k)*soln(i,k)
     969              :                      end do
     970              :                   end do
     971              :                else
     972            0 :                   do k=1,nz
     973            0 :                      do i=1,nvar
     974            0 :                         s% solver_dx(i,k) = s% solver_dx(i,k) + coeff*s% x_scale(i,k)*soln(i,k)
     975              :                      end do
     976              :                   end do
     977              :                end if
     978           33 :                return
     979              :             end if
     980              :             ! else use dxsave instead of dx
     981            0 :             if (coeff == 1d0) then
     982            0 :                do k=1,nz
     983            0 :                   do i=1,nvar
     984            0 :                      s% solver_dx(i,k) = dxsave(i,k) + s% x_scale(i,k)*soln(i,k)
     985              :                   end do
     986              :                end do
     987              :                return
     988              :             end if
     989            0 :             do k=1,nz
     990            0 :                do i=1,nvar
     991            0 :                   s% solver_dx(i,k) = dxsave(i,k) + coeff*s% x_scale(i,k)*soln(i,k)
     992              :                end do
     993              :             end do
     994              :          end subroutine apply_coeff
     995              : 
     996              : 
     997           33 :          logical function solve_equ()
     998              :             use star_utils, only: start_time, update_time
     999              :             use rsp_def, only: NV, MAX_NZN
    1000              :             integer ::  i, ierr
    1001              :             real(dp) :: total_time
    1002              : 
    1003              :             include 'formats'
    1004              :             ierr = 0
    1005           33 :             solve_equ = .true.
    1006              : 
    1007           33 :             if (s% doing_timing) then
    1008            0 :                call start_time(s, time0, total_time)
    1009              :             end if
    1010              : 
    1011           33 :             !$OMP PARALLEL DO SIMD
    1012              :             do i=1,neq
    1013              :                b1(i) = -equ1(i)
    1014              :             end do
    1015              :             !$OMP END PARALLEL DO SIMD
    1016              : 
    1017           33 :             if (s% use_DGESVX_in_bcyclic) then
    1018            0 :                !$OMP PARALLEL DO SIMD
    1019              :                do i = 1, nvar*nvar*nz
    1020              :                   save_ublk1(i) = ublk1(i)
    1021              :                   save_dblk1(i) = dblk1(i)
    1022              :                   save_lblk1(i) = lblk1(i)
    1023              :                end do
    1024              :                !$OMP END PARALLEL DO SIMD
    1025              :             end if
    1026              : 
    1027           66 :             select case (trim(s% hydro_matrix_solver))
    1028              :             case ('bcyclic')
    1029           33 :                call factor_bcyclic_mtx(ierr)
    1030           33 :                if (ierr == 0) call solve_bcyclic_mtx(ierr)
    1031              :             case ('banded')
    1032            0 :                call solve_banded_mtx(ierr)
    1033              :             case default
    1034              :                write(*,*) 'bad value for hydro_matrix_solver: ' // &
    1035            0 :                   trim(s% hydro_matrix_solver)
    1036           33 :                ierr = -1
    1037              :             end select
    1038              : 
    1039           33 :             if (s% use_DGESVX_in_bcyclic) then
    1040            0 :                !$OMP PARALLEL DO SIMD
    1041              :                do i = 1, nvar*nvar*nz
    1042              :                   ublk1(i) = save_ublk1(i)
    1043              :                   dblk1(i) = save_dblk1(i)
    1044              :                   lblk1(i) = save_lblk1(i)
    1045              :                end do
    1046              :                !$OMP END PARALLEL DO SIMD
    1047              :             end if
    1048              : 
    1049           33 :             if (s% doing_timing) then
    1050            0 :                call update_time(s, time0, total_time, s% time_solver_matrix)
    1051              :             end if
    1052           33 :             if (ierr /= 0) then
    1053            0 :                solve_equ = .false.
    1054            0 :                b(1:nvar,1:nz) = 0d0
    1055              :             end if
    1056              : 
    1057           33 :          end function solve_equ
    1058              : 
    1059              : 
    1060           33 :          subroutine factor_bcyclic_mtx(ierr)
    1061              :             use star_bcyclic, only: bcyclic_factor
    1062              :             integer, intent(out) :: ierr
    1063              :             call bcyclic_factor( &
    1064              :                s, nvar, nz, lblk1, dblk1, ublk1, lblkF1, dblkF1, ublkF1, ipiv_blk1, &
    1065              :                B1, row_scale_factors1, col_scale_factors1, &
    1066           33 :                equed1, iter, ierr)
    1067           33 :          end subroutine factor_bcyclic_mtx
    1068              : 
    1069              : 
    1070           33 :          subroutine solve_bcyclic_mtx(ierr)
    1071              :             use star_bcyclic, only: bcyclic_solve
    1072              :             integer, intent(out) :: ierr
    1073              :             call bcyclic_solve( &
    1074              :                s, nvar, nz, lblk1, dblk1, ublk1, lblkF1, dblkF1, ublkF1, ipiv_blk1, &
    1075              :                B1, soln1, row_scale_factors1, col_scale_factors1, equed1, &
    1076           33 :                iter, ierr)
    1077           33 :          end subroutine solve_bcyclic_mtx
    1078              : 
    1079              : 
    1080            0 :          subroutine solve_banded_mtx(ierr)
    1081              :             integer, intent(out) :: ierr
    1082              :             integer :: info, k, i_equ, i_var, irow, jcol, row0, col0, iband
    1083              : 
    1084            0 :             ierr = 0
    1085            0 :             if (.not. associated(band)) then
    1086            0 :                write(*,*) 'band storage is not allocated for hydro_matrix_solver=banded'
    1087            0 :                ierr = -1
    1088            0 :                return
    1089              :             end if
    1090              : 
    1091            0 :             band(1:band_ldab,1:neq) = 0d0
    1092            0 :             soln1(1:neq) = B1(1:neq)
    1093              : 
    1094            0 :             do k = 1, nz
    1095            0 :                row0 = nvar*(k-1)
    1096            0 :                do i_equ = 1, nvar
    1097            0 :                   irow = row0 + i_equ
    1098              : 
    1099            0 :                   do i_var = 1, nvar
    1100            0 :                      jcol = row0 + i_var
    1101            0 :                      iband = band_diag + irow - jcol
    1102            0 :                      if (iband < 1 .or. iband > band_ldab) then
    1103            0 :                         write(*,*) 'hydro banded matrix entry outside band', &
    1104            0 :                            irow, jcol, iband, band_ldab
    1105            0 :                         ierr = -1
    1106            0 :                         return
    1107              :                      end if
    1108            0 :                      band(iband,jcol) = dblk(i_equ,i_var,k)
    1109              :                   end do
    1110              : 
    1111            0 :                   if (k > 1) then
    1112            0 :                      col0 = nvar*(k-2)
    1113            0 :                      do i_var = 1, nvar
    1114            0 :                         jcol = col0 + i_var
    1115            0 :                         iband = band_diag + irow - jcol
    1116            0 :                         if (iband < 1 .or. iband > band_ldab) then
    1117            0 :                            write(*,*) 'hydro banded matrix entry outside band', &
    1118            0 :                               irow, jcol, iband, band_ldab
    1119            0 :                            ierr = -1
    1120            0 :                            return
    1121              :                         end if
    1122            0 :                         band(iband,jcol) = lblk(i_equ,i_var,k)
    1123              :                      end do
    1124              :                   end if
    1125              : 
    1126            0 :                   if (k < nz) then
    1127            0 :                      col0 = nvar*k
    1128            0 :                      do i_var = 1, nvar
    1129            0 :                         jcol = col0 + i_var
    1130            0 :                         iband = band_diag + irow - jcol
    1131            0 :                         if (iband < 1 .or. iband > band_ldab) then
    1132            0 :                            write(*,*) 'hydro banded matrix entry outside band', &
    1133            0 :                               irow, jcol, iband, band_ldab
    1134            0 :                            ierr = -1
    1135            0 :                            return
    1136              :                         end if
    1137            0 :                         band(iband,jcol) = ublk(i_equ,i_var,k)
    1138              :                      end do
    1139              :                   end if
    1140              :                end do
    1141              :             end do
    1142              : 
    1143            0 :             call DGBTRF(neq, neq, band_kl, band_ku, band, band_ldab, ipiv1, info)
    1144            0 :             if (info /= 0) then
    1145            0 :                write(*,*) 'hydro banded DGBTRF failed', info
    1146            0 :                ierr = info
    1147            0 :                return
    1148              :             end if
    1149              : 
    1150              :             call DGBTRS('N', neq, band_kl, band_ku, 1, band, band_ldab, &
    1151            0 :                ipiv1, soln1, neq, info)
    1152            0 :             if (info /= 0) then
    1153            0 :                write(*,*) 'hydro banded DGBTRS failed', info
    1154            0 :                ierr = info
    1155            0 :                return
    1156              :             end if
    1157              : 
    1158              :          end subroutine solve_banded_mtx
    1159              : 
    1160              : 
    1161            0 :          subroutine test_cell_partials(s, k, save_dx, save_equ, ierr)
    1162              :             use star_utils, only: lookup_nameofvar, lookup_nameofequ
    1163              :             type (star_info), pointer :: s
    1164              :             integer, intent(in) :: k
    1165              :             real(dp), pointer, dimension(:,:) :: save_dx, save_equ
    1166              :             integer, intent(out) :: ierr
    1167              :             integer :: i_equ, i_var, i_var_sink, i_var_xa_index, i_var_sink_xa_index
    1168              :             include 'formats'
    1169            0 :             ierr = 0
    1170            0 :             write(*,'(A)')
    1171            0 :             i_equ = lookup_nameofequ(s, s% solver_test_partials_equ_name)
    1172            0 :             if (i_equ == 0 .and. len_trim(s% solver_test_partials_equ_name) > 0) then
    1173            0 :                if (s% solver_test_partials_equ_name == 'lnE') then  ! testing eos
    1174            0 :                   i_equ = -1
    1175            0 :                else if (s% solver_test_partials_equ_name == 'eps_nuc') then
    1176            0 :                   i_equ = -2
    1177            0 :                else if (s% solver_test_partials_equ_name == 'opacity') then
    1178            0 :                   i_equ = -3
    1179            0 :                else if (s% solver_test_partials_equ_name == 'lnP') then
    1180            0 :                   i_equ = -4
    1181            0 :                else if (s% solver_test_partials_equ_name == 'non_nuc_neu') then
    1182            0 :                   i_equ = -5
    1183            0 :                else if (s% solver_test_partials_equ_name == 'gradT') then
    1184            0 :                   i_equ = -6
    1185            0 :                else if (s% solver_test_partials_equ_name == 'mlt_vc') then
    1186            0 :                   i_equ = -7
    1187            0 :                else if (s% solver_test_partials_equ_name == 'grad_ad') then
    1188            0 :                   i_equ = -8
    1189              :                end if
    1190            0 :             else if (i_equ /= 0) then
    1191            0 :                write(*,1) 'equ name ' // trim(s% solver_test_partials_equ_name)
    1192              :             end if
    1193            0 :             i_var = lookup_nameofvar(s, s% solver_test_partials_var_name)
    1194            0 :             if (i_var /= 0) write(*,1) 'var name ' // trim(s% solver_test_partials_var_name)
    1195            0 :             if (i_var > s% nvar_hydro) then  ! get index in xa
    1196            0 :                i_var_xa_index = i_var - s% nvar_hydro
    1197              :             else
    1198            0 :                i_var_xa_index = 0
    1199              :             end if
    1200            0 :             i_var_sink = lookup_nameofvar(s, s% solver_test_partials_sink_name)
    1201            0 :             i_var_sink_xa_index  = 0
    1202            0 :             if (i_var_sink > 0 .and. i_var > s% nvar_hydro) then
    1203            0 :                write(*,1) 'sink name ' // trim(s% solver_test_partials_sink_name)
    1204            0 :                if (i_var_sink > s% nvar_hydro) then  ! get index in xa
    1205            0 :                   i_var_sink_xa_index = i_var_sink - s% nvar_hydro
    1206              :                else
    1207            0 :                   write(*,*) 'ERROR: sink name must be a chem name for the current net'
    1208            0 :                   ierr = -1
    1209            0 :                   return
    1210              :                end if
    1211              :             end if
    1212            0 :             if (s% solver_test_partials_equ_name == 'all') then
    1213            0 :                do i_equ = 1, s% nvar_hydro
    1214              :                   call test_equ_partials(s, &
    1215              :                      i_equ, i_var, i_var_sink, i_var_xa_index, i_var_sink_xa_index, &
    1216            0 :                      k, save_dx, save_equ, ierr)
    1217            0 :                   if (ierr /= 0) call mesa_error(__FILE__,__LINE__,'failed solver_test_partials')
    1218              :                end do
    1219              :             else
    1220              :                call test_equ_partials(s, &
    1221              :                   i_equ, i_var, i_var_sink, i_var_xa_index, i_var_sink_xa_index, &
    1222            0 :                   k, save_dx, save_equ, ierr)
    1223            0 :                if (ierr /= 0) call mesa_error(__FILE__,__LINE__,'failed solver_test_partials')
    1224              :             end if
    1225              :          end subroutine test_cell_partials
    1226              : 
    1227              : 
    1228            0 :          subroutine test_equ_partials(s, &
    1229              :                i_equ, i_var, i_var_sink, i_var_xa_index, i_var_sink_xa_index, &
    1230              :                k, save_dx, save_equ, ierr)
    1231              :             type (star_info), pointer :: s
    1232              :             integer, intent(in) :: &
    1233              :                i_equ, i_var, i_var_sink, i_var_xa_index, i_var_sink_xa_index, k
    1234              :             real(dp), pointer, dimension(:,:) :: save_dx, save_equ
    1235              :             integer, intent(out) :: ierr
    1236              :             integer :: i, j_var_xa_index, j_var_sink_xa_index
    1237              :             include 'formats'
    1238            0 :             if (i_equ /= 0) then
    1239            0 :                if (s% solver_test_partials_var_name == 'all') then
    1240            0 :                   do i = 1, s% nvar_hydro
    1241              :                      call test3_partials(s, &
    1242              :                         i_equ, i, i_var_sink, i_var_xa_index, i_var_sink_xa_index, &
    1243            0 :                         k, save_dx, save_equ, ierr)
    1244            0 :                      if (ierr /= 0) call mesa_error(__FILE__,__LINE__,'failed solver_test_partials')
    1245            0 :                      write(*,'(A)')
    1246              :                   end do
    1247            0 :                else if (i_var == 0) then
    1248            0 :                   write(*,*) 'failed to recognize variable name'
    1249              :                else
    1250              :                   call test3_partials(s, &
    1251              :                      i_equ, i_var, i_var_sink, i_var_xa_index, i_var_sink_xa_index, &
    1252            0 :                      k, save_dx, save_equ, ierr)
    1253            0 :                   if (ierr /= 0) call mesa_error(__FILE__,__LINE__,'failed solver_test_partials')
    1254              :                end if
    1255              :             else  ! i_equ == 0
    1256            0 :                if (i_var /= 0) then
    1257              :                   call test1_partial(s, &
    1258              :                      i_equ, i_var, i_var_sink, i_var_xa_index, i_var_sink_xa_index, &
    1259            0 :                      k, 0, s% solver_test_partials_dval_dx, save_dx, save_equ, ierr)
    1260              :                else  ! i_var == 0
    1261            0 :                   if (s% solver_test_partials_var <= 0) then
    1262            0 :                      write(*,2) 'need to set solver_test_partials_var', s% solver_test_partials_var
    1263            0 :                      write(*,2) 'for solver_test_partials_k', s% solver_test_partials_k
    1264            0 :                      call mesa_error(__FILE__,__LINE__,'failed solver_test_partials')
    1265              :                   end if
    1266            0 :                   if (s% solver_test_partials_var > s% nvar_hydro) then
    1267            0 :                      j_var_xa_index = s% solver_test_partials_var - s% nvar_hydro
    1268            0 :                      if (s% solver_test_partials_dx_sink > s% nvar_hydro) then
    1269            0 :                         j_var_sink_xa_index = s% solver_test_partials_dx_sink - s% nvar_hydro
    1270              :                      else
    1271            0 :                         write(*,*) 'set solver_test_partials_dx_sink to variable index, not to xa index', &
    1272            0 :                            s% solver_test_partials_dx_sink
    1273            0 :                         call mesa_error(__FILE__,__LINE__,'failed solver_test_partials')
    1274              :                      end if
    1275              :                   else
    1276            0 :                      j_var_xa_index = 0
    1277            0 :                      j_var_sink_xa_index = 0
    1278              :                   end if
    1279              :                   call test1_partial(s, &
    1280              :                      i_equ, s% solver_test_partials_var, s% solver_test_partials_dx_sink, &
    1281              :                      j_var_xa_index, j_var_sink_xa_index, &
    1282            0 :                      k, 0, s% solver_test_partials_dval_dx, save_dx, save_equ, ierr)
    1283              :                end if
    1284            0 :                if (ierr /= 0) call mesa_error(__FILE__,__LINE__,'failed solver_test_partials')
    1285              :             end if
    1286            0 :             write(*,'(A)')
    1287            0 :          end subroutine test_equ_partials
    1288              : 
    1289              : 
    1290            0 :          subroutine get_lnE_partials(s, &
    1291              :                k, i_var, i_var_sink, i_var_xa_index, i_var_sink_xa_index, &
    1292              :                dvardx0_m1, dvardx0_00, dvardx0_p1)
    1293              :             use eos_def, only: i_lnE
    1294              :             type (star_info), pointer :: s
    1295              :             integer, intent(in) :: k, i_var, i_var_sink, i_var_xa_index, i_var_sink_xa_index
    1296              :             real(dp), intent(out) :: dvardx0_m1, dvardx0_00, dvardx0_p1
    1297            0 :             dvardx0_m1 = 0d0; dvardx0_00 = 0d0; dvardx0_p1 = 0d0
    1298            0 :             if (i_var_xa_index > 0) then
    1299              :                dvardx0_00 = s% d_eos_dxa(i_lnE,i_var_xa_index,k) - &
    1300            0 :                         s% d_eos_dxa(i_lnE,i_var_sink_xa_index,k)
    1301            0 :             else if (i_var == s% i_lnd) then
    1302            0 :                dvardx0_00 = s% dE_dRho_for_partials(k)*s% rho(k)/s% energy(k)
    1303            0 :             else if (i_var == s% i_lnT) then
    1304            0 :                dvardx0_00 = s% Cv_for_partials(k)*s% T(k)/s% energy(k)
    1305              :             end if
    1306            0 :          end subroutine get_lnE_partials
    1307              : 
    1308              : 
    1309            0 :          subroutine get_lnP_partials(s, &
    1310              :                k, i_var, i_var_sink, i_var_xa_index, i_var_sink_xa_index, &
    1311              :                dvardx0_m1, dvardx0_00, dvardx0_p1)
    1312              :             use eos_def, only: i_lnPgas
    1313              :             type (star_info), pointer :: s
    1314              :             integer, intent(in) :: k, i_var, i_var_sink, i_var_xa_index, i_var_sink_xa_index
    1315              :             real(dp), intent(out) :: dvardx0_m1, dvardx0_00, dvardx0_p1
    1316            0 :             dvardx0_m1 = 0d0; dvardx0_00 = 0d0; dvardx0_p1 = 0d0
    1317            0 :             if (i_var_xa_index > 0) then
    1318              :                dvardx0_00 = s% Pgas(k)/s% Peos(k) * &
    1319            0 :                   (s% d_eos_dxa(i_lnPgas,i_var_xa_index,k) - s% d_eos_dxa(i_lnPgas,i_var_sink_xa_index,k))
    1320            0 :             else if (i_var == s% i_lnd) then
    1321            0 :                dvardx0_00 = s% chiRho_for_partials(k)
    1322            0 :             else if (i_var == s% i_lnT) then
    1323            0 :                dvardx0_00 = s% chiT_for_partials(k)
    1324              :             end if
    1325            0 :          end subroutine get_lnP_partials
    1326              : 
    1327              : 
    1328            0 :          subroutine get_grad_ad_partials(s, &
    1329              :                k, i_var, i_var_sink, i_var_xa_index, i_var_sink_xa_index, &
    1330              :                dvardx0_m1, dvardx0_00, dvardx0_p1)
    1331              :             use eos_def, only: i_grad_ad
    1332              :             type (star_info), pointer :: s
    1333              :             integer, intent(in) :: k, i_var, i_var_sink, i_var_xa_index, i_var_sink_xa_index
    1334              :             real(dp), intent(out) :: dvardx0_m1, dvardx0_00, dvardx0_p1
    1335            0 :             dvardx0_m1 = 0d0; dvardx0_00 = 0d0; dvardx0_p1 = 0d0
    1336            0 :             if (i_var_xa_index > 0) then
    1337              :                dvardx0_00 = &
    1338            0 :                   (s% d_eos_dxa(i_grad_ad,i_var_xa_index,k) - s% d_eos_dxa(i_grad_ad,i_var_sink_xa_index,k))
    1339            0 :             else if (i_var == s% i_lnd) then
    1340            0 :                dvardx0_00 = s% d_eos_dlnd(i_grad_ad,k)
    1341            0 :             else if (i_var == s% i_lnT) then
    1342            0 :                dvardx0_00 = s% d_eos_dlnT(i_grad_ad,k)
    1343              :             end if
    1344            0 :          end subroutine get_grad_ad_partials
    1345              : 
    1346              : 
    1347            0 :          subroutine get_eps_nuc_partials(s, &
    1348              :                k, i_var, i_var_sink, i_var_xa_index, i_var_sink_xa_index, &
    1349              :                dvardx0_m1, dvardx0_00, dvardx0_p1)
    1350              :             type (star_info), pointer :: s
    1351              :             integer, intent(in) :: k, i_var, i_var_sink, i_var_xa_index, i_var_sink_xa_index
    1352              :             real(dp), intent(out) :: dvardx0_m1, dvardx0_00, dvardx0_p1
    1353            0 :             dvardx0_m1 = 0d0; dvardx0_00 = 0d0; dvardx0_p1 = 0d0
    1354            0 :             if (i_var > s% nvar_hydro) then
    1355            0 :                dvardx0_00 = s% d_epsnuc_dx(i_var_xa_index,k) - s% d_epsnuc_dx(i_var_sink_xa_index,k)
    1356            0 :             else if (i_var == s% i_lnd) then
    1357            0 :                dvardx0_00 = s% d_epsnuc_dlnd(k)
    1358            0 :             else if (i_var == s% i_lnT) then
    1359            0 :                dvardx0_00 = s% d_epsnuc_dlnT(k)
    1360              :             end if
    1361            0 :          end subroutine get_eps_nuc_partials
    1362              : 
    1363              : 
    1364            0 :          subroutine get_non_nuc_neu_partials(s, &
    1365              :                k, i_var, i_var_sink, i_var_xa_index, i_var_sink_xa_index, &
    1366              :                dvardx0_m1, dvardx0_00, dvardx0_p1)
    1367              :             type (star_info), pointer :: s
    1368              :             integer, intent(in) :: k, i_var, i_var_sink, i_var_xa_index, i_var_sink_xa_index
    1369              :             real(dp), intent(out) :: dvardx0_m1, dvardx0_00, dvardx0_p1
    1370            0 :             dvardx0_m1 = 0d0; dvardx0_00 = 0d0; dvardx0_p1 = 0d0
    1371            0 :             if (i_var > s% nvar_hydro) then
    1372              :                dvardx0_00 = 0d0
    1373            0 :             else if (i_var == s% i_lnd) then
    1374            0 :                dvardx0_00 = s% d_nonnucneu_dlnd(k)
    1375            0 :             else if (i_var == s% i_lnT) then
    1376            0 :                dvardx0_00 = s% d_nonnucneu_dlnT(k)
    1377              :             end if
    1378            0 :          end subroutine get_non_nuc_neu_partials
    1379              : 
    1380              : 
    1381            0 :          subroutine get_gradT_partials(s, &
    1382              :                k, i_var, i_var_sink, i_var_xa_index, i_var_sink_xa_index, &
    1383              :                dvardx0_m1, dvardx0_00, dvardx0_p1)
    1384              :             type (star_info), pointer :: s
    1385              :             integer, intent(in) :: k, i_var, i_var_sink, i_var_xa_index, i_var_sink_xa_index
    1386              :             real(dp), intent(out) :: dvardx0_m1, dvardx0_00, dvardx0_p1
    1387            0 :             dvardx0_m1 = 0d0; dvardx0_00 = 0d0; dvardx0_p1 = 0d0
    1388            0 :             if (i_var > s% nvar_hydro) then
    1389              :                dvardx0_00 = 0d0
    1390            0 :             else if (i_var == s% i_lnd) then
    1391            0 :                dvardx0_m1 = s% gradT_ad(k)%d1Array(i_lnd_m1)
    1392            0 :                dvardx0_00 = s% gradT_ad(k)%d1Array(i_lnd_00)
    1393            0 :             else if (i_var == s% i_lnT) then
    1394            0 :                dvardx0_m1 = s% gradT_ad(k)%d1Array(i_lnT_m1)
    1395            0 :                dvardx0_00 = s% gradT_ad(k)%d1Array(i_lnT_00)
    1396            0 :             else if (i_var == s% i_lnR) then
    1397            0 :                dvardx0_00 = s% gradT_ad(k)%d1Array(i_lnR_00)
    1398            0 :             else if (i_var == s% i_lum) then
    1399            0 :                dvardx0_00 = s% gradT_ad(k)%d1Array(i_L_00)
    1400            0 :             else if (i_var == s% i_w_div_wc) then
    1401            0 :                dvardx0_00 = s% gradT_ad(k)%d1Array(i_w_00)
    1402              :             end if
    1403            0 :          end subroutine get_gradT_partials
    1404              : 
    1405              : 
    1406            0 :          subroutine get_mlt_vc_partials(s, &
    1407              :                k, i_var, i_var_sink, i_var_xa_index, i_var_sink_xa_index, &
    1408              :                dvardx0_m1, dvardx0_00, dvardx0_p1)
    1409              :             type (star_info), pointer :: s
    1410              :             integer, intent(in) :: k, i_var, i_var_sink, i_var_xa_index, i_var_sink_xa_index
    1411              :             real(dp), intent(out) :: dvardx0_m1, dvardx0_00, dvardx0_p1
    1412            0 :             dvardx0_m1 = 0d0; dvardx0_00 = 0d0; dvardx0_p1 = 0d0
    1413            0 :             if (i_var > s% nvar_hydro) then
    1414              :                dvardx0_00 = 0d0
    1415            0 :             else if (i_var == s% i_lnd) then
    1416            0 :                dvardx0_m1 = s% mlt_vc_ad(k)%d1Array(i_lnd_m1)
    1417            0 :                dvardx0_00 = s% mlt_vc_ad(k)%d1Array(i_lnd_00)
    1418            0 :             else if (i_var == s% i_lnT) then
    1419            0 :                dvardx0_m1 = s% mlt_vc_ad(k)%d1Array(i_lnT_m1)
    1420            0 :                dvardx0_00 = s% mlt_vc_ad(k)%d1Array(i_lnT_00)
    1421            0 :             else if (i_var == s% i_lnR) then
    1422            0 :                dvardx0_00 = s% mlt_vc_ad(k)%d1Array(i_lnR_00)
    1423            0 :             else if (i_var == s% i_lum) then
    1424            0 :                dvardx0_00 = s% mlt_vc_ad(k)%d1Array(i_L_00)
    1425              :             end if
    1426            0 :          end subroutine get_mlt_vc_partials
    1427              : 
    1428              : 
    1429            0 :          subroutine get_opacity_partials(s, &
    1430              :                k, i_var, i_var_sink, i_var_xa_index, i_var_sink_xa_index, &
    1431              :                dvardx0_m1, dvardx0_00, dvardx0_p1)
    1432              :             type (star_info), pointer :: s
    1433              :             integer, intent(in) :: k, i_var, i_var_sink, i_var_xa_index, i_var_sink_xa_index
    1434              :             real(dp), intent(out) :: dvardx0_m1, dvardx0_00, dvardx0_p1
    1435            0 :             dvardx0_m1 = 0d0; dvardx0_00 = 0d0; dvardx0_p1 = 0d0
    1436            0 :             if (i_var > s% nvar_hydro) then
    1437              :                dvardx0_00 = 0d0  ! s% d_opacity_dx(i_var_xa_index,k) - s% d_opacity_dx(i_var_sink_xa_index,k)
    1438            0 :             else if (i_var == s% i_lnd) then
    1439            0 :                dvardx0_00 = s% d_opacity_dlnd(k)
    1440            0 :             else if (i_var == s% i_lnT) then
    1441            0 :                dvardx0_00 = s% d_opacity_dlnT(k)
    1442              :             end if
    1443            0 :          end subroutine get_opacity_partials
    1444              : 
    1445              : 
    1446            0 :          subroutine test3_partials(s, &
    1447              :                i_equ, i_var, i_var_sink, i_var_xa_index, i_var_sink_xa_index, &
    1448              :                k, save_dx, save_equ, ierr)
    1449              :             type (star_info), pointer :: s
    1450              :             integer, intent(in) :: &
    1451              :                i_equ, i_var, i_var_sink, i_var_xa_index, i_var_sink_xa_index, k
    1452              :             real(dp), pointer, dimension(:,:) :: save_dx, save_equ
    1453              :             integer, intent(out) :: ierr
    1454              :             real(dp) :: dvardx0_m1, dvardx0_00, dvardx0_p1
    1455            0 :             dvardx0_m1 = 0d0
    1456            0 :             dvardx0_00 = 0d0
    1457            0 :             dvardx0_p1 = 0d0
    1458            0 :             if (i_equ > 0) then
    1459            0 :                if (i_var > s% nvar_hydro) then  ! testing abundance
    1460            0 :                   if (k > 1) dvardx0_m1 = &
    1461            0 :                      s% lblk(i_equ,i_var,k)/s% x_scale(i_var,k-1) - s% lblk(i_equ,i_var_sink,k)/s% x_scale(i_var_sink,k-1)
    1462              :                   dvardx0_00 = &
    1463            0 :                      s% dblk(i_equ,i_var,k)/s% x_scale(i_var,k) - s% dblk(i_equ,i_var_sink,k)/s% x_scale(i_var_sink,k)
    1464            0 :                   if (k < s% nz) dvardx0_p1 = &
    1465            0 :                      s% ublk(i_equ,i_var,k)/s% x_scale(i_var,k+1) - s% ublk(i_equ,i_var_sink,k)/s% x_scale(i_var_sink,k+1)
    1466              :                else
    1467            0 :                   if (k > 1) dvardx0_m1 = s% lblk(i_equ,i_var,k)/s% x_scale(i_var,k-1)
    1468            0 :                   dvardx0_00 = s% dblk(i_equ,i_var,k)/s% x_scale(i_var,k)
    1469            0 :                   if (k < s% nz) dvardx0_p1 = s% ublk(i_equ,i_var,k)/s% x_scale(i_var,k+1)
    1470              :                end if
    1471            0 :             else if (i_equ == -1) then  ! 'lnE'
    1472              :                call get_lnE_partials(s, &
    1473              :                   k, i_var, i_var_sink, i_var_xa_index, i_var_sink_xa_index, &
    1474            0 :                   dvardx0_m1, dvardx0_00, dvardx0_p1)
    1475            0 :             elseif (i_equ == -2) then  ! 'eps_nuc'
    1476              :                call get_eps_nuc_partials(s, &
    1477              :                   k, i_var, i_var_sink, i_var_xa_index, i_var_sink_xa_index, &
    1478            0 :                   dvardx0_m1, dvardx0_00, dvardx0_p1)
    1479            0 :             else if (i_equ == -3) then  ! 'opacity'
    1480              :                call get_opacity_partials(s, &
    1481              :                   k, i_var, i_var_sink, i_var_xa_index, i_var_sink_xa_index, &
    1482            0 :                   dvardx0_m1, dvardx0_00, dvardx0_p1)
    1483            0 :             else if (i_equ == -4) then  ! 'lnP'
    1484              :                call get_lnP_partials(s, &
    1485              :                   k, i_var, i_var_sink, i_var_xa_index, i_var_sink_xa_index, &
    1486            0 :                   dvardx0_m1, dvardx0_00, dvardx0_p1)
    1487            0 :             else if (i_equ == -5) then  ! 'non_nuc_neu'
    1488              :                call get_non_nuc_neu_partials(s, &
    1489              :                   k, i_var, i_var_sink, i_var_xa_index, i_var_sink_xa_index, &
    1490            0 :                   dvardx0_m1, dvardx0_00, dvardx0_p1)
    1491            0 :             else if (i_equ == -6) then  ! 'gradT'
    1492              :                call get_gradT_partials(s, &
    1493              :                   k, i_var, i_var_sink, i_var_xa_index, i_var_sink_xa_index, &
    1494            0 :                   dvardx0_m1, dvardx0_00, dvardx0_p1)
    1495            0 :             else if (i_equ == -7) then  ! 'mlt_vc'
    1496              :                call get_mlt_vc_partials(s, &
    1497              :                   k, i_var, i_var_sink, i_var_xa_index, i_var_sink_xa_index, &
    1498            0 :                   dvardx0_m1, dvardx0_00, dvardx0_p1)
    1499            0 :             else if (i_equ == -8) then  ! 'grad_ad'
    1500              :                call get_grad_ad_partials(s, &
    1501              :                   k, i_var, i_var_sink, i_var_xa_index, i_var_sink_xa_index, &
    1502            0 :                   dvardx0_m1, dvardx0_00, dvardx0_p1)
    1503              :             end if
    1504            0 :             if (k > 1) then
    1505              :                call test1_partial(s, &
    1506              :                   i_equ, i_var, i_var_sink, i_var_xa_index, i_var_sink_xa_index, &
    1507            0 :                   k, -1, dvardx0_m1, save_dx, save_equ, ierr)
    1508            0 :                if (ierr /= 0) call mesa_error(__FILE__,__LINE__,'test3_partials')
    1509              :             end if
    1510              :             call test1_partial(s, &
    1511              :                i_equ, i_var, i_var_sink, i_var_xa_index, i_var_sink_xa_index, &
    1512            0 :                k, 0, dvardx0_00, save_dx, save_equ, ierr)
    1513            0 :             if (ierr /= 0) call mesa_error(__FILE__,__LINE__,'test3_partials')
    1514            0 :             if (k < s% nz) then
    1515              :                call test1_partial(s, &
    1516              :                   i_equ, i_var, i_var_sink, i_var_xa_index, i_var_sink_xa_index, &
    1517            0 :                   k, 1, dvardx0_p1, save_dx, save_equ, ierr)
    1518            0 :                if (ierr /= 0) call mesa_error(__FILE__,__LINE__,'test3_partials')
    1519              :             end if
    1520            0 :          end subroutine test3_partials
    1521              : 
    1522              : 
    1523            0 :          subroutine test1_partial(s, &
    1524              :                i_equ, i_var, i_var_sink, i_var_xa_index, i_var_sink_xa_index, &
    1525              :                k, k_off, dvardx_0, save_dx, save_equ, ierr)
    1526              :             use chem_def, only: chem_isos
    1527              :             type (star_info), pointer :: s
    1528              :             integer, intent(in) :: &
    1529              :                i_equ, i_var, i_var_sink, i_var_xa_index, i_var_sink_xa_index, k, k_off
    1530              :             real(dp), intent(in) :: dvardx_0
    1531              :             real(dp), pointer, dimension(:,:) :: save_dx, save_equ
    1532              :             character (len=3) :: k_off_str
    1533              :             integer, intent(out) :: ierr
    1534              :             character (len = 32) :: equ_str
    1535              :             real(dp) :: dx_0, err, dvardx, xdum, uncertainty
    1536              :             include 'formats'
    1537            0 :             ierr = 0
    1538              : 
    1539            0 :             if (i_var > s% nvar_hydro) then  ! testing abundance
    1540              :                dx_0 = s% solver_test_partials_dx_0 * &
    1541              :                   max(abs(s% xa_start(i_var_xa_index,k) + s% solver_dx(i_var,k)), &
    1542              :                       abs(s% xa_start(i_var_xa_index,k)), &
    1543            0 :                       1d-99)
    1544            0 :                write(*,1) 'var name ' // chem_isos% name(s% chem_id(i_var_xa_index))
    1545            0 :                write(*,1) 'sink name ' // chem_isos% name(s% chem_id(i_var_sink_xa_index))
    1546              :             else
    1547              :                dx_0 = s% solver_test_partials_dx_0 * &
    1548              :                   max(abs(s% xh_start(i_var,k) + s% solver_dx(i_var,k)), &
    1549            0 :                       abs(s% xh_start(i_var,k)))
    1550            0 :                if (dx_0 == 0d0) dx_0 = s% solver_test_partials_dx_0
    1551              :             end if
    1552              :             dvardx = dfridr(s, &
    1553              :                i_equ, i_var, i_var_sink, i_var_xa_index, i_var_sink_xa_index, &
    1554            0 :                k, k_off, dx_0, save_dx, err)
    1555            0 :             if (dvardx == 0d0 .and. abs(dvardx_0) < 1d-14) then
    1556            0 :                xdum = 0d0
    1557            0 :             else if (dvardx_0 == 0d0 .and. abs(dvardx) < 1d-14) then
    1558            0 :                xdum = 0d0
    1559            0 :             else if (dvardx == 0d0 .or. dvardx_0 == 0d0) then
    1560            0 :                xdum = 1d0
    1561              :             else
    1562            0 :                xdum = abs(dvardx - dvardx_0)/min(abs(dvardx),abs(dvardx_0))
    1563              :             end if
    1564            0 :             if (ierr /= 0) then
    1565            0 :                write(*,*) 'test1_partial failed'
    1566            0 :                call mesa_error(__FILE__,__LINE__,'setmatrix')
    1567              :             end if
    1568            0 :             if (i_equ /= 0) then
    1569            0 :                if (k_off == 0) then
    1570            0 :                   k_off_str = ')  '
    1571            0 :                else if (k_off == -1) then
    1572            0 :                   k_off_str = '-1)'
    1573            0 :                else if (k_off == 1) then
    1574            0 :                   k_off_str = '+1)'
    1575              :                end if
    1576            0 :                if (dvardx /= 0d0) then
    1577            0 :                   uncertainty = abs(err/dvardx)
    1578              :                else
    1579            0 :                   uncertainty = 0d0
    1580              :                end if
    1581            0 :                if (xdum > 1d-5 .and. uncertainty < 1d-6) then
    1582            0 :                   write(*, '(a5,1x)', advance='no') '*****'
    1583            0 :                else if (uncertainty > 1d-7) then
    1584            0 :                   write(*, '(a5,1x)', advance='no') '?????'
    1585              :                else
    1586            0 :                   write(*, '(6x)', advance='no')
    1587              :                end if
    1588            0 :                if (i_equ > 0) then
    1589            0 :                   equ_str = s% nameofequ(i_equ)
    1590              :                else if (i_equ == -1) then
    1591            0 :                   equ_str = 'lnE'
    1592              :                else if (i_equ == -2) then
    1593            0 :                   equ_str = 'eps_nuc'
    1594              :                else if (i_equ == -3) then
    1595            0 :                   equ_str = 'opacity'
    1596              :                else if (i_equ == -4) then
    1597            0 :                   equ_str = 'lnP'
    1598              :                else if (i_equ == -5) then
    1599            0 :                   equ_str = 'non_nuc_neu'
    1600              :                else if (i_equ == -6) then
    1601            0 :                   equ_str = 'gradT'
    1602              :                else if (i_equ == -7) then
    1603            0 :                   equ_str = 'mlt_vc'
    1604              :                else if (i_equ == -8) then
    1605            0 :                   equ_str = 'grad_ad'
    1606              :                else
    1607            0 :                   equ_str = 'unknown'
    1608              :                end if
    1609              :                write(*,'(a25,3x,i5,4x,a,f12.5,4x,a,f12.5,99(4x,a,1pe22.12))') &
    1610              :                   'd_' // trim(equ_str) // '(k)/d_' // trim(s% nameofvar(i_var)) // &
    1611            0 :                   '(k' // trim(k_off_str), &
    1612            0 :                   k, 'lg rel diff', safe_log10(xdum), 'lg uncertainty', safe_log10(uncertainty), &
    1613            0 :                   'Analytic', dvardx_0, 'Numeric', dvardx
    1614              : !               write(*,'(a70,2x,i5,f10.3,3x,a,f10.3,99(3x,a,1pe26.16))') &
    1615              : !                  'log dfridr rel_diff partials wrt  '  // trim(s% nameofvar(i_var)) // &
    1616              : !                  '(k' // k_off_str // ' of ' // trim(equ_str) // '(k)', &
    1617              : !                  k, safe_log10(xdum), 'log uncertainty', safe_log10(uncertainty), &
    1618              : !                  'analytic', dvardx_0, 'numeric', dvardx, &
    1619              : !                  'analytic/numeric', abs(dvardx_0)/max(1d-99,abs(dvardx))
    1620              : 
    1621              :             else
    1622            0 :                write(*,'(A)')
    1623            0 :                write(*,1) 'analytic and numeric partials wrt ' // trim(s% nameofvar(i_var)), &
    1624            0 :                   dvardx_0, dvardx
    1625            0 :                write(*,1) 'log dfridr relative uncertainty for numeric partial', &
    1626            0 :                   safe_log10(err/max(1d-99,abs(dvardx)))
    1627            0 :                if (dvardx_0 /= 0d0) write(*,1) 'rel_diff', xdum
    1628              :             end if
    1629            0 :          end subroutine test1_partial
    1630              : 
    1631              : 
    1632            0 :          real(dp) function dfridr_func(s, &
    1633              :                i_equ, i_var, i_var_sink, i_var_xa_index, i_var_sink_xa_index, &
    1634              :                k, k_off, delta_x, save_dx) result(val)
    1635              :             type (star_info), pointer :: s
    1636              :             integer, intent(in) :: &
    1637              :                i_equ, i_var, i_var_sink, i_var_xa_index, i_var_sink_xa_index, k, k_off
    1638              :             real(dp), intent(in) :: delta_x
    1639              :             real(dp), pointer, dimension(:,:) :: save_dx
    1640              :             include 'formats'
    1641            0 :             s% solver_dx(i_var,k+k_off) = save_dx(i_var,k+k_off) + delta_x
    1642            0 :             if (i_var_xa_index > 0) then  ! changing abundance
    1643              :                !write(*,2) 'new dx, x for abundance', i_var, &
    1644              :                !     dx(i_var,k+k_off), s% xa(i_var - s% nvar_hydro,k+k_off)
    1645            0 :                if (i_var_sink_xa_index <= 0 .or. i_var_sink_xa_index > s% species) then
    1646            0 :                   write(*,2) 'bad i_var_sink_xa_index', i_var_sink_xa_index
    1647            0 :                   call mesa_error(__FILE__,__LINE__,'star_solver dfridr_func')
    1648              :                end if
    1649            0 :                s% solver_dx(i_var_sink,k+k_off) = save_dx(i_var_sink,k+k_off) - delta_x
    1650              :             end if
    1651            0 :             call do_equations(ierr)
    1652            0 :             if (ierr /= 0) then
    1653              :                !exit
    1654            0 :                write(*,3) 'call eval_equations failed in dfridr_func'
    1655            0 :                call mesa_error(__FILE__,__LINE__,'setmatrix')
    1656              :             end if
    1657            0 :             if (i_equ > 0) then
    1658            0 :                val = equ(i_equ,k)  ! testing partial of residual for cell k equation
    1659              :             else if (i_equ == 0) then
    1660            0 :                val = s% solver_test_partials_val
    1661              :             else if (i_equ == -1) then
    1662            0 :                val = s% lnE(k)
    1663              :             else if (i_equ == -2) then
    1664            0 :                val = s% eps_nuc(k)
    1665              :             else if (i_equ == -3) then
    1666            0 :                val = s% opacity(k)
    1667              :             else if (i_equ == -4) then
    1668            0 :                val = s% lnPeos(k)
    1669              :             else if (i_equ == -5) then
    1670            0 :                val = s% non_nuc_neu(k)
    1671              :             else if (i_equ == -6) then
    1672            0 :                val = s% gradT(k)
    1673              :             else if (i_equ == -7) then
    1674            0 :                val = s% mlt_vc(k)
    1675              :             else if (i_equ == -8) then
    1676            0 :                val = s% grada(k)
    1677              :             else
    1678              :                val = 0d0
    1679              :             end if
    1680            0 :             s% solver_dx(i_var,k+k_off) = save_dx(i_var,k+k_off)
    1681            0 :             if (i_var_sink > 0) &  ! restore sink abundance
    1682            0 :                s% solver_dx(i_var_sink,k+k_off) = save_dx(i_var_sink,k+k_off)
    1683            0 :          end function dfridr_func
    1684              : 
    1685              : 
    1686            0 :          real(dp) function dfridr(s, &
    1687              :                i_equ, i_var, i_var_sink, i_var_xa_index, i_var_sink_xa_index, &
    1688              :                k, k_off, hx, save_dx, err)
    1689              :             type (star_info), pointer :: s
    1690              :             integer, intent(in) :: &
    1691              :                i_equ, i_var, i_var_sink, i_var_xa_index, i_var_sink_xa_index, k, k_off
    1692              :             real(dp), intent(in) :: hx
    1693              :             real(dp), pointer, dimension(:,:) :: save_dx
    1694              :             real(dp), intent(out) :: err
    1695              :             !  this routine returns the first derivative of a function func(x)
    1696              :             !  at the point x, by ridders method of polynomial extrapolation.
    1697              :             !  value hx is the initial step size;
    1698              :             !  it should be an increment for which func changes substantially.
    1699              :             !  an estimate of the error in the first derivative is returned in err.
    1700              :             integer, parameter :: ntab = 20
    1701              :             integer :: i,j
    1702              :             real(dp) :: errt,fac,hh,a(ntab,ntab),f1,f2
    1703              :             real(dp), parameter :: con2=2d0, con=sqrt(con2), big=1d50, safe=2d0
    1704              :             include 'formats'
    1705            0 :             dfridr = 0d0
    1706            0 :             hh = hx
    1707              :             ! 2nd order central difference
    1708              :             f1 = dfridr_func(s, &
    1709              :                i_equ, i_var, i_var_sink, i_var_xa_index, i_var_sink_xa_index, &
    1710            0 :                k, k_off, hh, save_dx)
    1711              :             !write(*,2) 'f1', 1, f1, save_dx(i_var,k) + hh
    1712              :             f2 = dfridr_func(s, &
    1713              :                i_equ, i_var, i_var_sink, i_var_xa_index, i_var_sink_xa_index, &
    1714            0 :                k, k_off, -hh, save_dx)
    1715              :             !write(*,2) 'f2', 1, f2, save_dx(i_var,k) - hh
    1716            0 :             a(1,1) = (f1 - f2)/(2d0*hh)
    1717              :             !write(*,2) 'dfdx', 1, a(1,1), &
    1718              :             !   hh, (save_dx(s% solver_test_partials_var,s% solver_test_partials_k) + hh)/ln10, &
    1719              :             !   save_dx(s% solver_test_partials_var,s% solver_test_partials_k)/ln10
    1720            0 :             err = big
    1721              :             ! successive columns in the neville tableu will go to smaller stepsizes
    1722              :             ! and higher orders of extrapolation
    1723            0 :             do i=2,ntab
    1724            0 :                hh = hh/con
    1725              :                f1 = dfridr_func(s, &
    1726              :                   i_equ, i_var, i_var_sink, i_var_xa_index, i_var_sink_xa_index, &
    1727            0 :                   k, k_off, hh, save_dx)
    1728              :                !write(*,2) 'f1', i, f1, save_dx(i_var,k) + hh
    1729              :                f2 = dfridr_func(s, &
    1730              :                   i_equ, i_var, i_var_sink, i_var_xa_index, i_var_sink_xa_index, &
    1731            0 :                   k, k_off, -hh, save_dx)
    1732              :                !write(*,2) 'f2', i, f2, save_dx(i_var,k) - hh
    1733            0 :                a(1,i) = (f1 - f2)/(2d0*hh)
    1734              :                !write(*,2) 'dfdx', i, a(1,i), &
    1735              :                !   hh, (save_dx(s% solver_test_partials_var,s% solver_test_partials_k) + hh)/ln10, &
    1736              :                !   save_dx(s% solver_test_partials_var,s% solver_test_partials_k)/ln10
    1737              :                ! compute extrapolations of various orders; the error strategy is to compare
    1738              :                ! each new extrapolation to one order lower but both at the same stepsize
    1739              :                ! and at the previous stepsize
    1740            0 :                fac = con2
    1741            0 :                do j=2,i
    1742            0 :                   a(j,i) = (a(j-1,i)*fac - a(j-1,i-1))/(fac-1d0)
    1743            0 :                   fac = con2*fac
    1744            0 :                   errt = max(abs(a(j,i)-a(j-1,i)),abs(a(j,i)-a(j-1,i-1)))
    1745            0 :                   if (errt <= err) then
    1746            0 :                      err = errt
    1747            0 :                      dfridr = a(j,i)
    1748              :                      !write(*,1) 'dfridr', err/dfridr
    1749              :                   end if
    1750              :                end do
    1751              :                ! if higher order is worse by a significant factor safe, then bail
    1752            0 :                if (abs(a(i,i) - a(i-1,i-1)) >= safe*err) then
    1753              :                   !write(*,1) 'higher order is worse'
    1754              :                   return
    1755              :                end if
    1756              :             end do
    1757              :          end function dfridr
    1758              : 
    1759              : 
    1760              :          subroutine set_xtras(x,num_xtra)
    1761              :             real(dp) :: x(:,:)
    1762              :             integer, intent(in) :: num_xtra
    1763              :             integer :: k
    1764              :             include 'formats'
    1765              :             if (.not. s% u_flag) then
    1766              :                x(1,1:nz) = 0
    1767              :                x(2,1:nz) = 0
    1768              :                return
    1769              :             end if
    1770              :             do k=1,nz
    1771              :                x(1,k) = s% u_face_ad(k)%val
    1772              :                if (is_bad_num(x(1,k))) then
    1773              :                   write(*,2) 'exit_setmatrix x(1,k)', k, x(1,k)
    1774              :                   stop
    1775              :                end if
    1776              :             end do
    1777              :             do k=1,nz
    1778              :                x(2,k) = s% P_face_ad(k)%val
    1779              :                if (is_bad_num(x(2,k))) then
    1780              :                   write(*,2) 'exit_setmatrix x(2,k)', k, x(2,k)
    1781              :                   stop
    1782              :                end if
    1783              :             end do
    1784              :          end subroutine set_xtras
    1785              : 
    1786              : 
    1787            0 :          subroutine store_mix_type_str(str, integer_string, i, k)
    1788              :             character (len=5) :: str
    1789              :             character (len=10) :: integer_string
    1790              :             integer, intent(in) :: i, k
    1791              :             integer :: mix_type, j
    1792            0 :             if (k < 1 .or. k > s% nz) then
    1793            0 :                str(i:i) = 'x'
    1794            0 :                return
    1795              :             end if
    1796            0 :             mix_type = s% mixing_type(k)
    1797            0 :             if (mix_type < 10) then
    1798            0 :                j = mix_type+1
    1799            0 :                str(i:i) = integer_string(j:j)
    1800              :             else
    1801            0 :                str(i:i) = '?'
    1802              :             end if
    1803              :          end subroutine store_mix_type_str
    1804              : 
    1805              : 
    1806            0 :          subroutine write_msg(msg)
    1807              :             use const_def, only: secyer
    1808              :             character(*)  :: msg
    1809              : 
    1810              :             integer :: k
    1811              :             character (len=64) :: max_resid_str, max_corr_str
    1812              :             character (len=5) :: max_resid_mix_type_str, max_corr_mix_type_str
    1813              :             character (len=10) :: integer_string
    1814              :             include 'formats'
    1815              : 
    1816            0 :             if (.not. dbg_msg) return
    1817              : 
    1818            0 :             if (max_resid_j < 0) then
    1819            0 :                call sizequ(s, nvar, residual_norm, max_residual, max_resid_k, max_resid_j, ierr)
    1820              :             end if
    1821              : 
    1822            0 :             if (max_resid_j > 0) then
    1823            0 :                write(max_resid_str,*) 'max resid ' // trim(s% nameofequ(max_resid_j))
    1824              :             else
    1825            0 :                max_resid_str = ''
    1826              :             end if
    1827              : 
    1828            0 :             if (max_corr_j < 0) then
    1829              :                call sizeB(s, nvar, B, &
    1830            0 :                   max_correction, correction_norm, max_corr_k, max_corr_j, ierr)
    1831              :             end if
    1832              : 
    1833            0 :             if (max_corr_j > 0) then
    1834            0 :                write(max_corr_str,*) 'max corr ' // trim(s% nameofvar(max_corr_j))
    1835              :             else
    1836            0 :                max_corr_str = ''
    1837              :             end if
    1838              : 
    1839            0 :             integer_string = '0123456789'
    1840            0 :             k = max_corr_k
    1841            0 :             call store_mix_type_str(max_corr_mix_type_str, integer_string, 1, k-2)
    1842            0 :             call store_mix_type_str(max_corr_mix_type_str, integer_string, 2, k-1)
    1843            0 :             call store_mix_type_str(max_corr_mix_type_str, integer_string, 3, k)
    1844            0 :             call store_mix_type_str(max_corr_mix_type_str, integer_string, 4, k+1)
    1845            0 :             call store_mix_type_str(max_corr_mix_type_str, integer_string, 5, k+2)
    1846              : 
    1847            0 :             k = max_resid_k
    1848            0 :             call store_mix_type_str(max_resid_mix_type_str, integer_string, 1, k-2)
    1849            0 :             call store_mix_type_str(max_resid_mix_type_str, integer_string, 2, k-1)
    1850            0 :             call store_mix_type_str(max_resid_mix_type_str, integer_string, 3, k)
    1851            0 :             call store_mix_type_str(max_resid_mix_type_str, integer_string, 4, k+1)
    1852            0 :             call store_mix_type_str(max_resid_mix_type_str, integer_string, 5, k+2)
    1853              : 
    1854              :   111       format(i6, i3, 2x, a, f7.4, &
    1855              :                1x, a, 1x, e10.3, 2x, a18, 1x, i5, e13.5, a, &
    1856              :                1x, a, 1x, e10.3, 2x, a16, 1x, i5, e13.5, a, &
    1857              :                1x, a)
    1858              : !  111       format(i6, 2x, i3, 2x, a, f8.4, &
    1859              : !               2x, a, 1x, e10.3, 2x, a19, 1x, i5, e11.3, 2x, a, &
    1860              : !               2x, a, 1x, e10.3, 2x, a14, 1x, i5, e11.3, 2x, a, &
    1861              : !               2x, a)
    1862              :             write(*,111) &
    1863            0 :                s% model_number, iter, &
    1864            0 :                'coeff', coeff,  &
    1865            0 :                'avg resid', residual_norm,  &
    1866              : !               '   avg resid', residual_norm,  &
    1867            0 :                trim(max_resid_str), max_resid_k, max_residual, &
    1868            0 :                ' mix type ' // trim(max_resid_mix_type_str),  &
    1869            0 :                'avg corr', correction_norm,  &
    1870              : !               'mix type ' // trim(max_resid_mix_type_str),  &
    1871              : !               '   avg corr', correction_norm,  &
    1872            0 :                trim(max_corr_str), max_corr_k, max_correction,  &
    1873            0 :                ' mix type ' // trim(max_corr_mix_type_str),  &
    1874            0 :                ' ' // trim(msg)
    1875              : !               'mix type ' // trim(max_corr_mix_type_str),  &
    1876              : !               '   ' // trim(msg)
    1877              : 
    1878            0 :             if (is_bad(slope)) call mesa_error(__FILE__,__LINE__,'write_msg')
    1879              : 
    1880              :          end subroutine write_msg
    1881              : 
    1882              : 
    1883           11 :          subroutine pointers(ierr)
    1884              :             use utils_lib, only: fill_with_NaNs, fill_with_NaNs_2D
    1885              : 
    1886              :             integer, intent(out) :: ierr
    1887              : 
    1888              :             integer :: i
    1889              : 
    1890           11 :             ierr = 0
    1891              : 
    1892           11 :             i = 1
    1893              : 
    1894           11 :             if(allocated(s% equ1)) then
    1895           10 :                if(size(s% equ1,dim=1) /= neq) then
    1896            4 :                   deallocate(s% equ1)
    1897           12 :                   allocate(s% equ1(1:neq))
    1898              :                end if
    1899              :             else
    1900            3 :                allocate(s% equ1(1:neq))
    1901              :             end if
    1902              : 
    1903           11 :             s% equ(1:nvar,1:nz) => s% equ1(1:neq)
    1904           11 :             equ1 => s% equ1
    1905           11 :             equ => s% equ
    1906              : 
    1907           33 :             allocate(dxsave1(1:neq))
    1908           33 :             allocate(ddxsave1(1:neq))
    1909           33 :             allocate(B1(1:neq))
    1910           33 :             allocate(soln1(1:neq))
    1911           33 :             allocate(grad_f1(1:neq))
    1912           44 :             allocate(rhs(1:nvar,1:nz))
    1913           44 :             allocate(xder(1:nvar,1:nz))
    1914           44 :             allocate(ddx(1:nvar,1:nz))
    1915           33 :             allocate(row_scale_factors1(1:neq))
    1916           33 :             allocate(col_scale_factors1(1:neq))
    1917           33 :             allocate(save_ublk1(1:nvar*neq))
    1918           33 :             allocate(save_dblk1(1:nvar*neq))
    1919           33 :             allocate(save_lblk1(1:nvar*neq))
    1920              : 
    1921           11 :             band_kl = 2*nvar
    1922           11 :             band_ku = 2*nvar
    1923           11 :             band_ldab = 2*band_kl + band_ku + 1
    1924           11 :             band_diag = band_kl + band_ku + 1
    1925           11 :             if (trim(s% hydro_matrix_solver) == 'banded') then
    1926            0 :                allocate(band1(1:band_ldab*neq))
    1927            0 :                band(1:band_ldab,1:neq) => band1(1:band_ldab*neq)
    1928              :             end if
    1929              : 
    1930           11 :             if (s% fill_arrays_with_NaNs) then
    1931            0 :                call fill_with_NaNs(dxsave1)
    1932            0 :                call fill_with_NaNs(ddxsave1)
    1933            0 :                call fill_with_NaNs(B1)
    1934            0 :                call fill_with_NaNs(soln1)
    1935            0 :                call fill_with_NaNs_2D(rhs)
    1936            0 :                call fill_with_NaNs_2D(xder)
    1937            0 :                call fill_with_NaNs_2D(ddx)
    1938            0 :                call fill_with_NaNs(row_scale_factors1)
    1939            0 :                call fill_with_NaNs(col_scale_factors1)
    1940            0 :                call fill_with_NaNs(save_ublk1)
    1941            0 :                call fill_with_NaNs(save_dblk1)
    1942            0 :                call fill_with_NaNs(save_lblk1)
    1943            0 :                if (associated(band1)) call fill_with_NaNs(band1)
    1944              :             end if
    1945              : 
    1946           11 :             dxsave(1:nvar,1:nz) => dxsave1(1:neq)
    1947           11 :             ddxsave(1:nvar,1:nz) => ddxsave1(1:neq)
    1948           11 :             B(1:nvar,1:nz) => B1(1:neq)
    1949           11 :             soln(1:nvar,1:nz) => soln1(1:neq)
    1950           11 :             grad_f(1:nvar,1:nz) => grad_f1(1:neq)
    1951              : 
    1952           33 :             allocate(ipiv1(1:neq))
    1953              : 
    1954           11 :             ipiv_blk1(1:neq) => ipiv1(1:neq)
    1955              : 
    1956           77 :             allocate(ublk1(1:nvar*neq),dblk1(1:nvar*neq),lblk1(1:nvar*neq))
    1957              : 
    1958           11 :             lblk(1:nvar,1:nvar,1:nz) => lblk1(1:nvar*neq)
    1959           11 :             dblk(1:nvar,1:nvar,1:nz) => dblk1(1:nvar*neq)
    1960           11 :             ublk(1:nvar,1:nvar,1:nz) => ublk1(1:nvar*neq)
    1961              : 
    1962           77 :             allocate(ublkF1(1:nvar*neq),dblkF1(1:nvar*neq),lblkF1(1:nvar*neq))
    1963              : 
    1964           11 :             lblkF(1:nvar,1:nvar,1:nz) => lblkF1(1:nvar*neq)
    1965           11 :             dblkF(1:nvar,1:nvar,1:nz) => dblkF1(1:nvar*neq)
    1966           11 :             ublkF(1:nvar,1:nvar,1:nz) => ublkF1(1:nvar*neq)
    1967              : 
    1968           11 :             if (s% fill_arrays_with_NaNs) then
    1969            0 :                call fill_with_NaNs(lblk1)
    1970            0 :                call fill_with_NaNs(dblk1)
    1971            0 :                call fill_with_NaNs(ublk1)
    1972            0 :                call fill_with_NaNs(lblkF1)
    1973            0 :                call fill_with_NaNs(dblkF1)
    1974            0 :                call fill_with_NaNs(ublkF1)
    1975              :             end if
    1976              : 
    1977           11 :          end subroutine pointers
    1978              : 
    1979           11 :          subroutine cleanup()
    1980              : 
    1981           11 :             if(associated(dxsave1)) deallocate(dxsave1)
    1982           11 :             if(associated(ddxsave)) deallocate(ddxsave)
    1983           11 :             if(associated(ddxsave)) deallocate(ddxsave)
    1984           11 :             if(associated(B1)) deallocate(B1)
    1985           11 :             if(associated(soln1)) deallocate(soln1)
    1986           11 :             if(associated(grad_f1)) deallocate(grad_f1)
    1987           11 :             if(associated(rhs)) deallocate(rhs)
    1988           11 :             if(associated(xder)) deallocate(xder)
    1989           11 :             if(associated(ddx)) deallocate(ddx)
    1990           11 :             if(associated(row_scale_factors1)) deallocate(row_scale_factors1)
    1991           11 :             if(associated(col_scale_factors1)) deallocate(col_scale_factors1)
    1992           11 :             if(associated(save_ublk1)) deallocate(save_ublk1)
    1993           11 :             if(associated(save_dblk1)) deallocate(save_dblk1)
    1994           11 :             if(associated(save_lblk1)) deallocate(save_lblk1)
    1995           11 :             if(associated(band1)) deallocate(band1)
    1996           11 :             if(associated(ipiv1)) deallocate(ipiv1)
    1997              : 
    1998           11 :             if(associated(ublk1)) deallocate(ublk1)
    1999           11 :             if(associated(dblk1)) deallocate(dblk1)
    2000           11 :             if(associated(lblk1)) deallocate(lblk1)
    2001           11 :             if(associated(ublkF1)) deallocate(ublkF1)
    2002           11 :             if(associated(dblkF1)) deallocate(dblkF1)
    2003           11 :             if(associated(lblkF1)) deallocate(lblkF1)
    2004              : 
    2005              : 
    2006           11 :             nullify(equ, equ1, dxsave1,dxsave, ddxsave, B1, &
    2007           11 :                      soln1, grad_f1, rhs, xder, ddx, row_scale_factors1,&
    2008           11 :                      col_scale_factors1, save_ublk1, save_dblk1, save_lblk1, band1,&
    2009           11 :                      B, soln, grad_f,ipiv1, ublk1, dblk1, lblk1, ublkF1,dblkF1, lblkF1, band)
    2010              : 
    2011           11 :          end subroutine cleanup
    2012              : 
    2013              : 
    2014            0 :          real(dp) function eval_slope(nvar, nz, grad_f, B)
    2015              :             integer, intent(in) :: nvar, nz
    2016              :             real(dp), intent(in), dimension(:,:) :: grad_f, B
    2017              :             integer :: i
    2018            0 :             eval_slope = 0
    2019            0 :             do i=1,nvar
    2020            0 :                eval_slope = eval_slope + dot_product(grad_f(i,1:nz),B(i,1:nz))
    2021              :             end do
    2022            0 :          end function eval_slope
    2023              : 
    2024              : 
    2025            0 :          real(dp) function eval_f(nvar, nz, equ)
    2026              :             integer, intent(in) :: nvar, nz
    2027              :             real(dp), intent(in), dimension(:,:) :: equ
    2028              :             integer :: k, i
    2029              :             real(dp) :: q
    2030              :             include 'formats'
    2031            0 :             eval_f = 0
    2032            0 :             do k = 1, nz
    2033            0 :                do i = 1, nvar
    2034            0 :                   q = equ(i,k)
    2035            0 :                   eval_f = eval_f + q*q
    2036              :                end do
    2037              :             end do
    2038            0 :             eval_f = eval_f/2
    2039            0 :          end function eval_f
    2040              : 
    2041              :       end subroutine do_solver
    2042              : 
    2043              :       end module star_solver
        

Generated by: LCOV version 2.0-1