coo_sparsity_pattern_procedures.f90 Source File


Source Code

!-----------------------------------------------------------------------------------------------------------------------------------
! This file is part of ReMKiT1D.
!
! ReMKiT1D is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as 
! published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version.
!
! ReMKiT1D is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of 
! MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
!
! You should have received a copy of the GNU General Public License along with ReMKiT1D. If not, see <https://www.gnu.org/licenses/>. 
!
! Copyright 2023 United Kingdom Atomic Energy Authority (stefan.mijin@ukaea.uk)
!-----------------------------------------------------------------------------------------------------------------------------------
submodule (coo_sparsity_pattern_class) coo_sparsity_pattern_procedures
    !! author: Stefan Mijin 
    !! 
    !!  Contains module procedures associated with the basic coo sparsity pattern class

implicit none

!-----------------------------------------------------------------------------------------------------------------------------------
contains
!-----------------------------------------------------------------------------------------------------------------------------------
pure module subroutine initCooSparsityPattern(this,numRows,numCols,bufferSize,rowOffset) 
    !! COO sparsity pattern initialization routine

    class(COOSparsityPattern)           ,intent(inout)  :: this
    integer(ik)                         ,intent(in)     :: numRows !! Matrix number of rows
    integer(ik)                         ,intent(in)     :: numCols !! Matrix number of columns
    integer(ik) ,optional               ,intent(in)     :: bufferSize !! Preallocated rolling buffer size
    integer(ik) ,optional               ,intent(in)     :: rowOffset !! Row offset for distributed arrays
    
    integer(ik) :: i

    call this%makeDefined()

    this%numNonZeros = 0
    this%numRows = numRows
    this%numCols = numCols
    this%bufferSize = 10000000
    if (present(bufferSize)) this%bufferSize = bufferSize
    allocate(this%rowIndex(this%bufferSize))
    allocate(this%colIndex(this%bufferSize))

    allocate(this%addedRow(this%numRows))
    this%addedRow = .false.
    allocate(this%addedCol(this%numCols))
    this%addedCol = .false.

    allocate(this%firstInstRow(this%numRows))
    this%firstInstRow = 0
    allocate(this%firstInstCol(this%numCols))
    this%firstInstCol = 0

    this%rowOffset = 0 
    if (present(rowOffset)) this%rowOffset = rowOffset

    allocatE(this%rowGlobalIndices(this%numRows))
    do i = 1,this%numRows
        allocate(this%rowGlobalIndices(i)%entry(0))
    end do
end subroutine initCooSparsityPattern
!-----------------------------------------------------------------------------------------------------------------------------------
pure module function hasIndices (this,row,column) result(found)
    !! Return true if all elements with indices (row,column) are present in sparsity pattern

    class(COOSparsityPattern)   ,intent(in) :: this
    integer(ik)   ,dimension(:) ,intent(in) :: row !! Row indices
    integer(ik)   ,dimension(:) ,intent(in) :: column !! Column indices
    logical                                 :: found

    logical      ,allocatable ,dimension(:) :: foundVec

    integer(ik) :: i ,j


    if (assertions) then 
        call assertPure(this%isDefined(),"Attempted to check if indices present in undefined sparsity pattern")
        call assertPure(size(row) == size(column), "Row and column index vectors passed to hasIndices must be same size")
    end if

    allocate(foundVec(size(row)))
    foundVec = .false.

    do i = 1,size(row)

        if (this%addedRow(row(i)-this%rowOffset) .and. this%addedCol(column(i))) then 

            do j = 1,size(this%rowGlobalIndices(row(i)-this%rowOffset)%entry)
                if (this%colIndex(this%rowGlobalIndices(row(i)-this%rowOffset)%entry(j)) == column(i)) then
                    foundVec(i) = .true.
                    exit
                end if
            end do

        end if
        
    end do 

    found = all(foundVec)

