-2

I'm trying to write a program which computes the hamiltonian of a ising system. The first part of the program works, and i obtain the matrix that i want, but a problem occurs when i try to get the eigenvalues of this complex*16 matrix by using the subroutine zheev. As i read i have to call it 2 times, in order to assign the best possible value to the integer lwork. But for the given matrix, instead of getting the eigenvalues (-2.236, -1, 1, 2.236), as matlab does, i get (132, 0, 1, 0). Could somebody help me?

Thank you very much

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
    I haven't looked closely, but you do a workspace query, and then do nothing to resize the workspace to the optimal size, (but tell the subroutine it's of that size). – francescalus Dec 06 '14 at 22:36

1 Answers1

1

Your assignsigx and assignsigz functions are allocating space for their return values based on undefined values of the row and col components of the respective return value. You probably want to pass in the row and col sizes you want to use, just as you do in the assign0 and assignid functions. Either that or just take out the Allocate lines referencing the undefined components and let the subsequent assignments using assign0 handle it?

If I take out lines 33 and 39, compiling and running using the NAG Fortran Compiler with full checking turned on tells me

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)

The crash is in the first call to tensprod, at line 145, when ii is 1. The kk and ll in ma2%el(kk,ll) are 1 and 2 respectively. This seems to be because you have not zeroed the off-diagonal elements in assignid. If I also do this, then I see

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)

So I think it certainly is the case that your omission of resizing work is a problem, as francescalus noted.

If I resize work according to the new lwork (by deallocating it and allocating it again) I get results

   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    

As an aside, why are you ending with printing work? The only thing of interest there should be work(1), when doing a workspace query.

MatCross
  • 389
  • 1
  • 5