利用numpy中的ctypeslib和python基础库ctypes调用fortran

目录

1、ubuntu18.04环境

2、win10环境

3、参考文章


上篇文章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下运行正常:

利用numpy中的ctypeslib和python基础库ctypes调用fortran

 2、win10环境

在win10环境下,编译指令:

gfortran py2f90.f90 -fPIC -shared -g -o test_mat.dll -fno-underscoring

编译能成功,但调用时出错:

利用numpy中的ctypeslib和python基础库ctypes调用fortran

错误定位到了第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)

运行结果如下:

利用numpy中的ctypeslib和python基础库ctypes调用fortran

可见用ndarray.ctypes.data_as方法比用ndarray.ctypes.data属性代码健壮性更好,既可以在linux下运行,也能在windows下运行,另外ndpointer和POINTER对代码的运行没什么影响,但ndpointer使用起来更灵活,因为既可以指定数组的返回值类型,也可以指定维度,更方便代码理解。

3、参考文章

Python调用C/Fortran混合的动态链接库-下篇利用numpy中的ctypeslib和python基础库ctypes调用fortranhttps://www.cnblogs.com/pasuka/p/4012508.html

Python使用ctypes模块调用DLL函数之C语言数组与numpy数组传递利用numpy中的ctypeslib和python基础库ctypes调用fortranhttps://baijiahao.baidu.com/s?id=1615404760897105428&wfr=spider&for=pc

上一篇:iOS-带参数的图片上传(适用于不太懂后端的小白~)


下一篇:Fortran确定文件的行数和列数(转)