Movatterモバイル変換


[0]ホーム

URL:


SciPy

Three ways to wrap - getting started

Wrapping Fortran or C functions to Python using F2PY consists of thefollowing steps:

  • Creating the so-called signature file that contains descriptions ofwrappers to Fortran or C functions, also called as signatures of thefunctions. In the case of Fortran routines, F2PY can create initialsignature file by scanning Fortran source codes andcatching all relevant information needed to create wrapperfunctions.
  • Optionally, F2PY created signature files can be edited to optimizewrappers functions, make them “smarter” and more “Pythonic”.
  • F2PY reads a signature file and writes a Python C/API module containingFortran/C/Python bindings.
  • F2PY compiles all sources and builds an extension module containingthe wrappers. In building extension modules, F2PY usesnumpy_distutils that supports a number of Fortran 77/90/95compilers, including Gnu, Intel,Sun Fortre, SGI MIPSpro, Absoft, NAG, Compaq etc. compilers.

Depending on a particular situation, these steps can be carried outeither by just in one command or step-by-step, some steps can beomitted or combined with others.

Below I’ll describe three typical approaches of using F2PY.The followingexample Fortran 77 code will be used forillustration:

CFILE:FIB1.FSUBROUTINEFIB(A,N)CCCALCULATEFIRSTNFIBONACCINUMBERSCINTEGERNREAL*8A(N)DOI=1,NIF(I.EQ.1)THENA(I)=0.0D0ELSEIF(I.EQ.2)THENA(I)=1.0D0ELSEA(I)=A(I-1)+A(I-2)ENDIFENDDOENDCENDFILEFIB1.F

The quick way

The quickest way to wrap the Fortran subroutineFIB to Python isto run

f2py-cfib1.f-mfib1

This command builds (see-c flag, executef2py withoutarguments to see the explanation of command line options) an extensionmodulefib1.so (see-m flag) to the current directory. Now, inPython the Fortran subroutineFIB is accessible viafib1.fib:

>>>importnumpy>>>importfib1>>>printfib1.fib.__doc__fib - Function signature:  fib(a,[n])Required arguments:  a : input rank-1 array('d') with bounds (n)Optional arguments:  n := len(a) input int>>>a=numpy.zeros(8,'d')>>>fib1.fib(a)>>>printa[  0.   1.   1.   2.   3.   5.   8.  13.]

Note

  • Note that F2PY found that the second argumentn is thedimension of the first array argumenta. Since by default allarguments are input-only arguments, F2PY concludes thatn canbe optional with the default valuelen(a).

  • One can use different values for optionaln:

    >>>a1=numpy.zeros(8,'d')>>>fib1.fib(a1,6)>>>printa1[ 0.  1.  1.  2.  3.  5.  0.  0.]

    but an exception is raised when it is incompatible with the inputarraya:

    >>>fib1.fib(a,10)fib:n=10Traceback (most recent call last):  File"<stdin>", line1, in?fib.error:(len(a)>=n) failed for 1st keyword n>>>

    This demonstrates one of the useful features in F2PY, that it,F2PY implements basic compatibility checks between relatedarguments in order to avoid any unexpected crashes.

  • When a NumPy array, that is Fortran contiguous and has a dtypecorresponding to presumed Fortran type, is used as an input arrayargument, then its C pointer is directly passed to Fortran.

    Otherwise F2PY makes a contiguous copy (with a proper dtype) ofthe input array and passes C pointer of the copy to Fortransubroutine. As a result, any possible changes to the (copy of)input array have no effect to the original argument, asdemonstrated below:

    >>>a=numpy.ones(8,'i')>>>fib1.fib(a)>>>printa[1 1 1 1 1 1 1 1]

    Clearly, this is not an expected behaviour. The fact that theabove example worked withdtype=float is consideredaccidental.

    F2PY providesintent(inplace) attribute that would modifythe attributes of an input array so that any changes made byFortran routine will be effective also in input argument. For example,if one specifiesintent(inplace)a (see below, how), thenthe example above would read:

    >>>a=numpy.ones(8,'i')>>>fib1.fib(a)>>>printa[  0.   1.   1.   2.   3.   5.   8.  13.]

    However, the recommended way to get changes made by Fortransubroutine back to python is to useintent(out) attribute. Itis more efficient and a cleaner solution.

  • The usage offib1.fib in Python is very similar to usingFIB in Fortran. However, usingin situ output arguments inPython indicates a poor style as there is no safety mechanismin Python with respect to wrong argument types. When using Fortranor C, compilers naturally discover any type mismatches duringcompile time but in Python the types must be checked inruntime. So, usingin situ output arguments in Python may causedifficult to find bugs, not to mention that the codes will be lessreadable when all required type checks are implemented.

Though the demonstrated way of wrapping Fortran routines to Pythonis very straightforward, it has several drawbacks (see the commentsabove). These drawbacks are due to the fact that there is no waythat F2PY can determine what is the actual intention of one or theother argument, is it input or output argument, or both, orsomething else. So, F2PY conservatively assumes that all argumentsare input arguments by default.

However, there are ways (see below) how to “teach” F2PY about thetrue intentions (among other things) of function arguments; and thenF2PY is able to generate more Pythonic (more explicit, easier touse, and less error prone) wrappers to Fortran functions.

The smart way

Let’s apply the steps of wrapping Fortran functions to Python one byone.

  • First, we create a signature file fromfib1.f by running

    f2pyfib1.f-mfib2-hfib1.pyf

    The signature file is saved tofib1.pyf (see-h flag) andits contents is shown below.

    !    -*- f90 -*-python module fib2 ! in     interface  ! in :fib2        subroutine fib(a,n) ! in :fib2:fib1.f            real*8 dimension(n) :: a            integer optional,check(len(a)>=n),depend(a) :: n=len(a)        end subroutine fib    end interface end python module fib2! This file was auto-generated with f2py (version:2.28.198-1366).! See http://cens.ioc.ee/projects/f2py2e/
  • Next, we’ll teach F2PY that the argumentn is an input argument(useintent(in) attribute) and that the result, i.e. thecontents ofa after calling Fortran functionFIB, should bereturned to Python (useintent(out) attribute). In addition, anarraya should be created dynamically using the size given bythe input argumentn (usedepend(n) attribute to indicatedependence relation).

    The content of a modified version offib1.pyf (saved asfib2.pyf) is as follows:

    !    -*- f90 -*-python module fib2     interface        subroutine fib(a,n)            real*8 dimension(n),intent(out),depend(n) :: a            integer intent(in) :: n        end subroutine fib    end interface end python module fib2
  • And finally, we build the extension module by running

    f2py-cfib2.pyffib1.f

In Python:

>>>importfib2>>>printfib2.fib.__doc__fib - Function signature:  a = fib(n)Required arguments:  n : input intReturn objects:  a : rank-1 array('d') with bounds (n)>>>printfib2.fib(8)[  0.   1.   1.   2.   3.   5.   8.  13.]

Note

  • Clearly, the signature offib2.fib now corresponds to theintention of Fortran subroutineFIB more closely: given thenumbern,fib2.fib returns the firstn Fibonacci numbersas a NumPy array. Also, the new Python signaturefib2.fibrules out any surprises that we experienced withfib1.fib.
  • Note that by default using singleintent(out) also impliesintent(hide). Argument that hasintent(hide) attributespecified, will not be listed in the argument list of a wrapperfunction.

The quick and smart way

The “smart way” of wrapping Fortran functions, as explained above, issuitable for wrapping (e.g. third party) Fortran codes for whichmodifications to their source codes are not desirable nor evenpossible.

However, if editing Fortran codes is acceptable, then the generationof an intermediate signature file can be skipped in mostcases. Namely, F2PY specific attributes can be inserted directly toFortran source codes using the so-called F2PY directive. A F2PYdirective defines special comment lines (starting withCf2py, forexample) which are ignored by Fortran compilers but F2PY interpretsthem as normal lines.

Here is shown amodified version of the example Fortran code, savedasfib3.f:

CFILE:FIB3.FSUBROUTINEFIB(A,N)CCCALCULATEFIRSTNFIBONACCINUMBERSCINTEGERNREAL*8A(N)Cf2pyintent(in)nCf2pyintent(out)aCf2pydepend(n)aDOI=1,NIF(I.EQ.1)THENA(I)=0.0D0ELSEIF(I.EQ.2)THENA(I)=1.0D0ELSEA(I)=A(I-1)+A(I-2)ENDIFENDDOENDCENDFILEFIB3.F

Building the extension module can be now carried out in one command:

f2py-c-mfib3fib3.f

Notice that the resulting wrapper toFIB is as “smart” as inprevious case:

>>>importfib3>>>printfib3.fib.__doc__fib - Function signature:  a = fib(n)Required arguments:  n : input intReturn objects:  a : rank-1 array('d') with bounds (n)>>>printfib3.fib(8)[  0.   1.   1.   2.   3.   5.   8.  13.]

Table Of Contents

Previous topic

F2PY Users Guide and Reference Manual

Next topic

Signature file

Quick search

  • © Copyright 2008-2018, The SciPy community.
  • Last updated on Jul 24, 2018.
  • Created usingSphinx 1.6.6.

[8]ページ先頭

©2009-2025 Movatter.jp