Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Why can I call Fortran subroutine through f2py without having right number of inputs?

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!

like image 416
zyy Avatar asked Mar 14 '19 03:03

zyy


People also ask

How does F2PY work?

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.

How do I use subroutine in Fortran?

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.

Can we call a subroutine in an subroutine Fortran?

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.

What does a Fortran subroutine return?

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.


1 Answers

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).

like image 160
Warren Weckesser Avatar answered Oct 19 '22 10:10

Warren Weckesser