Reputation: 3286
I am using f2py to integrate some Fortran77 routines into my python module but can't settle on a good way to solve the following problem. My Fortran routines destroy all input arrays during the course of computation. I'd like to offer the user both the option to use the memory efficient "inplace" behaviour of these routines as well as the option to execute the routine without destroying their Python side data.
I can think of two ways to do this:
I don't like either approach very much because they both seem non-pythonic. Is there a better way to approach this problem? Is there simpler way to implement approach 2, e.g. can I compile the same routine with two different signatures into a single shared object module?
Here's an example (based on this documentation).
Fortran routine fib.f:
C FILE: FIB.F
SUBROUTINE FIB(A,N)
C
C CALCULATE FIRST N FIBONACCI NUMBERS
C
INTEGER N
REAL*8 A(N)
DO I=1,N
IF (I.EQ.1) THEN
A(I) = 0.0D0
ELSEIF (I.EQ.2) THEN
A(I) = 1.0D0
ELSE
A(I) = A(I-1) + A(I-2)
ENDIF
ENDDO
END
C END FILE FIB.F
I generate my signature file using f2py fib.f -m fib.pyf
then I add some intent declarations:
! -*- f90 -*-
! Note: the context of this file is case sensitive.
python module fib ! in
interface ! in :fib
subroutine fib(a,n) ! in :fib:fib.f
real*8 dimension(n), intent(inout) :: a
integer, optional,check(len(a)>=n),depend(a) :: n=len(a)
end subroutine fib
end interface
end python module fib
! This file was auto-generated with f2py (version:2).
! See http://cens.ioc.ee/projects/f2py2e/
I compile with f2py -c fib.pyf fib.f
and then I can run my routine in place:
>>> import numpy as np
>>> from fib import fib
>>> A = np.zeros(10, dtype=float)
>>> fib(A)
>>> print(A)
[ 0. 1. 1. 2. 3. 5. 8. 13. 21. 34.]
To change this example to in/out mode, I just change my intent declaration in "fib.pyf" to intent(in,out)
.
Upvotes: 1
Views: 362
Reputation: 3286
I ended up using the fortranname
declaration in the signature files to generate both inplace and in,out flavors of the same subroutine. Here's the signature file:
! -*- f90 -*-
! Note: the context of this file is case sensitive.
python module fib ! in
interface ! in :fib
subroutine fib_inplace(a,n) ! in :fib:fib.f
fortranname fib
real*8 dimension(n), intent(inout) :: a
integer, optional,check(len(a)>=n),depend(a) :: n=len(a)
end subroutine fib
subroutine fib(a,n) ! in :fib:fib.f
fortranname fib
real*8 dimension(n), intent(copy, in,out) :: a
integer, optional,check(len(a)>=n),depend(a) :: n=len(a)
end subroutine fib
end interface
end python module fib
Note: to actually prevent the second routine from modifying the Python input I had to also add copy
to the intent directive.
Upvotes: 1