Array return when calling Fortran from Python using Ctypes

How do you return arrays from Fortran to Python using ctypes?

As an example, I am passing an array (length 5) from Python to Fortran. The output array is created with the same values. Then it returns to Python. Inside Fortran, the values ​​are correct, but after they are submitted to Python, this is not the case. How about the fact that my setup does not allow the array to go through correctly?

My Fortran code (e.g. test.f) contains the following:

SUBROUTINE mySub(inArray, lenInOut, outArray) BIND(C)

USE ISO_C_BINDING
IMPLICIT NONE

INTEGER(C_INT), INTENT(IN), VALUE :: lenInOut
REAL(C_DOUBLE), DIMENSION(lenInOut), INTENT(IN) :: inArray
REAL(C_DOUBLE), DIMENSION(lenInOut), INTENT(OUT) :: outArray

print *, "outArray from within Fortran"
do i = 1, lenInOut
  outArray(i) = inArray(i)
  print *, outArray(i)
end do
return
end subroutine mySub

This compiled as .so:

ifort -g -O0 -fpic -traceback -c -o "test.o" "../test.f"
ifort -shared -o "mylib.so"  ./test.o

Python code is as follows:

from ctypes import *

mylib = CDLL('mylib.so')

ArrayType = c_double*5
IntType = c_int
input1 = ArrayType(1.1,2.2,3.3,4.4,5.5)
input2 = IntType(5)
inputoutput = ArrayType(0,0,0,0,0)              

mylib.mySub.argtypes = [ArrayType,IntType,ArrayType]
mylib.mySub.restype =  ArrayType

output = mylib.mySub(input1,input2,inputoutput)

print '------------------------------------------------------'  
print 'output within Python'
print output
a = [0,1,2,3,4]
for ii in a: print output[ii]

The conclusion gives the following:

#outArray from within Fortran
#1.10000000000000     
#2.20000000000000     
#3.30000000000000     
#4.40000000000000     
#5.50000000000000     
#------------------------------------------------------
#output within Python
#<__main__.c_double_Array_5 object at 0x10aa830>
#2.96439387505e-323
#6.91177308417e-310
#1.48219693752e-323
#6.91177308238e-310
#6.91177319086e-310
+4
source share
1 answer

Few things:

  • , .. . , VALUE, . lenInOut, argtypes -
mylib.mySub.argtypes = [ POINTER(c_double), c_int, POINTER(c_double) ]
  • , . , . outArray. output Python undefined. @eryksun, , , / :
 
mylib.mySub.restype = None
  • , bind(c), . bind name, , . Fortran 2008 15.5.2 p2 ( @francescalus). , bind(c, name='mySub').

  • IMPLICIT NONE, i .

:

  • return .

  • ctypes Python int, input2 = 5 ( @eryksun )

  • ctypes , inputoutput inputoutput = ArrayType() ( @eryksun )


:

test.f90:

SUBROUTINE mySub(inArray, lenInOut, outArray) BIND(C, NAME='mySub')

USE ISO_C_BINDING
IMPLICIT NONE

INTEGER(C_INT), INTENT(IN), VALUE :: lenInOut
REAL(C_DOUBLE), DIMENSION(lenInOut), INTENT(IN) :: inArray
REAL(C_DOUBLE), DIMENSION(lenInOut), INTENT(OUT) :: outArray
integer :: i 

print *, "outArray from within Fortran"
do i = 1, lenInOut
  outArray(i) = inArray(i)
  print *, outArray(i)
end do

end subroutine mySub

test.py:

from ctypes import *

mylib = CDLL('./mylib.so')
mylib.mySub.argtypes = [ POINTER(c_double), c_int, POINTER(c_double) ]
mylib.mySub.restype = None

ArrayType = c_double*5
IntType = c_int
input1 = ArrayType(1.1,2.2,3.3,4.4,5.5)
input2 = 5
inputoutput = ArrayType()              

mylib.mySub( input1, input2, inputoutput )

print '------------------------------------------------------'  
print 'output within Python'
a = [0,1,2,3,4]
for ii in a: print inputoutput[ii]
+6

Source: https://habr.com/ru/post/1629933/