问题
Warning..... I am a relative python noob, and completely new to using f2py.
I have tried to exercise due diligence and search for the answer to my questions here and elsewhere on the interweb, but I've had little luck. This is very likely due to my own ignorance on this subject.
My problem: I have a legacy fortran (f77) subroutine along with several functions that are used by the subroutine to read in various arrays from a data file. This data file is itself the result of one of several f77 atomic physics codes.
I would like to wrap the fortran subroutines/functions using f2py, and have access to the data stored in the file in the form of numpy arrays. I'm stuck at how to properly allocate the arrays in python. I am using the Anaconda python distibrution (Python 3.4 - 64 bit) and the gfortran compiler on Ubuntu 14.04 (64 bit).
I've successfully (I hope) managed to create a python signature file using py2f, using py2f -h <filename.py2f> <input files>
. Here's the contents of the signature file. I apologize for its length. This is a fairly lengthy subroutine and has a lot of variables.
! -*- f90 -*-
! Note: the context of this file is case sensitive.
subroutine xxdata_04(iunit,ndlev,ndtrn,ndmet,ndqdn,nvmax,titled,iz,iz0,iz1,bwno,npl,bwnoa,lbseta,prtwta,cprta,il,qdorb,lqdorb,qdn,iorb,ia,cstrga,isa,ila,xja,wa,cpla,npla,ipla,zpla,nv,scef,itran,maxlev,tcode,i1a,i2a,aval,scom,beth,iadftyp,lprn,lcpl,lorb,lbeth,letyp,lptyp,lrtyp,lhtyp,lityp,lstyp,lltyp,itieactn,ltied) ! in xxdata04_string.for
integer :: iunit
integer, optional,check(len(ia)>=ndlev),depend(ia) :: ndlev=len(ia)
integer, optional,check(shape(tcode,0)==ndtrn),depend(tcode) :: ndtrn=shape(tcode,0)
integer, optional,check(len(bwnoa)>=ndmet),depend(bwnoa) :: ndmet=len(bwnoa)
integer, optional,check(len(qdn)>=ndqdn),depend(qdn) :: ndqdn=len(qdn)
integer, optional,check(len(scef)>=nvmax),depend(scef) :: nvmax=len(scef)
character*3 :: titled
integer :: iz
integer :: iz0
integer :: iz1
real*8 :: bwno
integer :: npl
real*8 dimension(ndmet) :: bwnoa
logical dimension(ndmet),depend(ndmet) :: lbseta
real*8 dimension(ndmet),depend(ndmet) :: prtwta
character dimension(ndmet,9),depend(ndmet) :: cprta
integer :: il
real*8 dimension((ndqdn*(ndqdn+1))/2),depend(ndqdn) :: qdorb
logical dimension((ndqdn*(ndqdn+1))/2),depend(ndqdn) :: lqdorb
real*8 dimension(ndqdn) :: qdn
integer :: iorb
integer dimension(ndlev) :: ia
character dimension(ndlev,(*)),depend(ndlev) :: cstrga
integer dimension(ndlev),depend(ndlev) :: isa
integer dimension(ndlev),depend(ndlev) :: ila
real*8 dimension(ndlev),depend(ndlev) :: xja
real*8 dimension(ndlev),depend(ndlev) :: wa
character dimension(ndlev,1),depend(ndlev) :: cpla
integer dimension(ndlev),depend(ndlev) :: npla
integer dimension(ndmet,ndlev),depend(ndmet,ndlev) :: ipla
real*8 dimension(ndmet,ndlev),depend(ndmet,ndlev) :: zpla
integer :: nv
real*8 dimension(nvmax) :: scef
integer :: itran
integer :: maxlev
character dimension(ndtrn,1) :: tcode
integer dimension(ndtrn),depend(ndtrn) :: i1a
integer dimension(ndtrn),depend(ndtrn) :: i2a
real*8 dimension(ndtrn),depend(ndtrn) :: aval
real*8 dimension(nvmax,ndtrn),depend(nvmax,ndtrn) :: scom
real*8 dimension(ndtrn),depend(ndtrn) :: beth
integer :: iadftyp
logical :: lprn
logical :: lcpl
logical :: lorb
logical :: lbeth
logical :: letyp
logical :: lptyp
logical :: lrtyp
logical :: lhtyp
logical :: lityp
logical :: lstyp
logical :: lltyp
integer :: itieactn
logical dimension(ndlev),depend(ndlev) :: ltied
end subroutine xxdata_04
function i4unit(iunit) ! in i4unit.for
integer :: iunit
integer :: i4unit
end function i4unit
subroutine xxword(ctext,cdelim,nfirst,iwords,ifirst,ilast,nwords) ! in xxword.for
character*(*) :: ctext
character*(*) :: cdelim
integer :: nfirst
integer, optional,check(len(ifirst)>=iwords),depend(ifirst) :: iwords=len(ifirst)
integer dimension(iwords) :: ifirst
integer dimension(iwords),depend(iwords) :: ilast
integer :: nwords
end subroutine xxword
subroutine xxslen(cstrng,ifirst,ilast) ! in xxslen.for
character*(*) :: cstrng
integer :: ifirst
integer :: ilast
end subroutine xxslen
subroutine xxprs1(ndmet,string_bn,wno,cpl,npt,ipla,zpla,ifail) ! in xxprs1.for
integer*4, optional,check(len(ipla)>=ndmet),depend(ipla) :: ndmet=len(ipla)
character*(*) :: string_bn
real*8 :: wno
character*1 :: cpl
integer*4 :: npt
integer*4 dimension(ndmet) :: ipla
real*8 dimension(ndmet),depend(ndmet) :: zpla
integer*4 :: ifail
end subroutine xxprs1
function r8fctn(str,iabt) ! in r8fctn.for
character*(*) :: str
integer :: iabt
real*8 :: r8fctn
end function r8fctn
function i4fctn(str,iabt) ! in i4fctn.for
character*(*) :: str
integer :: iabt
integer :: i4fctn
end function i4fctn
function i4idfl(n,l) ! in i4idfl.for
integer :: n
integer :: l
integer :: i4idfl
end function i4idfl
subroutine xxpars(ndmet,strng1,npt,bwnoa,lseta,prtwta,cprta,ifail,itype) ! in xxpars.for
integer*4, optional,check(len(bwnoa)>=ndmet),depend(bwnoa) :: ndmet=len(bwnoa)
character*(*) :: strng1
integer*4 :: npt
real*8 dimension(ndmet) :: bwnoa
logical dimension(ndmet),depend(ndmet) :: lseta
real*8 dimension(ndmet),depend(ndmet) :: prtwta
character dimension(ndmet,(*)),depend(ndmet) :: cprta
integer*4 :: ifail
integer*4 :: itype
end subroutine xxpars
subroutine xxrmve(cstrg1,cstrg2,crmve) ! in xxrmve.for
character*(*) :: cstrg1
character*(*) :: cstrg2
character*1 :: crmve
end subroutine xxrmve
subroutine xxcase(input,output,type_bn) ! in xxcase.for
character*(*) :: input
character*(*) :: output
character*2 :: type_bn
end subroutine xxcase
! This file was auto-generated with f2py (version:2).
! See http://cens.ioc.ee/projects/f2py2e/
I then compiled with f2py -c -m <filename> <input files>
. Compilation completed with a few warnings but no errors. The resulting python shared object is adf04_2py.cpython-35m-x86_64-linux-gnu.so
I have started building a python script that I would like to use to import the shared object and call the 'xxdata_04' subroutine. My process so far has been this.....
- Call the subroutine.
- Let it fail, and figure out what variable I need to pass to it.
- Initialize and allocate that variable in my python script.
- repeat.
I'm sure there's a better way to do this, but the fortran code(s) are many and somewhat lengthy, and not my own, so this seemed like the most direct method.
So far my script looks like this:
import adf04_2py as adf
import numpy as np
itieactn = 1
iunit = 19 ; titled = '---' ; iz = 18 ; iz0 = 0 ; iz1 = 0 ; il = 0
bwno = 0.0 ; npl = 0 ; bwnoa = 1.0 ; prtwta = 0.0
qdorb = 0.0 ; qdn =0.0 ; iorb = 0 ; ia = 0 ; cstrga = '-'
isa = 0 ; ila = 0 ; xja = 0.0 ; wa = 0.0 ; cpla = '-' ; npla = 0 ; ipla = 0
zpla = 0 ; nv = 0 ; scef = 0.0 ; itran = 0 ; maxlev = 0 ; tcode = '-'
ila = 0 ; i2a = 0 ; aval = 0.0 ; scom = 0.0 ; beth = 0 ; iadftyp = 0
cprta = np.asarray([['---------'],['---------'],['---------']],dtype='c')
lbseta = False ; lqdorb = False ; lprn = False ; lcpl= False ; lorb = False
lbeth = False ; letyp = False ; lptyp = False ; lrtyp = False ; lhtyp = False
lityp = False ; lstyp = False ; lltyp = False ; ltied = False
adf04_dat = adf.xxdata_04(iunit, titled, iz, iz0, iz1 , bwno, npl, bwnoa ,
lbseta , prtwta , cprta , il , qdorb , lqdorb ,
qdn , iorb , ia , cstrga , isa , ila , xja , wa ,
cpla , npla, ipla , zpla , nv , scef , itran ,
maxlev , tcode , ila , i2a , aval , scom , beth ,
iadftyp , lprn, lcpl , lorb , lbeth , letyp, lptyp ,
lrtyp , lhtyp , lityp , lstyp , lltyp , itieactn ,
Currently, it fails with:
runfile('/home/ivan/GoogleDrive/AUAMO/codes/read_adf04_2py/xxdata_04/read_adf2py.py', wdir='/home/ivan/GoogleDrive/AUAMO/codes/read_adf04_2py/xxdata_04')
File "/home/ivan/anaconda3/lib/python3.5/site-packages/spyderlib/widgets/externalshell/sitecustomize.py", line 699, in runfile
execfile(filename, namespace)
File "/home/ivan/anaconda3/lib/python3.5/site-packages/spyderlib/widgets/externalshell/sitecustomize.py", line 88, in execfile
exec(compile(open(filename, 'rb').read(), filename, 'exec'), namespace)
File "/home/ivan/GoogleDrive/AUAMO/codes/read_adf04_2py/xxdata_04/read_adf2py.py", line 32, in <module>
ltied )
error: failed in converting 11st argument `cprta' of adf04_2py.xxdata_04 to C/Fortran array
according to the signature file, cprta should be a character array of shape((ndmet),(# of characters)), where ndmet is the number of metastable states and # of characters is 9. I've tried to allocate this by using np.asarray. I still get the "failed in converting 11st argument `cprta' of adf04_2py.xxdata_04 to C/Fortran array" error.
Any help? I am fully aware that I have no clue what I'm doing.
回答1:
Thanks to CT Zhu for the solution to this problem. Running the script from a terminal gave a more informative error message.
0-th dimension must be fixed to 1 but got 3 (real index=0)
Traceback (most recent call last):
File "read_adf2py.py", line 33, in <module>
ltied )
adf04_2py.error: failed in converting 11st argument `cprta' of adf04_2py.xxdata_04 to C/Fortran array
I reallocated the string array to have dimension 1 x 9 and that error vanished.
cprta = np.asarray(['---------'],dtype='c')
Now I'm getting a segfault, but I think that's a separate issue.
Thanks CT Zhu!
来源:https://stackoverflow.com/questions/35298786/how-do-i-allocate-input-arrays-with-f2py