在fortran中使用zheev例程的问题

时间:2014-12-06 22:28:06

标签: matrix fortran lapack

我正在尝试编写一个程序来计算ising系统的哈密顿函数。程序的第一部分工作,我获得了我想要的矩阵,但是当我试图通过使用子程序zheev来获得这个复数* 16矩阵的特征值时会出现问题。当我读到我必须调用它2次,以便为整数lwork分配最好的值。但对于给定的矩阵,而不是像matlab那样得到特征值(-2.236,-1,1,2.236),我得到(132,0,1,0)。有人能帮助我吗?

非常感谢

module matrices
 implicit none
 type matrix
    complex*16, dimension(:,:), allocatable :: el
    integer :: row, col
 end type

 contains 

    type(matrix) function assign0(row, col)
       integer :: ii, jj, row, col
       assign0%row = row
       assign0%col = col
       allocate(assign0%el(assign0%row, assign0%col))
       do ii = 1, assign0%row
          do jj = 1, assign0%col
             assign0%el(ii, jj) = cmplx(0d0, 0d0)
          enddo
       enddo
    end function assign0

    type(matrix) function assignid(row, col)
       integer :: ii, jj, row, col
       assignid%row = row
       assignid%col = col
       allocate(assignid%el(assignid%row, assignid%col))
       do ii = 1, assignid%row
          jj = ii
          assignid%el(ii, jj) = cmplx(1d0, 0d0)
       enddo
    end function assignid

    type(matrix) function assignsigx()
       allocate(assignsigx%el(assignsigx%row, assignsigx%col))         
       assignsigx = assign0(2, 2)
       assignsigx%el(1, 2) = (1d0, 0d0)
       assignsigx%el(2, 1) = (1d0, 0d0)
    end function 

    type(matrix) function assignsigz() 
       allocate(assignsigz%el(assignsigz%row, assignsigz%col))
       assignsigz = assign0(2, 2)
       assignsigz%el(1, 1) = (1d0, 0d0)
       assignsigz%el(2, 2) = (-1d0, 0d0)
    end function

    type(matrix) function prodscal(lambda, ma1)
       type(matrix) :: ma1
       real :: lambda
       integer :: ii, jj
       prodscal%row = ma1%row
       prodscal%col = ma1%col
       allocate(prodscal%el(prodscal%row, prodscal%col))
       do ii = 1, ma1%row
          do jj = 1, ma1%col
             prodscal%el(ii, jj) = lambda*ma1%el(ii, jj)
          enddo
       enddo
    end function prodscal

    type(matrix) function matsum(ma1, ma2, sign)
       type(matrix) :: ma1, ma2
       integer :: ii, jj, sign
       matsum%row = ma1%row
       matsum%col = ma1%col
       allocate(matsum%el(matsum%row, matsum%col))
       do ii = 1, ma1%row
          do jj = 1, ma1%col
             if (sign .gt. 0) then
                matsum%el(ii, jj) = ma1%el(ii, jj) + ma2%el(ii, jj)
             else
                matsum%el(ii, jj) = ma1%el(ii, jj) - ma2%el(ii, jj)
             endif
          enddo
       enddo       
    end function matsum

    type(matrix) function tensprod(ma1, ma2)
       type(matrix) :: ma1, ma2
       integer :: ii, jj, kk, ll
       tensprod%row = ma1%row*ma2%row
       tensprod%col = ma1%col*ma2%col
       allocate(tensprod%el(tensprod%row, tensprod%col))
       tensprod = assign0(tensprod%row, tensprod%col)
       do ii = 1, ma1%row
          do jj = 1, ma1%col
             do kk = 1, ma2%row
                do ll = 1, ma2%col
                   tensprod%el((ii - 1)*ma2%row + kk, (jj - 1)*ma2%col + ll) = ma1%el(ii, jj)*ma2%el(kk, ll)
                enddo
             enddo
          enddo
       enddo
    end function tensprod

 end module matrices

    program test
       use matrices
       implicit none

       interface 
          function getdim()
             integer :: getdim
          end function getdim
       end interface

       integer :: row, col, ii, jj, N, ind, info, lwork, aus
       type(matrix), dimension(2, 2) :: arrmat1, arrmat2
       type(matrix), dimension(2) :: element1, element2, element3
       type(matrix) :: elementtot, elementtot1, elementtot2
       real :: lambda
       double precision, dimension(:), allocatable :: w, rwork
       complex*16, dimension(:), allocatable :: work
       N = 2        

       allocate(w(15))
       allocate(rwork(15))
       allocate(work(15))

       lwork = -1
       aus = 2
       lambda = 1d0
       do ii = 1, N
          ind = ii
          do jj = 1, N
             if(jj .eq. ind) then
                arrmat1(ii, jj) = assignsigz()
             else
                arrmat1(ii, jj) = assignid(2, 2)
             endif
          enddo
       enddo

       do ii = 1, N
          ind = ii
          do jj = 1, N
             if(jj .eq. ind) then
                arrmat2(ii, jj) = assignsigx()
             else
                arrmat2(ii, jj) = assignid(2, 2)
             endif
          enddo
       enddo

       do ii = 1, N
          element1(ii) = tensprod(arrmat1(ii, 1), arrmat1(ii, 2))
          if (N .gt. 2) then
             do jj = 3, N
                element1(ii) = tensprod(element1(ii), arrmat1(ii, jj))
             enddo
          endif
       enddo

       do ii = 1, N
          element2(ii) = tensprod(arrmat2(ii, 1), arrmat2(ii, 2))
          if (N .gt. 2) then
             do jj = 3, N
                element2(ii) = tensprod(element2(ii), arrmat2(ii, jj))
             enddo
          endif
       enddo              

       do ii = 1, N - 1              
          element3(ii) = assign0(2**N, 2**N)
          element3(ii)%el = matmul(element2(ii + 1)%el, element2(ii)%el)
       enddo

       elementtot = assign0(2**N, 2**N)
       elementtot1 = assign0(2**N, 2**N)
       elementtot2 = assign0(2**N, 2**N)

       do ii = 1, N 
          elementtot1 = matsum(elementtot1, element1(ii), 1)
       enddo

       do ii = 1, N - 1
          elementtot2 = matsum(elementtot2, element3(ii), 1)
       enddo

       elementtot2 = prodscal(lambda, elementtot2)

       elementtot = matsum(elementtot1, elementtot2, 1)

       do ii = 1, 2**N 
          write(*,'(20G12.4)') elementtot%el(ii, 1:2**N)
       enddo                   

       call zheev('N', 'U', 2**N, elementtot%el, 2**N, w, work, lwork, rwork, info)
       lwork = int(work(1))
       call zheev('N', 'U', 2**N, elementtot%el, 2**N, w, work, lwork, rwork, info)           

       print*, '***', info

       do ii = 1, 2**N
          write(*,'(20G12.4)') work(ii)
       enddo

       stop

    end program test 

