1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360
|
==================================
Using F2PY bindings in Python
==================================
In this page, you can find a full description and a few examples of common usage
patterns for F2PY with Python and different argument types. For more examples
and use cases, see :ref:`f2py-examples`.
Fortran type objects
====================
All wrappers for Fortran/C routines, common blocks, or 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 an attribute ``_cpointer`` that contains a
:c:type:`PyCapsule` referring to the C pointer of the corresponding Fortran/C function
or variable at the C level. Such ``PyCapsule`` objects can be used as callback
arguments for F2PY generated functions to bypass the Python C/API layer for
calling Python functions from Fortran or C. This can be useful when the
computational aspects of such functions are implemented in C or Fortran and
wrapped with F2PY (or any other tool capable of providing the ``PyCapsule``
containing a function).
Consider a Fortran 77 file ```ftype.f``:
.. literalinclude:: ./code/ftype.f
:language: fortran
and a wrapper built using ``f2py -c ftype.f -m ftype``.
In Python, you can observe the types of ``foo`` and ``data``, and how to access
individual objects of the wrapped Fortran code.
.. literalinclude:: ./code/results/ftype_session.dat
:language: python
Scalar arguments
=================
In general, a scalar argument for 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 the Fortran routine as a
scalar argument.
.. note::
* When type-casting is required and there is possible loss of information via
narrowing e.g. when type-casting float to integer or complex to float, F2PY
*does not* raise an exception.
* For 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. :ref:`Read more about
the intent attribute <f2py-attributes>`.
Consider the following Fortran 77 code:
.. literalinclude:: ./code/scalar.f
:language: fortran
and wrap it using ``f2py -c -m scalar scalar.f``.
In Python:
.. literalinclude:: ./code/results/scalar_session.dat
:language: python
String arguments
=================
F2PY generated wrapper functions accept almost any Python object as a string
argument, since ``str`` is applied for non-string objects. Exceptions are NumPy
arrays that must have type code ``'S1'`` or ``'b'`` (corresponding to the
outdated ``'c'`` or ``'1'`` typecodes, respectively) when used as string
arguments. See :ref:`arrays.scalars` for more information on these typecodes.
A string can have an arbitrary length when used as a string argument for an F2PY
generated wrapper function. If the length is greater than expected, the string
is truncated silently. If the length is smaller than expected, additional memory
is allocated and filled with ``\0``.
.. TODO: review this section once https://github.com/numpy/numpy/pull/19388 is merged.
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:
.. literalinclude:: ./code/string.f
:language: fortran
and wrap it using ``f2py -c -m mystring string.f``.
Python session:
.. literalinclude:: ./code/results/string_session.dat
:language: python
Array arguments
================
In general, array arguments for F2PY generated wrapper functions accept
arbitrary sequences that can be transformed to NumPy array objects. There are
two notable exceptions:
* ``intent(inout)`` array arguments must always be
:term:`proper-contiguous <contiguous>` and have a compatible ``dtype``,
otherwise an exception is raised.
* ``intent(inplace)`` array arguments will be changed *in situ* if the argument
has a different type than expected (see the ``intent(inplace)``
:ref:`attribute <f2py-attributes>` for more information).
In general, if a NumPy array is :term:`proper-contiguous <contiguous>` and has
a proper type then it is directly passed to the wrapped Fortran/C function.
Otherwise, an element-wise copy of the input array is made and the copy, being
proper-contiguous and with proper type, is used as the array argument.
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 the proper storage order; the underlying 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 care must be taken to ensure the usage of
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`.
Consider the following Fortran 77 code:
.. literalinclude:: ./code/array.f
:language: fortran
and wrap it using ``f2py -c -m arr array.f -DF2PY_REPORT_ON_ARRAY_COPY=1``.
In Python:
.. literalinclude:: ./code/results/array_session.dat
:language: python
.. _Call-back arguments:
Call-back arguments
====================
F2PY supports calling Python functions from Fortran or C codes.
Consider the following Fortran 77 code:
.. literalinclude:: ./code/callback.f
:language: fortran
and wrap it using ``f2py -c -m callback callback.f``.
In Python:
.. literalinclude:: ./code/results/callback_session.dat
:language: python
In the above example F2PY was able to guess accurately the signature
of the call-back function. However, sometimes F2PY cannot establish the
appropriate signature; in these cases the signature of the call-back
function must be explicitly defined in the signature file.
To facilitate this, signature files may contain special modules (the names of
these modules contain the special ``__user__`` sub-string) that define the
various signatures for call-back functions. Callback arguments in routine
signatures have the ``external`` attribute (see also the ``intent(callback)``
:ref:`attribute <f2py-attributes>`). To relate a callback argument with its
signature in a ``__user__`` module block, a ``use`` statement can be utilized as
illustrated below. The same signature for a callback argument can be referred to
in different routine signatures.
We use the same Fortran 77 code as in the previous example but now
we will 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:: ./code/callback2.pyf
:literal:
Finally, we build the extension module using
``f2py -c callback2.pyf callback.f``.
An example Python session for this snippet would be identical to the previous
example except that the 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 can be called from Fortran.
Consider the following Fortran 77 subroutine that takes an array as its input
and applies a function ``func`` to its elements.
.. literalinclude:: ./code/calculate.f
:language: fortran
The Fortran code expects that the function ``func`` has been defined externally.
In order to use a Python function for ``func``, it must have an attribute
``intent(callback)`` and it must be specified before the ``external`` statement.
Finally, build an extension module using ``f2py -c -m foo calculate.f``
In Python:
.. literalinclude:: ./code/results/calculate_session.dat
:language: python
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" keyword refers to the C function generated by f2py, not the
Python function itself. The python function is essentially being 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:
.. literalinclude:: ./code/extcallback.f
:language: fortran
and wrap it using ``f2py -c -m pfromf extcallback.f``.
In Python:
.. literalinclude:: ./code/results/extcallback_session.dat
:language: python
.. note::
When using modified Fortran code via ``callstatement`` or other directives,
the wrapped Python function must be called as a callback, otherwise only the
bare Fortran routine will be used. For more details, see
https://github.com/numpy/numpy/issues/26681#issuecomment-2466460943
Resolving arguments to call-back functions
------------------------------------------
F2PY generated interfaces are 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 functions.
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
evaluates 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,
and 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.
If the function ``gun`` may return any number of objects as a tuple; then the
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 to all Fortran codes linked to the current
extension module, but not to other extension modules (this restriction is due to
the way Python imports shared libraries). In Python, the F2PY wrappers to
``common`` blocks are ``fortran`` type objects that have (dynamic) attributes
related to the data members of the common blocks. When accessed, these
attributes return as NumPy array objects (multidimensional arrays are
Fortran-contiguous) which 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:
.. literalinclude:: ./code/common.f
:language: fortran
and wrap it using ``f2py -c -m common common.f``.
In Python:
.. literalinclude:: ./code/results/common_session.dat
:language: python
Fortran 90 module data
=======================
The F2PY interface to Fortran 90 module data is similar to the handling of
Fortran 77 common blocks.
Consider the following Fortran 90 code:
.. literalinclude:: ./code/moddata.f90
:language: fortran
and wrap it using ``f2py -c -m moddata moddata.f90``.
In Python:
.. literalinclude:: ./code/results/moddata_session.dat
:language: python
Allocatable arrays
===================
F2PY has basic support for Fortran 90 module allocatable arrays.
Consider the following Fortran 90 code:
.. literalinclude:: ./code/allocarr.f90
:language: fortran
and wrap it using ``f2py -c -m allocarr allocarr.f90``.
In Python:
.. literalinclude:: ./code/results/allocarr_session.dat
:language: python
|