Fortran:用csr存储格式并使用pardiso求解稀疏矩阵

使用链表,将大型稀疏对称矩阵存储为CSR格式,并用mkl函数库中的pardiso求解器进行快速求解
Program CSR
    !// author: luk
    !// qq: 735343320
    implicit none
    integer, parameter        :: n = 5  !// depend on your equation
    integer                   :: i, j, mm, tmp, nn, fileid, first, num
    real(kind=8)              :: matrix(n,n), b(n), x(n)
    real(kind=8), allocatable :: aa(:)
    integer, allocatable      :: ia(:), ja(:)
  
    !// =====================the variables of pardiso====================
    integer(kind=8)           :: pt(64)   !// kind=8:x64; kind=4:win32
    integer                   :: maxfct, mnum, mtype, phase, nrhs, error, msglvl
    integer, allocatable      :: perm(:)
    integer                   :: iparm(64)
    integer, external         :: mkl_get_max_threads
    !// =====================the variables of pardiso====================
  
    type                      :: node
        real(kind=8)          :: s
        integer               :: k1, k2
        type (node), pointer  :: next
    end type node 
    type (node), pointer      :: head, tail, p, q  
  
    !// input data
    allocate( perm( n ) )
    open ( newunit = fileid, file = 'SparseMatrix.txt' )  !// The sparse matrix data needs to be given by itself
    Do i = 1, n
        do j = 1, n
            read ( fileid,* ) matrix(i,j)
        end do
    End do
    read( fileid,* ) b
    close ( fileid )

    !// =========================store data by CSR format=======================
    first = 1
    If ( .not.associated(p) ) then
        allocate( p )
        q    => p
        nullify( p%next )
        q%k2 = first
        tmp  = q%k2
    End if
  
    num = 0  !// calculate the number of no-zero
    Do i =  1, n
        mm = 0  !// calculate the position of no-zero in every row
        do j = i, n
            If ( matrix(i,j) /= 0.0 ) then
                if ( .not.associated(head) ) then
                    allocate( head )
                    tail    => head
                    nullify( tail%next )
                    tail%s  = matrix(i,j)
                    tail%k1 = j
                    num     = num + 1
                    mm      = mm + 1
                else
                    allocate( tail%next )
                    tail    => tail%next
                    tail%s  = matrix(i,j)
                    tail%k1 = j
                    num     = num + 1  
                    mm      = mm + 1  
                    nullify( tail%next )
                end if
            End if
        end do
        if ( associated(p) ) then
            allocate( q%next )
            q    => q%next
            q%k2 = tmp + mm
            tmp  = q%k2
            nullify( q%next )
        end if
    End do
  
    allocate( aa(num), ja(num), ia(n+1) )  !// store the no-zero element
    !// output a and ja
    tail => head
    j = 1
    Do 
        if ( .not.associated(tail) ) exit
        aa(j) = tail%s
        ja(j) = tail%k1
        j     = j + 1
        tail  => tail%next
    End do
  
    !// output ia
    q => p
    j = 1
    Do 
        if ( .not.associated(q) ) exit
        ia(j) = q%k2
        j     = j + 1
        q     => q%next
    End do
  
    nullify( head, tail, p, q )
    !// =========================store data by CSR format=======================
    write ( *,'(a)' ) '>> Original data'
    write ( *,'(5f7.2)' ) matrix
    write ( *,'(a)' ) '>> CSR data'
    write ( *,'(*(f7.2))' ) aa
    write ( *,'(a)' ) '>> B data'
    write ( *,'(*(f7.2))' ) b
    write ( *,'(a)' ) '>> Colnum of CSR data'
    write ( *,'(*(i4))' ) ja
    write ( *,'(a)' ) '>> The position of CSR data'
    write ( *,'(*(i4))' ) ia
  
    !// ===========================solve equations=============================
    pt = 0  !// pointer initialization
    maxfct = 1; mnum = 1; mtype = -2  !// mtype = -2: symmetric nonpositive definite matrix, mtype = 2: symmetric positive definite matrix
    perm = 0; nrhs = 1
    x = 0.d0
    iparm(1) = 0  !// iparm use default values
    iparm(3) = mkl_get_max_threads()  !// iparm(3): parallel threads are obtained by MKL. In general, the number of cpus is the same as the number of threads
    error = 0  
    msglvl = 0
  
    phase = 12  !// LU decompose
    call pardiso( pt, maxfct, mnum, mtype, phase, n, aa, ia, ja, perm, nrhs, iparm, msglvl, b, x, error )
    phase = 33  !// solve equations
    call pardiso( pt, maxfct, mnum, mtype, phase, n, aa, ia, ja, perm, nrhs, iparm, msglvl, b, x, error )
    write ( *,'(a)' ) '>> The solution as follows ...... '
    do i = 1, n
        write( *,'(f7.4)' ) x(i)
    end do
  
    phase = -1
    call pardiso (pt, maxfct, mnum, mtype, phase, n, aa, ia, ja, perm, nrhs, iparm, msglvl, b, x, error)
  
    deallocate( aa, ja, ia, perm )
    !// ===========================stop solving equations=============================
  