end function hasIndices
!-----------------------------------------------------------------------------------------------------------------------------------
pure module function findLocationOfIndices (this,row,column) result(indices)
    !! Return indices with given values of (row,column)

    class(COOSparsityPattern)                ,intent(in) :: this
    integer(ik)                ,dimension(:) ,intent(in) :: row !! Row index
    integer(ik)                ,dimension(:) ,intent(in) :: column !! Column index
    integer(ik)   ,allocatable ,dimension(:)             :: indices

    integer(ik) ,allocatable ,dimension(:) :: indicesLoc
    integer(ik) :: i


    if (assertions) then 
        call assertPure(this%isDefined(),"Attempted to get location of indices from undefined sparsity pattern")
        call assertPure(this%hasIndices(row,column),"Attempted to get location of indices from sparsity pattern when those&
                                                    & indices are not present")
    end if

    allocate(indices(size(row)))
    indices = 0 
    do i = 1,size(row)

        indicesLoc = findIndices(this%colIndex(1:this%numNonZeros) == column(i) &
                                 .and. this%rowIndex(1:this%numNonZeros) == row(i))

        indices(i) = indicesLoc(1)
    end do

end function findLocationOfIndices
!-----------------------------------------------------------------------------------------------------------------------------------
pure module subroutine addEntry(this,row,column) 
    !! Add entry if not already present

    class(COOSparsityPattern)   ,intent(inout)  :: this
    integer(ik)                 ,intent(in)     :: row !! Row index
    integer(ik)                 ,intent(in)     :: column !! Column Index

    integer(ik) ,allocatable ,dimension(:) :: tempRow ,tempCol

    if (assertions) then 
        call assertPure(this%isDefined(),"Attempted to add entry to undefined sparsity pattern")
    end if

    if (.not. this%hasIndices([row],[column])) then 
        if (this%numNonZeros < size(this%rowIndex)) then
            this%numNonZeros = this%numNonZeros + 1
            this%rowIndex(this%numNonZeros) = row
            this%colIndex(this%numNonZeros) = column
        else
            tempCol = this%colIndex
            tempRow = this%rowIndex 

            deallocate(this%rowIndex)
            deallocate(this%colIndex)

            allocate(this%rowIndex(this%bufferSize+size(tempRow)))
            allocate(this%colIndex(this%bufferSize+size(tempRow)))

            this%rowIndex(1:size(tempRow)) = tempRow
            this%colIndex(1:size(tempCol)) = tempCol

            this%numNonZeros = this%numNonZeros + 1
            this%rowIndex(this%numNonZeros) = row
            this%colIndex(this%numNonZeros) = column

        end if
        
        if (.not. this%addedRow(row-this%rowOffset)) this%firstInstRow(row-this%rowOffset) = this%numNonZeros
        if (.not. this%addedCol(column)) this%firstInstCol(column) = this%numNonZeros

        this%addedRow(row-this%rowOffset) = .true.
        this%addedCol(column) = .true.

        this%rowGlobalIndices(row-this%rowOffset)%entry = [this%rowGlobalIndices(row-this%rowOffset)%entry,this%numNonZeros]
    end if

end subroutine addEntry
!-----------------------------------------------------------------------------------------------------------------------------------
pure module subroutine addPattern(this,pattern,rowOffset,colOffset) 
    !! Add entries from existing pattern that are not already present

    class(COOSparsityPattern)      ,intent(inout)  :: this
    type(COOSparsityPattern)       ,intent(in)     :: pattern !! Pattern to add to this pattern
    integer(ik)      ,dimension(:) ,intent(in)     :: rowOffset !! Array by which to offset pattern row indices before adding
    integer(ik)      ,dimension(:) ,intent(in)     :: colOffset !! Array by which to offset pattern column indices before adding

    integer(ik) :: i

    if (assertions) then 
        call assertPure(this%isDefined(),"Attempted to add pattern to undefined sparsity pattern")
        call assertPure(pattern%isDefined(),"Attempted to add undefined pattern to sparsity pattern")
        call assertPure(size(colOffset) == size(rowOffset),"colOffset and rowOffset passed to addPattern must be of same size")
        call assertPure(size(colOffset) == pattern%numNonZeros,"Colum/row offsets passed to addPattern must have the same&
                        & number of elements as the added pattern")

    end if

    do i = 1,pattern%numNonZeros
        call this%addEntry(pattern%rowIndex(i)+rowOffset(i),pattern%colIndex(i)+colOffset(i))
    end do 

end subroutine addPattern
!-----------------------------------------------------------------------------------------------------------------------------------
end submodule coo_sparsity_pattern_procedures
!-----------------------------------------------------------------------------------------------------------------------------------