LCOV - code coverage report
Current view: top level - mtx/private - DGBSVX_wrapper.f90 (source / functions) Coverage Total Hit
Test: coverage.info Lines: 0.0 % 107 0
Test Date: 2025-05-08 18:23:42 Functions: 0.0 % 2 0

            Line data    Source code
       1              :     module DGBSVX_wrapper
       2              : 
       3              :       use const_def, only: dp
       4              :       use pre_conditioners
       5              : 
       6              :       implicit none
       7              : 
       8              :       private
       9              :       public :: DGBSVX_tridiagonal_wrapper, DGBSVX_banded_wrapper
      10              : 
      11              :       contains
      12              : 
      13              :       !> Wraps the lapack DGBSVX routine for banded matrices with a preconditioner
      14              :       !! and a simpler input format.
      15              :       !!
      16              :       !! @param matrix_size The number of rows or columns in the square matrix.
      17              :       !! @params n_upper_bands The number of bands above the diagonal.
      18              :       !! @params n_lower_bands The number of bands below the diagonal.
      19              :       !! @params bands Array of shape (n_upper_bands + n_lower_bands + 1, matrix_size). Stores the bands going from upper-most to lower-most, aligned so the first entry in each band has index 1.
      20              :       !! @params x Array of shape (matrix_size). Stores the result of solving Matrix.x = b.
      21              :       !! @params b Array of shape (matrix_size). The right-hand side from the definition of x.
      22              :       !! @params pre_conditioner Pre-conditioning vector. Computed in this routine.
      23              :       !! @params ierr Integer-valued error code.
      24            0 :       subroutine DGBSVX_banded_wrapper(matrix_size, n_upper_bands, n_lower_bands, bands, x, b, pre_conditioner, ierr)
      25              :          ! Inputs
      26              :          real(dp), dimension(:,:), intent(in) :: bands
      27              :          real(dp), dimension(:), intent(in) :: b
      28              :          integer, intent(in) :: matrix_size, n_upper_bands, n_lower_bands
      29              : 
      30              :          ! Intermediates
      31              :          integer :: i, j
      32              :          character(len=1) :: FACT, TRANS, EQUED
      33              :          integer :: NRHS, LDAB, LDAFB, LDB, LDX
      34            0 :          integer :: IWORK(matrix_size),  IPIV(matrix_size)
      35            0 :          real(dp) :: WORK(3 * matrix_size), BERR(1), FERR(1)
      36            0 :          real(dp) :: C(matrix_size), R(matrix_size)
      37            0 :          real(dp) :: b_conditioned(matrix_size, 1), x_tmp(matrix_size, 1)
      38            0 :          real(dp) :: AB(n_lower_bands+n_upper_bands+1, matrix_size)
      39            0 :          real(dp) :: AFB(2*n_lower_bands+n_upper_bands+1, matrix_size)
      40            0 :          real(dp) ::  RCOND
      41              : 
      42              :          ! Outputs
      43              :          real(dp), dimension(:), intent(out) :: x
      44              :          real(dp), dimension(:), intent(out) :: pre_conditioner
      45              :          integer, intent(out) :: ierr
      46              : 
      47              :          ! Fixed arguments
      48              : 
      49            0 :          FACT = 'N'  ! We've already equilibrated the matrix
      50            0 :          TRANS = 'N'  ! This argument is irrelevant if FACT == 'N'
      51            0 :          EQUED = 'N'  ! No equilibration
      52            0 :          NRHS = 1                ! Number of columns in equ for A.x=b.
      53            0 :          LDX = matrix_size       ! Number of rows in flattened x
      54            0 :          LDB = matrix_size       ! Number of rows in flattened b
      55            0 :          LDAB = n_lower_bands+n_upper_bands+1  ! Number of rows in AB format of banded matrix
      56            0 :          LDAFB = 2*n_lower_bands+n_upper_bands+1  ! Number of rows in AB format of LU-factored matrix
      57              : 
      58              :          ! Compute preconditioner
      59            0 :          call compute_band_preconditioner(matrix_size, n_upper_bands, n_lower_bands, bands, pre_conditioner)
      60              : 
      61              :          ! Pre-condition b
      62            0 :          do i=1,matrix_size
      63            0 :             b_conditioned(i,1) = b(i) / pre_conditioner(i)
      64              :          end do
      65              : 
      66              :          ! Put bands into AB form for LAPACK
      67              :          ! We store column j in the original matrix in column j of AB.
      68              :          ! In that column, row k in the original matrix is stored in row
      69              :          ! n_upper_bands+1+k-j of AB. So the mapping from the matrix to AB is
      70              :          ! (k,j) -> (n_upper_bands+1+k-j,j)
      71            0 :          AB = 0d0
      72              : 
      73              :          ! In the upper bands, upper band i at index j (bands(i,j)) corresponds to
      74              :          ! position (j, n_upper_bands - i + j + 1) in the matrix. This is then
      75              :          ! position (i, n_upper_bands - i + j + 1) in AB.
      76            0 :          do i=1,n_upper_bands
      77            0 :             do j=1,matrix_size + i - n_upper_bands - 1
      78            0 :                AB(i, n_upper_bands - i + j + 1) = bands(i,j) / pre_conditioner(j)
      79              :             end do
      80              :          end do
      81              : 
      82              :          ! In the lower bands, lower band i+1+n_upper_bands at index j corresponds to
      83              :          ! position (i+j, j) in the matrix. This is then
      84              :          ! position (n_upper_bands+1+i, j) in AB.
      85            0 :          do i=1,n_lower_bands
      86            0 :             do j=1,matrix_size + n_lower_bands - i - 1
      87            0 :                AB(n_upper_bands+1+i,j) = bands(i+n_upper_bands+1,j) / pre_conditioner(i+j)
      88              :             end do
      89              :          end do
      90              : 
      91              :          ! In the diagonal band, position k corresponds to index (k,k), which is position
      92              :          ! (n_upper_bands+1,k) in AB.
      93            0 :          do i=1,matrix_size
      94            0 :             AB(n_upper_bands + 1, i) = bands(n_upper_bands + 1, i) / pre_conditioner(i)
      95              :          end do
      96              : 
      97              :          ! Solve
      98              :          call DGBSVX(FACT, TRANS, matrix_size, n_lower_bands, n_upper_bands, NRHS, AB, LDAB, AFB, LDAFB, IPIV,&
      99              :                 EQUED, R, C, b_conditioned, LDB, x_tmp, LDX, RCOND, FERR, BERR, WORK, IWORK,&
     100            0 :                 ierr)
     101              : 
     102              :          ! Check for errors
     103            0 :          if (RCOND < 1d-12 .or. ierr == matrix_size+1) then
     104            0 :             write(*,*) 'Matrix is singular to machine precision.'
     105            0 :             write(*,*) 'RCOND = ', RCOND
     106            0 :             write(*,*) 'ierr = ', ierr
     107            0 :             write(*,*) 'N = ', matrix_size
     108              : 
     109            0 :             open(unit=10, file="bands.data")
     110            0 :             do j=1,LDAB
     111            0 :                do i=1,matrix_size
     112            0 :                   write(10,*) bands(j,i)
     113              :                end do
     114              :             end do
     115            0 :          else if (ierr /= 0) then
     116            0 :             write(*,*) 'Matrix is exactly singular.'
     117            0 :             write(*,*) 'ierr = ', ierr
     118            0 :             write(*,*) 'N = ', matrix_size
     119              :          end if
     120              : 
     121              :          ! Store output
     122            0 :          do i=1,matrix_size
     123            0 :             x(i) = x_tmp(i,1)
     124              :          end do
     125              : 
     126            0 :       end subroutine DGBSVX_banded_wrapper
     127              : 
     128              :       !> Wraps the lapack DGBSVX routine for banded matrices to be used with block tridiagonal matrices.
     129              :       !! Also includes a pre-conditioning step and a simpler input format.
     130              :       !!
     131              :       !! @params ublk The upper blocks. Shape is (nvars, nvars, nblocks-1).
     132              :       !! @params lblk The lower blocks. Shape is (nvars, nvars, nblocks-1).
     133              :       !! @params dblk The diagonal blocks. Shape is (nvars, nvars, nblocks).
     134              :       !! @params nblocks The number of blocks on the diagonal.
     135              :       !! @params nvars The width and height of each block (e.g. each block is nvars by nvars).
     136              :       !! @params x Array of shape (nvar, nblocks). Stores the result of solving Matrix.x = b.
     137              :       !! @params b Array of shape (nvar, nblocks). The right-hand side from the definition of x.
     138              :       !! @params pre_conditioner Pre-conditioning vector. Computed in this routine.
     139              :       !! @params ierr Integer-valued error code.
     140            0 :       subroutine DGBSVX_tridiagonal_wrapper(ublk, lblk, dblk, pre_conditioner, x, b, nblocks, nvar, rcond, ierr)
     141              :          ! Inputs
     142              :          real(dp), dimension(:,:,:), intent(in) :: ublk, lblk, dblk
     143              :          real(dp), dimension(:,:), intent(in) :: b
     144              :          integer, intent(in) :: nblocks, nvar
     145              : 
     146              :          ! Intermediates
     147              :          integer :: counter, i, j, k, k1, k2
     148              :          character(len=1) :: FACT, TRANS, EQUED
     149              :          integer :: N, KL, KU, NRHS, LDAB, LDAFB, LDB, LDX
     150            0 :          integer :: IWORK(nvar * nblocks),  IPIV(nvar * nblocks)
     151            0 :          real(dp) :: WORK(3 * nvar * nblocks), BERR(1), FERR(1)
     152            0 :          real(dp) :: C(nvar * nblocks), R(nvar * nblocks)
     153            0 :          real(dp) :: b_flat(nvar * nblocks, 1), x_flat(nvar * nblocks, 1)
     154            0 :          real(dp) :: AB(4 * nvar + 1, nvar * nblocks)
     155            0 :          real(dp) :: AFB(6 * nvar + 1, nblocks*nvar)
     156            0 :          real(dp) :: left_pre_conditioner(nvar, nblocks)
     157              : 
     158              :          ! Outputs
     159              :          real(dp), dimension(:,:), intent(out) :: pre_conditioner
     160              :          real(dp), dimension(:,:), intent(out) :: x
     161              :          real(dp), intent(out) ::  rcond
     162              :          integer, intent(out) :: ierr
     163              : 
     164              :          ! Fixed arguments
     165              : 
     166            0 :          FACT = 'N'  ! We've already equilibrated the matrix
     167            0 :          TRANS = 'N'  ! This argument is irrelevant if FACT == 'N'
     168            0 :          EQUED = 'N'  ! No equilibration
     169            0 :          N = nblocks * nvar  ! Number of equations
     170            0 :          KL = 2 * nvar  ! Number of lower bands. We round up to the max number
     171              :                        ! which could be held by the block triadiagonal matrix.
     172              :                        ! If performance is ever an issue this solve can be sped
     173              :                        ! up by tightening KL.
     174            0 :          KU = 2 * nvar  ! Number of upper bands. We round up to the max number
     175              :                        ! which could be held by the block triadiagonal matrix.
     176              :                        ! If performance is ever an issue this solve can be sped
     177              :                        ! up by tightening KU.
     178            0 :          NRHS = 1      ! Number of columns in equ for A.x=b.
     179            0 :          LDX = N       ! Number of rows in flattened x
     180            0 :          LDB = N       ! Number of rows in flattened b
     181            0 :          LDAB = KL+KU+1  ! Number of rows in AB format of banded matrix
     182            0 :          LDAFB = 2*KL+KU+1  ! Number of rows in AB format of LU-factored matrix
     183              : 
     184              :          ! Compute preconditioners
     185            0 :          call compute_block_preconditioner(ublk, lblk, dblk, nblocks, nvar, pre_conditioner)
     186              :          call compute_block_left_preconditioner(ublk, lblk, dblk, nblocks, nvar, &
     187            0 :                                                       pre_conditioner, left_pre_conditioner)
     188              : 
     189              :          ! We solve M_{ij} x_j = b_i
     190              :          ! We pre-condition by dividing b_i by p_i, so
     191              :          ! M_{ij} x_j / p_i = b_i / p_i
     192              :          ! We also pre-condition by dividing x_j by L_j, so
     193              :          ! (M_{ij} / (p_i L_j) ) (x_j L_j) = b_i / p_i
     194              :          ! We solve for the composite x_j' = x_j L_j, so in the end x_j = x_j' / L_j.
     195              : 
     196              :          ! Flatten b and precondition
     197            0 :          counter = 1
     198            0 :          do j=1,nblocks
     199            0 :             do k=1,nvar
     200            0 :                b_flat(counter,1) = b(k,j) / pre_conditioner(k,j)
     201            0 :                counter = counter + 1
     202              :             end do
     203              :          end do
     204              : 
     205              :          ! Set up banded matrix
     206            0 :          AB = 0d0
     207            0 :          do i=1,nblocks
     208            0 :             do j=1,nvar
     209            0 :                do k=1,nvar
     210              :                   ! (j,k,i) in dblk corresponds to coordinate ((i-1)*nvar+j,(i-1)*nvar+k)
     211              :                   ! in the original matrix.
     212              :                   ! We store column m in the original matrix in column m of AB.
     213              :                   ! In that column, row l in the original matrix is stored in row
     214              :                   ! KU+1+l-m of AB. Hence
     215              :                   ! (j,k,i) goes in spot (KU+1+(i-1)*nvar+j-(i-1)*nvar-k,(i-1)*nvar+k)
     216              :                   ! = (KU+1+j-k,(i-1)*nvar+k) of AB.
     217            0 :                   AB(KU+1+j-k, (i-1)*nvar+k) = dblk(j,k,i) / pre_conditioner(j,i) / left_pre_conditioner(k,i)
     218              :                end do
     219              :             end do
     220              :          end do
     221              : 
     222            0 :          do i=1,nblocks-1
     223            0 :             do j=1,nvar
     224            0 :                do k=1,nvar
     225              :                   ! (j,k,i) in lblk corresponds to coordinate (i*nvar+j,(i-1)*nvar+k)
     226              :                   ! in the original matrix.
     227              :                   ! We store column m in the original matrix in column m of AB.
     228              :                   ! In that column, row l in the original matrix is stored in row
     229              :                   ! KU+1+l-m of AB. Hence
     230              :                   ! (j,k,i) goes in spot (KU+1+i*nvar+j-(i-1)*nvar-k,(i-1)*nvar+k)
     231              :                   ! = (KU+1+nvar+j-k,(i-1)*nvar+k) of AB.
     232            0 :                   AB(KU+1+nvar+j-k, (i-1)*nvar+k) = lblk(j,k,i) / pre_conditioner(j,i+1) / left_pre_conditioner(k,i)
     233              : 
     234              :                   ! (j,k,i) in ublk corresponds to coordinate ((i-1)*nvar+j,i*nvar+k)
     235              :                   ! in the original matrix.
     236              :                   ! We store column m in the original matrix in column m of AB.
     237              :                   ! In that column, row l in the original matrix is stored in row
     238              :                   ! KU+1+l-m of AB. Hence
     239              :                   ! (j,k,i) goes in spot (KU+1+(i-1)*nvar+j-i*nvar-k,i*nvar+k)
     240              :                   ! = (KU+1-nvar+j-k,(i-1)*nvar+k) of AB.
     241            0 :                   AB(KU+1-nvar+j-k, i*nvar+k) = ublk(j,k,i) / pre_conditioner(j,i) / left_pre_conditioner(k,i+1)
     242              :                end do
     243              :             end do
     244              :          end do
     245              : 
     246              :          ! Solve
     247              :          call DGBSVX(FACT, TRANS, N, KL, KU, NRHS, AB, LDAB, AFB, LDAFB, IPIV,&
     248              :                 EQUED, R, C, b_flat, LDB, x_flat, LDX, RCOND, FERR, BERR, WORK, IWORK,&
     249            0 :                 ierr)
     250              : 
     251              :          ! Check for errors
     252            0 :          if (ierr /= 0 .or. rcond < 1d-10) then
     253            0 :             write(*,*) 'WARNING: Matrix is singular to machine precision.'
     254            0 :             write(*,*) 'RCOND = ', RCOND
     255            0 :             write(*,*) 'ierr = ', ierr
     256            0 :             write(*,*) 'N = ', N
     257            0 :             write(*,*) 'nvars, nblocks', nvar, nblocks
     258              : 
     259            0 :             open(unit=10, file="lower.data")
     260            0 :             open(unit=11, file="upper.data")
     261            0 :             open(unit=12, file="diagonal.data")
     262            0 :             do k=1,nblocks
     263            0 :                do k1=1,nvar
     264            0 :                   do k2=1,nvar
     265            0 :                      if (k < nblocks) then
     266            0 :                         write(10,*) lblk(k1,k2,k)
     267            0 :                         write(11,*) ublk(k1,k2,k)
     268              :                      end if
     269            0 :                      write(12,*) dblk(k1,k2,k)
     270              :                   end do
     271              :                end do
     272              :             end do
     273            0 :             write(10,*) '---'
     274            0 :             write(11,*) '---'
     275            0 :             write(12,*) '---'
     276            0 :             ierr = N+1
     277              :          else if (ierr /= 0) then
     278              :             write(*,*) 'WARNING: Matrix is exactly singular.'
     279              :             write(*,*) 'ierr = ', ierr
     280              :             write(*,*) 'N = ', N
     281              :          end if
     282              : 
     283              :          ! Unflatten output
     284              :          counter = 1
     285            0 :          do j=1,nblocks
     286            0 :             do k=1,nvar
     287            0 :                x(k,j) = x_flat(counter,1) / left_pre_conditioner(k,j)
     288            0 :                counter = counter + 1
     289              :             end do
     290              :          end do
     291              : 
     292            0 :       end subroutine DGBSVX_tridiagonal_wrapper
     293              : 
     294              :    end module DGBSVX_wrapper
        

Generated by: LCOV version 2.0-1