.. _f2py-examples: F2PY examples ============= Below are some examples of F2PY usage. This list is not comprehensive, but can be used as a starting point when wrapping your own code. F2PY walkthrough: a basic extension module ------------------------------------------ Creating source for a basic extension module ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ Consider the following subroutine, contained in a file named :file:`add.f` .. literalinclude:: ./code/add.f :language: fortran This routine simply adds the elements in two contiguous arrays and places the result in a third. The memory for all three arrays must be provided by the calling routine. A very basic interface to this routine can be automatically generated by f2py:: python -m numpy.f2py -m add add.f This command will produce an extension module named :file:`addmodule.c` in the current directory. This extension module can now be compiled and used from Python just like any other extension module. Creating a compiled extension module ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ .. note:: This usage depends heavily on ``numpy.distutils``, see :ref:`f2py-bldsys` for more details. You can also get f2py to both compile :file:`add.f` along with the produced extension module leaving only a shared-library extension file that can be imported from Python:: python -m numpy.f2py -c -m add add.f This command produces a Python extension module compatible with your platform. This module may then be imported from Python. It will contain a method for each subroutine in ``add``. The docstring of each method contains information about how the module method may be called: .. code-block:: python >>> import add >>> print(add.zadd.__doc__) zadd(a,b,c,n) Wrapper for ``zadd``. Parameters ---------- a : input rank-1 array('D') with bounds (*) b : input rank-1 array('D') with bounds (*) c : input rank-1 array('D') with bounds (*) n : input int Improving the basic interface ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ The default interface is a very literal translation of the Fortran code into Python. The Fortran array arguments are converted to NumPy arrays and the integer argument should be mapped to a ``C`` integer. The interface will attempt to convert all arguments to their required types (and shapes) and issue an error if unsuccessful. However, because ``f2py`` knows nothing about the semantics of the arguments (such that ``C`` is an output and ``n`` should really match the array sizes), it is possible to abuse this function in ways that can cause Python to crash. For example: .. code-block:: python >>> add.zadd([1, 2, 3], [1, 2], [3, 4], 1000) will cause a program crash on most systems. Under the hood, the lists are being converted to arrays but then the underlying ``add`` function is told to cycle way beyond the borders of the allocated memory. In order to improve the interface, ``f2py`` supports directives. This is accomplished by constructing a signature file. It is usually best to start from the interfaces that ``f2py`` produces in that file, which correspond to the default behavior. To get ``f2py`` to generate the interface file use the ``-h`` option:: python -m numpy.f2py -h add.pyf -m add add.f This command creates the ``add.pyf`` file in the current directory. The section of this file corresponding to ``zadd`` is: .. literalinclude:: ./code/add.pyf :language: fortran By placing intent directives and checking code, the interface can be cleaned up quite a bit so the Python module method is both easier to use and more robust to malformed inputs. .. literalinclude:: ./code/add-edited.pyf :language: fortran The intent directive, intent(out) is used to tell f2py that ``c`` 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, ``n``, but instead to get it from the size of ``a``. The depend( ``a`` ) directive is necessary to tell f2py that the value of n depends on the input a (so that it won't try to create the variable n until the variable a is created). After modifying ``add.pyf``, the new Python module file can be generated by compiling both ``add.f`` and ``add.pyf``:: python -m numpy.f2py -c add.pyf add.f The new interface's docstring is: .. code-block:: python >>> import add >>> print(add.zadd.__doc__) c = zadd(a,b) Wrapper for ``zadd``. Parameters ---------- a : input rank-1 array('D') with bounds (n) b : input rank-1 array('D') with bounds (n) Returns ------- c : rank-1 array('D') with bounds (n) Now, the function can be called in a much more robust way: .. code-block:: >>> add.zadd([1, 2, 3], [4, 5, 6]) array([5.+0.j, 7.+0.j, 9.+0.j]) Notice the automatic conversion to the correct format that occurred. Inserting directives in Fortran source ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ The robust interface of the previous section can also be generated automatically by placing the variable directives as special comments in the original Fortran code. .. note:: For projects where the Fortran code is being actively developed, this may be preferred. Thus, if the source code is modified to contain: .. literalinclude:: ./code/add-improved.f :language: fortran Then, one can compile the extension module using:: python -m numpy.f2py -c -m add add.f The resulting signature for the function add.zadd is exactly the same one that was created previously. If the original source code had contained ``A(N)`` instead of ``A(*)`` and so forth with ``B`` and ``C``, then nearly the same interface can be obtained by placing the ``INTENT(OUT) :: C`` comment line in the source code. The only difference is that ``N`` would be an optional input that would default to the length of ``A``. A filtering example ------------------- This example shows a function that filters a two-dimensional array of double precision floating-point numbers using a fixed averaging filter. The advantage of using Fortran to index into multi-dimensional arrays should be clear from this example. .. literalinclude:: ./code/filter.f :language: fortran This code can be compiled and linked into an extension module named filter using:: python -m numpy.f2py -c -m filter filter.f This will produce an extension module in the current directory with a method named ``dfilter2d`` that returns a filtered version of the input. ``depends`` keyword example --------------------------- Consider the following code, saved in the file ``myroutine.f90``: .. literalinclude:: ./code/myroutine.f90 :language: fortran Wrapping this with ``python -m numpy.f2py -c myroutine.f90 -m myroutine``, we can do the following in Python:: >>> import numpy as np >>> import myroutine >>> x = myroutine.s(2, 3, np.array([5, 6, 7])) >>> x array([[5., 0., 0.], [0., 0., 0.]]) Now, instead of generating the extension module directly, we will create a signature file for this subroutine first. This is a common pattern for multi-step extension module generation. In this case, after running .. code-block:: python python -m numpy.f2py myroutine.f90 -h myroutine.pyf the following signature file is generated: .. literalinclude:: ./code/myroutine.pyf :language: fortran Now, if we run ``python -m numpy.f2py -c myroutine.pyf myroutine.f90`` we see an error; note that the signature file included a ``depend(m,n)`` statement for ``x`` which is not necessary. Indeed, editing the file above to read .. literalinclude:: ./code/myroutine-edited.pyf :language: fortran and running ``f2py -c myroutine.pyf myroutine.f90`` yields correct results. Read more --------- * `Wrapping C codes using f2py `_ * `F2py section on the SciPy Cookbook `_ * `F2py example: Interactive System for Ice sheet Simulation `_ * `"Interfacing With Other Languages" section on the SciPy Cookbook. `_