pythonfortranf2py

Using f2py for faster calculation on Python


I'm working on a sequence alignment project with python, and python for loop is too slow.

So, I decided to use f2py. I don't know much about fortran, so I'm stuck to the point below.

There are two sequence named 'column', and 'row' whose type is np.array

For example:

column = ['A', 'T', 'G', 'C']
row = ['A', 'A', 'C', 'C'] 

I created a matrix for the Needleman-Wunsch algorithm, and I scored two sequences (column, row).

    import numpy as np
    column = np.array(list('ATGC'))
    row = np.array(list('AACC'))
    matrix = np.zeros((len(column) + 1, len(row) + 1), dtype='int')

    for i in range(1, len(column)+1):
        self.matrix[i][0] = -1 * i

    for j in range(1, len(row)+1):
        self.matrix[0][j] = -1 * j

    matchCheck = 0

    for i in range(1, len(column) + 1):
        for j in range(1, len(row) + 1):
            if column[i-1] == row[j-1]:
                matchCheck = 1 
            else:
                matchCheck = -1 
            top = matrix[i-1][j] + -1
            left = matrix[i][j-1] + -1
            top_left = matrix[i-1][j-1] + matchCheck
            matrix[i][j] = max(top, left, top_left)

I wanted to get some help from fortran for faster calculation, so I wrote a code with fortran.

subroutine needlemanWunsch(matrix, column, row, cc, rr, new_matrix)
integer, intent(in) :: cc, rr
character, intent(in) :: column(0:cc-1), row(0:rr-1)
integer, intent(in) :: matrix(0:cc, 0:rr)
integer, intent(out) :: new_matrix(0:cc, 0:rr)
integer :: matchcheck, top, left, top_left

do i = 1, cc
    new_matrix(i, 0) = -1 * i
end do

do j = 1, rr
    new_matrix(i, 0) = -1 * j
end do

do k = 1, cc
    do l = 1, rr
        if (column(i-1).EQ.row(j-1)) then
            matchcheck = 1
        else
            matchcheck = -1 
        
        top = matrix(i-1, j) + inDel
        left = matrix(i, j-1) + inDel
        top_left = matrix(i-1, j-1) + matchCheck
        new_matrix(i, j) = max(top, left, top_left)
        end if 
    end do
end do 
return
end subroutine

Then, I converted this fortran code with f2py, and imported it on python with this code.

    import numpy as np
    column = np.array(list('ATGC'))
    row = np.array(list('AACC'))
    matrix = np.zeros((len(column) + 1, len(row) + 1), dtype='int')
    
    # import my fortran code 
    matrix = algorithm.needlemanwunsch(matrix, column, row, cc, rr)

whenever I tried to import the fortran code
it crasheds...


Solution

  • The following works in my case.

    File neeldemanWunsch.f90

    subroutine needlemanWunsch(matrix, column, row, cc, rr, new_matrix)
      integer, intent(in) :: cc, rr
      character, intent(in) :: column(0:cc-1), row(0:rr-1)
      integer, intent(in) :: matrix(0:cc, 0:rr)
      integer, intent(out) :: new_matrix(0:cc, 0:rr)
      integer :: matchcheck, top, left, top_left
    
      do i = 1, cc
          new_matrix(i, 0) = -1 * i
      end do
    
      do j = 1, rr
          new_matrix(i, 0) = -1 * j
      end do
    
      do k = 1, cc
          do l = 1, rr
              if (column(i-1).EQ.row(j-1)) then
                  matchcheck = 1
              else
                  matchcheck = -1
    
              top = matrix(i-1, j) + inDel
              left = matrix(i, j-1) + inDel
              top_left = matrix(i-1, j-1) + matchCheck
              new_matrix(i, j) = max(top, left, top_left)
              end if
          end do
      end do
      return
    end subroutine
    

    Compiling it via f2py

    $ f2py -c needlemanWunsch.f90 -m needlemanWunsch
    

    Importing into python file needlemanWunsch.py. This is where your error comes from! You need to import the compiled module see example below.

    import needlemanWunsch         # THIS IS MISSING IN YOUR CODE!!
    import numpy as np
    
    # create matrix
    _column = ['A', 'T', 'G', 'C']
    _row = ['A', 'A', 'C', 'C']
    column = np.array(list(_column))
    row = np.array(list(_row))
    cc = len(column)
    rr = len(column)
    matrix = np.zeros((len(column) + 1, len(row) + 1), dtype='int')
    
    # import my fortran code
    matrix = needlemanWunsch.needlemanwunsch(matrix, column, row, cc, rr)
    
    print(matrix)
    

    The output is

    $ python needlemanWunsch.py 
    [[ 0 -4  0  0  0]
     [-1  0  0  0  0]
     [-2  0  0  0  0]
     [-3  0  0  0  0]
     [-4  0  0  0  0]]