End program CSR
  

!// remark:
!// windows: set mkl libraries or use command line with /Qmkl  [ifort /Qmkl pardiso.f90]
!// linux: use command line with -mkl   [ifort -mkl pardiso.f90]
!// phase = 12  !// LU decompose
!// call pardiso( pt, maxfct, mnum, mtype, phase, n, aa, ia, ja, perm, nrhs, iparm, msglvl, b, x, error )
!// phase = 33  !// solve equations 
!// call pardiso( pt, maxfct, mnum, mtype, phase, n, aa, ia, ja, perm, nrhs, iparm, msglvl, b, x, error )
!// The top four rows can be replaced by the bottom two rows
!// phase = 13  !// solve equations 
!// call pardiso( pt, maxfct, mnum, mtype, phase, n, aa, ia, ja, perm, nrhs, iparm, msglvl, b, x, error )

这里给出测试矩阵文件SparseMatrix.txt, 元素如下:
   1.00  -1.00   0.00  -3.00   0.00
  -1.00   5.00   0.00   0.00   0.00
   0.00   0.00   4.00   6.00   4.00
  -3.00   0.00   6.00   7.00   0.00
   0.00   0.00   4.00   0.00  -5.00
右端项为:
  -13.00   
   9.00  
   56.00  
   43.00 
  -13.00
得其解为:
1
2
3
4
5

 

您好!为了使用PARDISO求解求解CSR格式稀疏矩阵方程,您需要进行以下步骤: 1. 首先,确保您已经安装了PARDISO求解,并将其与Fortran编程环境进行了适当的集成。 2. 在您的Fortran程序中,将PARDISO求解的接口函数包含在您的代码中。您可以使用类似以下的声明来引入PARDISO接口函数: ```fortran ! PARDISO 接口函数声明 interface subroutine pardisoinit(handle, mtype, iparm) integer, intent(out) :: handle, mtype, iparm(64) end subroutine pardisoinit subroutine pardiso(handle, maxfct, mnum, mtype, phase, n, a, ia, ja, perm, nrhs, iparm, msglvl, b, x, error) integer, intent(inout) :: handle, maxfct, mnum, mtype, phase, n, ia(:), ja(:), perm(:), nrhs, iparm(64), error real(kind=8), intent(inout) :: a(:) real(kind=8), intent(in) :: b(n,nrhs), x(n,nrhs) character(len=64), intent(out) :: msglvl end subroutine pardiso subroutine pardisofree(handle, mtype) integer, intent(inout) :: handle, mtype end subroutine pardisofree end interface ``` 3. 在您的代码中,定义并初始化与PARDISO求解相关的参数。这些参数存储在`iparm`数组中,并在调用PARDISO求解之前进行设置。例如,您可以通过以下方式初始化`iparm`数组: ```fortran ! 初始化 PARDISO 参数 integer :: iparm(64) iparm = 0 iparm(1) = 1 ! 设置矩阵的非零元素以列优先存储 iparm(3) = 0 ! 设置矩阵乘法类型为稀疏乘法 ! ... 其他参数设置 ``` 4. 准备好您的稀疏矩阵数据。您需要将矩阵的非零元素存储在一维数组`a`中,并将每一行的起始位置存储在`ia`数组中。非零元素的列索引应存储在`ja`数组中。 5. 在调用PARDISO求解之前,使用`pardisoinit`函数初始化PARDISO求解的句柄和参数。例如: ```fortran ! 初始化 PARDISO 求解 integer :: handle, mtype character(len=64) :: msglvl handle = 0 mtype = 11 ! 实数矩阵 call pardisoinit(handle, mtype, iparm) ``` 6. 调用`pardiso`函数来解决您的稀疏矩阵方程。例如,对于一个右手边向量`b`和解向量`x`,您可以使用以下代码: ```fortran ! 调用 PARDISO 求解求解方程 integer :: phase, n, nrhs, error real(kind=8) :: a(size), b(n,nrhs), x(n,nrhs) ! 设置求解阶段 phase = 13 ! 分析、因子化和求解 ! 调用 PARDISO 求解 call pardiso(handle, 1, 1, mtype, phase, n, a, ia, ja, perm, nrhs, iparm, msglvl, b, x, error) ``` 7. 在完成求解后,使用`pardisofree`函数释放PARDISO求解的内存。例如: ```fortran ! 释放 PARDISO 求解内存 call pardisofree(handle, mtype) ``` 这样,您就可以使用PARDISO求解求解CSR格式稀疏矩阵方程了。请根据您的具体需求和数据,进行相应的参数设置和调用。希望对您有所帮助!
评论 38
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值