1 个答案:

答案 0 :(得分:1)

您的assignsigxassignsigz函数正在根据相应返回值的rowcol组件的未定义值为其返回值分配空间。您可能希望传递要使用的rowcol尺寸,就像在assign0assignid函数中一样。要么只是取出引用未定义组件的分配行,让后续分配使用assign0来处理它?<​​/ p>

如果我取出第33和39行,使用NAG Fortran编译器进行编译和运行并打开完整检查告诉我

Extension: test.f90, line 4: Byte count on numeric data type
           detected at *@16
Extension: test.f90, line 112: Byte count on numeric data type
           detected at *@16
Questionable: test.f90, line 199: Variable AUS set but never referenced
Warning: test.f90, line 199: Unused local variable COL
Warning: test.f90, line 199: Unused interface for procedure GETDIM
Warning: test.f90, line 199: Unused local variable ROW
Questionable: test.f90, line 17: Intrinsic function CMPLX with double precision argument and no KIND= argument returns single precision result
Questionable: test.f90, line 29: Intrinsic function CMPLX with double precision argument and no KIND= argument returns single precision result
[NAG Fortran Compiler normal termination, 8 warnings]
Runtime Error: test.f90, line 87: Reference to undefined variable MA2%EL(KK,LL)
Program terminated by fatal error
Abort (core dumped)

tensprodii时,崩溃是在第145行第一次调用1kk中的llma2%el(kk,ll)分别为12。这似乎是因为你没有将assignid中的非对角元素归零。如果我也这样做,那么我看到了

Extension: test.f90, line 4: Byte count on numeric data type
           detected at *@16
Extension: test.f90, line 113: Byte count on numeric data type
           detected at *@16
Questionable: test.f90, line 200: Variable AUS set but never referenced
Warning: test.f90, line 200: Unused local variable COL
Warning: test.f90, line 200: Unused interface for procedure GETDIM
Warning: test.f90, line 200: Unused local variable ROW
Questionable: test.f90, line 17: Intrinsic function CMPLX with double precision argument and no KIND= argument returns single precision result
Questionable: test.f90, line 30: Intrinsic function CMPLX with double precision argument and no KIND= argument returns single precision result
[NAG Fortran Compiler normal termination, 8 warnings]
   2.000       0.000       0.000       0.000       0.000       0.000       1.000       0.000    
   0.000       0.000       0.000       0.000       1.000       0.000       0.000       0.000    
   0.000       0.000       1.000       0.000       0.000       0.000       0.000       0.000    
   1.000       0.000       0.000       0.000       0.000       0.000      -2.000       0.000    
Runtime Error: zheev.f90, line 1: Invalid reference to procedure ZHEEV - Dummy array WORK (number 7) has 36 elements but actual argument only has 15 elements
Program terminated by fatal error
Abort (core dumped)

所以我认为,正如francescalus指出的那样,你遗漏调整大小work的问题肯定是个问题。

如果我根据新work重新调整lwork(通过解除分配并重新分配),我会得到结果

   2.000       0.000       0.000       0.000       0.000       0.000       1.000       0.000    
   0.000       0.000       0.000       0.000       1.000       0.000       0.000       0.000    
   0.000       0.000       1.000       0.000       0.000       0.000       0.000       0.000    
   1.000       0.000       0.000       0.000       0.000       0.000      -2.000       0.000    
 *** 0
   36.00       0.000    
   0.000       0.000    
   1.000       0.000    

顺便说一下,为什么以打印work结束?在进行工作空间查询时,唯一感兴趣的是work(1)