LCOV - code coverage report
Current view: top level - interp_1d/private - interp_1d_mp_sg.f90 (source / functions) Coverage Total Hit
Test: coverage.info Lines: 42.5 % 179 76
Test Date: 2025-05-08 18:23:42 Functions: 50.0 % 2 1

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

Generated by: LCOV version 2.0-1