File size: 3,989 Bytes
c011401
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
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

Title:     Wrapping F compiled Fortran 90 modules with F2PY
           ================================================

Rationale: The F compiler does not support external procedures which
           makes it impossible to use it in F2PY in a normal way.
           This document describes a workaround to this problem so
           that F compiled codes can be still wrapped with F2PY.

Author:    Pearu Peterson
Date:      May 8, 2002

Acknowledgement: Thanks to Siegfried Gonzi who hammered me to produce
           this document.

Normally wrapping Fortran 90 modules to Python using F2PY is carried
out with the following command

  f2py -c -m fun foo.f90

where file foo.f90 contains, for example,

module foo
  public :: bar
  contains
  subroutine bar (a)
    integer,intent(inout) ::  a
    print *,"Hello from foo.bar"
    print *,"a=",a
    a = a + 5
    print *,"a=",a
  end subroutine bar
end module foo

Then with a supported F90 compiler (running `f2py -c --help-compiler'
will display the found compilers) f2py will generate an extension
module fun.so into the current directory and the Fortran module foo
subroutine bar can be called from Python as follows

>>> import fun
>>> print fun.foo.bar.__doc__
bar - Function signature:
  bar(a)
Required arguments:
  a : in/output rank-0 array(int,'i')

>>> from Numeric import array
>>> a = array(3)
>>> fun.foo.bar(a)
 Hello from foo.bar
 a=           3
 a=           8
>>> a
8
>>>

This works nicely with all supported Fortran compilers.

However, the F compiler (http://www.fortran.com/F/compilers.html) is
an exception. Namely, the F compiler is designed to recognize only
module procedures (and main programs, of course) but F2PY needs to
compile also the so-called external procedures that it generates to
facilitate accessing Fortran F90 module procedures from C and
subsequently from Python.  As a result, wrapping F compiled Fortran
procedures to Python is _not_ possible using the simple procedure as
described above. But, there is a workaround that I'll describe below
in five steps.

1) Compile foo.f90:

   F -c foo.f90

This creates an object file foo.o into the current directory.

2) Create the signature file:

  f2py foo.f90 -h foo.pyf

This creates a file foo.pyf containing

module foo ! in foo.f90
    real public :: bar
    subroutine bar(a) ! in foo.f90:foo
        integer intent(inout) :: a
    end subroutine bar
end module foo

3) Open the file foo.pyf with your favorite text editor and change the
   above signature to

python module foo
  interface
    subroutine bar(a)
        fortranname foo_MP_bar
        intent(c) bar
        integer intent(in,out) :: a
    end subroutine bar
  end interface
end python module foo

The most important modifications are

 a) adding `python' keyword everywhere before the `module' keyword

 b) including an `interface' block around the all subroutine blocks.

 c) specifying the real symbol name of the subroutine using
    `fortranname' statement. F generated symbol names are in the form
    <module name>_MP_<subroutine name>

 d) specifying that subroutine is `intent(c)'.

Notice that the `intent(inout)' attribute is changed to
`intent(in,out)' that instructs the wrapper to return the modified
value of `a'.

4) Build the extension module

   f2py -c foo.pyf foo.o --fcompiler=Gnu /opt/F/lib/quickfit.o \
       /opt/F/lib/libf96.a

This will create the extension module foo.so into the current
directory.  Notice that you must use Gnu compiler (gcc) for linking.
And the paths to F specific object files and libraries may differ for
your F installation.

5) Finally, we can call the module subroutine `bar' from Python

>>> import foo
>>> print foo.bar.__doc__
bar - Function signature:
  a = bar(a)
Required arguments:
  a : input int
Return objects:
  a : int

>>> foo.bar(3)
8
>>>

Notice that the F compiled module procedures are called as ordinary
external procedures. Also I/O seems to be lacking for F compiled
Fortran modules.

Enjoy,
	Pearu