LCOV - code coverage report
Current view: top level - interp_1d/private - interp_1d_mp_autodiff.f90 (source / functions) Coverage Total Hit
Test: coverage.info Lines: 0.0 % 177 0
Test Date: 2025-06-06 17:08:43 Functions: 0.0 % 2 0

            Line data    Source code
       1              : ! ***********************************************************************
       2              : !
       3              : !   Copyright (C) 2010  The MESA Team
       4              : !
       5              : !   This program is free software: you can redistribute it and/or modify
       6              : !   it under the terms of the GNU Lesser General Public License
       7              : !   as published by the Free Software Foundation,
       8              : !   either version 3 of the License, or (at your option) any later version.
       9              : !
      10              : !   This program is distributed in the hope that it will be useful,
      11              : !   but WITHOUT ANY WARRANTY; without even the implied warranty of
      12              : !   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
      13              : !   See the GNU Lesser General Public License for more details.
      14              : !
      15              : !   You should have received a copy of the GNU Lesser General Public License
      16              : !   along with this program. If not, see <https://www.gnu.org/licenses/>.
      17              : !
      18              : ! ***********************************************************************
      19              : 
      20              :       module interp_1d_mp_autodiff  ! high accuracy monotonicity preserving algorithms
      21              : 
      22              :       use const_def, only: dp
      23              :       use auto_diff
      24              : 
      25              :       implicit none
      26              :       private
      27              :       public :: m3_autodiff, m3_on_uniform_grid_autodiff
      28              : 
      29              :       contains
      30              : 
      31              : 
      32            0 :       subroutine m3_autodiff(x, nx, f1, which, slope_only, nwork, work1, str, ierr)
      33              :          use interp_1d_def
      34              :          use auto_diff
      35              :          use interp_1d_misc
      36              :          use interp_1d_pm_autodiff, only: mk_pmlinear, mk_pmquad
      37              :          integer, intent(in) :: nx       ! length of x vector
      38              :          type(auto_diff_real_2var_order1), intent(in)    :: x(:)  ! (nx)    ! junction points, strictly monotonic
      39              :          type(auto_diff_real_2var_order1), intent(inout), pointer :: f1(:)  ! =(4, nx)  ! data & interpolation coefficients
      40              :          integer, intent(in) :: which
      41              :          logical, intent(in) :: slope_only
      42              :          integer, intent(in) :: nwork
      43              :          type(auto_diff_real_2var_order1), intent(inout), pointer :: work1(:)  ! =(nx, nwork)
      44              :          character (len=*) :: str
      45              :          integer, intent(out) :: ierr
      46              : 
      47            0 :          type(auto_diff_real_2var_order1), dimension(:), pointer :: h, s_mid, s, d, d_mid, e_mid, hd_mid,  &
      48            0 :                spL, spR, t, tmax, tmp, tmp1, tmp2
      49              :          real(dp), parameter :: tiny = 1d-20
      50              :          integer :: i
      51            0 :          type(auto_diff_real_2var_order1), pointer :: f(:,:)  ! (4, nx)  ! data & interpolation coefficients
      52            0 :          f(1:4,1:nx) => f1(1:4*nx)
      53              : 
      54            0 :          ierr = 0
      55              : 
      56            0 :          if (nx < 2) then
      57              :             return
      58              :          end if
      59              : 
      60            0 :          if (nx == 2) then
      61            0 :             call mk_pmlinear(x, f1, slope_only, nwork, work1, str, ierr)
      62            0 :             return
      63              :          end if
      64              : 
      65            0 :          if (nx == 3) then
      66            0 :             call mk_pmquad(x, f1, slope_only, nwork, work1, str, ierr)
      67            0 :             return
      68              :          end if
      69              : 
      70            0 :          if (nwork < mp_work_size) then
      71            0 :             ierr = -1
      72            0 :             return
      73              :          end if
      74              : 
      75              :          i = 0
      76            0 :          h(1:nx) => work1(i+1:i+nx); i = i+nx
      77            0 :          s_mid(1:nx) => work1(i+1:i+nx); i = i+nx
      78            0 :          s(1:nx) => work1(i+1:i+nx); i = i+nx
      79            0 :          d(1:nx) => work1(i+1:i+nx); i = i+nx
      80            0 :          d_mid(1:nx) => work1(i+1:i+nx); i = i+nx
      81            0 :          e_mid(1:nx) => work1(i+1:i+nx); i = i+nx
      82            0 :          hd_mid(1:nx) => work1(i+1:i+nx); i = i+nx
      83            0 :          spL(1:nx) => work1(i+1:i+nx); i = i+nx
      84            0 :          spR(1:nx) => work1(i+1:i+nx); i = i+nx
      85            0 :          t(1:nx) => work1(i+1:i+nx); i = i+nx
      86            0 :          tmax(1:nx) => work1(i+1:i+nx); i = i+nx
      87            0 :          tmp(1:nx) => work1(i+1:i+nx); i = i+nx
      88            0 :          tmp1(1:nx) => work1(i+1:i+nx); i = i+nx
      89            0 :          tmp2(1:nx) => work1(i+1:i+nx); i = i+nx
      90              : 
      91              :          ! grid spacing
      92            0 :          do i=1,nx-1
      93            0 :             h(i) = x(i+1) - x(i)
      94              :          end do
      95            0 :          do i = 1, nx-1
      96            0 :             if (h(i) == 0) then
      97              :                write(*, '(a,1x,2i5,1x,a)')  &
      98            0 :                   'same interpolation x values at', i, i+1, 'for ' // trim(str)
      99            0 :                ierr = -1
     100            0 :                return
     101              :             end if
     102              :          end do
     103              : 
     104              :          ! divided differences
     105            0 :          do i=1,nx-1
     106            0 :             s_mid(i) = (f(1,i+1) - f(1,i)) / h(i)  ! eqn 2.1
     107              :          end do
     108            0 :          do i=2,nx-1
     109            0 :             d(i) = (s_mid(i) - s_mid(i-1)) / (x(i+1) - x(i-1))  ! eqn 3.1
     110              :          end do
     111              :          ! need to extend d to full range. simplest way is just to copy from neighbor
     112            0 :          d(1) = d(2)
     113            0 :          d(nx) = d(nx-1)
     114              : 
     115              :          ! d_mid eqn(3.4) -- modified according to eqn (2.27) of Suresh & Huynh, 1997
     116            0 :          do i=1,nx-1
     117            0 :             tmp1(i) = 4*d(i+1) - d(i)
     118            0 :             tmp2(i) = 4*d(i) - d(i+1)
     119              :          end do
     120            0 :          call minmod4_autodiff(d_mid(1:nx-1), nx-1, d(2:nx), d(1:nx-1), tmp1(1:nx-1), tmp2(1:nx-1))
     121              : 
     122            0 :          do i=1,nx-1
     123            0 :             hd_mid(i) = h(i)*d_mid(i)
     124              :          end do
     125              : 
     126              :          ! spL(i) = p'(i-1/2)(xi) = smid(i-1) + h(i-1)*d_mid(i-1) from Theorem 1
     127            0 :          do i=1,nx-1
     128            0 :             spL(i+1) = s_mid(i) + hd_mid(i)
     129              :          end do
     130              : 
     131              :          ! spR(i) = p'(i+1/2)(xi) = smid(i) - h(i)*d_mid(i) from Theorem 1
     132            0 :          do i=1,nx-1
     133            0 :             spR(i) = s_mid(i) - hd_mid(i)
     134              :          end do
     135              : 
     136            0 :          call minmod_autodiff(s(2:nx-1), nx-2, s_mid(1:nx-2), s_mid(2:nx-1))  ! eqn (2.8)
     137            0 :          call minmod_autodiff(t(2:nx-1), nx-2, spL(2:nx-1), spR(2:nx-1))
     138              : 
     139            0 :          if (which == average) then
     140              : 
     141            0 :             do i=2,nx-1
     142              :                f(2,i) = sign(t(i))* &
     143              :                   min((abs(spL(i)+spR(i)))/2d0,  &
     144            0 :                      max(3*abs(s(i)), 1.5d0*abs(t(i))))
     145              :             end do
     146              : 
     147            0 :          else if (which == quartic) then
     148              : 
     149            0 :             do i=2,nx-2
     150            0 :                e_mid(i) = (d(i+1) - d(i)) / (x(i+2) - x(i-1))  ! eqn 4.1
     151              :             end do
     152              :             ! eqn 3.5b for p'(i); eqn 4.20 for quadratic f'(i)
     153            0 :             do i=3,nx-2
     154              :                f(2,i) = s_mid(i) -  &
     155              :                   h(i) * (d(i) + h(i-1)* &
     156              :                      (e_mid(i-1)*(x(i+2)-x(i))  &
     157            0 :                         + e_mid(i)*(x(i)-x(i-2)))/(x(i+2)-x(i-2)))
     158              :             end do
     159              :             ! finish off ends with average
     160              :             f(2,2) = sign(t(2))* &
     161            0 :                   min((abs(spL(2)+spR(2)))/2d0, max(3*abs(s(2)), 1.5d0*abs(t(2))))
     162              :             f(2,nx-1) = sign(t(nx-1))* &
     163              :                   min((abs(spL(nx-1)+spR(nx-1)))/2d0,  &
     164            0 :                   max(3*abs(s(nx-1)), 1.5d0*abs(t(nx-1))))
     165            0 :             do i=2,nx-1
     166            0 :                tmp1(i) = f(2,i)
     167            0 :                tmp2(i) = tmp1(i)
     168              :             end do
     169            0 :             call median_autodiff(tmp1(2:nx-1), nx-2, tmp2(2:nx-1), spL(2:nx-1), spR(2:nx-1))
     170            0 :             do i=2,nx-1
     171            0 :                f(2,i) = tmp1(i)
     172              :             end do
     173            0 :             do i=2,nx-1
     174              :                tmax(i) = sign(t(i))* &
     175            0 :                   max(3*abs(s(i)), 1.5d0*abs(t(i)))
     176              :             end do
     177            0 :             do i=2,nx-1
     178            0 :                tmp1(i) = f(2,i)
     179              :             end do
     180            0 :             call minmod_autodiff(tmp2(2:nx-1), nx-2, tmp1(2:nx-1), tmax(2:nx-1))
     181            0 :             do i=2,nx-1
     182            0 :                f(2,i) = tmp2(i)
     183              :             end do
     184              : 
     185              :          else  !if (which == super_bee) then
     186              : 
     187            0 :             do i=2,nx-1
     188              :                f(2,i) = sign(t(i))* &
     189              :                   min(max(abs(spL(i)), abs(spR(i))),  &
     190            0 :                      max(3*abs(s(i)), 1.5d0*abs(t(i))))
     191              :             end do
     192              : 
     193              :          end if
     194              : 
     195              :          ! slope at i=1
     196              :          !f(2, 1) = minmod1_autodiff(spR(1), 3*s_mid(1)) ! eqn (5.2)
     197            0 :          f(2,1) = minmod1_autodiff(s_mid(1), s_mid(2))  ! stabilize the ends
     198              : 
     199              :          ! slope at i=nx
     200              :          !f(2, nx) = minmod1_autodiff(spL(nx), 3*s_mid(nx-1)) ! eqn (5.2)
     201            0 :          f(2,nx) = minmod1_autodiff(s_mid(nx-2), s_mid(nx-1))  ! stabilize the ends
     202              : 
     203            0 :          if (slope_only) return
     204              : 
     205              :          ! 2nd and 3rd derivatives
     206            0 :          do i=1,nx-1
     207            0 :             f(3,i) = (3*s_mid(i) - 2*f(2,i) - f(2,i+1)) / h(i)
     208            0 :             f(4,i) = (f(2,i) + f(2,i+1) - 2*s_mid(i)) / (h(i)*h(i))
     209              :          end do
     210            0 :          f(3,nx) = (3*f(1, nx-1) - 3*f(1, nx) + (f(2, nx-1) + 2*f(2, nx)) * h(nx-1)) / (h(nx-1)*h(nx-1))
     211            0 :          f(4,nx) = (-2*f(1, nx-1) + 2*f(1, nx) - (f(2, nx-1) + f(2, nx))*h(nx-1)) / (h(nx-1)*h(nx-1)*h(nx-1))
     212              : 
     213            0 :       end subroutine m3_autodiff
     214              : 
     215              : 
     216            0 :       subroutine m3_on_uniform_grid_autodiff(dx, nx, f1, which, slope_only, nwork, work1, str, ierr)
     217            0 :          use interp_1d_def
     218              :          use auto_diff
     219              :          use interp_1d_misc
     220              :          use interp_1d_pm_autodiff, only: mk_pmlinear, mk_pmquad
     221              :          ! make piecewise monotonic cubic interpolant
     222              :          type(auto_diff_real_2var_order1), intent(in) :: dx  ! the grid spacing
     223              :          integer, intent(in) :: nx       ! length of x vector
     224              :          type(auto_diff_real_2var_order1), intent(inout), pointer :: f1(:)  ! =(4, nx)  ! data & interpolation coefficients
     225              :          integer, intent(in) :: which
     226              :          logical, intent(in) :: slope_only
     227              :          integer, intent(in) :: nwork
     228              :          type(auto_diff_real_2var_order1), intent(inout), pointer :: work1(:)  ! =(nx, nwork)
     229              :          character (len=*) :: str
     230              :          integer, intent(out) :: ierr
     231              : 
     232            0 :          type(auto_diff_real_2var_order1), dimension(:), pointer :: s_mid, s, d, d_mid, e_mid, spL, spR, t, tmax,  &
     233            0 :             tmp, tmp1, tmp2
     234              :          real(dp), parameter :: tiny = 1d-20
     235              :          type(auto_diff_real_2var_order1) :: x(3)
     236              :          integer :: i
     237            0 :          type(auto_diff_real_2var_order1), pointer :: f(:,:)  ! (4, nx)  ! data & interpolation coefficients
     238            0 :          f(1:4,1:nx) => f1(1:4*nx)
     239              : 
     240            0 :          ierr = 0
     241              : 
     242            0 :          if (nx < 2) then
     243              :             return
     244              :          end if
     245              : 
     246            0 :          if (nx == 2) then
     247            0 :             x(1) = 0
     248            0 :             x(2) = dx
     249            0 :             call mk_pmlinear(x, f1, slope_only, nwork, work1, str, ierr)
     250            0 :             return
     251              :          end if
     252              : 
     253            0 :          if (nx == 3) then
     254            0 :             x(1) = 0
     255            0 :             x(2) = dx
     256            0 :             x(3) = 2*dx
     257            0 :             call mk_pmquad(x, f1, slope_only, nwork, work1, str, ierr)
     258            0 :             return
     259              :          end if
     260              : 
     261            0 :          if (dx == 0) then
     262            0 :             ierr = -1
     263            0 :             return
     264              :          end if
     265              : 
     266            0 :          if (nwork < mp_work_size) then
     267            0 :             ierr = -1
     268            0 :             return
     269              :          end if
     270              : 
     271            0 :          i = 0
     272            0 :          s_mid(1:nx) => work1(i+1:i+nx); i = i+nx
     273            0 :          s(1:nx) => work1(i+1:i+nx); i = i+nx
     274            0 :          d(1:nx) => work1(i+1:i+nx); i = i+nx
     275            0 :          d_mid(1:nx) => work1(i+1:i+nx); i = i+nx
     276            0 :          e_mid(1:nx) => work1(i+1:i+nx); i = i+nx
     277            0 :          spL(1:nx) => work1(i+1:i+nx); i = i+nx
     278            0 :          spR(1:nx) => work1(i+1:i+nx); i = i+nx
     279            0 :          t(1:nx) => work1(i+1:i+nx); i = i+nx
     280            0 :          tmax(1:nx) => work1(i+1:i+nx); i = i+nx
     281            0 :          tmp(1:nx) => work1(i+1:i+nx); i = i+nx
     282            0 :          tmp1(1:nx) => work1(i+1:i+nx); i = i+nx
     283            0 :          tmp2(1:nx) => work1(i+1:i+nx); i = i+nx
     284              : 
     285              :          ! divided differences
     286            0 :          do i=1,nx-1
     287            0 :             s_mid(i) = (f(1,i+1) - f(1,i)) / dx  ! eqn 2.1
     288              :          end do
     289            0 :          do i=2,nx-1
     290            0 :             d(i) = (s_mid(i) - s_mid(i-1)) / (2*dx)  ! eqn 3.1
     291              :          end do
     292              :          ! need to extend d to full range. simplest way is just to copy from neighbor
     293            0 :          d(1) = d(2)
     294            0 :          d(nx) = d(nx-1)
     295              : 
     296              :          ! d_mid eqn(3.4) -- modified according to eqn (2.27) of Suresh & Huynh, 1997
     297            0 :          do i=1,nx-1
     298            0 :             tmp1(i) = 4*d(i+1) - d(i)
     299            0 :             tmp2(i) = 4*d(i) - d(i+1)
     300              :          end do
     301            0 :          call minmod4_autodiff(d_mid(1:nx-1), nx-1, d(2:nx), d(1:nx-1), tmp1(1:nx-1), tmp2(1:nx-1))
     302              : 
     303              :          ! spL(i) = p'(i-1/2)(xi) = smid(i-1) + h(i-1)*d_mid(i-1) from Theorem 1
     304            0 :          do i=1,nx-1
     305            0 :             spL(i+1) = s_mid(i) + dx*d_mid(i)
     306              :          end do
     307              : 
     308              :          ! spR(i) = p'(i+1/2)(xi) = smid(i) - h(i)*d_mid(i) from Theorem 1
     309            0 :          do i=1,nx-1
     310            0 :             spR(i) = s_mid(i) - dx*d_mid(i)
     311              :          end do
     312              : 
     313            0 :          call minmod_autodiff(s(2:nx-1), nx-2, s_mid(1:nx-2), s_mid(2:nx-1))  ! eqn (2.8)
     314            0 :          call minmod_autodiff(t(2:nx-1), nx-2, spL(2:nx-1), spR(2:nx-1))
     315              : 
     316            0 :          if (which == average) then
     317              : 
     318            0 :             do i=2,nx-1
     319              :                f(2,i) = sign(t(i))* &
     320              :                   min((abs(spL(i)+spR(i)))/2d0,  &
     321            0 :                      max(3*abs(s(i)), 1.5d0*abs(t(i))))
     322              :             end do
     323              : 
     324            0 :          else if (which == quartic) then
     325              : 
     326            0 :             do i=2,nx-2
     327            0 :                e_mid(i) = (d(i+1) - d(i)) / (3*dx)  ! eqn 4.1
     328              :             end do
     329              :             ! eqn 3.5b for p'(i); eqn 4.20 for quadratic f'(i)
     330            0 :             do i=3,nx-2
     331              :                f(2,i) = s_mid(i) -  &
     332            0 :                   dx * (d(i) + dx*(e_mid(i-1)*(2*dx) + e_mid(i)*(2*dx))/(4*dx))
     333              :             end do
     334              :             ! finish off ends with average
     335              :             f(2,2) = sign(t(2))* &
     336            0 :                   min((abs(spL(2)+spR(2)))/2d0, max(3*abs(s(2)), 1.5d0*abs(t(2))))
     337              :             f(2,nx-1) = sign(t(nx-1))* &
     338              :                   min((abs(spL(nx-1)+spR(nx-1)))/2d0,  &
     339            0 :                   max(3*abs(s(nx-1)), 1.5d0*abs(t(nx-1))))
     340            0 :             do i=2,nx-1
     341            0 :                tmp1(i) = f(2,i)
     342            0 :                tmp2(i) = tmp1(i)
     343              :             end do
     344            0 :             call median_autodiff(tmp1(2:nx-1), nx-2, tmp2(2:nx-1), spL(2:nx-1), spR(2:nx-1))
     345            0 :             do i=2,nx-1
     346            0 :                f(2,i) = tmp1(i)
     347              :             end do
     348            0 :             do i=2,nx-1
     349              :                tmax(i) = sign(t(i))* &
     350            0 :                   max(3*abs(s(i)), 1.5d0*abs(t(i)))
     351              :             end do
     352            0 :             do i=2,nx-1
     353            0 :                tmp1(i) = f(2,i)
     354              :             end do
     355            0 :             call minmod_autodiff(tmp2(2:nx-1), nx-2, tmp1(2:nx-1), tmax(2:nx-1))
     356            0 :             do i=2,nx-1
     357            0 :                f(2,i) = tmp2(i)
     358              :             end do
     359              : 
     360              :          else  !if (which == super_bee) then
     361              : 
     362            0 :             do i=2,nx-1
     363              :                f(2,i) = sign(t(i))* &
     364              :                   min(max(abs(spL(i)), abs(spR(i))),  &
     365            0 :                      max(3*abs(s(i)), 1.5d0*abs(t(i))))
     366              :             end do
     367              : 
     368              :          end if
     369              : 
     370              :          ! slope at i=1
     371              :          !f(2, 1) = minmod1_autodiff(spR(1), 3*s_mid(1)) ! eqn (5.2)
     372            0 :          f(2,1) = minmod1_autodiff(s_mid(1), s_mid(2))  ! stabilize the ends
     373              : 
     374              :          ! slope at i=nx
     375              :          !f(2, nx) = minmod1_autodiff(spL(nx), 3*s_mid(nx-1)) ! eqn (5.2)
     376            0 :          f(2, nx) = minmod1_autodiff(s_mid(nx-2), s_mid(nx-1))  ! stabilize the ends
     377              : 
     378            0 :          if (slope_only) return
     379              : 
     380              :          ! 2nd and 3rd derivatives
     381            0 :          do i=1,nx-1
     382            0 :             f(3,i) = (3*s_mid(i) - 2*f(2,i) - f(2,i+1)) / dx
     383            0 :             f(4,i) = (f(2,i) + f(2,i+1) - 2*s_mid(i)) / (dx*dx)
     384              :          end do
     385            0 :          f(3, nx) = (3*f(1, nx-1) - 3*f(1, nx) + (f(2, nx-1) + 2*f(2, nx)) * dx) / (dx*dx)
     386            0 :          f(4, nx) = (-2*f(1, nx-1) + 2*f(1, nx) - (f(2, nx-1) + f(2, nx))*dx) / (dx*dx*dx)
     387              : 
     388            0 :       end subroutine m3_on_uniform_grid_autodiff
     389              : 
     390              : 
     391              :       end module interp_1d_mp_autodiff
        

Generated by: LCOV version 2.0-1