Fortran To Python Interface Generator With An Appl

Download as pdf or txt
Download as pdf or txt
You are on page 1of 12

See discussions, stats, and author profiles for this publication at: https://www.researchgate.

net/publication/228769730

Fortran to Python interface generator with an application to aerospace


engineering

Article · February 2001

CITATIONS READS

14 542

3 authors:

Pearu Peterson Joaquim R. R. A. Martins


Quansight University of Michigan
61 PUBLICATIONS 10,046 CITATIONS 303 PUBLICATIONS 8,932 CITATIONS

SEE PROFILE SEE PROFILE

Juan J. Alonso
Stanford University
290 PUBLICATIONS 7,464 CITATIONS

SEE PROFILE

Some of the authors of this publication are also working on these related projects:

SUAVE - Aerospace Vehicle Environment View project

LEARN project View project

All content following this page was uploaded by Joaquim R. R. A. Martins on 20 May 2014.

The user has requested enhancement of the downloaded file.


Fortran to Python Interface Generator with an Application to
Aerospace Engineering
Pearu Peterson
<[email protected]>
Center of Nonlinear Studies
Institute of Cybernetics at TTU
Akadeemia Rd 21, 12618 Tallinn, ESTONIA

Joaquim R. R. A. Martins and Juan J. Alonso


<[email protected]>, <[email protected]>
Department of Aeronautics and Astronautics
Stanford University, CA

Revision : 1.16
January 18, 2001

Abstract Contents
1 Preface 2
FPIG — Fortran to Python Interface Generator —
is a tool for generating Python C/API extension 2 Introduction 2
modules that interface Fortran 77/90/95 codes with
Python. This tool automates the process of interface 3 Getting Started 3
generation by scanning the Fortran source code to 3.1 Interfacing Simple Routines . . . . . . 3
determine the signatures of Fortran routines and cre- 3.2 Interfacing Libraries . . . . . . . . . . 4
ating a Python C/API module that contains the cor-
responding interface functions. FPIG also attempts 4 Basic Features 4
to find dependence relations between the arguments
5 Implementation Issues 6
of a Fortran routine call (e.g. an array and its dimen-
5.1 Mapping Fortran Types to C Types . 6
sions) and constructs interface functions with poten-
5.2 Calling Fortran (Module) Routines . . 6
tially fewer arguments. The tool is extremely flexible
since the user has control over the generation process 5.3 Wrapping Fortran Functions . . . . . . 7
of the interface by specifying the desired function sig- 5.4 Accessing Fortran Data . . . . . . . . 7
natures. The home page for FPIG can be found at 5.5 PyFortranObject . . . . . . . . . . . 7
http://cens.ioc.ee/projects/f2py2e/. 5.6 Callback Functions . . . . . . . . . . . 8

FPIG has been used successfully to wrap a large 6 Future Work 8


number of Fortran programs and libraries. Advances
in computational science have led to large improve- 7 Application to a Large Aero-Structural
ments in the modeling of physical systems which Analysis Framework 8
are often a result of the coupling of a variety of 7.1 The Need for Python and FPIG . . . . 8
physical models that were typically run in isolation. 7.2 Wrapping the Fortran Programs . . . 9
Since a majority of the available physical models have 7.3 Module Design . . . . . . . . . . . . . 9
been previously written in Fortran, the importance of 7.3.1 Geometry . . . . . . . . . . . . 9
FPIG in accomplishing these couplings cannot be un- 7.3.2 Flow . . . . . . . . . . . . . . . 9
derstated. In this paper, we present an application 7.3.3 Structure . . . . . . . . . . . . 9
of FPIG to create an object-oriented framework for 7.3.4 Aerostructure . . . . . . . . . . 10
aero-structural analysis and design of aircraft. 7.4 Results . . . . . . . . . . . . . . . . . . 10

