LCOV - code coverage report
Current view: top level - num/test/src - test_diffusion.f90 (source / functions) Coverage Total Hit
Test: coverage.info Lines: 91.7 % 145 133
Test Date: 2025-05-08 18:23:42 Functions: 85.7 % 7 6

            Line data    Source code
       1              : module test_diffusion
       2              :    use num_def
       3              :    use num_lib
       4              :    use math_lib
       5              :    use test_int_support, only: i_nfcn, i_njac
       6              :    use utils_lib, only: mesa_error
       7              : 
       8              :    implicit none
       9              : 
      10              :    integer :: mljac, mujac, nstep
      11              : 
      12              :    integer, parameter :: nz = 48
      13              :    integer, parameter :: diff_mujac = 1, diff_mljac = 1, diff_ldjac = diff_mujac + diff_mljac + 1
      14              : 
      15              :    real(dp) :: y0(nz), yexact(nz), dfdy2(4, nz), rcond, work(3*nz)
      16              :    integer :: ipiv(nz), iwork(nz), info
      17              : 
      18              :    real(dp) :: sig_dm(nz)
      19              : 
      20              : contains
      21              : 
      22         7847 :    subroutine diffusion_op(n, x, h, y, f, dfdy, ld_dfdy, lrpar, rpar, lipar, ipar, ierr)
      23              :       integer, intent(in) :: n, ld_dfdy, lrpar, lipar
      24              :       real(dp), intent(in) :: x, h
      25              :       real(dp), intent(inout) :: y(n)
      26              :       real(dp), intent(inout) :: f(n), dfdy(ld_dfdy, n)
      27              :       integer, intent(inout), pointer :: ipar(:)  ! (lipar)
      28              :       real(dp), intent(inout), pointer :: rpar(:)  ! (lrpar)
      29              :       integer, intent(out) :: ierr
      30              : 
      31         7847 :       real(dp) :: sig1, sig2
      32              :       integer :: i
      33         7847 :       ierr = 0
      34              : 
      35      1204894 :       f = 0; dfdy = 0
      36              : 
      37              :       sig2 = 0
      38       384503 :       do i = 1, n
      39       376656 :          sig1 = sig2
      40       376656 :          if (i < n) then
      41       368809 :             sig2 = sig_dm(i + 1)
      42              :          else
      43              :             sig2 = 0
      44              :          end if
      45       376656 :          if (ld_dfdy > 0) then
      46       145296 :             if (i > 1) then
      47       142269 :                dfdy(3, i - 1) = sig1
      48              :             end if
      49       145296 :             dfdy(2, i) = -(sig1 + sig2)
      50       145296 :             if (i < n) then
      51       142269 :                dfdy(1, i + 1) = sig2
      52              :             end if
      53              :          end if
      54       384503 :          if (i == n) then
      55         7847 :             f(i) = sig1*(y(i - 1) - y(i))
      56       368809 :          else if (i == 1) then
      57         7847 :             f(i) = -sig2*(y(i) - y(i + 1))
      58              :          else
      59       360962 :             f(i) = sig1*(y(i - 1) - y(i)) - sig2*(y(i) - y(i + 1))
      60              :          end if
      61              :       end do
      62              : 
      63         7847 :    end subroutine diffusion_op
      64              : 
      65         4820 :    subroutine diffusion_derivs(n, x, h, y, f, lrpar, rpar, lipar, ipar, ierr)
      66              :       integer, intent(in) :: n, lrpar, lipar
      67              :       real(dp), intent(in) :: x, h
      68              :       real(dp), intent(inout) :: y(:)  ! (n)
      69              :       real(dp), intent(inout) :: f(:)  ! (n)
      70              :       integer, intent(inout), pointer :: ipar(:)  ! (lipar)
      71              :       real(dp), intent(inout), pointer :: rpar(:)  ! (lrpar)
      72              :       integer, intent(out) :: ierr
      73              : 
      74         9640 :       real(dp) :: dfdy(0, n)
      75              : 
      76         4820 :       ierr = 0
      77         4820 :       ipar(i_nfcn) = ipar(i_nfcn) + 1
      78         4820 :       call diffusion_op(n, x, h, y, f, dfdy, 0, lrpar, rpar, lipar, ipar, ierr)
      79         4820 :    end subroutine diffusion_derivs
      80              : 
      81         3027 :    subroutine diffusion_jacob(n, x, h, y, f, dfdy, ld_dfdy, lrpar, rpar, lipar, ipar, ierr)
      82              :       use mtx_lib, only: mtx_rcond_banded
      83              :       integer, intent(in) :: n, ld_dfdy, lrpar, lipar
      84              :       real(dp), intent(in) :: x, h
      85              :       real(dp), intent(inout) :: y(:)
      86              :       real(dp), intent(inout) :: f(:), dfdy(:, :)
      87              :       integer, intent(inout), pointer :: ipar(:)  ! (lipar)
      88              :       real(dp), intent(inout), pointer :: rpar(:)  ! (lrpar)
      89              :       integer, intent(out) :: ierr
      90              :       include 'formats'
      91         3027 :       ierr = 0
      92         3027 :       ipar(i_njac) = ipar(i_njac) + 1
      93         3027 :       call diffusion_op(n, x, h, y, f, dfdy, ld_dfdy, lrpar, rpar, lipar, ipar, ierr)
      94              : 
      95              :       return
      96              : 
      97              :       dfdy2(2, 1:n) = dfdy(1, 1:n)
      98              :       dfdy2(3, 1:n) = dfdy(2, 1:n) - 1
      99              :       dfdy2(4, 1:n) = dfdy(3, 1:n)
     100              : 
     101              :       call mtx_rcond_banded('N', n, n, 1, 1, dfdy2, 4, ipiv, rcond, work, iwork, info)
     102              :       write (*, 2) 'diffusion_jacob rcond', info, x, safe_log10(rcond)
     103              : 
     104              :    end subroutine diffusion_jacob
     105              : 
     106            0 :    subroutine diffusion_sjac(n, x, h, y, f, nzmax, ia, ja, values, lrpar, rpar, lipar, ipar, ierr)
     107              :       ! sparse jacobian. format either compressed row or compressed column.
     108              :       use mtx_lib, only: band_to_row_sparse_with_diag, band_to_col_sparse_with_diag, mtx_rcond_banded
     109              :       use test_int_support, only: ipar_sparse_format
     110              :       integer, intent(in) :: n, nzmax, lrpar, lipar
     111              :       real(dp), intent(in) :: x, h
     112              :       real(dp), intent(inout) :: y(:)  ! (n)
     113              :       real(dp), intent(inout) :: f(:)  ! (n) ! dy/dx
     114              :       integer, intent(inout) :: ia(:)  ! (n+1)
     115              :       integer, intent(inout) :: ja(:)  ! (nzmax)
     116              :       real(dp), intent(inout) :: values(:)  ! (nzmax)
     117              :       integer, intent(inout), pointer :: ipar(:)  ! (lipar)
     118              :       real(dp), intent(inout), pointer :: rpar(:)  ! (lrpar)
     119              :       integer, intent(out) :: ierr  ! nonzero means terminate integration
     120              : 
     121            0 :       real(dp) :: dfdy(n, n)
     122              :       integer :: ld_dfdy, nz
     123            0 :       ld_dfdy = n
     124              :       ierr = 0
     125            0 :       call diffusion_jacob(n, x, h, y, f, dfdy, ld_dfdy, lrpar, rpar, lipar, ipar, ierr)
     126            0 :       if (ierr /= 0) return
     127            0 :       if (ipar(ipar_sparse_format) == 0) then
     128            0 :          call band_to_row_sparse_with_diag(n, mljac, mujac, dfdy, ld_dfdy, nzmax, nz, ia, ja, values, ierr)
     129              :       else
     130            0 :          call band_to_col_sparse_with_diag(n, mljac, mujac, dfdy, ld_dfdy, nzmax, nz, ia, ja, values, ierr)
     131              :       end if
     132            0 :    end subroutine diffusion_sjac
     133              : 
     134         3034 :    subroutine diffusion_solout(nr, xold, x, n, y, rwork, iwork, interp_y, lrpar, rpar, lipar, ipar, irtrn)
     135              :       ! nr is the step number.
     136              :       ! x is the current x value; xold is the previous x value.
     137              :       ! y is the current y value.
     138              :       ! irtrn negative means terminate integration.
     139              :       ! rwork and iwork hold info for
     140              :       integer, intent(in) :: nr, n, lrpar, lipar
     141              :       real(dp), intent(in) :: xold, x
     142              :       real(dp), intent(inout) :: y(:)  ! (n)
     143              :       real(dp), intent(inout), target :: rwork(*)
     144              :       integer, intent(inout), target :: iwork(*)
     145              :       integer, intent(inout), pointer :: ipar(:)  ! (lipar)
     146              :       real(dp), intent(inout), pointer :: rpar(:)  ! (lrpar)
     147              :       interface
     148              :          ! this subroutine can be called from your solout routine.
     149              :          ! it computes interpolated values for y components during the just completed step.
     150              :          real(dp) function interp_y(i, s, rwork, iwork, ierr)
     151              :             use const_def, only: dp
     152              :             implicit none
     153              :             integer, intent(in) :: i  ! result is interpolated approximation of y(i) at x=s.
     154              :             real(dp), intent(in) :: s  ! interpolation x value (between xold and x).
     155              :             real(dp), intent(inout), target :: rwork(*)
     156              :             integer, intent(inout), target :: iwork(*)
     157              :             integer, intent(out) :: ierr
     158              :          end function interp_y
     159              :       end interface
     160              :       integer, intent(out) :: irtrn
     161         3034 :       irtrn = 0
     162            0 :    end subroutine diffusion_solout
     163              : 
     164            7 :    subroutine do_test_diffusion(which_solver, which_decsol, numerical_jacobian, show_all, quiet)
     165              :       use test_support, only: show_results, show_statistics, check_results
     166              :       use test_int_support, only: do_test_stiff_int
     167              :       integer, intent(in) :: which_solver, which_decsol
     168              :       logical, intent(in) :: numerical_jacobian, show_all, quiet
     169              : 
     170              :       real(dp), parameter :: sig = 1d-2
     171              : 
     172              :       real(dp), parameter :: ystart = 1d0, tend = 1d4
     173              :       integer, parameter :: n = nz
     174              :       integer, parameter :: lrpar = 1, lipar = 3, iout = 1
     175              :       integer, parameter :: ndisc = 0, n_soln = 10
     176          343 :       real(dp), target :: y_ary(n)
     177              :       real(dp), pointer :: y(:)
     178          196 :       real(dp) :: result(n_soln), soln(n_soln), h0, atol(1), rtol(1), t(0:ndisc + 1)
     179              :       integer :: i, k, matrix_type_spec, ierr, imas, mlmas, mumas, m1, m2, itol
     180           14 :       real(dp), target :: rpar_ary(lrpar)
     181              :       integer, target :: ipar_ary(lipar)
     182              :       real(dp), pointer :: rpar(:)
     183              :       integer, pointer :: ipar(:)
     184              :       integer :: caller_id, nvar_blk_dble, nz_blk_dble
     185            7 :       real(dp), dimension(:), pointer :: lblk, dblk, ublk  ! =(nvar,nvar,nz)
     186            7 :       real(dp), dimension(:), pointer :: uf_lblk, uf_dblk, uf_ublk  ! =(nvar,nvar,nz)
     187              : 
     188            7 :       nullify (lblk, dblk, ublk, uf_lblk, uf_dblk, uf_ublk)
     189            7 :       caller_id = 0
     190            7 :       nvar_blk_dble = 0
     191            7 :       nz_blk_dble = 0
     192              : 
     193            7 :       rpar => rpar_ary
     194            7 :       ipar => ipar_ary
     195            7 :       y => y_ary
     196              : 
     197            7 :       if (.not. quiet) write (*, *) 'diffusion'
     198              : 
     199            7 :       t(0) = 0d0
     200            7 :       t(1) = tend
     201              : 
     202            7 :       itol = 0  ! scalar tolerances
     203           14 :       rtol = 1d-6
     204           14 :       atol = 1d-6
     205            7 :       h0 = atol(1)*1d-1  ! initial step size
     206              : 
     207            7 :       matrix_type_spec = banded_matrix_type
     208            7 :       mljac = diff_mljac
     209            7 :       mujac = diff_mujac
     210              : 
     211            7 :       imas = 0
     212            7 :       mlmas = 0
     213            7 :       mumas = 0
     214              : 
     215            7 :       m1 = 0
     216            7 :       m2 = 0
     217              : 
     218            7 :       k = nz/2
     219          175 :       y(1:k) = 0
     220          182 :       y(k + 1:nz) = ystart
     221              : 
     222          350 :       y0 = y
     223              : 
     224          343 :       do k = 1, nz
     225          343 :          if (k == 1) then
     226            7 :             sig_dm(k) = 0
     227          329 :          else if (5*k <= n) then
     228           56 :             sig_dm(k) = 0
     229          273 :          else if (5*k >= 4*n) then
     230           70 :             sig_dm(k) = 0
     231              :          else
     232          203 :             sig_dm(k) = sig
     233              :          end if
     234              :       end do
     235              : 
     236            7 :       nstep = 0
     237              : 
     238              :       call do_test_stiff_int(which_solver, which_decsol, numerical_jacobian, &
     239              :                              diffusion_derivs, diffusion_jacob, diffusion_sjac, diffusion_solout, iout, &
     240              :                              null_fcn_blk_dble, null_jac_blk_dble, &
     241              :                              caller_id, nvar_blk_dble, nz_blk_dble, lblk, dblk, ublk, uf_lblk, uf_dblk, uf_ublk, &
     242              :                              n, ndisc, mljac, mujac, matrix_type_spec, null_mas, imas, mlmas, mumas, m1, m2, &
     243            7 :                              t, rtol, atol, itol, h0, y, nstep, lrpar, rpar, lipar, ipar, quiet, ierr)
     244            7 :       if (ierr /= 0) then
     245            0 :          write (*, *) 'test_diffusion ierr', ierr
     246            0 :          call mesa_error(__FILE__, __LINE__)
     247              :       end if
     248              : 
     249              :       !call write_diffusion_results
     250              : 
     251            7 :       call set_yexact
     252            7 :       i = 0
     253            7 :       do k = 10, nz - 10, (nz - 10)/12
     254           70 :          i = i + 1
     255              :          if (i > n_soln) exit
     256           70 :          soln(i) = yexact(k)
     257           70 :          result(i) = y(k)
     258              :       end do
     259              : 
     260            7 :       call show_results(n_soln, result, soln, show_all)
     261           14 :       call show_statistics(ipar(i_nfcn), ipar(i_njac), nstep, show_all)
     262              : 
     263              :    contains
     264              : 
     265            7 :       subroutine set_yexact
     266              :          ! for nz=48, sig = 1d-2, ystart = 1d0, tend = 1d4
     267            7 :          yexact(1) = 0.0000000000000000D+00
     268            7 :          yexact(2) = 0.0000000000000000D+00
     269            7 :          yexact(3) = 0.0000000000000000D+00
     270            7 :          yexact(4) = 0.0000000000000000D+00
     271            7 :          yexact(5) = 0.0000000000000000D+00
     272            7 :          yexact(6) = 0.0000000000000000D+00
     273            7 :          yexact(7) = 0.0000000000000000D+00
     274            7 :          yexact(8) = 0.0000000000000000D+00
     275            7 :          yexact(9) = 2.5602881146875722D-01
     276            7 :          yexact(10) = 2.5830832258765279D-01
     277            7 :          yexact(11) = 2.6284365888436573D-01
     278            7 :          yexact(12) = 2.6958764648712957D-01
     279            7 :          yexact(13) = 2.7847002063795223D-01
     280            7 :          yexact(14) = 2.8939802361837114D-01
     281            7 :          yexact(15) = 3.0225720584222654D-01
     282            7 :          yexact(16) = 3.1691243229910382D-01
     283            7 :          yexact(17) = 3.3320909577496399D-01
     284            7 :          yexact(18) = 3.5097453679942375D-01
     285            7 :          yexact(19) = 3.7001966806159553D-01
     286            7 :          yexact(20) = 3.9014079814263225D-01
     287            7 :          yexact(21) = 4.1112164592868455D-01
     288            7 :          yexact(22) = 4.3273553313243934D-01
     289            7 :          yexact(23) = 4.5474773813802244D-01
     290            7 :          yexact(24) = 4.7691799008736224D-01
     291            7 :          yexact(25) = 4.9900307794850141D-01
     292            7 :          yexact(26) = 5.2075954544461744D-01
     293            7 :          yexact(27) = 5.4194643935567555D-01
     294            7 :          yexact(28) = 5.6232807598367041D-01
     295            7 :          yexact(29) = 5.8167678861286254D-01
     296            7 :          yexact(30) = 5.9977561767405640D-01
     297            7 :          yexact(31) = 6.1642090507187908D-01
     298            7 :          yexact(32) = 6.3142475475257254D-01
     299            7 :          yexact(33) = 6.4461732303943897D-01
     300            7 :          yexact(34) = 6.5584890447885325D-01
     301            7 :          yexact(35) = 6.6499178183713092D-01
     302            7 :          yexact(36) = 6.7194181237134964D-01
     303            7 :          yexact(37) = 6.7661972646501933D-01
     304            7 :          yexact(38) = 6.7897211907369082D-01
     305            7 :          yexact(39) = 1.0000000000000000D+00
     306            7 :          yexact(40) = 1.0000000000000000D+00
     307            7 :          yexact(41) = 1.0000000000000000D+00
     308            7 :          yexact(42) = 1.0000000000000000D+00
     309            7 :          yexact(43) = 1.0000000000000000D+00
     310            7 :          yexact(44) = 1.0000000000000000D+00
     311            7 :          yexact(45) = 1.0000000000000000D+00
     312            7 :          yexact(46) = 1.0000000000000000D+00
     313            7 :          yexact(47) = 1.0000000000000000D+00
     314            7 :          yexact(48) = 1.0000000000000000D+00
     315            7 :       end subroutine set_yexact
     316              : 
     317              :       subroutine write_diffusion_results
     318              :          use utils_lib, only: mkdir
     319              :          use const_def
     320              :          character(len=100) :: filename, dir
     321              :          integer :: k, ierr, iounit
     322              :          dir = 'plot_data'
     323              :          call mkdir(dir)
     324              :          filename = trim(dir)//'/'//'diffusion.data'
     325              :          ierr = 0
     326              :          open (newunit=iounit, file=trim(filename), action='write', status='replace', iostat=ierr)
     327              :          if (ierr == 0) then
     328              :             write (*, *) 'write burn results to '//trim(filename)
     329              :             write (iounit, '(a)') 'burn log'
     330              :             write (iounit, '(99(a,1x))') 'y', 'y0', 'sigma'
     331              :             do k = 1, nz
     332              :                write (iounit, '(99e24.10)') y(k), y0(k), sig_dm(k)
     333              :             end do
     334              :             close (iounit)
     335              :          else
     336              :             write (*, *) 'failed to open internals file '//trim(filename)
     337              :          end if
     338              :       end subroutine write_diffusion_results
     339              : 
     340              :    end subroutine do_test_diffusion
     341              : 
     342              : end module test_diffusion
        

Generated by: LCOV version 2.0-1