目录
上篇文章windows下python利用f2py调用Fortran我记录了利用numpy中的f2py调用fortran的方法,本文再介绍下在windows环境下,利用ctypeslib和ctypes调用fortran所踩过的坑。
基本的环境搭建参考上篇文章,这里就不再赘述,即安装好mingw-w64编译环境。
参考了博客园pasuka大神的文章Python调用C/Fortran混合的动态链接库-下篇,在ubuntu18.04环境下测试成功,但在windows下编译能成功,调用时却出了问题!
1、ubuntu18.04环境
ctypes2d_array_test.f90
module py2f90
use,intrinsic::iso_c_binding
implicit none
contains
subroutine transferMat2For(matrix,n1,n2)bind(c,name='array2py')
implicit none
integer(c_int),intent(in),value::n1,n2
real(c_float),intent(out)::matrix(n1,n2)
integer::i,j
! initialize matrix
matrix = 0.0E0
! loop
do i=1,n1
do j=1,n2
matrix(i,j) = real(i,4)*1.E1+real(j,4)*2.E0
write(*,"('Row:',i4,1x,'Col:',i4,1x,'Value:',1x,F5.2)")i,j,matrix(i,j)
enddo
enddo
return
end subroutine
end module
program test
use py2f90
implicit none
real(kind=4)::aa(4,5)
call transferMat2For(aa,4,5)
end program
py2f90_test.py
#! /usr/bin/env python
#coding=utf-8
import numpy as np
from numpy.ctypeslib import load_library,ndpointer
from ctypes import c_int
# shape of 2d array
n1,n2 = 2,4+1
# create an empty 2d array
data = np.empty(shape=(n1,n2),dtype='f4',order='f')
flib = load_library("test","./")
flib.argtypes = [ndpointer(dtype='f4',ndim=2),c_int,c_int]
flib.array2py(data.ctypes.data,n1,n2)
print("*"*80)
print(data)
用gfortran编译:
gfortran ctypes2d_array_test.f90 -fPIC -shared -o test.so
在ubuntu下运行正常:
2、win10环境
在win10环境下,编译指令:
gfortran py2f90.f90 -fPIC -shared -g -o test_mat.dll -fno-underscoring
编译能成功,但调用时出错:
错误定位到了第14行,flib.array2py(data.ctypes.data, n1, n2)这句,提示int too long to convert
但明明python3中,int是没有大小上限的,那为啥还会出现溢出错误呢?原因是fortran里的整数类型会出现溢出,其实我们的目的只是想把data这个numpy数组的首地址传递到fortran编写的array2py函数,这时可以用到ndarray.ctypes.data_as方法替换ndarray.ctypes.data属性,将py2f90_test.py代码做一些更改如下:
#coding=utf-8
from sys import flags
import numpy as np
from numpy.ctypeslib import load_library,ndpointer
from ctypes import c_int,POINTER,c_float
# shape of 2d array
n1,n2 = 2,4+1
# create an empty 2d array
data = np.empty(shape=(n1,n2),dtype='f4',order='f')
flib = load_library("test","./")
# flib.argtypes = [ndpointer(dtype='f4',ndim=2),c_int,c_int]
flib.argtypes = [POINTER(c_float),c_int,c_int]
print(data.ctypes.data_as(POINTER(c_float)))
print(data.ctypes.data)
flib.array2py(data.ctypes.data_as(POINTER(c_float)),n1,n2)
# flib.array2py(data.ctypes.data,n1,n2)
print("*"*80)
print(data)
运行结果如下:
可见用ndarray.ctypes.data_as方法比用ndarray.ctypes.data属性代码健壮性更好,既可以在linux下运行,也能在windows下运行,另外ndpointer和POINTER对代码的运行没什么影响,但ndpointer使用起来更灵活,因为既可以指定数组的返回值类型,也可以指定维度,更方便代码理解。
3、参考文章
Python调用C/Fortran混合的动态链接库-下篇https://www.cnblogs.com/pasuka/p/4012508.html