1
1 Preface In an ideal world, scientists and engineers would
use higher-level languages for the manipulation of
The use of high-performance computing has made the mathematical formulas in a problem rather than
it possible to tackle many important problems and having to struggle with tedious programming details.
discover new physical phenomena in science and en- For tasks that are computationally demanding, they
gineering. These accomplishments would not have would use interfaces to high-performance routines
been achieved without the computer’s ability to pro- that are written in a lower-level language optimized
cess large amounts of data in a reasonably short time. for execution speed.
It can safely be said that the computer has become an
essential tool for scientists and engineers. However,
the diversity of problems in science and engineering 2 Introduction
has left its mark as computer programs have been de-
veloped in different programming languages, includ- This paper presents a tool that has been developed
ing languages developed to describe certain specific for the creation of interfaces between Fortran and
classes of problems. Python.
In interdisciplinary fields it is not uncommon for The Fortran language is popular in scientific com-
scientists and engineers to face problems that have puting, and is used mostly in applications that use
already been solved in a different programming envi- extensive matrix manipulations (e.g. linear algebra).
ronment from the one they are familiar with. Unfor- Since Fortran has been the standard language among
tunately, researchers may not have the time or will- scientists and engineers for at least three decades,
ingness to learn a new programming language and there is a large number of legacy codes available that
typically end up developing the corresponding tools perform a variety of tasks using very sophisticated
in the language that they normally use. This ap- algorithms (see e.g. [1]).
proach to the development of new software can sub- The Python language [2], on the other hand, is a
stantially impact the time to develop and the qual- relatively new programming language. It is a very
ity of the resulting product: firstly, it usually takes high-level scripting language that supports object-
longer to develop and test a new tool than to learn oriented programming. What makes Python espe-
a new programming environment, and secondly it is cially appealing is its very clear and natural syntax,
very unlikely that a non-specialist in a given field can which makes it easy to learn and use. With Python
produce a program that is more efficient than more one can implement relatively complicated algorithms
established tools. and tasks in a short time with very compact source
To avoid situations such as the one described code.
above, one alternative would be to provide auto- Although there are ongoing projects for extending
matic or semi-automatic interfaces between program- Python’s usage in scientific computation, it lacks re-
ming languages. Another possibility would be to pro- liable tools that are common in scientific and engi-
vide language translators, but these obviously require neering such as ODE integrators, equation solvers,
more work than interface generators — a translator tools for FEM, etc. The implementation of all of
must understand all language constructs while an in- these tools in Python would be not only too time-
terface generator only needs to understand a subset consuming but also inefficient. On the other hand,
of these constructs. With an automatic interface be- these tools are already developed in other, computa-
tween two languages, scientists or engineers can ef- tionally more efficient languages such as Fortran or C.
fectively use programs written in other programming Therefore, the perfect role for Python in the context
languages without ever having to learn them. of scientific computing would be that of a “gluing”
Although it is clear that it is impossible to interface language. That is, the role of providing high-level
arbitrary programming languages with each other, interfaces to C, C++ and Fortran libraries.
there is no reason for doing so. Low-level languages There are a number of widely-used tools that can
such as C and Fortran are well known for their speed be used for interfacing software libraries to Python.
and are therefore suitable for applications where per- For binding C libraries with various scripting lan-
formance is critical. High-level scripting languages, guages, including Python, the tool most often used is
on the other hand, are generally slower but much SWIG [3]. Wrapping Fortran routines with Python
easier to learn and use, especially when performing is less popular, mainly because there are many plat-
interactive analysis. Therefore, it makes sense to cre- form and compiler-specific issues that need to be ad-
ate interfaces only in one direction: from lower-level dressed. Nevertheless, there is great interest in in-
languages to higher-level languages. terfacing Fortran libraries because they provide in-

