summaryrefslogtreecommitdiff
path: root/numpy/f2py/doc/fortranobject.tex
diff options
context:
space:
mode:
Diffstat (limited to 'numpy/f2py/doc/fortranobject.tex')
-rw-r--r--numpy/f2py/doc/fortranobject.tex574
1 files changed, 574 insertions, 0 deletions
diff --git a/numpy/f2py/doc/fortranobject.tex b/numpy/f2py/doc/fortranobject.tex
new file mode 100644
index 000000000..dbb244cdd
--- /dev/null
+++ b/numpy/f2py/doc/fortranobject.tex
@@ -0,0 +1,574 @@
+\documentclass{article}
+
+\headsep=0pt
+\topmargin=0pt
+\headheight=0pt
+\oddsidemargin=0pt
+\textwidth=6.5in
+\textheight=9in
+
+\usepackage{xspace}
+\usepackage{verbatim}
+\newcommand{\fpy}{\texttt{f2py}\xspace}
+\newcommand{\bs}{\symbol{`\\}}
+\newcommand{\email}[1]{\special{html:<A href="mailto:#1">}\texttt{<#1>}\special{html:</A>}}
+\title{\texttt{PyFortranObject} --- example usages}
+\author{
+\large Pearu Peterson\\
+\small \email{pearu@cens.ioc.ee}
+}
+
+\begin{document}
+
+\maketitle
+
+\special{html: Other formats of this document:
+<A href=pyfobj.ps.gz>Gzipped PS</A>,
+<A href=pyfobj.pdf>PDF</A>
+}
+
+\tableofcontents
+
+\section{Introduction}
+\label{sec:intro}
+
+Fortran language defines the following concepts that we would like to
+access from Python: functions, subroutines, data in \texttt{COMMON} blocks,
+F90 module functions and subroutines, F90 module data (both static and
+allocatable arrays).
+
+In the following we shall assume that we know the signatures (full
+specifications of routine arguments and variables) of these concepts
+from their Fortran source codes. Now, in order to call or use them
+from C, one needs to have pointers to the corresponding objects. The
+pointers to Fortran 77 objects (routines, data in \texttt{COMMON}
+blocks) are readily available to C codes (there are various sources
+available about mixing Fortran 77 and C codes). On the other hand, F90
+module specifications are highly compiler dependent and sometimes it
+is not even possible to access F90 module objects from C (at least,
+not directly, see remark about MIPSPro 7 Compilers). But using some
+tricks (described below), the pointers to F90 module objects can be
+determined in runtime providing a compiler independent solution.
+
+To use Fortran objects from Python in unified manner, \fpy introduces
+\texttt{PyFortranObject} to hold pointers of the Fortran objects and
+the corresponing wrapper functions. In fact, \texttt{PyFortranObject}
+does much more: it generates documentation strings in run-time (for
+items in \texttt{COMMON} blocks and data in F90 modules), provides
+methods for accessing Fortran data and for calling Fortran routines,
+etc.
+
+\section{\texttt{PyFortranObject}}
+\label{sec:pyfortobj}
+
+\texttt{PyFortranObject} is defined as follows
+\begin{verbatim}
+typedef struct {
+ PyObject_HEAD
+ int len; /* Number of attributes */
+ FortranDataDef *defs; /* An array of FortranDataDef's */
+ PyObject *dict; /* Fortran object attribute dictionary */
+} PyFortranObject;
+\end{verbatim}
+where \texttt{FortranDataDef} is
+\begin{verbatim}
+typedef struct {
+ char *name; /* attribute (array||routine) name */
+ int rank; /* array rank, 0 for scalar, max is F2PY_MAX_DIMS,
+ || rank=-1 for Fortran routine */
+ struct {int d[F2PY_MAX_DIMS];} dims; /* dimensions of the array, || not used */
+ int type; /* PyArray_<type> || not used */
+ char *data; /* pointer to array || Fortran routine */
+ void (*func)(); /* initialization function for
+ allocatable arrays:
+ func(&rank,dims,set_ptr_func,name,len(name))
+ || C/API wrapper for Fortran routine */
+ char *doc; /* documentation string; only recommended
+ for routines. */
+} FortranDataDef;
+\end{verbatim}
+In the following we demonstrate typical usages of
+\texttt{PyFortranObject}. Just relevant code fragments will be given.
+
+
+\section{Fortran 77 subroutine}
+\label{sec:f77subrout}
+
+Consider Fortran 77 subroutine
+\begin{verbatim}
+subroutine bar()
+end
+\end{verbatim}
+The corresponding \texttt{PyFortranObject} is defined in C as follows:
+\begin{verbatim}
+static char doc_bar[] = "bar()";
+static PyObject *c_bar(PyObject *self, PyObject *args,
+ PyObject *keywds, void (*f2py_func)()) {
+ static char *capi_kwlist[] = {NULL};
+ if (!PyArg_ParseTupleAndKeywords(args,keywds,"|:bar",capi_kwlist))
+ return NULL;
+ (*f2py_func)();
+ return Py_BuildValue("");
+}
+extern void F_FUNC(bar,BAR)();
+static FortranDataDef f2py_routines_def[] = {
+ {"bar",-1, {-1}, 0, (char *)F_FUNC(bar,BAR),(void*)c_bar,doc_bar},
+ {NULL}
+};
+void initfoo() {
+ <snip>
+ d = PyModule_GetDict(m);
+ PyDict_SetItemString(d, f2py_routines_def[0].name,
+ PyFortranObject_NewAsAttr(&f2py_routines_def[0]));
+}
+\end{verbatim}
+where CPP macro \texttt{F\_FUNC} defines how Fortran 77 routines are
+seen in C.
+In Python, Fortran subroutine \texttt{bar} is called as follows
+\begin{verbatim}
+>>> import foo
+>>> foo.bar()
+\end{verbatim}
+
+\section{Fortran 77 function}
+\label{sec:f77func}
+Consider Fortran 77 function
+\begin{verbatim}
+function bar()
+complex bar
+end
+\end{verbatim}
+The corresponding \texttt{PyFortranObject} is defined in C as in
+previous example but with the following changes:
+\begin{verbatim}
+static char doc_bar[] = "bar = bar()";
+static PyObject *c_bar(PyObject *self, PyObject *args,
+ PyObject *keywds, void (*f2py_func)()) {
+ complex_float bar;
+ static char *capi_kwlist[] = {NULL};
+ if (!PyArg_ParseTupleAndKeywords(args,keywds,"|:bar",capi_kwlist))
+ return NULL;
+ (*f2py_func)(&bar);
+ return Py_BuildValue("O",pyobj_from_complex_float1(bar));
+}
+extern void F_WRAPPEDFUNC(bar,BAR)();
+static FortranDataDef f2py_routines_def[] = {
+ {"bar",-1,{-1},0,(char *)F_WRAPPEDFUNC(bar,BAR),(void *)c_bar,doc_bar},
+ {NULL}
+};
+\end{verbatim}
+where CPP macro \texttt{F\_WRAPPEDFUNC} gives the pointer to the following
+Fortran 77 subroutine:
+\begin{verbatim}
+subroutine f2pywrapbar (barf2pywrap)
+external bar
+complex bar, barf2pywrap
+barf2pywrap = bar()
+end
+\end{verbatim}
+With these hooks, calling Fortran functions returning composed types
+becomes platform/compiler independent.
+
+
+\section{\texttt{COMMON} block data}
+\label{sec:commondata}
+
+Consider Fortran 77 \texttt{COMMON} block
+\begin{verbatim}
+integer i
+COMMON /bar/ i
+\end{verbatim}
+In order to access the variable \texttt{i} from Python,
+\texttt{PyFortranObject} is defined as follows:
+\begin{verbatim}
+static FortranDataDef f2py_bar_def[] = {
+ {"i",0,{-1},PyArray_INT},
+ {NULL}
+};
+static void f2py_setup_bar(char *i) {
+ f2py_bar_def[0].data = i;
+}
+extern void F_FUNC(f2pyinitbar,F2PYINITBAR)();
+static void f2py_init_bar() {
+ F_FUNC(f2pyinitbar,F2PYINITBAR)(f2py_setup_bar);
+}
+void initfoo() {
+ <snip>
+ PyDict_SetItemString(d, "bar", PyFortranObject_New(f2py_bar_def,f2py_init_bar));
+}
+\end{verbatim}
+where auxiliary Fortran function \texttt{f2pyinitbar} is defined as follows
+\begin{verbatim}
+subroutine f2pyinitbar(setupfunc)
+external setupfunc
+integer i
+common /bar/ i
+call setupfunc(i)
+end
+\end{verbatim}
+and it is called in \texttt{PyFortranObject\_New}.
+
+
+\section{Fortran 90 module subroutine}
+\label{sec:f90modsubrout}
+
+Consider
+\begin{verbatim}
+module fun
+ subroutine bar()
+ end subroutine bar
+end module fun
+\end{verbatim}
+\texttt{PyFortranObject} is defined as follows
+\begin{verbatim}
+static char doc_fun_bar[] = "fun.bar()";
+static PyObject *c_fun_bar(PyObject *self, PyObject *args,
+ PyObject *keywds, void (*f2py_func)()) {
+ static char *kwlist[] = {NULL};
+ if (!PyArg_ParseTupleAndKeywords(args,keywds,"",kwlist))
+ return NULL;
+ (*f2py_func)();
+ return Py_BuildValue("");
+}
+static FortranDataDef f2py_fun_def[] = {
+ {"bar",-1,{-1},0,NULL,(void *)c_fun_bar,doc_fun_bar},
+ {NULL}
+};
+static void f2py_setup_fun(char *bar) {
+ f2py_fun_def[0].data = bar;
+}
+extern void F_FUNC(f2pyinitfun,F2PYINITFUN)();
+static void f2py_init_fun() {
+ F_FUNC(f2pyinitfun,F2PYINITFUN)(f2py_setup_fun);
+}
+void initfoo () {
+ <snip>
+ PyDict_SetItemString(d, "fun", PyFortranObject_New(f2py_fun_def,f2py_init_fun));
+}
+\end{verbatim}
+where auxiliary Fortran function \texttt{f2pyinitfun} is defined as
+follows
+\begin{verbatim}
+subroutine f2pyinitfun(f2pysetupfunc)
+use fun
+external f2pysetupfunc
+call f2pysetupfunc(bar)
+end subroutine f2pyinitfun
+\end{verbatim}
+The following Python session demonstrates how to call Fortran 90
+module function \texttt{bar}:
+\begin{verbatim}
+>>> import foo
+>>> foo.fun.bar()
+\end{verbatim}
+
+\section{Fortran 90 module function}
+\label{sec:f90modfunc}
+
+Consider
+\begin{verbatim}
+module fun
+ function bar()
+ complex bar
+ end subroutine bar
+end module fun
+\end{verbatim}
+\texttt{PyFortranObject} is defined as follows
+\begin{verbatim}
+static char doc_fun_bar[] = "bar = fun.bar()";
+static PyObject *c_fun_bar(PyObject *self, PyObject *args,
+ PyObject *keywds, void (*f2py_func)()) {
+ complex_float bar;
+ static char *kwlist[] = {NULL};
+ if (!PyArg_ParseTupleAndKeywords(args,keywds,"",kwlist))
+ return NULL;
+ (*f2py_func)(&bar);
+ return Py_BuildValue("O",pyobj_from_complex_float1(bar));
+}
+static FortranDataDef f2py_fun_def[] = {
+ {"bar",-1,{-1},0,NULL,(void *)c_fun_bar,doc_fun_bar},
+ {NULL}
+};
+static void f2py_setup_fun(char *bar) {
+ f2py_fun_def[0].data = bar;
+}
+extern void F_FUNC(f2pyinitfun,F2PYINITFUN)();
+static void f2py_init_fun() {
+ F_FUNC(f2pyinitfun,F2PYINITFUN)(f2py_setup_fun);
+}
+void initfoo() {
+ <snip>
+ PyDict_SetItemString(d, "fun", PyFortranObject_New(f2py_fun_def,f2py_init_fun));
+}
+\end{verbatim}
+where
+\begin{verbatim}
+subroutine f2pywrap_fun_bar (barf2pywrap)
+use fun
+complex barf2pywrap
+barf2pywrap = bar()
+end
+
+subroutine f2pyinitfun(f2pysetupfunc)
+external f2pysetupfunc,f2pywrap_fun_bar
+call f2pysetupfunc(f2pywrap_fun_bar)
+end
+\end{verbatim}
+
+
+\section{Fortran 90 module data}
+\label{sec:f90moddata}
+
+Consider
+\begin{verbatim}
+module fun
+ integer i
+end module fun
+\end{verbatim}
+Then
+\begin{verbatim}
+static FortranDataDef f2py_fun_def[] = {
+ {"i",0,{-1},PyArray_INT},
+ {NULL}
+};
+static void f2py_setup_fun(char *i) {
+ f2py_fun_def[0].data = i;
+}
+extern void F_FUNC(f2pyinitfun,F2PYINITFUN)();
+static void f2py_init_fun() {
+ F_FUNC(f2pyinitfun,F2PYINITFUN)(f2py_setup_fun);
+}
+void initfoo () {
+ <snip>
+ PyDict_SetItemString(d, "fun",
+ PyFortranObject_New(f2py_fun_def,f2py_init_fun));
+}
+\end{verbatim}
+where
+\begin{verbatim}
+subroutine f2pyinitfun(f2pysetupfunc)
+use fun
+external f2pysetupfunc
+call f2pysetupfunc(i)
+end subroutine f2pyinitfun
+\end{verbatim}
+Example usage in Python:
+\begin{verbatim}
+>>> import foo
+>>> foo.fun.i = 4
+\end{verbatim}
+
+\section{Fortran 90 module allocatable array}
+\label{sec:f90modallocarr}
+
+Consider
+\begin{verbatim}
+module fun
+ real, allocatable :: r(:)
+end module fun
+\end{verbatim}
+Then
+\begin{verbatim}
+static FortranDataDef f2py_fun_def[] = {
+ {"r",1,{-1},PyArray_FLOAT},
+ {NULL}
+};
+static void f2py_setup_fun(void (*r)()) {
+ f2py_fun_def[0].func = r;
+}
+extern void F_FUNC(f2pyinitfun,F2PYINITFUN)();
+static void f2py_init_fun() {
+ F_FUNC(f2pyinitfun,F2PYINITFUN)(f2py_setup_fun);
+}
+void initfoo () {
+ <snip>
+ PyDict_SetItemString(d, "fun", PyFortranObject_New(f2py_fun_def,f2py_init_fun));
+}
+\end{verbatim}
+where
+\begin{verbatim}
+subroutine f2py_fun_getdims_r(r,s,f2pysetdata)
+use fun, only: d => r
+external f2pysetdata
+logical ns
+integer s(*),r,i,j
+ns = .FALSE.
+if (allocated(d)) then
+ do i=1,r
+ if ((size(d,r-i+1).ne.s(i)).and.(s(i).ge.0)) then
+ ns = .TRUE.
+ end if
+ end do
+ if (ns) then
+ deallocate(d)
+ end if
+end if
+if ((.not.allocated(d)).and.(s(1).ge.1)) then
+ allocate(d(s(1)))
+end if
+if (allocated(d)) then
+ do i=1,r
+ s(i) = size(d,r-i+1)
+ end do
+end if
+call f2pysetdata(d,allocated(d))
+end subroutine f2py_fun_getdims_r
+
+subroutine f2pyinitfun(f2pysetupfunc)
+use fun
+external f2pysetupfunc,f2py_fun_getdims_r
+call f2pysetupfunc(f2py_fun_getdims_r)
+end subroutine f2pyinitfun
+\end{verbatim}
+Usage in Python:
+\begin{verbatim}
+>>> import foo
+>>> foo.fun.r = [1,2,3,4]
+\end{verbatim}
+
+\section{Callback subroutine}
+\label{sec:cbsubr}
+
+Thanks to Travis Oliphant for working out the basic idea of the
+following callback mechanism.
+
+Consider
+\begin{verbatim}
+subroutine fun(bar)
+external bar
+call bar(1)
+end
+\end{verbatim}
+Then
+\begin{verbatim}
+static char doc_foo8_fun[] = "
+Function signature:
+ fun(bar,[bar_extra_args])
+Required arguments:
+ bar : call-back function
+Optional arguments:
+ bar_extra_args := () input tuple
+Call-back functions:
+ def bar(e_1_e): return
+ Required arguments:
+ e_1_e : input int";
+static PyObject *foo8_fun(PyObject *capi_self, PyObject *capi_args,
+ PyObject *capi_keywds, void (*f2py_func)()) {
+ PyObject *capi_buildvalue = NULL;
+ PyObject *bar_capi = Py_None;
+ PyTupleObject *bar_xa_capi = NULL;
+ PyTupleObject *bar_args_capi = NULL;
+ jmp_buf bar_jmpbuf;
+ int bar_jmpbuf_flag = 0;
+ int bar_nofargs_capi = 0;
+ static char *capi_kwlist[] = {"bar","bar_extra_args",NULL};
+
+ if (!PyArg_ParseTupleAndKeywords(capi_args,capi_keywds,\
+ "O!|O!:foo8.fun",\
+ capi_kwlist,&PyFunction_Type,&bar_capi,&PyTuple_Type,&bar_xa_capi))
+ goto capi_fail;
+
+ bar_nofargs_capi = cb_bar_in_fun__user__routines_nofargs;
+ if (create_cb_arglist(bar_capi,bar_xa_capi,1,0,
+ &cb_bar_in_fun__user__routines_nofargs,&bar_args_capi)) {
+ if ((PyErr_Occurred())==NULL)
+ PyErr_SetString(foo8_error,"failed in processing argument list for call-back bar." );
+ goto capi_fail;
+ }
+
+ SWAP(bar_capi,cb_bar_in_fun__user__routines_capi,PyObject);
+ SWAP(bar_args_capi,cb_bar_in_fun__user__routines_args_capi,PyTupleObject);
+ memcpy(&bar_jmpbuf,&cb_bar_in_fun__user__routines_jmpbuf,sizeof(jmp_buf));
+ bar_jmpbuf_flag = 1;
+
+ if ((setjmp(cb_bar_in_fun__user__routines_jmpbuf))) {
+ if ((PyErr_Occurred())==NULL)
+ PyErr_SetString(foo8_error,"Failure of a callback function");
+ goto capi_fail;
+ } else
+ (*f2py_func)(cb_bar_in_fun__user__routines);
+
+ capi_buildvalue = Py_BuildValue("");
+capi_fail:
+
+ if (bar_jmpbuf_flag) {
+ cb_bar_in_fun__user__routines_capi = bar_capi;
+ Py_DECREF(cb_bar_in_fun__user__routines_args_capi);
+ cb_bar_in_fun__user__routines_args_capi = bar_args_capi;
+ cb_bar_in_fun__user__routines_nofargs = bar_nofargs_capi;
+ memcpy(&cb_bar_in_fun__user__routines_jmpbuf,&bar_jmpbuf,sizeof(jmp_buf));
+ bar_jmpbuf_flag = 0;
+ }
+ return capi_buildvalue;
+}
+extern void F_FUNC(fun,FUN)();
+static FortranDataDef f2py_routine_defs[] = {
+ {"fun",-1,{-1},0,(char *)F_FUNC(fun,FUN),(void *)foo8_fun,doc_foo8_fun},
+ {NULL}
+};
+void initfoo8 () {
+ <snip>
+ PyDict_SetItemString(d, f2py_routine_defs[0].name,
+ PyFortranObject_NewAsAttr(&f2py_routine_defs[0]));
+}
+\end{verbatim}
+where
+\begin{verbatim}
+PyObject *cb_bar_in_fun__user__routines_capi = Py_None;
+PyTupleObject *cb_bar_in_fun__user__routines_args_capi = NULL;
+int cb_bar_in_fun__user__routines_nofargs = 0;
+jmp_buf cb_bar_in_fun__user__routines_jmpbuf;
+static void cb_bar_in_fun__user__routines (int *e_1_e_cb_capi) {
+ PyTupleObject *capi_arglist = cb_bar_in_fun__user__routines_args_capi;
+ PyObject *capi_return = NULL;
+ PyObject *capi_tmp = NULL;
+ int capi_j,capi_i = 0;
+
+ int e_1_e=(*e_1_e_cb_capi);
+ if (capi_arglist == NULL)
+ goto capi_fail;
+ if (cb_bar_in_fun__user__routines_nofargs>capi_i)
+ if (PyTuple_SetItem((PyObject *)capi_arglist,capi_i++,pyobj_from_int1(e_1_e)))
+ goto capi_fail;
+
+ capi_return = PyEval_CallObject(cb_bar_in_fun__user__routines_capi,
+ (PyObject *)capi_arglist);
+
+ if (capi_return == NULL)
+ goto capi_fail;
+ if (capi_return == Py_None) {
+ Py_DECREF(capi_return);
+ capi_return = Py_BuildValue("()");
+ }
+ else if (!PyTuple_Check(capi_return)) {
+ capi_tmp = capi_return;
+ capi_return = Py_BuildValue("(O)",capi_tmp);
+ Py_DECREF(capi_tmp);
+ }
+ capi_j = PyTuple_Size(capi_return);
+ capi_i = 0;
+ goto capi_return_pt;
+capi_fail:
+ fprintf(stderr,"Call-back cb_bar_in_fun__user__routines failed.\n");
+ Py_XDECREF(capi_return);
+ longjmp(cb_bar_in_fun__user__routines_jmpbuf,-1);
+capi_return_pt:
+ ;
+}
+\end{verbatim}
+Usage in Python:
+\begin{verbatim}
+>>> import foo8 as foo
+>>> def bar(i): print 'In bar i=',i
+...
+>>> foo.fun(bar)
+In bar i= 1
+\end{verbatim}
+
+\end{document}
+
+
+%%% Local Variables:
+%%% mode: latex
+%%% TeX-master: t
+%%% End: