673 lines (484 with data), 14.7 kB
#LyX 1.3 created this file. For more info see http://www.lyx.org/
\lyxformat 221
\textclass amsbook
\begin_preamble
\usepackage{ae,aecompl}
\usepackage{hyperref}
%\usepackage{html}
\usepackage{color}
\definecolor{orange}{cmyk}{0,0.4,0.8,0.2}
% Use and configure listings package for nicely formatted code
\usepackage{listings}
\lstset{
language=Python,
basicstyle=\small\ttfamily,
commentstyle=\ttfamily\color{blue},
stringstyle=\ttfamily\color{orange},
showstringspaces=false,
breaklines=true,
postbreak = \space\dots
}
% Some extra commands
\newcommand{\fig}[4]
{\begin{figure}[ht]
\begin{center}
\includegraphics[width=#1]{#2}
\caption{\label{#4} #3}
\end{center}
\end{figure}}
\newcommand{\matlab}[0]{matlab{\texttrademark}}
\newcommand{\fname}[1]{{\tt #1}}
\newcommand{\func}[1]{{\tt #1}}
\newcommand{\class}[1]{{\tt #1}}
\newcommand{\mpldoc}[1]{{\tt #1}}
\newcommand{\code}[1]{{\tt #1}}
\newcommand{\prompt}[1]{\code{>>> #1}}
\newcommand{\carg}[1]{\textit{#1}} % command argument
\newcommand{\val}[1]{\textit{#1}}
\newcommand{\rc}[1]{{\tt #1}}
\end_preamble
\language english
\inputencoding auto
\fontscheme default
\graphics default
\paperfontsize default
\spacing single
\papersize Default
\paperpackage a4
\use_geometry 1
\use_amsmath 0
\use_natbib 0
\use_numerical_citations 0
\paperorientation portrait
\leftmargin 1.15in
\topmargin 1in
\rightmargin 1.15in
\bottommargin 1in
\secnumdepth 3
\tocdepth 3
\paragraph_separation indent
\defskip medskip
\quotes_language english
\quotes_times 2
\papercolumns 1
\papersides 1
\paperpagestyle default
\layout Chapter
Interfacing with external libraries
\begin_inset OptArg
collapsed true
\layout Standard
External libraries
\end_inset
\layout Section
weave
\layout Comment
John - should we talk to Eric Jones about letting us use parts of his weave
docs? There's a very old set of docs for weave, I could update some of
it and this would make an excellent section.
Weave is really amazing, but badly under-documented and hence unknown.
\layout Standard
Below is a listing of examples of weave use.
This needs a lot of cleaning, as some of this code is very old and doesn't
actually run with current weave.
\layout Standard
\begin_inset ERT
status Open
\layout Standard
\backslash
lstinputlisting{examples/wrap_weave.py}
\end_inset
\layout Section
swig
\layout Section
f2py
\layout Standard
This is a rough set of notes on how to use f2py.
It does NOT substitute the official manual, but is rather meant to be used
alongside with it.
\layout Standard
For any non-trivial poject involving f2py, one should also keep at hand
Pierre Schnizer's excellent 'A short introduction to F2PY', available from
http://fubphpc.tu-graz.ac.at/~pierre/f2py_tutorial.tar.gz
\layout Subsection
Usage for the impatient
\layout Standard
Start by building a scratch signature file automatically from your Fortran
sources (in this case all, you can choose only those .f files you need):
\layout LyX-Code
f2py -m MODULENAME -h MODULENAME.pyf *.f
\layout Standard
This writes the file MODULENAME.pyf, making the best guesses it can from
the Fortran sources.
It builds an interface for the module to be accessed as 'import adap1d'
from python.
\layout Standard
You will then edit the .pyf file to fine-tune the python interface exhibited
by the resulting extension.
This means for example making unnecessary scratch areas or array dimensions
hidden, or making certain parameters be optional and take a default value.
\layout Standard
Then, write your setup.py file using distutils, and list the .pyf file along
with the Fortran sources it is meant to wrap.
f2py will build the module for you automatically, respecting all the interface
specifications you made in the .pyf file.
\layout Standard
This approach is ultimately far easier than trying to get all the declarations
(especially dependencies) right through Cf2py directives in the Fortran
sources.
While that may seem appealing at first, experience seems to show that it's
ultimately far more time-consuming and prone to subtle errors.
Using this approach, the first f2py pass can do the bulk of the interface
writing and only fine-tuning needs to be done manually.
I would only recommend embedded Cf2py directives for very simple problems
(where it works very well).
\layout Standard
The only drawback of this approach is that the interface and the original
Fortran source lie in different files, which need to be kept in sync.
This increases a bit the chances of forgetting to update the .pyf file if
the Fortran interface changes (adding a parameter, for example).
However, the benefit of having explicit, clear control over f2py's behavior
far outweighs this concern.
\layout Subsection
Choosing a default compiler
\layout Standard
Set the FC_VENDOR environment variable.
This will then prevent f2py from testing all the compilers it knows about.
\layout Subsection
Using Cf2py directives
\layout Standard
For simpler cases you may choose to go the route of Cf2py directives.
Below are some tips and examples for this approach.
\layout Standard
Here's the signature of a simple Fortran routine:
\begin_inset ERT
status Open
\layout Standard
\backslash
lstinputlisting[language=Fortran]{snippets/wrap_sub_sig.f}
\end_inset
\layout Standard
The above is correctly handled by f2py, but it can't know what is meant
to be input/output and what the relations between the various variables
are (such as integers which are array dimensions).
If we add the following f2py directives, the generated python interface
is a lot nicer:
\begin_inset ERT
status Collapsed
\layout Standard
\backslash
lstinputlisting[language=Fortran]{snippets/wrap_sub_sig_f2py.f}
\layout Standard
\end_inset
\layout Standard
Some comments on the above:
\layout Itemize
The f2py directives should come immediately after the 'subroutine' line
and before the Fortran variable lines.
This allows the f2py dimension directives to override the Fortran var(*)
directives.
\layout Itemize
If the Fortran code uses var(N) instead of var(*), the f2py directives can
be placed after the Fortran declarations.
This mode is preferred, as there is less redundancy overall.
The result is much simpler:
\layout Standard
\begin_inset ERT
status Collapsed
\layout Standard
\backslash
lstinputlisting[language=Fortran]{snippets/wrap_sub_sig_f2py.f}
\layout Standard
\end_inset
\layout Standard
Since python can automatically manage memory, it is possible to hide the
need for manually passed 'work' areas.
The C/python wrapper to the underlying fortran routine will allocate the
memory for the needed work areas on the fly.
This is done by specifying intent(hide,cache).
'hide' tells f2py to remove the variable from the argument list and 'cache'
tells it to auto-generate it.
\layout Standard
In cases where the allocation cost becomes a performance problem, one can
remove the 'hide' part and make it an optional argument.
In this case it will only be generated if not given.
For this, the line above should be changed to:
\layout LyX-Code
\size small
Cf2py real *8 dimension(2*mm+2), intent(cache), optional, depend(mm) ::
wrk
\layout Standard
Note that this should only be done after proving that the scratch areas
are causing a performance problem.
The
\family typewriter
cache
\family default
directive causes f2py to keep cached copies of the scratch areas, so no
unnecessary mallocs should be triggered.
\layout Standard
Since f2py relies on Numeric arrays, all dimensions can be determined from
the arrays themselves and it is not necessary to pass them explicitly.
\layout Standard
With all this, the resulting f2py-generated docstring becomes:
\layout LyX-Code
phipol - Function signature:
\layout LyX-Code
phi = phipol(j,nodes,wei,x)
\layout LyX-Code
Required arguments:
\layout LyX-Code
j : input int
\layout LyX-Code
nodes : input rank-1 array('d') with bounds (mm)
\layout LyX-Code
wei : input rank-1 array('d') with bounds (mm)
\layout LyX-Code
x : input rank-1 array('d') with bounds (nn)
\layout LyX-Code
Return objects:
\layout LyX-Code
phi : rank-1 array('d') with bounds (nn)
\layout Subsection
Debugging
\layout Standard
For debugging, use the --debug-capi option to f2py.
This causes the extension modules to print detailed information while in
operation.
In distutils, this must be passed as an option in the f2py_options to the
Extension constructor.
\layout Subsection
Wrapping C codes with f2py
\layout Standard
Below is Pearu Peterson's (the f2py author) response to a question about
using f2py to wrap existing C codes.
While SWIG provides similar functionality and weave is perfect for inlining
C, f2py seems to be an incredibly simple and convenient tool for wrapping
C libraries.
\layout Standard
Pearu's response follows:
\layout Standard
For example, consider the following C file:
\layout LyX-Code
/* foo.c */
\layout LyX-Code
double foo(double *x, int n) {
\layout LyX-Code
int i;
\layout LyX-Code
double r = 0;
\layout LyX-Code
for (i=0;i<n;++i)
\layout LyX-Code
r += x[i];
\layout LyX-Code
return r;
\layout LyX-Code
}
\layout LyX-Code
/* EOF foo.c */
\layout Standard
To wrap the C function foo() with f2py, create the following signature file
bar.pyf:
\layout LyX-Code
! -*- F90 -*-
\layout LyX-Code
python module bar
\layout LyX-Code
interface
\layout LyX-Code
real*8 function foo(x,n)
\layout LyX-Code
intent(c) foo
\layout LyX-Code
real*8 dimension(n),intent(in) :: x
\layout LyX-Code
integer intent(c,hide),depend(x) :: n = len(x)
\layout LyX-Code
end function foo
\layout LyX-Code
end interface
\layout LyX-Code
end python module bar
\layout LyX-Code
! EOF bar.pyf
\layout Standard
(see usersguide for more info about intent(c)) and run
\layout LyX-Code
f2py -c bar.pyf foo.c
\layout Standard
Finally, in Python:
\layout LyX-Code
>>> import bar
\layout LyX-Code
>>> bar.foo([1,2,3])
\layout LyX-Code
6.0
\layout Subsection
Passing offset arrays to Fortran routines
\layout Standard
It is possible to pass offset arrays (like pointers to the middle of other
arrays) by using Numeric's slice notation.
\layout Standard
The print_dvec function below simply prints its argument as "print*,'x',x".
We show some examples of how it behaves with both 1 and 2-d arrays:
\layout LyX-Code
In [3]: x
\layout LyX-Code
Out[3]: array([ 2.8, 3.4, 4.1])
\layout LyX-Code
In [4]: tf.print_dvec(x)
\layout LyX-Code
n 3
\layout LyX-Code
x 2.8 3.4 4.1
\layout LyX-Code
In [5]: tf.print_dvec ?
\layout LyX-Code
Type: fortran
\layout LyX-Code
String Form: <fortran object at 0x8306fe8>
\layout LyX-Code
Namespace: Currently not defined in user session.
\layout LyX-Code
Docstring:
\layout LyX-Code
print_dvec - Function signature:
\layout LyX-Code
print_dvec(x,[n])
\layout LyX-Code
Required arguments:
\layout LyX-Code
x : input rank-1 array('d') with bounds (n)
\layout LyX-Code
Optional arguments:
\layout LyX-Code
n := len(x) input int
\layout LyX-Code
In [6]: tf.print_dvec (x[1])
\layout LyX-Code
n 1
\layout LyX-Code
x 3.4
\layout LyX-Code
In [7]: tf.print_dvec (x[1:])
\layout LyX-Code
n 2
\layout LyX-Code
x 3.4 4.1
\layout LyX-Code
In [8]: A
\layout LyX-Code
Out[8]:
\layout LyX-Code
array([[ 3.5, 5.6, 8.2],
\layout LyX-Code
[ 2.1, 4.5, 1.2],
\layout LyX-Code
[ 6.3, 3.4, 3.1]])
\layout LyX-Code
In [9]: tf.print_dvec(A)
\layout LyX-Code
n 9
\layout LyX-Code
x 3.5 5.6 8.2 2.1 4.5 1.2 6.3 3.4 3.1
\layout LyX-Code
In [10]: A
\layout LyX-Code
Out[10]:
\layout LyX-Code
array([[ 3.5, 5.6, 8.2],
\layout LyX-Code
[ 2.1, 4.5, 1.2],
\layout LyX-Code
[ 6.3, 3.4, 3.1]])
\layout LyX-Code
In [11]: tf.print_dvec(A[1:])
\layout LyX-Code
n 6
\layout LyX-Code
x 2.1 4.5 1.2 6.3 3.4 3.1
\layout LyX-Code
In [12]: A[1:]
\layout LyX-Code
Out[12]:
\layout LyX-Code
array([[ 2.1, 4.5, 1.2],
\layout LyX-Code
[ 6.3, 3.4, 3.1]])
\layout LyX-Code
In [13]: A[1:,1:]
\layout LyX-Code
Out[13]:
\layout LyX-Code
array([[ 4.5, 1.2],
\layout LyX-Code
[ 3.4, 3.1]])
\layout LyX-Code
In [14]: tf.print_dvec(A[1:,1:])
\layout LyX-Code
n 4
\layout LyX-Code
x 4.5 1.2 3.4 3.1
\layout Subsection
On matrix ordering and in-memory copies
\layout Standard
Numeric (which f2py relies on) is C-based, and therefore its arrays are
stored in row-major order.
Fortran stores its arrays in column-major order.
This means that copying issues must be dealt with.
Below we reproduce some comments from Pearu on this topic given in the
f2py mailing list in June/2002:
\layout Quote
To avoid copying, you should create array that has internally Fortran data
ordering.
This is achived, for example, by reading/creating your data in Fortran
ordering to Numeric array and then doing Numeric.transpose on that.
Every f2py generated extension module provides also function
\layout Quote
has_column_major_storage
\layout Quote
to check if an array is Fortran contiguous or not.
If has_column_major_storage(arr) returns true then there will be no copying
for the array arr if passed to f2py generated functions (assuming that
the types are proper, of cource).
\layout Quote
Also note that copying done by f2py generated interface is carried out in
C on the raw data and therefore it is extremely fast compared to if you
would make a copy in Python, even when using Numeric.
Tests with say 1000x1000 matrices show that there is no noticable performance
hit when copying is carried out, in fact, sometimes making a copy may speed
up things a bit -- I was quite surprised about that myself.
\layout Quote
So, I think, you should worry about copying only if the sizes of matrices
are really large, say, larger than 5000x5000 and efficient memory usage
is relevant.
The time spent for copying is negligible even for large arrays provided
that your computer has plenty of memory (>=256MB).
\layout Subsection
Distutils
\layout Standard
Below is an example setup.py file which generates a Python extension module
from Fortran90 sources and a .pyf interface file generated by f2py and later
fine tuned.
\layout Standard
\begin_inset ERT
status Open
\layout Standard
\backslash
lstinputlisting{examples/wrap_f2py_setup.py}
\end_inset
\layout Section
Others
\layout Standard
boost, pyrex, cxx
\layout Section
Distributing standalone applications
\begin_inset OptArg
collapsed true
\layout Standard
Standalone applications
\end_inset
\layout Standard
py2exe, mcmillan installer
\the_end