2
valuable tools for scientific computing. At LLNL, for subroutine exp1(l,u,n)
example, a tool called PyFort has been developed for C Input: n is number of iterations
connecting Fortran and Python [4]. C Output: l,u are such that
The tools mentioned above require an input file de- C l(1)/l(2) < exp(1) < u(1)/u(2)
scribing signatures of functions to be interfaced. To C
create these input files, one needs to have a good Cf2py integer*4 :: n = 1
knowledge of either C or Fortran. In addition, bind- Cf2py intent(out) l,u
ing libraries that have thousands of routines can cer- integer*4 n,i
tainly constitute a very tedious task, even with these real*8 l(2),u(2),t,t1,t2,t3,t4
tools. l(2) = 1
The tool that is introduced in this paper, FPIG l(1) = 0
(Fortran to Python Interface Generator) [5], auto- u(2) = 0
matically generates interfaces between Fortran and u(1) = 1
Python. It is different from the tools mentioned do 10 i=0,n
above in that FPIG can create signature files auto- t1 = 4 + 32*(1+i)*i
matically by scanning the source code of the libraries t2 = 11 + (40+32*i)*i
and then construct Python C/API extension mod- t3 = 3 + (24+32*i)*i
ules. Note that the user need not be experienced in t4 = 8 + 32*(1+i)*i
C or even Fortran. In addition, FPIG is designed to t = u(1)
wrap large Fortran libraries containing many routines u(1) = l(1)*t1 + t*t2
with only one or two commands. This process is very l(1) = l(1)*t3 + t*t4
flexible since one can always modify the generated t = u(2)
signature files to insert additional attributes in or- u(2) = l(2)*t1 + t*t2
der to achieve more sophisticated interface functions l(2) = l(2)*t3 + t*t4
such as taking care of optional arguments, predicting 10 continue
the sizes of array arguments and performing various end
checks on the correctness of the input arguments.
The organization of this paper is as follows. First, a Figure 1: Example Fortran code exp1.f. This rou-
simple example of FPIG usage is given. Then FPIG’s tine calculates the simplest rational lower and upper
basic features are described and solutions to platform approximations to e (for details of the algorithm see
and compiler specific issues are discussed. Unsolved [7], p.122)
problems and future work on FPIG’s development
are also addressed. Finally, an application to a large
aero-structural solver is presented as real-world ex-
(FPIG’s front-end program). In order to do this, we
ample of FPIG’s usage.
issue the following command,
sh> f2py -m foo exp1.f
3 Getting Started where the option -m foo sets the name of the Python
To get acquainted with FPIG, let us consider the sim- C/API extension module that f2py will create to
ple Fortran 77 subroutine shown in Fig. 1. In the sec- foo. To learn more about the f2py command line
tions that follow, two ways of creating interfaces to options, run f2py without arguments.
this Fortran subroutine are described. The first and The output messages in Fig. 2 illustrate the proce-
simplest way is suitable for Fortran codes that are dure followed by f2py: (i) it scans the Fortran source
developed in connection with f2py. The second and code specified in the command line, (ii) it analyses
not much more difficult method, is suitable for in- and determines the routine signatures, (iii) it con-
terfacing existing Fortran libraries which might have structs the corresponding Python C/API extension
been developed by other programmers. modules, (iv) it writes documentation to a LaTeX
Numerical Python [6] is needed in order to compile file, and (v) it creates a GNU Makefile for building
extension modules generated by FPIG. the shared modules.
Now we can build the foo module:
3.1 Interfacing Simple Routines sh> make -f Makefile-foo
In order to call the Fortran routine exp1 from
Python, let us create an interface to it by using f2py Figure 3 illustrates a sample session for calling the

3
Reading fortran codes... >>> import foo,Numeric
Reading file ’exp1.f’ >>> print foo.exp1.__doc__
Post-processing... exp1 - Function signature:
Block: foo l,u = exp1([n])
Block: exp1
Optional arguments:
Creating ’Makefile-foo’...
n := 1 input int
Linker: ld (’GNU ld’ 2.9.5)
Fortran compiler: f77 (’g77 2.x.x’ 2.95.2) Return objects:
C compiler: cc (’gcc 2.x.x’ 2.95.2) l : rank-1 array(’d’) with bounds (2)
Building modules... u : rank-1 array(’d’) with bounds (2)
Building module "foo"...
Constructing wrapper function "exp1"... >>> l,u = foo.exp1()
l,u = exp1([n]) >>> print l,u
Wrote C/API module "foo" to file "foomodule.c" [ 1264. 465.] [ 1457. 536.]
Documentation is saved to file "foomodule.tex" >>> print l[0]/l[1], u[0]/u[1]-l[0]/l[1]
Run GNU make to build shared modules: 2.71827956989 2.25856657199e-06
gmake -f Makefile-<modulename> [test]
>>> l,u = foo.exp1(2)
>>> print l,u
Figure 2: Output messages of f2py -m foo exp1.f. [ 517656. 190435.] [ 566827. 208524.]
>>> print l[0]/l[1], u[0]/u[1]-l[0]/l[1]
2.71828182845 1.36437527942e-11
Fortran routine exp1 from Python.
Note the difference between the signatures of the
Fortran routine exp1(l,u,n) and the corresponding Figure 3: Calling Fortran routine exp1 from Python.
wrapper function l,u=exp1([n]). Clearly, the later Here l[0]/l[1] gives an estimate to e with abso-
is more informative to the user: exp1 takes one op- lute error less than u[0]/u[1]-l[0]/l[1] (this value
tional argument n and it returns l, u. This exchange may depend on the platform and compiler used).
of signatures is achieved by special comment lines
(starting with Cf2py) in the Fortran source code —
no lines starting with Cf2py, the corresponding
these lines are interpreted by f2py as normal For-
signature file foo.pyf would be as shown in Fig. 4.
tran code. Therefore, in the given example the line
In order to obtain the exchanged and more con-
Cf2py integer*4 :: n = 1 informs f2py that the
venient signature l,u=foo.exp1([n]), we would
variable n is optional with a default value equal to
edit foo.pyf as shown in Fig. 5. The Python
one. The line Cf2py intent(out) l,u informs f2py
C/API extension module foo can be constructed by
that the variables l,u are to be returned to Python
applying f2py to the signature file with the following
after calling Fortran function exp1.
command:
sh> f2py foo.pyf
3.2 Interfacing Libraries
The procedure for building the corresponding shared
In our example the Fortran source exp1.f contains module and using it in Python is identical to the one
f2py specific information, though only as comments. described in the previous section.
When interfacing libraries from other parties, it is
As we can see, the syntax of the signature file is an
not recommended to modify their source. Instead,
extension of the Fortran 90/95 syntax. This means
one should use a special auxiliary file to collect the
that only a few new constructs are introduced for
signatures of all Fortran routines and insert f2py spe-
f2py in addition to all standard Fortran constructs;
cific declaration and attribute statements in that file.
signature files can even be written in fixed form. A
This auxiliary file is called a signature file and is iden-
complete set of constructs that are used when creat-
tified by the extension .pyf.
ing interfaces, is described in the f2py User’s Guide
We can use f2py to generate these signature
[8].
files by using the -h <filename>.pyf option. In
our example, f2py could have been called as follows,
sh> f2py -m foo -h foo.pyf exp1.f 4 Basic Features
where the option -h foo.pyf requests f2py to read
the routine signatures, save them to the file foo.pyf, In this section a short overview of f2py features is
and then exit. If exp1.f in Fig. 1 were to contain given.

4
!%f90 -*- f90 -*- 3. The following attributes are supported:
python module foo
interface • intent(in): used for input-only argu-
subroutine exp1(l,u,n) ments.
real*8 dimension(2) :: l • intent(inout): used for arguments that
real*8 dimension(2) :: u are changed in place.
integer*4 :: n
• intent(out): used for return arguments.
end subroutine exp1
end interface • intent(hide): used for arguments to be
end python module foo removed from the signature of the Python
! This file was auto-generated with f2py function.
! (version:2.298). • intent(in,out), intent(inout,out):
! See http://cens.ioc.ee/projects/f2py2e/ used for arguments with combined behav-
ior.

Figure 4: Raw signature file foo.pyf generated with • dimension(<dimspec>)


f2py -m foo -h foo.pyf exp1.f • depend([<names>]): used for arguments
that depend on other arguments in
!%f90 -*- f90 -*- <names>.
python module foo
• check([<C booleanexpr>]): used for
interface
checking the correctness of input argu-
subroutine exp1(l,u,n)
ments.
real*8 dimension(2) :: l
real*8 dimension(2) :: u • note(<LaTeX text>): used for adding
intent(out) l,u notes to the module documentation.
integer*4 optional :: n = 1 • optional, required
end subroutine exp1 • external: used for call-back arguments.
end interface
end python module foo • allocatable: used for Fortran 90/95 allo-
! This file was auto-generated with f2py catable arrays.
! (version:2.298) and modified by pearu. 4. Using f2py one can call arbitrary For-
! See http://cens.ioc.ee/projects/f2py2e/ tran 77/90/95 subroutines and functions from
Python, including Fortran 90/95 module rou-
tines.
Figure 5: Modified signature file foo.pyf
5. Using f2py one can access data in Fortran 77
1. All basic Fortran types are supported. They in- COMMON blocks and variables in Fortran 90/95
clude the following type specifications: modules, including allocatable arrays.
6. Using f2py one can call Python functions from
integer[ | *1 | *2 | *4 | *8 ]
Fortran (call-back functions). f2py supports
logical[ | *1 | *2 | *4 | *8 ]
very flexible hooks for call-back functions.
real[ | *4 | *8 | *16 ]
complex[ | *8 | *16 | *32 ] 7. Wrapper functions perform the necessary type
double precision, double complex conversations for their arguments resulting in
character[ |*(*)|*1|*2|*3|...] contiguous Numeric arrays that are suitable for
passing to Fortran routines.
In addition, they can all be in the kind-selector
form (e.g. real(kind=8)) or char-selector form 8. f2py generates documentation strings for doc
(e.g. character(len=5)). attributes of the wrapper functions automati-
cally.
2. Arrays of all basic types are supported. Dimen-
sion specifications can be of form <dimension> 9. f2py scans Fortran codes and creates the sig-
or <start>:<end>. In addition, * and : di- nature files. It automatically detects the signa-
mension specifications can be used for input ar- tures of call-back functions, solves argument de-
rays. Dimension specifications may contain also pendencies, decides the order of initialization of
PARAMETER’s. optional arguments, etc.

