summaryrefslogtreecommitdiff
path: root/doc/source/f2py/advanced.rst
blob: 9a7b88e692ee5b24facf214d5c8fcd437d689663 (plain)
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
========================
Advanced F2PY use cases
========================

Adding user-defined functions to F2PY generated modules
=========================================================

User-defined Python C/API functions can be defined inside
signature files using ``usercode`` and ``pymethoddef`` statements
(they must be used inside the ``python module`` block). For
example, the following signature file ``spam.pyf``

.. include:: ./code/spam.pyf
   :literal:

wraps the C library function ``system()``::

  f2py -c spam.pyf

In Python this can then be used as:

.. literalinclude:: ./code/results/spam_session.dat
   :language: python

Adding user-defined variables
==============================

The following example illustrates how to add user-defined variables to a F2PY
generated extension module by modifying the dictionary of a F2PY generated
module. Consider the following signature file (compiled with ``f2py -c var.pyf``):

.. literalinclude:: ./code/var.pyf
  :language: fortran

Notice that the second ``usercode`` statement must be defined inside
an ``interface`` block and the module dictionary is available through
the variable ``d`` (see ``varmodule.c`` generated by ``f2py var.pyf`` for
additional details).

Usage in Python:

.. literalinclude:: ./code/results/var_session.dat
  :language: python


Dealing with KIND specifiers
============================

Currently, F2PY can handle only ``<type spec>(kind=<kindselector>)``
declarations where ``<kindselector>`` is a numeric integer (e.g. 1, 2,
4,...), but not a function call ``KIND(..)`` or any other
expression. F2PY needs to know what would be the corresponding C type
and a general solution for that would be too complicated to implement.

However, F2PY provides a hook to overcome this difficulty, namely,
users can define their own <Fortran type> to <C type> maps. For
example, if Fortran 90 code contains::

    REAL(kind=KIND(0.0D0)) ...

then create a mapping file containing a Python dictionary::

    {'real': {'KIND(0.0D0)': 'double'}}

for instance.

Use the ``--f2cmap`` command-line option to pass the file name to F2PY.
By default, F2PY assumes file name is ``.f2py_f2cmap`` in the current
working directory.

More generally, the f2cmap file must contain a dictionary
with items::

    <Fortran typespec> : {<selector_expr>:<C type>}

that defines mapping between Fortran type::

    <Fortran typespec>([kind=]<selector_expr>)

and the corresponding <C type>. The <C type> can be one of the following::

    double
    float
    long_double
    char
    signed_char
    unsigned_char
    short
    unsigned_short
    int
    long
    long_long
    unsigned
    complex_float
    complex_double
    complex_long_double
    string

For example, for a Fortran file ``func1.f`` containing:

.. literalinclude:: ./code/f2cmap_demo.f
    :language: fortran

In order to convert ``int64`` and ``real64`` to valid ``C`` data types,
a ``.f2py_f2cmap`` file with the following content can be created in the current directory:

.. code-block:: python

  dict(real=dict(real64='double'), integer=dict(int64='long long'))

and create the module as usual. F2PY checks if a ``.f2py_f2cmap`` file is present
in the current directory and will use it to map ``KIND`` specifiers to ``C`` data types.

.. code-block:: sh

  f2py -c func1.f -m func1

Alternatively, the mapping file can be saved with any other name, for example 
``mapfile.txt``, and this information can be passed to F2PY by using the ``--f2cmap`` option.

.. code-block:: sh

  f2py -c func1.f -m func1 --f2cmap mapfile.txt

For more information, see F2Py source code ``numpy/f2py/capi_maps.py``.

.. _Character strings:

Character strings
=================

Assumed length character strings
-----------------------------------

In Fortran, assumed length character string arguments are declared as
``character*(*)`` or ``character(len=*)``, that is, the length of such
arguments are determined by the actual string arguments at runtime.
For ``intent(in)`` arguments, this lack of length information poses no
problems for f2py to construct functional wrapper functions. However,
for ``intent(out)`` arguments, the lack of length information is
problematic for f2py generated wrappers because there is no size
information available for creating memory buffers for such arguments
and F2PY assumes the length is 0.  Depending on how the length of
assumed length character strings are specified, there exist ways to
workaround this problem, as exemplified below.

If the length of the ``character*(*)`` output argument is determined
by the state of other input arguments, the required connection can be
established in a signature file or within a f2py-comment by adding an
extra declaration for the corresponding argument that specifies the
length in character selector part. For example, consider a Fortran
file ``asterisk1.f90``:

.. include:: ./code/asterisk1.f90
  :literal:

Compile it with ``f2py -c asterisk1.f90 -m asterisk1`` and then in Python:

.. include:: ./code/results/asterisk1_session.dat
  :literal:

Notice that the extra declaration ``character(f2py_len=12) s`` is
interpreted only by f2py and in the ``f2py_len=`` specification one
can use C-expressions as a length value.

In the following example:

.. include:: ./code/asterisk2.f90
  :literal:

the length of the output assumed length string depends on an input
argument ``n``, after wrapping with F2PY, in Python:

.. include:: ./code/results/asterisk2_session.dat
  :literal: