365 lines
12 KiB
ReStructuredText
365 lines
12 KiB
ReStructuredText
==================================
|
|
Using F2PY bindings in Python
|
|
==================================
|
|
|
|
All wrappers for Fortran/C routines, common blocks, or for Fortran
|
|
90 module data generated by F2PY are exposed to Python as ``fortran``
|
|
type objects. Routine wrappers are callable ``fortran`` type objects
|
|
while wrappers to Fortran data have attributes referring to data
|
|
objects.
|
|
|
|
All ``fortran`` type objects have attribute ``_cpointer`` that contains
|
|
CObject referring to the C pointer of the corresponding Fortran/C
|
|
function or variable in C level. Such CObjects can be used as a
|
|
callback argument of F2PY generated functions to bypass Python C/API
|
|
layer of calling Python functions from Fortran or C when the
|
|
computational part of such functions is implemented in C or Fortran
|
|
and wrapped with F2PY (or any other tool capable of providing CObject
|
|
of a function).
|
|
|
|
Consider a Fortran 77 file ``ftype.f``:
|
|
|
|
.. include:: ftype.f
|
|
:literal:
|
|
|
|
and build a wrapper using ``f2py -c ftype.f -m ftype``.
|
|
|
|
In Python:
|
|
|
|
.. include:: ftype_session.dat
|
|
:literal:
|
|
|
|
|
|
Scalar arguments
|
|
=================
|
|
|
|
In general, a scalar argument of a F2PY generated wrapper function can
|
|
be an ordinary Python scalar (integer, float, complex number) as well as
|
|
an arbitrary sequence object (list, tuple, array, string) of
|
|
scalars. In the latter case, the first element of the sequence object
|
|
is passed to Fortran routine as a scalar argument.
|
|
|
|
Note that when type-casting is required and there is possible loss of
|
|
information (e.g. when type-casting float to integer or complex to
|
|
float), F2PY does not raise any exception. In complex to real
|
|
type-casting only the real part of a complex number is used.
|
|
|
|
``intent(inout)`` scalar arguments are assumed to be array objects in
|
|
order to have *in situ* changes be effective. It is recommended to use
|
|
arrays with proper type but also other types work.
|
|
|
|
Consider the following Fortran 77 code:
|
|
|
|
.. include:: scalar.f
|
|
:literal:
|
|
|
|
and wrap it using ``f2py -c -m scalar scalar.f``.
|
|
|
|
In Python:
|
|
|
|
.. include:: scalar_session.dat
|
|
:literal:
|
|
|
|
|
|
String arguments
|
|
=================
|
|
|
|
F2PY generated wrapper functions accept (almost) any Python object as
|
|
a string argument, ``str`` is applied for non-string objects.
|
|
Exceptions are NumPy arrays that must have type code ``'c'`` or
|
|
``'1'`` when used as string arguments.
|
|
|
|
A string can have arbitrary length when using it as a string argument
|
|
to F2PY generated wrapper function. If the length is greater than
|
|
expected, the string is truncated. If the length is smaller that
|
|
expected, additional memory is allocated and filled with ``\0``.
|
|
|
|
Because Python strings are immutable, an ``intent(inout)`` argument
|
|
expects an array version of a string in order to have *in situ* changes be effective.
|
|
|
|
Consider the following Fortran 77 code:
|
|
|
|
.. include:: string.f
|
|
:literal:
|
|
|
|
and wrap it using ``f2py -c -m mystring string.f``.
|
|
|
|
Python session:
|
|
|
|
.. include:: string_session.dat
|
|
:literal:
|
|
|
|
|
|
Array arguments
|
|
================
|
|
|
|
In general, array arguments of F2PY generated wrapper functions accept
|
|
arbitrary sequences that can be transformed to NumPy array objects.
|
|
An exception is ``intent(inout)`` array arguments that always must be
|
|
proper-contiguous and have proper type, otherwise an exception is
|
|
raised. Another exception is ``intent(inplace)`` array arguments that
|
|
attributes will be changed *in situ* if the argument has different type
|
|
than expected (see ``intent(inplace)`` attribute for more
|
|
information).
|
|
|
|
In general, if a NumPy array is proper-contiguous and has a proper
|
|
type then it is directly passed to wrapped Fortran/C function.
|
|
Otherwise, an element-wise copy of an input array is made and the
|
|
copy, being proper-contiguous and with proper type, is used as an
|
|
array argument.
|
|
|
|
There are two types of proper-contiguous NumPy arrays:
|
|
|
|
* Fortran-contiguous arrays when data is stored column-wise,
|
|
i.e. indexing of data as stored in memory starts from the lowest
|
|
dimension;
|
|
* C-contiguous or simply contiguous arrays when data is stored
|
|
row-wise, i.e. indexing of data as stored in memory starts from the
|
|
highest dimension.
|
|
|
|
For one-dimensional arrays these notions coincide.
|
|
|
|
For example, a 2x2 array ``A`` is Fortran-contiguous if its elements
|
|
are stored in memory in the following order::
|
|
|
|
A[0,0] A[1,0] A[0,1] A[1,1]
|
|
|
|
and C-contiguous if the order is as follows::
|
|
|
|
A[0,0] A[0,1] A[1,0] A[1,1]
|
|
|
|
To test whether an array is C-contiguous, use the ``.flags.c_contiguous``
|
|
attribute of NumPy arrays. To test for Fortran contiguity, use the
|
|
``.flags.f_contiguous`` attribute.
|
|
|
|
Usually there is no need to worry about how the arrays are stored in
|
|
memory and whether the wrapped functions, being either Fortran or C
|
|
functions, assume one or another storage order. F2PY automatically
|
|
ensures that wrapped functions get arguments with proper storage
|
|
order; the corresponding algorithm is designed to make copies of
|
|
arrays only when absolutely necessary. However, when dealing with very
|
|
large multidimensional input arrays with sizes close to the size of
|
|
the physical memory in your computer, then a care must be taken to use
|
|
always proper-contiguous and proper type arguments.
|
|
|
|
To transform input arrays to column major storage order before passing
|
|
them to Fortran routines, use the function ``numpy.asfortranarray(<array>)``.
|
|
|
|
Consider the following Fortran 77 code:
|
|
|
|
.. include:: array.f
|
|
:literal:
|
|
|
|
and wrap it using ``f2py -c -m arr array.f -DF2PY_REPORT_ON_ARRAY_COPY=1``.
|
|
|
|
In Python:
|
|
|
|
.. include:: array_session.dat
|
|
:literal:
|
|
|
|
.. _Call-back arguments:
|
|
|
|
Call-back arguments
|
|
====================
|
|
|
|
F2PY supports calling Python functions from Fortran or C codes.
|
|
|
|
Consider the following Fortran 77 code:
|
|
|
|
.. include:: callback.f
|
|
:literal:
|
|
|
|
and wrap it using ``f2py -c -m callback callback.f``.
|
|
|
|
In Python:
|
|
|
|
.. include:: callback_session.dat
|
|
:literal:
|
|
|
|
In the above example F2PY was able to guess accurately the signature
|
|
of a call-back function. However, sometimes F2PY cannot establish the
|
|
signature as one would wish and then the signature of a call-back
|
|
function must be modified in the signature file manually. Namely,
|
|
signature files may contain special modules (the names of such modules
|
|
contain a substring ``__user__``) that collect various signatures of
|
|
call-back functions. Callback arguments in routine signatures have
|
|
attribute ``external`` (see also ``intent(callback)`` attribute). To
|
|
relate a callback argument and its signature in ``__user__`` module
|
|
block, use ``use`` statement as illustrated below. The same signature
|
|
of a callback argument can be referred in different routine
|
|
signatures.
|
|
|
|
We use the same Fortran 77 code as in previous example but now
|
|
we'll pretend that F2PY was not able to guess the signatures of
|
|
call-back arguments correctly. First, we create an initial signature
|
|
file ``callback2.pyf`` using F2PY::
|
|
|
|
f2py -m callback2 -h callback2.pyf callback.f
|
|
|
|
Then modify it as follows
|
|
|
|
.. include:: callback2.pyf
|
|
:literal:
|
|
|
|
Finally, build the extension module using ``f2py -c callback2.pyf callback.f``.
|
|
|
|
An example Python session would be identical to the previous example
|
|
except that argument names would differ.
|
|
|
|
Sometimes a Fortran package may require that users provide routines
|
|
that the package will use. F2PY can construct an interface to such
|
|
routines so that Python functions could be called from Fortran.
|
|
|
|
Consider the following Fortran 77 subroutine that takes an array
|
|
and applies a function ``func`` to its elements.
|
|
|
|
.. include:: calculate.f
|
|
:literal:
|
|
|
|
It is expected that function ``func`` has been defined
|
|
externally. In order to use a Python function as ``func``, it must
|
|
have an attribute ``intent(callback)`` (it must be specified before
|
|
the ``external`` statement).
|
|
|
|
Finally, build an extension module using ``f2py -c -m foo calculate.f``
|
|
|
|
In Python:
|
|
|
|
.. include:: calculate_session.dat
|
|
:literal:
|
|
|
|
The function is included as an argument to the python function call to
|
|
the Fortran subroutine even though it was *not* in the Fortran subroutine argument
|
|
list. The "external" refers to the C function generated by f2py, not the python
|
|
function itself. The python function must be supplied to the C function.
|
|
|
|
The callback function may also be explicitly set in the module.
|
|
Then it is not necessary to pass the function in the argument list to
|
|
the Fortran function. This may be desired if the Fortran function calling
|
|
the python callback function is itself called by another Fortran function.
|
|
|
|
Consider the following Fortran 77 subroutine:
|
|
|
|
.. include:: extcallback.f
|
|
:literal:
|
|
|
|
and wrap it using ``f2py -c -m pfromf extcallback.f``.
|
|
|
|
In Python:
|
|
|
|
.. include:: extcallback_session.dat
|
|
:literal:
|
|
|
|
Resolving arguments to call-back functions
|
|
------------------------------------------
|
|
|
|
F2PY generated interface is very flexible with respect to call-back
|
|
arguments. For each call-back argument an additional optional
|
|
argument ``<name>_extra_args`` is introduced by F2PY. This argument
|
|
can be used to pass extra arguments to user provided call-back
|
|
arguments.
|
|
|
|
If a F2PY generated wrapper function expects the following call-back
|
|
argument::
|
|
|
|
def fun(a_1,...,a_n):
|
|
...
|
|
return x_1,...,x_k
|
|
|
|
but the following Python function
|
|
|
|
::
|
|
|
|
def gun(b_1,...,b_m):
|
|
...
|
|
return y_1,...,y_l
|
|
|
|
is provided by a user, and in addition,
|
|
|
|
::
|
|
|
|
fun_extra_args = (e_1,...,e_p)
|
|
|
|
is used, then the following rules are applied when a Fortran or C
|
|
function calls the call-back argument ``gun``:
|
|
|
|
* If ``p == 0`` then ``gun(a_1, ..., a_q)`` is called, here
|
|
``q = min(m, n)``.
|
|
* If ``n + p <= m`` then ``gun(a_1, ..., a_n, e_1, ..., e_p)`` is called.
|
|
* If ``p <= m < n + p`` then ``gun(a_1, ..., a_q, e_1, ..., e_p)`` is called, here
|
|
``q=m-p``.
|
|
* If ``p > m`` then ``gun(e_1, ..., e_m)`` is called.
|
|
* If ``n + p`` is less than the number of required arguments to ``gun``
|
|
then an exception is raised.
|
|
|
|
The function ``gun`` may return any number of objects as a tuple. Then
|
|
following rules are applied:
|
|
|
|
* If ``k < l``, then ``y_{k + 1}, ..., y_l`` are ignored.
|
|
* If ``k > l``, then only ``x_1, ..., x_l`` are set.
|
|
|
|
|
|
Common blocks
|
|
==============
|
|
|
|
F2PY generates wrappers to ``common`` blocks defined in a routine
|
|
signature block. Common blocks are visible by all Fortran codes linked
|
|
with the current extension module, but not to other extension modules
|
|
(this restriction is due to how Python imports shared libraries). In
|
|
Python, the F2PY wrappers to ``common`` blocks are ``fortran`` type
|
|
objects that have (dynamic) attributes related to data members of
|
|
common blocks. When accessed, these attributes return as NumPy array
|
|
objects (multidimensional arrays are Fortran-contiguous) that
|
|
directly link to data members in common blocks. Data members can be
|
|
changed by direct assignment or by in-place changes to the
|
|
corresponding array objects.
|
|
|
|
Consider the following Fortran 77 code:
|
|
|
|
.. include:: common.f
|
|
:literal:
|
|
|
|
and wrap it using ``f2py -c -m common common.f``.
|
|
|
|
In Python:
|
|
|
|
.. include:: common_session.dat
|
|
:literal:
|
|
|
|
|
|
Fortran 90 module data
|
|
=======================
|
|
|
|
The F2PY interface to Fortran 90 module data is similar to Fortran 77
|
|
common blocks.
|
|
|
|
Consider the following Fortran 90 code:
|
|
|
|
.. include:: moddata.f90
|
|
:literal:
|
|
|
|
and wrap it using ``f2py -c -m moddata moddata.f90``.
|
|
|
|
In Python:
|
|
|
|
.. include:: moddata_session.dat
|
|
:literal:
|
|
|
|
|
|
Allocatable arrays
|
|
-------------------
|
|
|
|
F2PY has basic support for Fortran 90 module allocatable arrays.
|
|
|
|
Consider the following Fortran 90 code:
|
|
|
|
.. include:: allocarr.f90
|
|
:literal:
|
|
|
|
and wrap it using ``f2py -c -m allocarr allocarr.f90``.
|
|
|
|
In Python:
|
|
|
|
.. include:: allocarr_session.dat
|
|
:literal:
|