5
10. f2py automatically generates GNU Makefiles Fortran type C type
for compiling Fortran and C codes, and linking integer *1 char
them to a shared module. f2py detects avail- byte char
able Fortran and C compilers. The supported integer *2 short
compilers include the GNU project C Compiler integer[ | *4] int
(gcc), Compaq Fortran, VAST/f90 Fortran, Ab- integer *8 long long
soft F77/F90, and MIPSpro 7 Compilers, etc. logical *1 char
f2py has been tested to work on the following logical *2 short
platforms: Intel/Alpha Linux, HP-UX, IRIX64. logical[ | *4] int
logical *8 int
11. Finally, the complete f2py User’s Guide is avail- real[ | *4] float
able in various formats (ps, pdf, html, dvi). real *8 double
A mailing list, <[email protected]>, is real *16 long double
open for support and feedback. See the FPIG’s complex[ | *8] struct {float r,i;}
home page for more information [5]. complex *16 struct {double r,i;}
complex *32 struct {long double r,i;}
character[*...] char *
5 Implementation Issues
Table 1: Mapping Fortran types to C types.
The Fortran to Python interface can be thought of
as a three layer “sandwich” of different languages:
Python, C, and Fortran. This arrangement has two
interfaces: Python-C and C-Fortran. Since Python Unfortunately, there are Fortran compilers that use
itself is written in C, there are no basic difficulties symbols in constructing low-level routine names that
in implementing the Python-C interface [9]. The C- are not valid for C. For example, the (IRIX64) MIP-
Fortran interface, on the other hand, results in many Spro 7 Compilers use ‘$’ character in the low-level
platform and compiler specific issues that have to be names of module routines which makes it impossible
dealt with. We will now discuss these issues in some (at least directly) to call such routines from C when
detail and describe how they are solved in FPIG. using the MIPSpro 7 C Compiler.
In order to overcome this difficulty, FPIG intro-
5.1 Mapping Fortran Types to C duces an unique solution: instead of using low-level
symbols for calling Fortran module routines from C,
Types the references to such routines are determined at run-
Table 1 defines how Fortran types are mapped to C time by using special wrappers. These wrappers are
types in f2py. Users may redefine these mappings called once during the initialization of an extension
by creating a .f2py f2cmap file in the working direc- module. They are simple Fortran subroutines that
tory. This file should contain a Python dictionary of use a Fortran module and call another C function
dictionaries, e.g. {’real’:{’low’:’float’}}, that with Fortran module routines as arguments in order
informs f2py to map Fortran type real(low) to C to save their references to C global variables that are
type float (here PARAMETER low = ...). later used for calling the corresponding Fortran mod-
ule routines. This arrangement is set up as follows.
Consider the following Fortran 90 module with the
5.2 Calling Fortran (Module) Rou-
subroutine bar:
tines
module fun
When mixing Fortran and C codes, one has to know subroutine bar()
how function names are mapped to low-level symbols end
in their object files. Different compilers may use dif- end
ferent conventions for this purpose. For example, gcc
appends the underscore to a Fortran routine name. Figure 6 illustrates a Python C/API extension mod-
Other compilers may use upper case names, prepend ule for accessing the F90 module subroutine bar from
or append different symbols to Fortran routine names Python. When the Python module foo is loaded,
or both. In any case, if the low-level symbols corre- finitbar is called. finitbar calls init bar by pass-
sponding to Fortran routines are valid for the C lan- ing the reference of the Fortran 90 module subroutine
guage specification, compiler specific issues can be bar to C where it is saved to the variable bar ptr.
solved by using CPP macro features. Now, when one executes foo.bar() from Python,

