JayKimDevolved's picture
JayKimDevolved/deepseek
c011401 verified
Title: Wrapping F compiled Fortran 90 modules with F2PY
================================================
Rationale: The F compiler does not support external procedures which
makes it impossible to use it in F2PY in a normal way.
This document describes a workaround to this problem so
that F compiled codes can be still wrapped with F2PY.
Author: Pearu Peterson
Date: May 8, 2002
Acknowledgement: Thanks to Siegfried Gonzi who hammered me to produce
this document.
Normally wrapping Fortran 90 modules to Python using F2PY is carried
out with the following command
f2py -c -m fun foo.f90
where file foo.f90 contains, for example,
module foo
public :: bar
contains
subroutine bar (a)
integer,intent(inout) :: a
print *,"Hello from foo.bar"
print *,"a=",a
a = a + 5
print *,"a=",a
end subroutine bar
end module foo
Then with a supported F90 compiler (running `f2py -c --help-compiler'
will display the found compilers) f2py will generate an extension
module fun.so into the current directory and the Fortran module foo
subroutine bar can be called from Python as follows
>>> import fun
>>> print fun.foo.bar.__doc__
bar - Function signature:
bar(a)
Required arguments:
a : in/output rank-0 array(int,'i')
>>> from Numeric import array
>>> a = array(3)
>>> fun.foo.bar(a)
Hello from foo.bar
a= 3
a= 8
>>> a
8
>>>
This works nicely with all supported Fortran compilers.
However, the F compiler (http://www.fortran.com/F/compilers.html) is
an exception. Namely, the F compiler is designed to recognize only
module procedures (and main programs, of course) but F2PY needs to
compile also the so-called external procedures that it generates to
facilitate accessing Fortran F90 module procedures from C and
subsequently from Python. As a result, wrapping F compiled Fortran
procedures to Python is _not_ possible using the simple procedure as
described above. But, there is a workaround that I'll describe below
in five steps.
1) Compile foo.f90:
F -c foo.f90
This creates an object file foo.o into the current directory.
2) Create the signature file:
f2py foo.f90 -h foo.pyf
This creates a file foo.pyf containing
module foo ! in foo.f90
real public :: bar
subroutine bar(a) ! in foo.f90:foo
integer intent(inout) :: a
end subroutine bar
end module foo
3) Open the file foo.pyf with your favorite text editor and change the
above signature to
python module foo
interface
subroutine bar(a)
fortranname foo_MP_bar
intent(c) bar
integer intent(in,out) :: a
end subroutine bar
end interface
end python module foo
The most important modifications are
a) adding `python' keyword everywhere before the `module' keyword
b) including an `interface' block around the all subroutine blocks.
c) specifying the real symbol name of the subroutine using
`fortranname' statement. F generated symbol names are in the form
<module name>_MP_<subroutine name>
d) specifying that subroutine is `intent(c)'.
Notice that the `intent(inout)' attribute is changed to
`intent(in,out)' that instructs the wrapper to return the modified
value of `a'.
4) Build the extension module
f2py -c foo.pyf foo.o --fcompiler=Gnu /opt/F/lib/quickfit.o \
/opt/F/lib/libf96.a
This will create the extension module foo.so into the current
directory. Notice that you must use Gnu compiler (gcc) for linking.
And the paths to F specific object files and libraries may differ for
your F installation.
5) Finally, we can call the module subroutine `bar' from Python
>>> import foo
>>> print foo.bar.__doc__
bar - Function signature:
a = bar(a)
Required arguments:
a : input int
Return objects:
a : int
>>> foo.bar(3)
8
>>>
Notice that the F compiled module procedures are called as ordinary
external procedures. Also I/O seems to be lacking for F compiled
Fortran modules.
Enjoy,
Pearu