LCOV - code coverage report
Current view: top level - mtx/private - mtx_support.f90 (source / functions) Coverage Total Hit
Test: coverage.info Lines: 40.5 % 410 166
Test Date: 2025-05-08 18:23:42 Functions: 40.6 % 32 13

            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              : 
      21              :       module mtx_support
      22              : 
      23              :       use const_def, only: dp, qp
      24              :       use utils_lib, only: mesa_error
      25              : 
      26              :       implicit none
      27              : 
      28              :       integer, parameter :: num_chunks = 4
      29              : 
      30              :       contains
      31              : 
      32              : 
      33              : 
      34            1 :       subroutine do_dense_to_band(n,ndim,a,ml,mu,ab,ldab,ierr)
      35              :          integer, intent(in) :: n,ndim,ml,mu,ldab
      36              :          real(dp), intent(in) :: a(:,:)  ! (ndim,n)
      37              :          real(dp), intent(inout) :: ab(:,:)  ! (ldab,n)
      38              :          integer, intent(out) :: ierr
      39              :          integer :: i, j
      40            1 :          if (ml+mu+1 > n) then
      41            0 :             ierr = -1
      42            0 :             return
      43              :          end if
      44            1 :          ierr = 0
      45           37 :          ab = 0
      46            7 :          do j=1,n
      47           27 :             do i=max(1,j-mu),min(n,j+ml)
      48           26 :                ab(ldab-ml+i-j,j) = a(i,j)
      49              :             end do
      50              :          end do
      51              :       end subroutine do_dense_to_band
      52              : 
      53              : 
      54            1 :       subroutine do_band_to_dense(n,ml,mu,ab,ldab,ndim,a,ierr)
      55              :          integer, intent(in) :: n,ndim,ml,mu,ldab
      56              :          real(dp), intent(in) :: ab(:,:)  ! (ldab,n)
      57              :          real(dp), intent(inout) :: a(:,:)  ! (ndim,n)
      58              :          integer, intent(out) :: ierr
      59              :          integer :: i, j
      60            1 :          if (ml+mu+1 > n) then
      61            0 :             ierr = -1
      62            0 :             return
      63              :          end if
      64            1 :          ierr = 0
      65           43 :          a = 0
      66            7 :          do j=1,n
      67           27 :             do i=max(1,j-mu),min(n,j+ml)
      68           26 :                a(i,j) = ab(ldab-ml+i-j,j)
      69              :             end do
      70              :          end do
      71              :       end subroutine do_band_to_dense
      72              : 
      73              : 
      74            1 :       subroutine do_band_to_column_sparse(n,ml,mu,ab,ldab,nzmax,nz,colptr,rowind,values,diags,ierr)
      75              :          integer, intent(in) :: n,ml,mu,nzmax,ldab
      76              :          real(dp), intent(in) :: ab(ldab,n)
      77              :          integer, intent(inout) :: colptr(n+1),rowind(nzmax)
      78              :          real(dp), intent(inout) :: values(nzmax)
      79              : !         real(dp), intent(in) :: ab(:,:) ! (ldab,n)
      80              : !         integer, intent(inout) :: colptr(:) ! (n+1)
      81              : !         integer, intent(inout) :: rowind(:) ! (nzmax)
      82              : !         real(dp), intent(inout) :: values(:) ! (nzmax)
      83              :          logical, intent(in) :: diags
      84              :          integer, intent(out) :: nz,ierr
      85              :          integer :: i, j
      86            1 :          if (ml+mu+1 > n) then
      87            0 :             ierr = -1
      88            0 :             return
      89              :          end if
      90            1 :          ierr = 0
      91            1 :          nz = 0
      92            7 :          do j=1,n
      93            6 :             colptr(j) = nz+1  ! index in values of first entry in this column
      94           27 :             do i=max(1,j-mu),min(n,j+ml)
      95           20 :                if (ab(ldab-ml+i-j,j) == 0) then
      96            7 :                   if (i /= j) cycle  ! not a diagonal
      97            0 :                   if (.not. diags) cycle
      98              :                   ! else include diagonals even if are == 0
      99              :                end if
     100           13 :                nz = nz+1
     101           13 :                if (nz > nzmax) then
     102            0 :                   ierr = j
     103            0 :                   return
     104              :                end if
     105           13 :                values(nz) = ab(ldab-ml+i-j,j)
     106           26 :                rowind(nz) = i
     107              :             end do
     108              :          end do
     109            1 :          colptr(n+1) = nz+1
     110              :       end subroutine do_band_to_column_sparse
     111              : 
     112              : 
     113            1 :       subroutine do_column_sparse_to_band(n,ml,mu,ab,ldab,nz,colptr,rowind,values,ierr)
     114              :          integer, intent(in) :: n,ml,mu,nz,ldab
     115              : 
     116              :          real(dp), intent(inout) :: ab(ldab,n)
     117              :          integer, intent(in) :: colptr(n+1),rowind(nz)
     118              :          real(dp), intent(in) :: values(nz)
     119              : !         real(dp), intent(inout) :: ab(:,:) ! (ldab,n)
     120              : !         integer, intent(inout) :: colptr(:) ! (n+1)
     121              : !         integer, intent(inout) :: rowind(:) ! (nzmax)
     122              : !         real(dp), intent(in) :: values(:) ! (nz)
     123              :          integer, intent(out) :: ierr
     124              :          integer :: i,j,k
     125            1 :          ierr = 0
     126           37 :          ab = 0
     127            7 :          do j=1,n
     128           20 :             do k=colptr(j),colptr(j+1)-1
     129           13 :                i = rowind(k)
     130           13 :                if (i > j+ml .or. i < j-mu) then
     131            0 :                   ierr = j
     132            0 :                   return
     133              :                end if
     134           19 :                ab(ldab-ml+i-j,j) = values(k)
     135              :             end do
     136              :          end do
     137              :       end subroutine do_column_sparse_to_band
     138              : 
     139              : 
     140            1 :       subroutine do_band_to_row_sparse(n,ml,mu,ab,ldab,nzmax,nz,rowptr,colind,values,diags,ierr)
     141              :          integer, intent(in) :: n,ml,mu,nzmax,ldab
     142              : 
     143              :          real(dp), intent(in) :: ab(ldab,n)
     144              :          integer, intent(inout) :: rowptr(n+1),colind(nzmax)
     145              :          real(dp), intent(inout) :: values(nzmax)
     146              : !         real(dp), intent(in) :: ab(:,:) ! (ldab,n)
     147              : !         integer, intent(out) :: rowptr(:) ! (n+1)
     148              : !         integer, intent(out) :: colind(:) ! (nzmax)
     149              : !         real(dp), intent(inout) :: values(:) ! (nzmax)
     150              :          logical, intent(in) :: diags
     151              :          integer, intent(out) :: ierr, nz
     152              :          integer :: idiag, op_err, j1, j2, k, i, nz1
     153              :          integer, dimension(num_chunks) :: nz_per_chunk, nz_start, nz_max, i_lo, i_hi
     154              : 
     155              :          logical, parameter :: dbg = .false.
     156              : 
     157              :          include 'formats'
     158              : 
     159              :          if (dbg) write(*,*) 'enter do_band_to_row_sparse'
     160              : 
     161            1 :          if (ml+mu+1 > n) then
     162            0 :             ierr = -1
     163              :             if (dbg) then
     164              :                write(*,*) 'do_band_to_row_sparse'
     165              :                write(*,*) 'ml+mu+1', ml+mu+1
     166              :                write(*,*) 'n', n
     167              :             end if
     168            0 :             return
     169              :          end if
     170              : 
     171            1 :          ierr = 0
     172            1 :          nz = 0
     173            1 :          idiag = ldab - ml
     174              : 
     175            1 :          nz_start(1) = 1
     176            1 :          i_lo(1) = 1
     177            4 :          do k = 2, num_chunks
     178            3 :             nz_start(k) = ((k-1)*nzmax)/num_chunks
     179            3 :             nz_max(k-1) = nz_start(k) - 1
     180            3 :             i_lo(k) = ((k-1)*n)/num_chunks
     181            4 :             i_hi(k-1) = i_lo(k) - 1
     182              :          end do
     183            1 :          nz_max(num_chunks) = nzmax
     184            1 :          i_hi(num_chunks) = n
     185              : 
     186              :          if (dbg) write(*,*) 'do_band_to_row_sparse - do chunks'
     187            1 :          op_err = 0
     188            1 : !$OMP PARALLEL DO PRIVATE(k,op_err)
     189              :          do k = 1, num_chunks
     190              :             call do_chunk_band_to_row_sparse( &
     191              :                k, ldab, n, nzmax, nz_per_chunk, nz_start, nz_max, ml, mu, idiag, diags, &
     192              :                i_lo, i_hi, ab, rowptr, colind, values, op_err)
     193              :             if (op_err /= 0) ierr = op_err
     194              :          end do
     195              : !$OMP END PARALLEL DO
     196              :          if (dbg) write(*,*) 'do_band_to_row_sparse - done chunks'
     197              : 
     198            1 :          if (ierr /= 0) then
     199              : 
     200            0 :             write(*,*) 'do_band_to_row_sparse: failed to fit in chunks'
     201            0 :             write(*,*) 'please increase the max fill factor for your sparse matrix'
     202            0 :             call mesa_error(__FILE__,__LINE__)
     203              : 
     204              :          else
     205              : 
     206              :             if (dbg) then
     207              :                do k=1,num_chunks
     208              :                   write(*,2) 'k', k
     209              :                   write(*,2) 'nz_per_chunk(k)', nz_per_chunk(k)
     210              :                   write(*,2) 'nz_start(k)', nz_start(k)
     211              :                   write(*,2) 'nz_max(k)', nz_max(k)
     212              :                   write(*,2) 'i_lo(k)', i_lo(k)
     213              :                   write(*,2) 'i_hi(k)', i_hi(k)
     214              :                   write(*,'(A)')
     215              :                end do
     216              :             end if
     217              : 
     218              :             ! reposition the chunk results
     219              :             if (dbg) write(*,*) 'reposition the chunk results'
     220            1 :             i = nz_per_chunk(1)
     221            4 :             do k = 2, num_chunks
     222            3 :                nz1 = nz_per_chunk(k)
     223              :                if (dbg) write(*,2) 'i', i
     224              :                if (dbg) write(*,2) 'nz1', nz1
     225              :                if (dbg) write(*,2) 'k', k
     226              :                if (dbg) write(*,2) 'nz_start(k)', nz_start(k)
     227            3 :                j2 = nz_start(k)
     228           16 :                do j1 = i+1, i+nz1  ! avoid ifort segfault
     229           13 :                   values(j1) = values(j2)
     230           13 :                   colind(j1) = colind(j2)
     231           16 :                   j2 = j2+1
     232              :                end do
     233              :                if (dbg) write(*,2) 'i_lo(k)', i_lo(k)
     234              :                if (dbg) write(*,2) 'i_hi(k)', i_hi(k)
     235              :                if (dbg) write(*,2) 'nz_start(k)-i-1', nz_start(k)-i-1
     236            3 :                j2 = (nz_start(k)-i-1)
     237            9 :                do j1 = i_lo(k), i_hi(k)
     238            9 :                   rowptr(j1) = rowptr(j1) - j2
     239              :                end do
     240            4 :                i = i+nz1
     241              :             end do
     242            1 :             nz = i
     243              :          end if
     244              : 
     245              : 
     246            1 :          rowptr(n+1) = nz+1
     247              :          !write(*,*) 'done do_band_to_row_sparse - fill fraction', dble(nz)/dble(nzmax)
     248              : 
     249              :       end subroutine do_band_to_row_sparse
     250              : 
     251              : 
     252            4 :       subroutine do_chunk_band_to_row_sparse( &
     253              :             num, ldab, n, nzmax, nz_per_chunk, nz_start, nz_max, ml, mu, idiag, diags, &
     254            4 :             i_lo, i_hi, ab, rowptr, colind, values, ierr)
     255              :          integer, intent(in) :: num, ldab, n, nzmax, ml, mu, idiag
     256              :          logical, intent(in) :: diags
     257              : 
     258              :          real(dp), intent(in) :: ab(ldab,n)
     259              :          integer, intent(inout) :: rowptr(n+1), colind(nzmax)
     260              :          real(dp), intent(inout) :: values(nzmax)
     261              : !         real(dp), intent(in) :: ab(:,:) ! (ldab,n)
     262              : !         integer, intent(inout) :: rowptr(:) ! (n+1)
     263              : !         integer, intent(inout) :: colind(:) ! (nzmax)
     264              : !         real(dp), intent(inout) :: values(:) ! (nzmax)
     265              :          integer, dimension(num_chunks) :: nz_per_chunk, nz_start, nz_max, i_lo, i_hi
     266              :          integer, intent(out) :: ierr
     267              : 
     268              :          integer :: i, j, nz
     269            4 :          real(dp) :: val
     270              : 
     271              :          logical, parameter :: dbg = .false.
     272              :          include 'formats'
     273              : 
     274            4 :          ierr = 0
     275            4 :          nz = nz_start(num) - 1
     276           10 :          do i = i_lo(num), i_hi(num)
     277            6 :             rowptr(i) = nz+1  ! index in values of first entry in this row
     278              :             !write(*,*) 'set rowptr(i)', i, rowptr(i)
     279           30 :             do j = max(1,i-ml), min(n,i+mu)
     280           20 :                val = ab(idiag+i-j,j)
     281           20 :                if (val == 0) then
     282            7 :                   if (i /= j) cycle  ! not a diagonal, so skip if 0
     283            0 :                   if (.not. diags) cycle
     284              :                   ! if (diags) then include diagonals even if are == 0
     285              :                end if
     286           13 :                nz = nz+1
     287           13 :                if (nz > nz_max(num)) then
     288            0 :                   ierr = i
     289              :                   if (dbg) then
     290              :                      write(*,*) 'nz > nz_max(num)', nz, nz_max(num), num
     291              :                   end if
     292              :                   return
     293              :                end if
     294           13 :                values(nz) = val
     295           26 :                colind(nz) = j
     296              :             end do
     297              :          end do
     298            4 :          nz_per_chunk(num) = nz - nz_start(num) + 1  ! number of non-zero values for this chunk
     299              :       end subroutine do_chunk_band_to_row_sparse
     300              : 
     301              : 
     302              : 
     303            0 :       subroutine do_row_sparse_to_band(n,ml,mu,ab,ldab,nz,rowptr,colind,values,ierr)
     304              :          integer, intent(in) :: n,ml,mu,nz,ldab
     305              :          real(dp), intent(inout) :: ab(ldab,n)
     306              :          integer, intent(in) :: rowptr(n+1),colind(nz)
     307              :          real(dp), intent(in) :: values(nz)
     308              : !         real(dp), intent(inout) :: ab(:,:) ! (ldab,n)
     309              : !         integer, intent(inout) :: rowptr(:) ! (n+1)
     310              : !         integer, intent(inout) :: colind(:) ! (nz)
     311              : !         real(dp), intent(in) :: values(:) ! (nz)
     312              :          integer, intent(out) :: ierr
     313              :          integer :: i,j,k
     314            0 :          ierr = 0
     315            0 :          ab = 0
     316            0 :          do i=1,n
     317            0 :             do k=rowptr(i),rowptr(i+1)-1
     318            0 :                j = colind(k)
     319            0 :                if (i > j+ml .or. i < j-mu) then
     320            0 :                   ierr = j
     321            0 :                   return
     322              :                end if
     323            0 :                ab(ldab-ml+i-j,j) = values(k)
     324              :             end do
     325              :          end do
     326              :       end subroutine do_row_sparse_to_band
     327              : 
     328              : 
     329              :       ! sparse conversion based on similar routines from sparskit_src/formats.f
     330              : 
     331            1 :       subroutine do_dense_to_row_sparse(n,ndim,a,nzmax,nz,rowptr,colind,values,diags,ierr)
     332              :          integer, intent(in) :: n,ndim,nzmax
     333              :          !real(dp), intent(in) :: a(ndim,n)
     334              :          !integer, intent(inout) :: rowptr(n+1),colind(nzmax)
     335              :          !real(dp), intent(inout) :: values(nzmax)
     336              :          real(dp), intent(in) :: a(:,:)  ! (ndim,n)
     337              :          integer, intent(inout) :: rowptr(:)  ! (n+1)
     338              :          integer, intent(inout) :: colind(:)  ! (nzmax)
     339              :          real(dp), intent(inout) :: values(:)  ! (nzmax)
     340              :          logical, intent(in) :: diags
     341              :          integer, intent(out) :: nz,ierr
     342              :          integer :: i,j
     343            1 :          ierr = 0
     344            1 :          nz = 0
     345            7 :          do i=1,n
     346            6 :             rowptr(i) = nz+1  ! index in values of first entry in this row
     347           43 :             do j=1,n
     348           36 :                if (a(i,j) == 0) then
     349           21 :                   if (i /= j) cycle  ! not a diagonal
     350            0 :                   if (.not. diags) cycle
     351              :                   ! else include diagonals even if are == 0
     352              :                end if
     353           15 :                nz = nz+1
     354           15 :                if (nz > nzmax) then
     355            0 :                   ierr = i
     356            0 :                   return
     357              :                end if
     358           15 :                values(nz) = a(i,j)
     359           42 :                colind(nz) = j
     360              :             end do
     361              :          end do
     362            1 :          rowptr(n+1) = nz+1
     363              :       end subroutine do_dense_to_row_sparse
     364              : 
     365              : 
     366            0 :       subroutine do_dense_to_row_sparse_0_based( &
     367            0 :             n,ndim,a,nzmax,nz,rowptr,colind,values,diags,ierr)
     368              :          integer, intent(in) :: n,ndim,nzmax
     369              :          !real(dp), intent(in) :: a(ndim,n)
     370              :          !integer, intent(inout) :: rowptr(n+1),colind(nzmax)
     371              :          !real(dp), intent(inout) :: values(nzmax)
     372              :          real(dp), intent(in) :: a(:,:)  ! (ndim,n)
     373              :          integer, intent(inout) :: rowptr(:)  ! (n+1)
     374              :          integer, intent(inout) :: colind(:)  ! (nzmax)
     375              :          real(dp), intent(inout) :: values(:)  ! (nzmax)
     376              :          logical, intent(in) :: diags
     377              :          integer, intent(out) :: nz,ierr
     378              :          integer :: i,j
     379            0 :          ierr = 0
     380            0 :          nz = 0
     381            0 :          do i=1,n
     382            0 :             rowptr(i) = nz  ! index in values of first entry in this row
     383            0 :             do j=1,n
     384            0 :                if (a(i,j) == 0) then
     385            0 :                   if (i /= j) cycle  ! not a diagonal
     386            0 :                   if (.not. diags) cycle
     387              :                   ! else include diagonals even if are == 0
     388              :                end if
     389            0 :                nz = nz+1
     390            0 :                if (nz > nzmax) then
     391            0 :                   ierr = i
     392            0 :                   return
     393              :                end if
     394            0 :                values(nz) = a(i,j)
     395            0 :                colind(nz) = j-1
     396              :             end do
     397              :          end do
     398            0 :          rowptr(n+1) = nz
     399              :       end subroutine do_dense_to_row_sparse_0_based
     400              : 
     401              : 
     402            0 :       subroutine do_row_sparse_to_dense(n,ndim,a,nz,rowptr,colind,values,ierr)
     403              :          integer, intent(in) :: n,ndim,nz
     404              :          real(dp), intent(inout) :: a(ndim,n)
     405              :          integer, intent(in) :: rowptr(n+1),colind(nz)
     406              :          real(dp), intent(in) :: values(nz)
     407              : !         real(dp), intent(inout) :: a(:,:) ! (ndim,n)
     408              : !         integer, intent(inout) :: rowptr(:) ! (n+1)
     409              : !         integer, intent(inout) :: colind(:) ! (nz)
     410              : !         real(dp), intent(inout) :: values(:) ! (nz)
     411              :          integer, intent(out) :: ierr
     412              :          integer :: i,j,k
     413            0 :          ierr = 0
     414            0 :          a = 0
     415            0 :          do i=1,n
     416            0 :             do k=rowptr(i),rowptr(i+1)-1
     417            0 :                j = colind(k)
     418            0 :                if (j > n) then
     419            0 :                   ierr = i
     420            0 :                   return
     421              :                end if
     422            0 :                a(i,j) = values(k)
     423              :             end do
     424              :          end do
     425              :       end subroutine do_row_sparse_to_dense
     426              : 
     427              : 
     428            0 :       subroutine do_row_sparse_0_based_to_dense(n,ndim,a,nz,rowptr,colind,values,ierr)
     429              :          integer, intent(in) :: n,ndim,nz
     430              :          real(dp), intent(inout) :: a(ndim,n)
     431              :          integer, intent(in) :: rowptr(0:n),colind(0:nz-1)
     432              :          real(dp), intent(in) :: values(nz)
     433              :          integer, intent(out) :: ierr
     434              :          integer :: i,j,k
     435            0 :          ierr = 0
     436            0 :          a = 0
     437            0 :          do i=1,n
     438            0 :             do k=rowptr(i),rowptr(i+1)-1
     439            0 :                j = colind(k)
     440            0 :                if (j > n) then
     441            0 :                   ierr = i
     442            0 :                   return
     443              :                end if
     444            0 :                a(i,j) = values(k)
     445              :             end do
     446              :          end do
     447              :       end subroutine do_row_sparse_0_based_to_dense
     448              : 
     449              : 
     450            0 :       subroutine do_dense_to_column_sparse(n,ndim,a,nzmax,nz,colptr,rowind,values,diags,ierr)
     451              :          integer, intent(in) :: n,ndim,nzmax
     452              :          !real(dp), intent(in) :: a(ndim,n)
     453              :          !integer, intent(inout) :: colptr(n+1),rowind(nzmax)
     454              :          !real(dp), intent(inout) :: values(nzmax)
     455              :          real(dp), intent(in) :: a(:,:)  ! (ndim,n)
     456              :          integer, intent(inout) :: colptr(:)  ! (n+1)
     457              :          integer, intent(inout) :: rowind(:)  ! (nzmax)
     458              :          real(dp), intent(inout) :: values(:)  ! (nzmax)
     459              :          logical, intent(in) :: diags
     460              :          integer, intent(out) :: nz,ierr
     461              :          integer :: i,j
     462            0 :          ierr = 0
     463            0 :          nz = 0
     464            0 :          do j=1,n
     465            0 :             colptr(j) = nz+1  ! index in values of first entry in this column
     466            0 :             do i=1,n
     467            0 :                if (a(i,j) == 0) then
     468            0 :                   if (i /= j) cycle  ! not a diagonal
     469            0 :                   if (.not. diags) cycle
     470              :                   ! else include diagonals even if are == 0
     471              :                end if
     472            0 :                nz = nz+1
     473            0 :                if (nz > nzmax) then
     474            0 :                   ierr = j
     475            0 :                   return
     476              :                end if
     477            0 :                values(nz) = a(i,j)
     478            0 :                rowind(nz) = i
     479              :             end do
     480              :          end do
     481            0 :          colptr(n+1) = nz+1
     482              :       end subroutine do_dense_to_column_sparse
     483              : 
     484              : 
     485            0 :       subroutine do_dense_to_col_sparse_0_based( &
     486            0 :             n,ndim,a,nzmax,nz,colptr,rowind,values,diags,ierr)
     487              :          integer, intent(in) :: n,ndim,nzmax
     488              :          !real(dp), intent(in) :: a(ndim,n)
     489              :          !integer, intent(inout) :: colptr(n+1),rowind(nzmax)
     490              :          !real(dp), intent(inout) :: values(nzmax)
     491              :          real(dp), intent(in) :: a(:,:)  ! (ndim,n)
     492              :          integer, intent(inout) :: colptr(:)  ! (n+1)
     493              :          integer, intent(inout) :: rowind(:)  ! (nzmax)
     494              :          real(dp), intent(inout) :: values(:)  ! (nzmax)
     495              :          logical, intent(in) :: diags
     496              :          integer, intent(out) :: nz,ierr
     497              :          integer :: i,j
     498            0 :          ierr = 0
     499            0 :          nz = 0
     500            0 :          do j=1,n
     501            0 :             colptr(j) = nz  ! index in values of first entry in this column
     502            0 :             do i=1,n
     503            0 :                if (a(i,j) == 0) then
     504            0 :                   if (i /= j) cycle  ! not a diagonal
     505            0 :                   if (.not. diags) cycle
     506              :                   ! else include diagonals even if are == 0
     507              :                end if
     508            0 :                nz = nz+1
     509            0 :                if (nz > nzmax) then
     510            0 :                   ierr = j
     511            0 :                   return
     512              :                end if
     513            0 :                values(nz) = a(i,j)
     514            0 :                rowind(nz) = i-1
     515              :             end do
     516              :          end do
     517            0 :          colptr(n+1) = nz
     518              :       end subroutine do_dense_to_col_sparse_0_based
     519              : 
     520              : 
     521            0 :       subroutine do_dense_to_col_sparse_0_based_qp( &
     522            0 :             n,ndim,a,nzmax,nz,colptr,rowind,values,diags,ierr)
     523              :          integer, intent(in) :: n,ndim,nzmax
     524              :          !real(dp), intent(in) :: a(ndim,n)
     525              :          !integer, intent(inout) :: colptr(n+1),rowind(nzmax)
     526              :          !real(dp), intent(inout) :: values(nzmax)
     527              :          real(dp), intent(in) :: a(:,:)  ! (ndim,n)
     528              :          integer, intent(inout) :: colptr(:)  ! (n+1)
     529              :          integer, intent(inout) :: rowind(:)  ! (nzmax)
     530              :          real(qp), intent(out) :: values(:)  ! (nzmax)
     531              :          logical, intent(in) :: diags
     532              :          integer, intent(out) :: nz,ierr
     533              :          integer :: i,j
     534            0 :          ierr = 0
     535            0 :          nz = 0
     536            0 :          do j=1,n
     537            0 :             colptr(j) = nz  ! index in values of first entry in this column
     538            0 :             do i=1,n
     539            0 :                if (a(i,j) == 0) then
     540            0 :                   if (i /= j) cycle  ! not a diagonal
     541            0 :                   if (.not. diags) cycle
     542              :                   ! else include diagonals even if are == 0
     543              :                end if
     544            0 :                nz = nz+1
     545            0 :                if (nz > nzmax) then
     546            0 :                   ierr = j
     547            0 :                   return
     548              :                end if
     549            0 :                values(nz) = a(i,j)
     550            0 :                rowind(nz) = i-1
     551              :             end do
     552              :          end do
     553            0 :          colptr(n+1) = nz
     554              :       end subroutine do_dense_to_col_sparse_0_based_qp
     555              : 
     556              : 
     557         2935 :       subroutine do_column_sparse_to_dense(n,ndim,a,nz,colptr,rowind,values,ierr)
     558              :          integer, intent(in) :: n,ndim,nz
     559              :          real(dp), intent(inout) :: a(ndim,n)
     560              :          integer, intent(in) :: colptr(n+1),rowind(nz)
     561              :          real(dp), intent(in) :: values(nz)
     562              : !         real(dp), intent(inout) :: a(:,:) ! (ndim,n)
     563              : !         integer, intent(in) :: colptr(:) ! (n+1)
     564              : !         integer, intent(in) :: rowind(:) ! (nz)
     565              : !         real(dp), intent(in) :: values(:) ! (nz)
     566              :          integer, intent(out) :: ierr
     567              :          integer :: i,j,k
     568         2935 :          ierr = 0
     569      1910685 :          a = 0
     570        76310 :          do j=1,n
     571       200137 :             do k=colptr(j),colptr(j+1)-1
     572       123827 :                i = rowind(k)
     573       123827 :                if (i > n) then
     574            0 :                   ierr = j
     575            0 :                   return
     576              :                end if
     577       197202 :                a(i,j) = values(k)
     578              :             end do
     579              :          end do
     580              :       end subroutine do_column_sparse_to_dense
     581              : 
     582              : 
     583            0 :       subroutine do_col_sparse_0_based_to_dense(n,ndim,a,nz,colptr,rowind,values,ierr)
     584              :          integer, intent(in) :: n,ndim,nz
     585              :          real(dp), intent(inout) :: a(ndim,n)
     586              :          integer, intent(in) :: colptr(n+1),rowind(nz)
     587              :          real(dp), intent(in) :: values(nz)
     588              : !         real(dp), intent(inout) :: a(:,:) ! (ndim,n)
     589              : !         integer, intent(in) :: colptr(:) ! (n+1)
     590              : !         integer, intent(in) :: rowind(:) ! (nz)
     591              : !         real(dp), intent(in) :: values(:) ! (nz)
     592              :          integer, intent(out) :: ierr
     593              :          integer :: i,j,k
     594            0 :          ierr = 0
     595            0 :          a = 0
     596            0 :          do j=1,n
     597            0 :             do k=colptr(j)+1,colptr(j+1)
     598            0 :                i = rowind(k)+1
     599            0 :                if (i > n) then
     600            0 :                   ierr = j
     601            0 :                   return
     602              :                end if
     603            0 :                a(i,j) = values(k)
     604              :             end do
     605              :          end do
     606              :       end subroutine do_col_sparse_0_based_to_dense
     607              : 
     608              : 
     609            1 :       subroutine do_block_dble_mv(nvar, nz, lblk, dblk, ublk, b, prod)
     610              :          use my_lapack95, only: my_gemv_p1
     611              :          integer, intent(in) :: nvar, nz
     612              :          real(dp), pointer, dimension(:,:,:), intent(in) :: lblk, dblk, ublk  ! (nvar,nvar,nz)
     613              :          real(dp), pointer, dimension(:,:), intent(in) :: b  ! (nvar,nz)
     614              :          real(dp), pointer, dimension(:,:), intent(inout) :: prod  ! (nvar,nz)
     615              :          integer :: k
     616           21 :          do k = 1, nz
     617          520 :             prod(1:nvar,k) = 0
     618           20 :             call my_gemv_p1(nvar,nvar,dblk(1:nvar,1:nvar,k),nvar,b(1:nvar,k),prod(1:nvar,k))
     619           20 :             if (k > 1) then
     620           19 :                call my_gemv_p1(nvar,nvar,lblk(1:nvar,1:nvar,k),nvar,b(1:nvar,k-1),prod(1:nvar,k))
     621              :             end if
     622           21 :             if (k < nz) then
     623           19 :                call my_gemv_p1(nvar,nvar,ublk(1:nvar,1:nvar,k),nvar,b(1:nvar,k+1),prod(1:nvar,k))
     624              :             end if
     625              :          end do
     626            1 :       end subroutine do_block_dble_mv
     627              : 
     628              : 
     629            0 :       subroutine do_LU_factored_block_dble_mv(lblk, dblk, ublk, b, ipiv, prod)
     630              :          real(dp), pointer, dimension(:,:,:), intent(in) :: lblk, dblk, ublk  ! (nvar,nvar,nz)
     631              :          real(dp), pointer, dimension(:,:), intent(in) :: b  ! (nvar,nz)
     632              :          integer, intent(in) :: ipiv(:,:)  ! (nvar,nz)
     633              :          real(dp), pointer, dimension(:,:), intent(inout) :: prod  ! (nvar,nz)
     634              :          integer :: nvar, nz, k, incx, incy
     635            0 :          nvar = size(b,dim=1)
     636            0 :          nz = size(b,dim=2)
     637            0 :          incx = 1
     638            0 :          incy = 1
     639            0 : !$OMP PARALLEL DO PRIVATE(k)
     640              :          do k = 1, nz
     641              :             call do_LU_factored_square_mv(nvar,dblk(:,:,k),b(:,k),ipiv(:,k),prod(:,k))
     642              :             if (k > 1) then
     643              :                call dgemv('N',nvar,nvar,1d0,lblk(:,:,k),nvar,b(:,k-1),incx,1d0,prod(:,k),incy)
     644              :             end if
     645              :             if (k < nz) then
     646              :                call dgemv('N',nvar,nvar,1d0,ublk(:,:,k),nvar,b(:,k+1),incx,1d0,prod(:,k),incy)
     647              :             end if
     648              :          end do
     649              : !$OMP END PARALLEL DO
     650            0 :       end subroutine do_LU_factored_block_dble_mv
     651              : 
     652              : 
     653            0 :       subroutine do_LU_factored_square_mv(m,a,b,ipiv,x)  ! set x = A*b
     654              :          ! A factored in LU manner = P*L*U.
     655              :          integer, intent(in) :: m
     656              :          real(dp), intent(in) :: a(:,:)  ! (lda,m), lda >= m
     657              :          real(dp), intent(in) :: b(:)  ! (m)
     658              :          integer, intent(in) :: ipiv(:)  ! (m)
     659              :          real(dp), intent(inout) :: x(:)  ! (m)
     660              :          integer :: i, j
     661            0 :          real(dp), dimension(m) :: y
     662              :          include 'formats'
     663              :          ! y = U*b
     664            0 :          do i=1,m
     665            0 :             y(i) = 0
     666            0 :             do j=i,m
     667            0 :                y(i) = y(i) + a(i,j)*b(j)
     668              :             end do
     669              :          end do
     670              :          ! x = L*y
     671            0 :          do i=1,m
     672            0 :             x(i) = y(i)
     673            0 :             do j=1,i-1
     674            0 :                x(i) = x(i) + a(i,j)*y(j)
     675              :             end do
     676              :          end do
     677              :          ! x = P*x
     678            0 :          call dlaswp(1, x, m, 1, m, ipiv, -1)
     679            0 :       end subroutine do_LU_factored_square_mv
     680              : 
     681              : 
     682            0 :       subroutine do_LU_factored_square_mm(m,A,B,ipiv,C)  ! set C = A*B
     683              :          ! A factored in LU manner = P*L*U.
     684              :          integer, intent(in) :: m
     685              :          real(dp), intent(in) :: A(:,:)  ! (m,m)
     686              :          real(dp), intent(in) :: B(:,:)  ! (m,m)
     687              :          integer, intent(in) :: ipiv(:)  ! (m)
     688              :          real(dp), intent(inout) :: C(:,:)  ! (m,m)
     689              :          integer :: i, j, k
     690            0 :          real(dp), dimension(m,m) :: Y
     691              :          include 'formats'
     692              :          ! Y = U*B
     693            0 :          do i=1,m
     694            0 :             do j=1,m
     695            0 :                Y(i,j) = 0
     696            0 :                do k=i,m
     697            0 :                   Y(i,j) = Y(i,j) + A(i,k)*B(k,j)
     698              :                end do
     699              :             end do
     700              :          end do
     701              :          ! C = L*Y
     702            0 :          do i=1,m
     703            0 :             do j=1,m
     704            0 :                C(i,j) = Y(i,j)
     705            0 :                do k=1,i-1
     706            0 :                   C(i,j) = C(i,j) + A(i,k)*Y(k,j)
     707              :                end do
     708              :             end do
     709              :          end do
     710              :          ! C = P*C
     711            0 :          call dlaswp(m, C, m, 1, m, ipiv, -1)
     712            0 :       end subroutine do_LU_factored_square_mm
     713              : 
     714              : 
     715            0 :       subroutine do_multiply_xa(n, A1, x, b)
     716              :          !  calculates b = x*A
     717              :          integer, intent(in) :: n
     718              :          real(dp), pointer, intent(in) :: A1(:)  ! =(n, n)
     719              :          real(dp), pointer, intent(in) :: x(:)  ! (n)
     720              :          real(dp), pointer, intent(inout) :: b(:)  ! (n)
     721              :          integer :: j
     722            0 :          real(dp), pointer :: A(:,:)  ! (n, n)
     723            0 :          A(1:n,1:n) => A1(1:n*n)
     724            0 :          do j = 1, n
     725            0 :             b(j) = dot_product(x(1:n),A(1:n,j))
     726              :          end do
     727            0 :       end subroutine do_multiply_xa
     728              : 
     729              : 
     730            0 :       subroutine do_multiply_xa_plus_c(n, A1, x, c, b)
     731              :          !  calculates b = x*A + c
     732              :          integer, intent(in) :: n
     733              :          real(dp), pointer, intent(in) :: A1(:)  ! =(n,n)
     734              :          real(dp), pointer, intent(in) :: x(:)  ! (n)
     735              :          real(dp), pointer, intent(in) :: c(:)  ! (n)
     736              :          real(dp), pointer, intent(inout) :: b(:)  ! (n)
     737              :          integer :: j
     738            0 :          real(dp), pointer :: A(:,:)  ! (n,n)
     739            0 :          A(1:n,1:n) => A1(1:n*n)
     740            0 :          do j = 1, n
     741            0 :             b(j) = dot_product(x(1:n),A(1:n,j)) + c(j)
     742              :          end do
     743            0 :       end subroutine do_multiply_xa_plus_c
     744              : 
     745              : 
     746            0 :       subroutine do_block_multiply_xa(nvar, nz, lblk1, dblk1, ublk1, x1, b1)
     747              :          !  calculates b = x*A
     748              :          integer, intent(in) :: nvar, nz
     749              :          real(dp), dimension(:), intent(in), pointer :: lblk1, dblk1, ublk1  ! =(nvar,nvar,nz)
     750              :          real(dp), intent(in), pointer :: x1(:)  ! =(nvar,nz)
     751              :          real(dp), intent(inout), pointer :: b1(:)  ! =(nvar,nz)
     752              :          integer :: k, shift, shift2, nvar2
     753            0 :          real(dp), pointer, dimension(:) :: p1, p2, p3, p4
     754            0 :          nvar2 = nvar*nvar
     755            0 : !$OMP PARALLEL DO PRIVATE(k,shift,shift2,p1,p2,p3,p4)
     756              :          do k = 1, nz
     757              :             shift = nvar*(k-1)
     758              :             shift2 = nvar2*(k-1)
     759              :             p1(1:nvar2) => dblk1(shift2+1:shift2+nvar2)
     760              :             p2(1:nvar) => x1(shift+1:shift+nvar)
     761              :             p3(1:nvar) => b1(shift+1:shift+nvar)
     762              :             call do_multiply_xa(nvar,p1,p2,p3)
     763              :             if (k > 1) then
     764              :                p1(1:nvar2) => ublk1(shift2+1:shift2+nvar2)
     765              :                p2(1:nvar) => x1(shift+1:shift+nvar)
     766              :                p3(1:nvar) => b1(shift+1:shift+nvar)
     767              :                p4(1:nvar) => b1(shift+1:shift+nvar)
     768              :                call do_multiply_xa_plus_c(nvar,p1,p2,p3,p4)
     769              :             end if
     770              :             if (k < nz) then
     771              :                p1(1:nvar2) => lblk1(shift2+1:shift2+nvar2)
     772              :                p2(1:nvar) => x1(shift+1+nvar:shift+2*nvar)
     773              :                p3(1:nvar) => b1(shift+1:shift+nvar)
     774              :                p4(1:nvar) => b1(shift+1:shift+nvar)
     775              :                call do_multiply_xa_plus_c(nvar,p1,p2,p3,p4)
     776              :             end if
     777              :          end do
     778              : !$OMP END PARALLEL DO
     779            0 :       end subroutine do_block_multiply_xa
     780              : 
     781              : 
     782           20 :       subroutine do_band_multiply_xa(n, kl, ku, ab1, ldab, x, b)
     783              :          !  calculates b = x*a = transpose(a)*x
     784              :             integer, intent(in) :: n
     785              :          !          the number of linear equations, i.e., the order of the
     786              :          !          matrix a.  n >= 0.
     787              :             integer, intent(in) :: kl
     788              :          !          the number of subdiagonals within the band of a.  kl >= 0.
     789              :             integer, intent(in) :: ku
     790              :          !          the number of superdiagonals within the band of a.  ku >= 0.
     791              :             integer, intent(in) :: ldab
     792              :          !          the leading dimension of the array ab.  ldab >= kl+ku+1.
     793              :             real(dp), intent(in), pointer :: ab1(:)  ! =(ldab, n)
     794              :          !          the matrix a in band storage, in rows 1 to kl+ku+1;
     795              :          !          the j-th column of a is stored in the j-th column of the
     796              :          !          array ab as follows:
     797              :          !          ab(ku+1+i-j, j) = a(i, j) for max(1, j-ku)<=i<=min(n, j+kl)
     798              :             real(dp), intent(in), pointer :: x(:)  ! (n)
     799              :          !          the input vector to be multiplied by the matrix.
     800              :             real(dp), intent(inout), pointer :: b(:)  ! (n)
     801              :          !          on exit, set to matrix product of x*a = b
     802              :          integer ::  i, j, k
     803           20 :          real(dp), pointer :: ab(:,:)
     804           20 :          ab(1:ldab,1:n) => ab1(1:ldab*n)
     805        40060 :          do j = 1, n
     806        40040 :             k = ku+1-j
     807        40040 :             b(j) = 0
     808       320100 :             do i = max(1,j-ku), min(n,j+kl)
     809       320080 :                b(j) = b(j) + x(i)*ab(k+i,j)
     810              :             end do
     811              :          end do
     812           20 :       end subroutine do_band_multiply_xa
     813              : 
     814              : 
     815            0 :       subroutine do_clip_blocks( &
     816            0 :             mblk, clip_limit, lmat, dmat, umat, dmat_nnz, total_nnz)
     817              :          integer, intent(in) :: mblk
     818              :          real(dp), intent(in) :: clip_limit
     819              :          real(dp), intent(inout) :: lmat(:,:), dmat(:,:), umat(:,:)
     820              :          integer, intent(inout) :: dmat_nnz, total_nnz
     821              :          integer :: i, j
     822            0 :          dmat_nnz = 0; total_nnz = 0
     823            0 :          do j=1,mblk
     824            0 :             do i=1,mblk
     825            0 :                if (i /= j .and. abs(lmat(i,j)) < clip_limit) lmat(i,j) = 0d0
     826            0 :                if (lmat(i,j) /= 0) total_nnz = total_nnz + 1
     827            0 :                if (i /= j .and. abs(dmat(i,j)) < clip_limit) dmat(i,j) = 0d0
     828            0 :                if (dmat(i,j) /= 0) then
     829            0 :                   total_nnz = total_nnz + 1
     830            0 :                   dmat_nnz = dmat_nnz + 1
     831              :                end if
     832            0 :                if (i /= j .and. abs(umat(i,j)) < clip_limit) umat(i,j) = 0d0
     833            0 :                if (umat(i,j) /= 0) total_nnz = total_nnz + 1
     834              :             end do
     835              :          end do
     836            0 :       end subroutine do_clip_blocks
     837              : 
     838              : 
     839            0 :       subroutine do_clip_block(mblk, clip_limit, dmat, dmat_nnz)
     840              :          integer, intent(in) :: mblk
     841              :          real(dp), intent(in) :: clip_limit
     842              :          real(dp), intent(inout) :: dmat(:,:)
     843              :          integer, intent(inout) :: dmat_nnz
     844              :          integer :: i, j
     845            0 :          dmat_nnz = 0
     846            0 :          do j=1,mblk
     847            0 :             do i=1,mblk
     848            0 :                if (i /= j .and. abs(dmat(i,j)) < clip_limit) dmat(i,j) = 0d0
     849            0 :                if (dmat(i,j) /= 0) dmat_nnz = dmat_nnz + 1
     850              :             end do
     851              :          end do
     852            0 :       end subroutine do_clip_block
     853              : 
     854              : 
     855         2935 :       subroutine read_hbcode1(iounit, nrow, ncol, nnzero, values, rowind, colptr, ierr)
     856              : 
     857              :       character :: TITLE*72, KEY*8, MXTYPE*3, PTRFMT*16, INDFMT*16, VALFMT*20, RHSFMT*20
     858              : 
     859              :       integer :: TOTCRD, PTRCRD, INDCRD, VALCRD, RHSCRD, iounit, NROW  , NCOL  , NNZERO, NELTVL
     860              : 
     861              :       integer, pointer :: COLPTR (:), ROWIND (:)
     862              : 
     863              :       real(dp), pointer :: VALUES (:)
     864              :       integer, intent(out) :: ierr
     865              : 
     866              :       integer :: i
     867         2935 :       ierr = 0
     868         2935 :       READ (iounit, 1000, iostat=ierr ) TITLE , KEY   , &
     869         2935 :                            TOTCRD, PTRCRD, INDCRD, VALCRD, RHSCRD, &
     870         2935 :                            MXTYPE, NROW  , NCOL  , NNZERO, NELTVL, &
     871         5870 :                            PTRFMT, INDFMT, VALFMT, RHSFMT
     872         2935 :       if (ierr /= 0) return
     873              :  1000 FORMAT ( A72, A8 / 5I14 / A3, 11X, 4I14 / 2A16, 2A20 )
     874              : 
     875         2935 :       allocate(VALUES(NNZERO), ROWIND(NNZERO), COLPTR(NCOL+1), stat=ierr)
     876         2935 :       if (ierr /= 0) return
     877              : 
     878         2935 :       READ (iounit, PTRFMT, iostat=ierr ) ( COLPTR (I), I = 1, NCOL+1 )
     879         2935 :       if (ierr /= 0) return
     880              : 
     881         2935 :       READ (iounit, INDFMT, iostat=ierr ) ( ROWIND (I), I = 1, NNZERO )
     882         2935 :       if (ierr /= 0) return
     883              : 
     884         2935 :       IF  ( VALCRD > 0 )  THEN
     885              : 
     886              : !         ----------------------
     887              : !         ... READ MATRIX VALUES
     888              : !         ----------------------
     889              : 
     890         2935 :           READ (iounit, VALFMT, iostat=ierr ) ( VALUES (I), I = 1, NNZERO )
     891         2935 :           if (ierr /= 0) return
     892              : 
     893              :       end if
     894              : 
     895              : 
     896              :       end subroutine read_hbcode1
     897              : 
     898              : 
     899            0 :       subroutine write_hbcode1(iounit, nrow, ncol, nnzero, values, rowind, colptr, ierr)
     900              : 
     901              :       character :: TITLE*72 , KEY*8, MXTYPE*3, PTRFMT*16, INDFMT*16, use_VALFMT*20, VALFMT*20, RHSFMT*20
     902              : 
     903              :       integer :: TOTCRD, PTRCRD, INDCRD, VALCRD, RHSCRD, iounit, NROW  , NCOL  , NNZERO, NELTVL
     904              : 
     905              :       integer :: COLPTR (*), ROWIND (*), ierr
     906              : 
     907              :       real(dp) :: VALUES (*)
     908              : 
     909              :       integer :: i
     910              : 
     911            0 :       ierr = 0
     912              : 
     913              : !    ------------------------
     914              : !     ... WRITE HEADER BLOCK
     915              : !     ------------------------
     916              : 
     917              : !  Line 1 (A72, A8)
     918              : !       Col. 1 - 72   Title (TITLE)
     919              : !       Col. 73 - 80  Matrix name / identifier (MTRXID)
     920              : !
     921              : !  Line 2 (I14, 3(1X, I13))
     922              : !       Col. 1 - 14   Total number of lines excluding header (TOTCRD)
     923              : !       Col. 16 - 28  Number of lines for pointers (PTRCRD)
     924              : !       Col. 30 - 42  Number of lines for row (or variable) indices (INDCRD)
     925              : !       Col. 44 - 56  Number of lines for numerical values (VALCRD)
     926              : !
     927              : !  Line 3 (A3, 11X, 4(1X, I13))
     928              : !       Col. 1 - 3    Matrix type (see below) (MXTYPE)
     929              : !       Col. 15 - 28  Compressed Column: Number of rows (NROW)
     930              : !                     Elemental: Largest integer used to index variable (MVAR)
     931              : !       Col. 30 - 42  Compressed Column: Number of columns (NCOL)
     932              : !                     Elemental: Number of element matrices (NELT)
     933              : !       Col. 44 - 56  Compressed Column: Number of entries (NNZERO)
     934              : !                     Elemental: Number of variable indices (NVARIX)
     935              : !       Col. 58 - 70  Compressed Column: Unused, explicitly zero
     936              : !                     Elemental: Number of elemental matrix entries (NELTVL)
     937              : !
     938              : !  Line 4 (2A16, A20)
     939              : !       Col. 1 - 16   Fortran format for pointers (PTRFMT)
     940              : !       Col. 17 - 32  Fortran format for row (or variable) indices (INDFMT)
     941              : !       Col. 33 - 52  Fortran format for numerical values of coefficient matrix
     942              : !                     (VALFMT)
     943              : !                     (blank in the case of matrix patterns)
     944              : !
     945              : !  The three character type field on line 3 describes the matrix type.
     946              : !  The following table lists the permitted values for each of the three
     947              : !  characters. As an example of the type field, RSA denotes that the matrix
     948              : !  is real, symmetric, and assembled.
     949              : !
     950              : !  First Character:
     951              : !       R Real matrix
     952              : !       C Complex matrix
     953              : !       I integer matrix
     954              : !       P Pattern only (no numerical values supplied)
     955              : !       Q Pattern only (numerical values supplied in associated auxiliary value
     956              : !         file)
     957              : !
     958              : !  Second Character:
     959              : !       S Symmetric
     960              : !       U Unsymmetric
     961              : !       H Hermitian
     962              : !       Z Skew symmetric
     963              : !       R Rectangular
     964              : !
     965              : !  Third Character:
     966              : !       A Compressed column form
     967              : !       E Elemental form
     968              : !
     969              : 
     970              : 
     971              : 
     972            0 :       TITLE = ''
     973            0 :       KEY = ''
     974              : 
     975            0 :       PTRFMT = '(10I8)'
     976            0 :       INDFMT = '(12I6)'
     977            0 :       use_VALFMT = '(5(1pE27.16))'
     978            0 :       VALFMT = '(5E27.16)'
     979            0 :       RHSFMT = ''
     980              : 
     981            0 :       PTRCRD = (NCOL+1)/10 + 1  ! number of lines for COLPTR
     982            0 :       INDCRD = NNZERO/12 + 1  ! number of lines for ROWIND
     983            0 :       VALCRD = NNZERO/5 + 1  ! number of lines for VALUES
     984            0 :       RHSCRD = 0
     985            0 :       TOTCRD = 3 + PTRCRD + INDCRD + VALCRD + RHSCRD
     986              : 
     987            0 :       MXTYPE = 'RUA'
     988            0 :       NELTVL = 0
     989              : 
     990            0 :       WRITE (iounit, 1000 ) TITLE , KEY   , &
     991            0 :                            TOTCRD, PTRCRD, INDCRD, VALCRD, RHSCRD, &
     992            0 :                            MXTYPE, NROW  , NCOL  , NNZERO, NELTVL, &
     993            0 :                            PTRFMT, INDFMT, VALFMT, RHSFMT
     994              :  1000 FORMAT ( A72, A8 / 5I14 / A3, 11X, 4I14 / 2A16, 2A20 )
     995              : 
     996              : !     -------------------------
     997              : !     ... WRITE MATRIX STRUCTURE
     998              : !     -------------------------
     999              : 
    1000            0 :       WRITE (iounit, PTRFMT ) ( COLPTR (I), I = 1, NCOL+1 )
    1001              : 
    1002            0 :       WRITE (iounit, INDFMT ) ( ROWIND (I), I = 1, NNZERO )
    1003              : 
    1004            0 :       IF  ( VALCRD > 0 )  THEN
    1005              : 
    1006              : !         ----------------------
    1007              : !         ... WRITE MATRIX VALUES
    1008              : !         ----------------------
    1009              : 
    1010            0 :           WRITE (iounit, use_VALFMT ) ( VALUES (I), I = 1, NNZERO )
    1011              : 
    1012              :       end if
    1013              : 
    1014            0 :       return
    1015              :       end subroutine write_hbcode1
    1016              : 
    1017              : 
    1018            1 :       subroutine read_block_tridiagonal(iounit,nvar,nblk,lblk1,dblk1,ublk1,ierr)
    1019              :          integer, intent(in) :: iounit
    1020              :          integer, intent(out) :: nvar, nblk
    1021              :          real(dp), pointer, dimension(:) :: lblk1,dblk1,ublk1  ! will be allocated
    1022              :          integer, intent(out) :: ierr
    1023              :          integer :: k
    1024            1 :          real(dp), pointer, dimension(:,:,:) :: lblk,dblk,ublk
    1025            1 :          ierr = 0
    1026            1 :          read(iounit,*,iostat=ierr) nvar, nblk
    1027            1 :          if (ierr /= 0) return
    1028            1 :          allocate(lblk1(nvar*nvar*nblk), dblk1(nvar*nvar*nblk), ublk1(nvar*nvar*nblk), stat=ierr)
    1029            1 :          if (ierr /= 0) return
    1030            1 :          lblk(1:nvar,1:nvar,1:nblk) => lblk1(1:nvar*nvar*nblk)
    1031            1 :          dblk(1:nvar,1:nvar,1:nblk) => dblk1(1:nvar*nvar*nblk)
    1032            1 :          ublk(1:nvar,1:nvar,1:nblk) => ublk1(1:nvar*nvar*nblk)
    1033          980 :          do k=1,nblk
    1034          979 :             if (k > 1) then
    1035          978 :                call read1_sparse_block(iounit, nvar, lblk(:,:,k), ierr)
    1036          978 :                if (ierr /= 0) return
    1037              :             end if
    1038          979 :             call read1_sparse_block(iounit, nvar, dblk(:,:,k), ierr)
    1039          979 :             if (ierr /= 0) return
    1040          980 :             if (k < nblk) then
    1041          978 :                call read1_sparse_block(iounit, nvar, ublk(:,:,k), ierr)
    1042          978 :                if (ierr /= 0) return
    1043              :             end if
    1044              :          end do
    1045              : 
    1046            1 :       end subroutine read_block_tridiagonal
    1047              : 
    1048              : 
    1049         2935 :       subroutine read1_sparse_block(iounit, nvar, blk, ierr)
    1050              :          integer, intent(in) :: iounit, nvar
    1051              :          real(dp) :: blk(:,:)  ! (nvar,nvar)
    1052              :          integer, intent(out) :: ierr
    1053              :          integer :: nnz, nrow, ncol
    1054         2935 :          integer, pointer :: rowind(:), colptr(:)
    1055         2935 :          real(dp), pointer :: values(:)
    1056              :          ierr = 0
    1057         2935 :          call read_hbcode1(iounit, nrow, ncol, nnz, values, rowind, colptr,ierr)
    1058         2935 :          if (ierr /= 0 .or. nrow /= nvar .or. nrow /= ncol) return
    1059         2935 :          call do_column_sparse_to_dense(nrow,ncol,blk,nnz,colptr,rowind,values,ierr)
    1060         2935 :          deallocate(colptr,rowind,values)
    1061         2935 :       end subroutine read1_sparse_block
    1062              : 
    1063              : 
    1064            0 :       subroutine write_block_tridiagonal(iounit,nvar,nblk,lblk,dblk,ublk,ierr)
    1065              :          integer, intent(in) :: iounit, nvar, nblk
    1066              :          real(dp), intent(in), dimension(:,:,:) :: lblk,dblk,ublk
    1067              :          integer, intent(out) :: ierr
    1068              :          integer :: k
    1069            0 :          ierr = 0
    1070            0 :          write(iounit,*) nvar, nblk
    1071            0 :          do k=1,nblk
    1072            0 :             if (k > 1) then
    1073            0 :                call write1_sparse_block(iounit, nvar, lblk(:,:,k), ierr)
    1074            0 :                if (ierr /= 0) return
    1075              :             end if
    1076            0 :             call write1_sparse_block(iounit, nvar, dblk(:,:,k), ierr)
    1077            0 :             if (ierr /= 0) return
    1078            0 :             if (k < nblk) then
    1079            0 :                call write1_sparse_block(iounit, nvar, ublk(:,:,k), ierr)
    1080            0 :                if (ierr /= 0) return
    1081              :             end if
    1082              :          end do
    1083              :       end subroutine write_block_tridiagonal
    1084              : 
    1085              : 
    1086            0 :       subroutine write1_sparse_block(iounit, nvar, blk, ierr)
    1087              :          integer, intent(in) :: iounit, nvar
    1088              :          real(dp), intent(in) :: blk(:,:)  ! (nvar,nvar)
    1089              :          integer, intent(out) :: ierr
    1090            0 :          integer :: nnz, rowind(nvar*nvar), colptr(nvar+1)
    1091            0 :          real(dp) :: values(nvar*nvar)
    1092              :          call do_dense_to_column_sparse( &
    1093            0 :             nvar, nvar, blk, nvar*nvar, nnz, colptr, rowind, values, .true., ierr)
    1094            0 :          if (ierr /= 0) return
    1095            0 :          call write_hbcode1(iounit, nvar, nvar, nnz, values, rowind, colptr, ierr)
    1096              :       end subroutine write1_sparse_block
    1097              : 
    1098              : 
    1099              :       end module mtx_support
        

Generated by: LCOV version 2.0-1