6
bar ptr is used in bar capi to call the F90 module tion returns a composed type such as COMPLEX or
subroutine bar. CHARACTER-array then calling this function directly
from C may not work for all compilers, as C func-
#include "Python.h"
tions are not supposed to return such references. In
...
order to avoid this, FPIG constructs an additional
char *bar_ptr;
Fortran wrapper subroutine for each such Fortran
void init_bar(char *bar) {
function. These wrappers call just the corresponding
bar_ptr = bar;
functions in the Fortran layer and return the result
}
to C through its first argument.
static PyObject *
bar_capi(PyObject *self,PyObject *args) {
... 5.4 Accessing Fortran Data
(*((void *)bar_ptr))(); In Fortran one can use COMMON blocks and Fortran
... module variables to save data that is accessible from
} other routines. Using FPIG, one can also access these
static PyMethodDef data containers from Python. To achieve this, FPIG
foo_module_methods[] = { uses special wrapper functions (similar to the ones
{"bar",bar_capi,METH_VARARGS}, used for wrapping Fortran module routines) to save
{NULL,NULL} the references to these data containers so that they
}; can later be used from C.
extern void finitbar_; /* GCC convention */ FPIG can also handle allocatable arrays. For ex-
void initfoo() { ample, if a Fortran array is not yet allocated, then by
... assigning it in Python, the Fortran to Python inter-
finitbar_(init_bar); face will allocate and initialize the array. For exam-
Py_InitModule("foo",foo_module_methods); ple, the F90 module allocatable array bar defined in
...
}
module fun
integer, allocatable :: bar(:)
Figure 6: Sketch of Python C/API for accessing end module
F90 module subroutine bar. The Fortran function
finitbar is defined in Fig. 7. can be allocated from Python as follows
>>> import foo
>>> foo.fun.bar = [1,2,3,4]
subroutine finitbar(cinit)
use fun
extern cinit 5.5 PyFortranObject
call cinit(bar)
end In general, we would like to access from Python the
following Fortran objects:

Figure 7: Wrapper for passing the reference of bar • subroutines and functions,
to C code. • F90 module subroutines and functions,

Surprisingly, mixing C code and Fortran modules • items in COMMON blocks,


in this way is as portable and compiler independent • F90 module data.
as mixing C and ordinary Fortran 77 code.
Assuming that the Fortran source is available, we can
Note that extension modules generated by f2py ac-
tually use PyFortranObject that implements abovedetermine the signatures of these objects (the full
specification of routine arguments, the layout of For-
described scheme with exchanged functionalities (see
Section 5.5). tran data, etc.). In fact, f2py gets this information
while scanning the Fortran source.
In order to access these Fortran objects from C, we
5.3 Wrapping Fortran Functions
need to determine their references. Note that the di-
The Fortran language has two types of routines: rect access of F90 module objects is extremely com-
subroutines and functions. When a Fortran func- piler dependent and in some cases even impossible.

7
Therefore, FPIG uses various wrapper functions for But f2py cannot determine the signature of the user
obtaining the references to Fortran objects. These routine boo because the source contains no informa-
wrapper functions are ordinary F77 subroutines that tion at all about the boo specification. Here user
can easily access objects from F90 modules and that needs to provide the signature of boo manually.
pass the references to Fortran objects as C variables.
f2py generated Python C/API extension modules
use PyFortranObject to store the references of For- 6 Future Work
tran objects. In addition to the storing functional-
FPIG can be used to wrap almost any Fortran code.
ity, the PyFortranObject also provides methods for
However, there are still issues that need to be re-
accessing/calling Fortran objects from Python in a
solved. Some of them are listed below:
user-friendly manner. For example, the item a in
COMMON /bar/ a(2) can be accessed from Python as 1. One of the FPIG’s goals is to become as plat-
foo.bar.a. form and compiler independent as possible. Cur-
Detailed examples of PyFortranObject usage can rently FPIG can be used on any UN*X platform
be found in [10]. that has gcc installed in it. In the future, FPIG
should be also tested on Windows systems.

5.6 Callback Functions 2. Another goal of FPIG is to become as sim-


