您的位置:首页 > 编程语言 > Python开发

Python调用C/Fortran混合的动态链接库--中篇

2014-09-15 14:09 399 查看
接下来,介绍一个简单的例子,从fortran中传递并返回一维自定义结构体数组到python
注意点:
1、fortran新标准支持可分配数组作为变量传入并在subroutine或function分配后返回;
2、BIND不支持传入可分配数组(也即1和2无法同时使用);
3、fortran没有垃圾自动回收机制;
综合上述3点,利用ctypes调用fortran不能也不宜直接返回形状大小在计算前无法确定的数组,折衷的办法是:
a、估算出返回数组的大小,可以适当偏大;
b、在fortran的module定义全局可分配数组,第一次调用后存储结果并返回数组形状数值,在python中利用numpy开辟空数组,再次调用fortran得到结果并清空fortran中module的全局变量
fortran代码:

module sam
use,intrinsic::iso_c_binding
implicit none
type,bind(C)::abc
!Define struct
character(len=80)::nam
real(c_float)::val(10)
end type
! Global variable in fortran module
! Notice: dealloacte after using to avoid memory leak
type(abc),allocatable::stu(:)
contains
subroutine calc(input,output,n1)bind(c,name='ex01')
! Example 01
! Both in and out variables has assumed shape
! Bind(C) not allowed pass alloctable variables
! Pure Fortran2008 allows pass alloctable array to subroutine to allocate or deallocate
implicit none
integer(c_int),intent(in),value::n1
real(c_float),intent(in)::input(n1)
type(abc),intent(out)::output(2*n1)

integer::i

do i=1,size(output)
output(i)%nam = "abcdefea"
output(i)%val(1:5) = real(i-1,4)
output(i)%val(6::1) = i*2.5E0
enddo
return
end subroutine

subroutine calc2(input,n1,n2)bind(c,name='ex02_1')
! Example 02_1
! Return result's shape
implicit none
integer(c_int),intent(in),value::n1
real(c_float),intent(in)::input(n1)
integer(c_int),intent(out)::n2

integer::i,j

call clear()
if(input(1)<1.E0)then
allocate(stu(10))
else
allocate(stu(int(input(1))+1))
endif
do i=1,size(stu)
stu(i)%nam = "daefvdefefadfad"
do j=1,size(stu(i)%val)
stu(i)%val(j) = i*j*1.5E0
enddo
enddo
n2 = size(stu)
return
end subroutine

subroutine getdata(output,n)bind(c,name='ex02_2')
! Example 02_2
! Return result and do clear
implicit none
integer(c_int),intent(in),value::n
type(abc),intent(out)::output(n)

output = stu
call clear()
return
end subroutine

subroutine clear()
implicit none
if(allocated(stu))deallocate(stu)
end subroutine
end module

program test
use sam
implicit none
real(c_float)::array(5)
type(abc)::student(5*2)
integer::i

array = [5.E0,4.E0,6.E0,1.E0,7.E0]
call calc(array,student,5)
do i=1,size(student)
write(*,*)student(i)%nam,student(i)%val
enddo
end program


python代码:

#! /usr/bin/env python
#coding=utf-8

'''
A short example of use ctypes and numpy to call fortran dynamic library
example for 1d struct array pass or access
'''
import numpy as np
from numpy.ctypeslib import load_library,ndpointer
from ctypes import c_int

#define struct as same sa fortran
abc = np.dtype([("nam",'S80',1),("val",'f4',10)])
#load dynamic library
flib = load_library("libexample",".")
#function handle of ex01
fun01 = flib.ex01
#define input arguments
fun01.argtypes = [ndpointer('f4'),ndpointer(abc),c_int]
#
n1,n2 = 5,np.array(0,'i4')
vec = np.zeros((n1,),'f4')
student = np.empty((n1*2,),abc)
#print vec
fun01(vec,student,n1)
#print student
#function handle of ex02_1
fun02_1 = flib.ex02_1
fun02_1.argtypes = [ndpointer('f4'),c_int,ndpointer('i4')]
fun02_1(vec,n1,n2)
#print n1,n2
#function handle of ex02_2
fun02_2 = flib.ex02_2
fun02_2.argtypes = [ndpointer(abc),c_int]
student2 = np.empty((n2,),abc)
fun02_2(student2,n2)
print student2


编译命令:

gfortran test.f90 -fPIC -shared -o libexample.so
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: