Interfacing Fortran and Python ############################## Documentation: ============== A nice reference for Python for Fortran programmers: http://fortran90.org/src/rosetta.html Fortran best practices (including interfacing with Python) http://fortran90.org/src/best-practices.html http://fortran90.org/src/best-practices.html#interfacing-with-python Interfacing methods: ==================== There a a handful of ways to interface Fortran and Python: f2py: ----- http://docs.scipy.org/doc/numpy/user/c-info.python-as-glue.html#f2py Been around a long time, and maintained (at least a little) as part of the numpy project -- but more useful with older fortran -- not up to modern fortran standards. Perhaps the best option for interfacing with old-style fortran. fwrap: -------- http://fwrap.sourceforge.net/ Very promising, but its development has stalled out -- so probably not a good bet unless you want to actually work on it yourself. Cython and iso_c_binding: --------------------------- http://fortran90.org/src/best-practices.html#interfacing-with-python By using the iso_binding calls to extend a C interace to your fortran code, you can call it with Cython. And Cython is very useful for calling C, optimizing Python, and adding "thick" wrappers to either C or fortran. An Example: ============ The following is an example of using Cython to call fortran from Python. The problem at hand is an automatic gain control function function, expressed in fortran as:: subroutine AGC(nAGC,npts,amp,ampAGC) real fmax,amp(npts),absamp(npts),ampAGC(npts) integer i,j,npts,nAGC,nAGC2 do i=1,npts ampAGC(i)=0. absamp(i)=abs(amp(i)) enddo nAGC2=nAGC/2 do i=nAGC2+1,npts-nAGC2 fmax=0. do j=i-nAGC2,i+nAGC2 if (absamp(j).gt.fmax) fmax=absamp(j) enddo ampAGC(i)=amp(i)/fmax enddo return end f2py: ----- f2py is a command line utility that comes with numpy. You can build a default simple wrapper with the f2py command:: f2py -m agc_subroutine agc_subroutine.f This will result in the file `agc_subroutinemodule.c`, which is hte c source for a python extension module. Or you can have f2py build the module itself all at once:: f2py -m -c agc_subroutine agc_subroutine.f This will generate a compiled python extension named agc_subroutine that can be imported in python as:: import agc_subroutine f2p automatically generates a docstring for the function it created:: agc - Function signature: agc(nagc,amp,ampagc,[npts]) Required arguments: nagc : input int amp : input rank-1 array('f') with bounds (npts) ampagc : input rank-1 array('f') with bounds (npts) Optional arguments: npts := len(amp) input int So it can be called like so:: agc_subroutine.agc(5, signal, filtered) where `signal` and `filtered` are 1-d arrays of float32 values, both of the same length. Giving f2py extra information: .............................. f2py can build an interface to a fortran subroutine, but it can't do it all that well without some extra information. For instnce, note from the docstring that the argument `ampagc` is listed as an input argument, when it is really intended to be used for output. To get f2py to generate an interface file use the -h option:: f2py -h agc_subroutine.pyf -m agc_subroutine agc_subroutine.f This command leaves the file agc_subroutine.pyf in the current directory, which contains:: ! -*- f90 -*- ! Note: the context of this file is case sensitive. python module agc_subroutine ! in interface ! in :agc_subroutine subroutine agc(nagc,npts,amp,ampagc) ! in :agc_subroutine:agc_subroutine.f integer :: nagc integer, optional,check(len(amp)>=npts),depend(amp) :: npts=len(amp) real dimension(npts) :: amp real dimension(npts),depend(npts) :: ampagc end subroutine agc end interface end python module agc_subroutine ! This file was auto-generated with f2py (version:2). ! See http://cens.ioc.ee/projects/f2py2e/ You can then add to the interface file by placing intent directives and checking code. This will clean up the interface quite a bit so that the Python module method is both easier to use and more robust. This is the edited version:: ! -*- f90 -*- ! Note: the context of this file is case sensitive. python module agc_subroutine ! in interface ! in :agc_subroutine subroutine agc(nagc,npts,amp,ampagc) ! in :agc_subroutine:agc_subroutine.f integer :: nagc integer, optional,intent(hide),check(len(amp)>=npts),depend(amp) :: npts=len(amp) real dimension(npts) :: amp real dimension(npts),intent(out),depend(npts) :: ampagc end subroutine agc end interface end python module agc_subroutine ! This file was auto-generated with f2py (version:2). ! Then hand edited for a better interface. ! See http://cens.ioc.ee/projects/f2py2e/ The intent directive, intent(out) is used to tell f2py that ampagc is an output variable and should be created by the interface before being passed to the underlying code. The intent(hide) directive tells f2py to not allow the user to specify the variable, npts, but instead to get it from the size of amp. Inserting directives in the Fortran source ........................................... Directives can alternatively be inserted in the fortran source as special comments:: c c Subrooutine to compute an automatic gain control filter. c c subroutine AGC(nAGC,npts,amp,ampAGC) CF2PY INTENT(OUT) :: ampAGC CF2PY INTENT(HIDE) :: npts real fmax,amp(npts),absamp(npts),ampAGC(npts) integer i,j,npts,nAGC,nAGC2 This is probably an easier and clearer option if you maintaining the fortran source yourself. Either way, you get a nicer, more pythonic and safer interface:: agc - Function signature: ampagc = agc(nagc,amp) Required arguments: nagc : input int amp : input rank-1 array('f') with bounds (npts) Return objects: ampagc : rank-1 array('f') with bounds (npts) called like so:: filtered = agc_subroutine.agc(10, signal) You can see that you don't need (and can't) specify the length of the array, and the output array is automatically created by the wrappers, and memory-managed by python.