ple to use as possible. To achieve that, FPIG
Fortran routines may have arguments specified as should start using the facilities of distutils,
external. These arguments are functions or subrou- the new Python standard to distribute and build
tines names that the receiving Fortran routine will Python modules. Therefore, a contribution to
call from its body. For such arguments FPIG con- distutils that can handle Fortran extensions
structs a call-back mechanism (originally contributed should be developed.
by Travis Oliphant) that allows Fortran routines to
call Python functions. This is actually realized using 3. Currently users must be aware of the fact that
a C layer between Python and Fortran. Currently, multi-dimensional arrays are stored differently in
the call-back mechanism is compiler independent un- C and Fortran (they must provide transposed
less a call-back function needs to return a composed multi-dimensional arrays to wrapper functions).
type (e.g. COMPLEX). In the future a solution should be found such
The signatures of call-back functions are deter- that users do not need to worry about this rather
mined when f2py scans the Fortran source code. To confusing and technical detail.
illustrate this, consider the following example:
4. Finally, a repository of signature files for widely-
used Fortran libraries (e.g. BLAS, LAPACK,
subroutine foo(bar, fun, boo)
MINPACK, ODEPACK, EISPACK, LINPACK)
integer i
should be provided.
real r
external bar,fun,boo
call bar(i, 1.2) 7 Application to a Large Aero-
r = fun()
call sun(boo) Structural Analysis Frame-
end work
f2py recognizes the signatures of the user routines 7.1 The Need for Python and FPIG
bar and fun using the information contained in the
lines call bar(i, 1.2) and r = fun(): As a demonstration of the power and usefulness of
FPIG, we will present work that has been done at the
subroutine bar(a,b) Aerospace Computing Laboratory at Stanford Uni-
integer a versity. The focus of the research is on aircraft design
real b optimization using high-fidelity analysis tools such as
end Computational Fluid Dynamics (CFD) and Compu-
function fun() tational Structural Mechanics (CSM) [11].
real fun The group’s analysis programs are written mainly
end in Fortran and are the result of many years of de-
velopment. Until now, any researcher that needed to

8
use these tools would have to learn a less than user- Once Python interfaces were created for each For-
friendly interface and become relatively familiar with tran application by running f2py, it was just a mat-
the inner workings of the codes before starting the re- ter of using Python to achieve the final objective of
search itself. The need to couple analyses of different developing an object-oriented framework for our mul-
disciplines revealed the additional inconvenience of tidisciplinary solvers. The Python modules that we
gluing and scripting the different codes with Fortran. designed are discussed in the following section.
It was therefore decided that the existing tools
should be wrapped using an object-oriented language
in order to improve their ease of use and versatil-
7.3 Module Design
ity. The use of several different languages such as The first objective of this effort was to design the
C++, Java and Perl was investigated but Python classes for each type of analysis, each representing
seemed to provide the best solution. The fact that an independent Python module. In our case, we are
it combines scripting capability with a fully-featured interested in performing aero-structural analysis and
object-oriented programming language, and that it optimization of aircraft wings. We therefore needed
has a clean syntax were factors that determined our an analysis tool for the flow (CFD), another for an-
choice. The introduction of tools that greatly facili- alyzing the structure (CSM), as well as a geometry
tate the task of wrapping Fortran with Python pro- database. In addition, we needed to interface these
vided the final piece needed to realize our objective. two tools in order to analyze the coupled system. The
object design for each of these modules should be
7.2 Wrapping the Fortran Programs general enough that the underlying analysis code in
Fortran can be changed without changing the Python
In theory, it would have been possible to wrap our interface. Another requirement was that the modules
Fortran programs with C and then with Python by be usable on their own for single discipline analysis.
hand. However, this would have been a labor inten-
sive task that would detract from our research. The 7.3.1 Geometry
use of tools that automate the task of wrapping has
been extremely useful. The Geometry class provides a database for the outer
The first such tool that we used was PyFort. This mold geometry of the aircraft. This database needs
tool created the C wrappers and Python modules au- to be accessed by both the flow and structural solvers.
tomatically, based on signature files (.pyf) provided It contains a parametric description of the aircraft’s
by the user. Although it made the task of wrapping surface as well as methods that extract and update
considerably easier, PyFort was limited by the fact this information.
that any Fortran data that was needed at the Python
level had to be passed in the argument list of the For- 7.3.2 Flow
tran subroutine. Since the bulk of the data in our pro-
grams is shared by using Fortran 77 common blocks The flow solver was wrapped in a class called Flow.
and Fortran 90 modules, this required adding many The class was designed so that it can wrap any type
more arguments to the subroutine headers. Further- of CFD solver. It contains two main objects: the
more, since Fortran does not allow common block computational mesh and a solver object. A graph
variables or module data to be specified in a subrou- showing the hierarchy of the objects in Flow is shown
tine argument list, a dummy pointer for each desired in Fig. 8. Methods in the flow class include those
variable had to be created and initialized. used for the initialization of all the class components
The search for a better solution to this problem as well as methods that write the current solution to
led us to f2py. Since f2py provides a solution for a file.
accessing common block and module variables, there
was no need to change the Fortran source anymore, 7.3.3 Structure
making the wrapping process even easier. With f2py
we also experienced an increased level of automation The Structure class wraps a structural analysis code.
since it produces the signature files automatically, as The class stores the information about the structure
well as a Makefile for the joint compilation of the itself in an object called Model which also provides
original Fortran and C wrapper codes. This increased methods for changing and exporting its information.
automation did not detract from its flexibility since A list of the objects contained in this class can be
it was always possible to edit the signature files to seen in Fig. 9. Since the Structure class contains
provide different functionality. a dictionary of LoadCase objects, it is able to store

