I am trying to learn f2py
and I have the following Fortran code
subroutine fibonacci(a, n)
implicit none
integer :: i, n
double precision :: a(n)
do i = 1, n
if (i .eq. 1) then
a(i) = 0d0
elseif (i .eq. 2) then
a(i) = 1d0
else
a(i) = a(i - 1) + a(i - 2)
endif
enddo
end subroutine fibonacci
which is compiled with f2py -c fibonacci.f -m fibonacci
and later called in Python
import numpy
import fibonacci
a = numpy.zeros(13)
fibonacci.fibonacci(a)
print a
The subroutine fibonacci
called in Python did not get enough number of arguments, but the code mysteriously worked. By the way, calling the subroutine fibonacci
with fibonacci.fibonacci(a, len(a))
also worked!
Could someone please explain this? Thanks!
How does F2PY work? F2PY works by creating an extension module that can be imported in Python using the import keyword. The module contains automatically generated wrapper functions that can be called from Python, acting as an interface between Python and the compiled Fortran routines.
In the main program, a subroutine is activated by using a CALL statement which include the subroutine name followed by the list of inputs to and outputs from the subroutine surrounded by parenthesis. The inputs and outputs are collectively called the arguments.
Normally you put all procedures in a module and then use the module. If, as your question suggest make all procedures as internal to your main program, there is no problem in calling them. Just invoke them normally using the call statement, or by using the function name with the argument list.
Return (in Subroutines) A return statement in a subroutine instructs Fortran to terminate the subroutine and return to the main program at the point where it departed. Thus it works like a stop statement in the main program, halting the program prematurely before the final end statement.
f2py
knows that a
and n
are function parameters, and from the declaration
double precision :: a(n)
it is able to infer that n
is the length of a
. NumPy arrays have a length, so there is no need for the parameter n
in the Python wrapper, and f2py
makes it optional.
Note that the code generated by f2py
checks that you don't give a value of n
that is too big:
In [19]: a = np.zeros(10)
In [20]: fibonacci.fibonacci(a, 99)
---------------------------------------------------------------------------
error Traceback (most recent call last)
<ipython-input-20-e9497469fd10> in <module>()
----> 1 fibonacci.fibonacci(a, 99)
error: (len(a)>=n) failed for 1st keyword n: fibonacci:n=99
You can give a smaller value:
In [21]: a = np.zeros(10)
In [22]: fibonacci.fibonacci(a, 6)
In [23]: a
Out[23]: array([0., 1., 1., 2., 3., 5., 0., 0., 0., 0.])
You might find it useful to generate and look at the interface file that f2py
produces for this function. The command
f2py -h fibonacci.pyf fibonacci.f
displays
Reading fortran codes...
Reading file 'fibonacci.f' (format:fix,strict)
Post-processing...
Block: fibonacci
Post-processing (stage 2)...
Saving signatures to file "./fibonacci.pyf"
and generates the file fibonacci.pyf
, which contains
! -*- f90 -*-
! Note: the context of this file is case sensitive.
subroutine fibonacci(a,n) ! in fibonacci.f
double precision dimension(n) :: a
integer, optional,check(len(a)>=n),depend(a) :: n=len(a)
end subroutine fibonacci
! This file was auto-generated with f2py (version:2).
! See http://cens.ioc.ee/projects/f2py2e/
You can see from the generated declaration
integer, optional,check(len(a)>=n),depend(a) :: n=len(a)
that f2py
has inferred that n
should be an optional parameter whose value must not exceed the length of a
and whose default value is len(a)
.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With