9
Structure

Model
Flow
Mesh Node

Block Element

Surface Group

Solver Material

Parameters LoadCase

Figure 8: The Flow container class. Figure 9: The Structure container class.

and solve multiple load cases, a capability that the


7.4 Results
original Fortran code does not have. In order to visualize results, and because we needed to
view results from multiple disciplines simultaneously,
we selected OpenDX. Output files in DX format are
7.3.4 Aerostructure written at the Python level and the result can be
seen in Fig. 10 for the case of a transonic airliner
The Aerostructure class is the main class in the aero- configuration.
structural analysis module and contains a Geometry, The figure illustrates the multidisciplinary nature
a Flow and a Structure. In addition, the class de- of the problem. The grid pictured in the background
fines all the functions that are necessary to translate is the mesh used by the flow solver and is colored
aerodynamic loads to structural loads and structural by the pressure values computed at the cell centers.
displacements to geometry surface deformations. The wing in the foreground and its outer surface is
One of the main methods of this class is the one clipped to show the internal structural components
that solves the aeroelastic system. This method is which are colored by their stress value.
printed below: In conclusion, f2py and Python have been ex-
tremely useful tools in our pursuit for increasing the
def Iterate(self, load_case): usability and flexibility of existing Fortran tools.
"""Iterates the aero-structural solution."""
self.flow.Iterate()
self._UpdateStructuralLoads()
References
self.structure.CalcDisplacements(load_case) [1] Netlib repository at UTK and ORNL.
self.structure.CalcStresses(load_case) http://www.netlib.org/
self._UpdateFlowMesh()
return [2] Python language.
http://www.python.org/
This is indeed a very readable script, thanks to [3] SWIG — Simplified Wrapper and Interface Gen-
Python, and any high-level changes to the solution erator.
procedure can be easily implemented. The Aerostruc- http://www.swig.org/
ture class also contains methods that export all the
information on the current solution for visualization, [4] PyFort — The Python-Fortran connection tool.
an example of which is shown in the next section. http://pyfortran.sourceforge.net/

10
View publication stats
Figure 10: Aero-structural model and results.

[5] FPIG — Fortran to Python Interface Generator. Aircraft Configurations”, Proceedings of the 37th
http://cens.ioc.ee/projects/f2py2e/ Aerospace Sciences Meeting, AIAA Paper 1999-
0187. Reno, NV, January, 1999
[6] Numerical Extension to Python.
http://numpy.sourceforge.net/

[7] R. L. Graham, D. E. Knuth, and O. Patashnik.


Concrete Mathematics: a foundation for com-
puter science. Addison-Wesley, 1988

[8] P. Peterson. f2py - Fortran to Python Interface


Generator. Second Edition. 2000
http://cens.ioc.ee/projects/f2py2e/usersguide.html

[9] Python Documentation: Extending and Embed-


ding.
http://www.python.org/doc/ext/

[10] P. Peterson. PyFortranObject example usages.


2001
http://cens.ioc.ee/projects/f2py2e/pyfobj.html

[11] Reuther, J., J. J. Alonso, J. R. R. A. Mar-


tins, and S. C. Smith. “A Coupled Aero-
Structural Optimization Method for Complete

11

You might also like