Calling Fortran from Python

Collapse
This topic is closed.
X
X
 
  • Time
  • Show
Clear All
new posts
  • Mangabasi

    #1

    Calling Fortran from Python

    Howdy,

    I have been trying to call the following Fortran function from Python
    (using Windows XP, Compaq Fortran and Python 2.4). I tried F2Py,
    Pyfort and calldll with no success.

    I think I came very close with calldll. Here is a short summary

    Fortran code:

    SUBROUTINE SAMPLE(IERR1,IE RR2,AIN,AOUT)
    C
    C SIMPLE SAMPLE OF A DLL
    C
    !DEC$ATTRIBUTES DLLEXPORT :: SAMPLE
    !DEC$ATTRIBUTES ALIAS:'SAMPLE' :: SAMPLE
    INTEGER,INTENT( OUT) :: IERR1,IERR2
    REAL*8,INTENT(I N) :: AIN(*)
    REAL*8,INTENT(O UT) :: AOUT(*)
    C
    C *** SET MAXIMUM EXPECTED ELEMENTS OF ARRAY AIN AND AOUT
    C
    PARAMETER (MAXNVIN=101,MA XNVOUT=200)
    C
    C *** SET ERROR INDICATORS TO ZERO
    C
    IERR1=0
    IERR2=0
    C
    C *** GET NUMBER OF INPUT VALUES
    C
    NVIN=AIN(1)
    C *** IF NUMBER EXCEEDS MAXIMUM EXPECTED SET ERRORS AND RETURN
    IF(NVIN .GT. MAXNVIN) THEN
    IERR1=1
    IERR2=1
    RETURN
    ENDIF
    C
    C *** SET NUMBER OF OUTPUT VALUES
    C
    NVOUT=2*NVIN
    C *** IF NUMBER EXCEEDS MAXIMUM EXPECTED SET ERRORS AND RETURN
    IF(NVOUT .GT. MAXNVOUT) THEN
    IERR1=1
    IERR2=2
    RETURN
    ENDIF
    C
    C *** INITIALIZE AOUT INDEX
    C
    JOUT=0
    C
    C *** COMPUTE TWO OUTPUT VALUES FOR EACH INPUT VALUE
    C
    DO I=1,NVIN
    JOUT=JOUT+1
    AOUT(JOUT)=2.*A IN(I+1)
    JOUT=JOUT+1
    AOUT(JOUT)=3.*A IN(I+1)
    END DO
    RETURN
    END

    compiled it to a dll and called this dll from another Fortran program
    with success, so this tells me that dll is OK.

    This is how I tried to call it from python 2.4

    import calldll
    handle = calldll.load_li brary('c:/sample_dll.dll' )
    addr = calldll.get_pro c_address(handl e, 'SAMPLE')
    #so far so good, I got a handle and address
    e1 = 0
    e2 = 0
    ain = [2, 3, 4]
    aout = [ ]
    calldll.call_fo reign_function( addr, 'hhll', 'l',(e1, e2,ain,aout))
    Traceback (most recent call last):
    File "<interacti ve input>", line 1, in ?
    TypeError: an integer is required

    Has anyone provide a similar example with Pyfort, F2Py or calldll?

    Thanks in advance.

  • Robert Kern

    #2
    Re: Calling Fortran from Python

    Mangabasi wrote:
    Has anyone provide a similar example with Pyfort, F2Py or calldll?
    With the latest f2py in numpy:

    $ cat sample.pyf
    ! -*- f90 -*-
    ! Note: the context of this file is case sensitive.

    python module sample ! in
    interface ! in :sample
    subroutine sample(ierr1,ie rr2,ain,aout) ! in :sample:sample. f
    integer intent(out) :: ierr1
    integer intent(out) :: ierr2
    real*8 dimension(*),in tent(in) :: ain

    !! This is what I had to modify from the generated interface. I
    !! changed 'dimension(*)' to 'dimension(len( ain))'.
    real*8 dimension(len(a in)),intent(out ) :: aout
    end subroutine sample
    end interface
    end python module sample

    ! This file was auto-generated with f2py (version:2_3582 ).
    ! See http://cens.ioc.ee/projects/f2py2e/

    ]$ f2py -c -m sample sample.pyf sample.f

    running build
    running config_fc
    running build_src
    building extension "sample" sources
    creating /tmp/tmpZL8qAw
    creating /tmp/tmpZL8qAw/src.macosx-10.3-fat-2.5
    f2py options: []
    f2py: sample.pyf
    Reading fortran codes...
    Reading file 'sample.pyf' (format:free)
    Post-processing...
    Block: sample
    Block: sample
    Post-processing (stage 2)...
    Building modules...
    Building module "sample"...
    Constructing wrapper function "sample"...
    ierr1,ierr2,aou t = sample(ain)
    Wrote C/API module "sample" to file
    "/tmp/tmpZL8qAw/src.macosx-10.3-fat-2.5/samplemodule.c"
    adding '/tmp/tmpZL8qAw/src.macosx-10.3-fat-2.5/fortranobject.c ' to sources.
    adding '/tmp/tmpZL8qAw/src.macosx-10.3-fat-2.5' to include_dirs.

    .... Etc.

    $ ipython
    Activating auto-logging. Current session state plus future input saved.
    Filename : /Users/rkern/.ipython/ipython.log
    Mode : backup
    Output logging : False
    Raw input log : False
    Timestamping : False
    State : active

    In [1]: import sample

    In [2]: sample.sample([1, 2, 3])
    Out[2]: (0, 0, array([ 4., 6., 0.]))


    --
    Robert Kern

    "I have come to believe that the whole world is an enigma, a harmless enigma
    that is made terrible by our own mad attempt to interpret it as though it had
    an underlying truth."
    -- Umberto Eco

    Comment

    • Mangabasi

      #3
      Re: Calling Fortran from Python

      Robert,

      Thanks for your prompt response. I think I got a lot closer but no
      cigar yet.

      This is the output

      C:\fortrandll>f 2py -c -m sample sample.pyf sample.for
      numpy_info:
      FOUND:
      define_macros = [('NUMERIC_VERSI ON', '"\\"24.2\\" "')]
      include_dirs = ['C:\\Python24\\ include']

      running build
      running config_fc
      running build_src
      building extension "sample" sources
      creating c:\docume~1\fb\ locals~1\temp\t mpcosvgv
      creating c:\docume~1\fb\ locals~1\temp\t mpcosvgv\src
      f2py: sample.pyf
      Reading fortran codes...
      Reading file 'sample.pyf'
      Post-processing...
      Block: sample
      Block: sample
      Post-processing (stage 2)...
      Building modules...
      Building module "sample"...
      Constructing wrapper function "sample"...
      ierr1,ierr2,aou t = sample(ain)
      Wrote C/API module "sample" to file "c:\docume~ 1\fb
      \locals~1\temp\ tmpcos
      vgv\src/samplemodule.c"
      adding 'c:\docume~1\fb \locals~1\temp\ tmpcosvgv\src\f ortranobject.c'
      to sources
      ..
      adding 'c:\docume~1\fb \locals~1\temp\ tmpcosvgv\src' to include_dirs.
      copying C:\python24\lib \site-packages\f2py2e \src\fortranobj ect.c -c:
      \docume~1\
      fb\locals~1\tem p\tmpcosvgv\src
      copying C:\python24\lib \site-packages\f2py2e \src\fortranobj ect.h -c:
      \docume~1\
      fb\locals~1\tem p\tmpcosvgv\src
      running build_ext
      No module named msvccompiler in scipy_distutils , trying from
      distutils..
      error: The .NET Framework SDK needs to be installed before building
      extensions f
      or Python.

      I think I have a problem with distutils' msvccompiler.py . It may be
      the MacroExpander in distutils guessing the visual studio path
      incorrectly or something related to the registry keys. Is there a way
      to specify the C compiler path to f2py so that it does not rely on the
      distutils? Or maybe I am totally off base here, I don't know.

      Any thoughts?


      Comment

      • Mangabasi

        #4
        Re: Calling Fortran from Python

        There may be a way to finish this without having to deal with
        distutils.
        F2py created three files so far

        samplemodule.c
        fortranobject.h
        fortranobject.c

        Is there a way to create the sample.pyd from these files?

        Comment

        • Robert Kern

          #5
          Re: Calling Fortran from Python

          Mangabasi wrote:
          Robert,
          >
          Thanks for your prompt response. I think I got a lot closer but no
          cigar yet.
          >
          This is the output
          >
          C:\fortrandll>f 2py -c -m sample sample.pyf sample.for
          numpy_info:
          FOUND:
          define_macros = [('NUMERIC_VERSI ON', '"\\"24.2\\" "')]
          include_dirs = ['C:\\Python24\\ include']
          >
          running build
          running config_fc
          running build_src
          building extension "sample" sources
          creating c:\docume~1\fb\ locals~1\temp\t mpcosvgv
          creating c:\docume~1\fb\ locals~1\temp\t mpcosvgv\src
          f2py: sample.pyf
          Reading fortran codes...
          Reading file 'sample.pyf'
          Post-processing...
          Block: sample
          Block: sample
          Post-processing (stage 2)...
          Building modules...
          Building module "sample"...
          Constructing wrapper function "sample"...
          ierr1,ierr2,aou t = sample(ain)
          Wrote C/API module "sample" to file "c:\docume~ 1\fb
          \locals~1\temp\ tmpcos
          vgv\src/samplemodule.c"
          adding 'c:\docume~1\fb \locals~1\temp\ tmpcosvgv\src\f ortranobject.c'
          to sources
          .
          adding 'c:\docume~1\fb \locals~1\temp\ tmpcosvgv\src' to include_dirs.
          copying C:\python24\lib \site-packages\f2py2e \src\fortranobj ect.c -c:
          \docume~1\
          fb\locals~1\tem p\tmpcosvgv\src
          copying C:\python24\lib \site-packages\f2py2e \src\fortranobj ect.h -c:
          \docume~1\
          fb\locals~1\tem p\tmpcosvgv\src
          running build_ext
          No module named msvccompiler in scipy_distutils , trying from
          distutils..
          error: The .NET Framework SDK needs to be installed before building
          extensions f
          or Python.
          >
          I think I have a problem with distutils' msvccompiler.py . It may be
          the MacroExpander in distutils guessing the visual studio path
          incorrectly or something related to the registry keys. Is there a way
          to specify the C compiler path to f2py so that it does not rely on the
          distutils? Or maybe I am totally off base here, I don't know.
          What C and Fortran compilers are you trying to use? You can look at f2py's help
          for flags that you can use to help control where the compilers get picked up,
          but you can't avoid distutils.

          --
          Robert Kern

          "I have come to believe that the whole world is an enigma, a harmless enigma
          that is made terrible by our own mad attempt to interpret it as though it had
          an underlying truth."
          -- Umberto Eco

          Comment

          • Mangabasi

            #6
            Re: Calling Fortran from Python

            On Apr 4, 12:22 pm, Robert Kern <robert.k...@gm ail.comwrote:
            Mangabasi wrote:
            Robert,
            >
            Thanks for your prompt response. I think I got a lot closer but no
            cigar yet.
            >
            This is the output
            >
            C:\fortrandll>f 2py -c -m sample sample.pyf sample.for
            numpy_info:
            FOUND:
            define_macros = [('NUMERIC_VERSI ON', '"\\"24.2\\" "')]
            include_dirs = ['C:\\Python24\\ include']
            >
            running build
            running config_fc
            running build_src
            building extension "sample" sources
            creating c:\docume~1\fb\ locals~1\temp\t mpcosvgv
            creating c:\docume~1\fb\ locals~1\temp\t mpcosvgv\src
            f2py: sample.pyf
            Reading fortran codes...
            Reading file 'sample.pyf'
            Post-processing...
            Block: sample
            Block: sample
            Post-processing (stage 2)...
            Building modules...
            Building module "sample"...
            Constructing wrapper function "sample"...
            ierr1,ierr2,aou t = sample(ain)
            Wrote C/API module "sample" to file "c:\docume~ 1\fb
            \locals~1\temp\ tmpcos
            vgv\src/samplemodule.c"
            adding 'c:\docume~1\fb \locals~1\temp\ tmpcosvgv\src\f ortranobject.c'
            to sources
            .
            adding 'c:\docume~1\fb \locals~1\temp\ tmpcosvgv\src' to include_dirs.
            copying C:\python24\lib \site-packages\f2py2e \src\fortranobj ect.c -c:
            \docume~1\
            fb\locals~1\tem p\tmpcosvgv\src
            copying C:\python24\lib \site-packages\f2py2e \src\fortranobj ect.h -c:
            \docume~1\
            fb\locals~1\tem p\tmpcosvgv\src
            running build_ext
            No module named msvccompiler in scipy_distutils , trying from
            distutils..
            error: The .NET Framework SDK needs to be installed before building
            extensions f
            or Python.
            >
            I think I have a problem with distutils' msvccompiler.py . It may be
            the MacroExpander in distutils guessing the visual studio path
            incorrectly or something related to the registry keys. Is there a way
            to specify the C compiler path to f2py so that it does not rely on the
            distutils? Or maybe I am totally off base here, I don't know.
            >
            What C and Fortran compilers are you trying to use? You can look at f2py's help
            for flags that you can use to help control where the compilers get picked up,
            but you can't avoid distutils.
            >
            --
            Robert Kern
            >
            "I have come to believe that the whole world is an enigma, a harmless enigma
            that is made terrible by our own mad attempt to interpret it as though it had
            an underlying truth."
            -- Umberto Eco- Hide quoted text -
            >
            - Show quoted text -
            I am using Visual Studio 6.0 and Compaq Visual Fortran 6.6.

            Comment

            • Robert Kern

              #7
              Re: Calling Fortran from Python

              Mangabasi wrote:
              I am using Visual Studio 6.0 and Compaq Visual Fortran 6.6.
              Ah. You can't use VS6 with that version of Python. I believe you need the .NET
              SDK 2003.

              You could also use gcc, but I'm not sure if that will work well with Compaq
              Visual Fortran; you might have to use gfortran.



              --
              Robert Kern

              "I have come to believe that the whole world is an enigma, a harmless enigma
              that is made terrible by our own mad attempt to interpret it as though it had
              an underlying truth."
              -- Umberto Eco

              Comment

              • Mangabasi

                #8
                Re: Calling Fortran from Python

                On Apr 4, 4:39 pm, Robert Kern <robert.k...@gm ail.comwrote:
                Mangabasi wrote:
                I am using Visual Studio 6.0 and Compaq Visual Fortran 6.6.
                >
                Ah. You can't use VS6 with that version of Python. I believe you need the .NET
                SDK 2003.
                >
                You could also use gcc, but I'm not sure if that will work well with Compaq
                Visual Fortran; you might have to use gfortran.
                >

                >
                --
                Robert Kern
                >
                "I have come to believe that the whole world is an enigma, a harmless enigma
                that is made terrible by our own mad attempt to interpret it as though it had
                an underlying truth."
                -- Umberto Eco
                Would Python 2.5 work with Visual Studio 6.6?

                Comment

                • Robert Kern

                  #9
                  Re: Calling Fortran from Python

                  Mangabasi wrote:
                  Would Python 2.5 work with Visual Studio 6.6?
                  No.

                  --
                  Robert Kern

                  "I have come to believe that the whole world is an enigma, a harmless enigma
                  that is made terrible by our own mad attempt to interpret it as though it had
                  an underlying truth."
                  -- Umberto Eco

                  Comment

                  • Mangabasi

                    #10
                    Re: Calling Fortran from Python

                    On Apr 4, 5:48 pm, Robert Kern <robert.k...@gm ail.comwrote:
                    Mangabasi wrote:
                    Would Python 2.5 work with Visual Studio 6.6?
                    >
                    No.
                    >
                    --
                    Robert Kern
                    >
                    "I have come to believe that the whole world is an enigma, a harmless enigma
                    that is made terrible by our own mad attempt to interpret it as though it had
                    an underlying truth."
                    -- Umberto Eco
                    I will try the GCC then. It is a shame that I could not get calldll
                    to work. It was very simple to use. I think I am making a mistake
                    with the argument types but not sure.

                    Thanks for your help, it is greatly appreciated.

                    Comment

                    • Lenard Lindstrom

                      #11
                      Re: Calling Fortran from Python

                      Mangabasi wrote:
                      On Apr 4, 5:48 pm, Robert Kern <robert.k...@gm ail.comwrote:
                      >Mangabasi wrote:
                      >>Would Python 2.5 work with Visual Studio 6.6?
                      >No.
                      >>
                      >--
                      >Robert Kern
                      >>
                      >"I have come to believe that the whole world is an enigma, a harmless enigma
                      > that is made terrible by our own mad attempt to interpret it as though it had
                      > an underlying truth."
                      > -- Umberto Eco
                      >
                      I will try the GCC then. It is a shame that I could not get calldll
                      to work. It was very simple to use. I think I am making a mistake
                      with the argument types but not sure.
                      >
                      Thanks for your help, it is greatly appreciated.
                      >
                      Did you try ctypes?
                      >>from ctypes import *
                      >>sample=cdll.s ample.sample_
                      >>sample.restyp e=None
                      >>sample.argtyp es=[POINTER(c_int), POINTER(c_int), POINTER(c_doubl e),
                      POINTER(c_doubl e)]
                      >>e1 = c_int(0)
                      >>e2 = c_int(0)
                      >>ain = (c_double*3)(2. 0, 3.0, 4.0)
                      >>aout = (c_double*4)()
                      >>sample(e1, e2, ain, aout)
                      >>aout[:]
                      [6.0, 9.0, 8.0, 12.0]
                      >>e1.value
                      0
                      >>e2.value
                      0

                      I compile the SAMPLE example with mingw g77 3.4.5:

                      g77 -shared -o sample.dll sample.for

                      I had to take out the "INTENT(OUT )"s because g77 didn't like them. And
                      "SAMPLE" became "sample_" in the dll. Also note that argument passing to
                      Fortran subroutines is strictly pass-by-reference. Thus the ain pointer.

                      Lenard Lindstrom

                      Comment

                      • Mangabasi

                        #12
                        Re: Calling Fortran from Python

                        On Apr 4, 10:10 pm, Lenard Lindstrom <l...@telus.net wrote:
                        Mangabasi wrote:
                        On Apr 4, 5:48 pm, Robert Kern <robert.k...@gm ail.comwrote:
                        Mangabasi wrote:
                        >Would Python 2.5 work with Visual Studio 6.6?
                        No.
                        >
                        --
                        Robert Kern
                        >
                        "I have come to believe that the whole world is an enigma, a harmless enigma
                        that is made terrible by our own mad attempt to interpret it as though it had
                        an underlying truth."
                        -- Umberto Eco
                        >
                        I will try the GCC then. It is a shame that I could not get calldll
                        to work. It was very simple to use. I think I am making a mistake
                        with the argument types but not sure.
                        >
                        Thanks for your help, it is greatly appreciated.
                        >
                        Did you try ctypes?
                        >
                        >>from ctypes import *
                        >>sample=cdll.s ample.sample_
                        >>sample.restyp e=None
                        >>sample.argtyp es=[POINTER(c_int), POINTER(c_int), POINTER(c_doubl e),
                        POINTER(c_doubl e)]
                        >>e1 = c_int(0)
                        >>e2 = c_int(0)
                        >>ain = (c_double*3)(2. 0, 3.0, 4.0)
                        >>aout = (c_double*4)()
                        >>sample(e1, e2, ain, aout)
                        >>aout[:]
                        [6.0, 9.0, 8.0, 12.0]
                        >>e1.value
                        0
                        >>e2.value
                        0
                        >
                        I compile the SAMPLE example with mingw g77 3.4.5:
                        >
                        g77 -shared -o sample.dll sample.for
                        >
                        I had to take out the "INTENT(OUT )"s because g77 didn't like them. And
                        "SAMPLE" became "sample_" in the dll. Also note that argument passing to
                        Fortran subroutines is strictly pass-by-reference. Thus the ain pointer.
                        >
                        Lenard Lindstrom- Hide quoted text -
                        >
                        - Show quoted text -
                        Lenard,

                        Now I tried it as you suggested. I did not install G77 yet. I tried
                        it with the dll I already had. Something interesting happened:
                        >>from ctypes import *
                        >>sample=cdll.s ample_dll.SAMPL E
                        >>sample.restyp e=None
                        >>sample.argtyp es=[POINTER(c_int), POINTER(c_int), POINTER(c_doubl e), POINTER(c_doubl e)]
                        >>sample.argtyp es=[POINTER(c_int), POINTER(c_int), POINTER(c_doubl e), POINTER(c_doubl e)]
                        >>e1 = c_int(-10)
                        >>e2 = c_int(-10)
                        >>ain = (c_double*3)(2. 0, 3.0, 4.0)
                        >>ain = (c_double*3)(2. 0, 3.0, 4.0)
                        >>aout = (c_double*4)()
                        >>aout = (c_double*4)()
                        >>sample(e1, e2, ain, aout)
                        Traceback (most recent call last):
                        File "<interacti ve input>", line 1, in ?
                        ValueError: Procedure called with not enough arguments (16 bytes
                        missing) or wrong calling convention
                        >>aout[:]
                        [6.0, 9.0, 8.0, 12.0]

                        I got an error message and the expected answer! Any guesses?

                        Comment

                        • Mangabasi

                          #13
                          Re: Calling Fortran from Python

                          On Apr 4, 10:10 pm, Lenard Lindstrom <l...@telus.net wrote:
                          Mangabasi wrote:
                          On Apr 4, 5:48 pm, Robert Kern <robert.k...@gm ail.comwrote:
                          Mangabasi wrote:
                          >Would Python 2.5 work with Visual Studio 6.6?
                          No.
                          >
                          --
                          Robert Kern
                          >
                          "I have come to believe that the whole world is an enigma, a harmless enigma
                          that is made terrible by our own mad attempt to interpret it as though it had
                          an underlying truth."
                          -- Umberto Eco
                          >
                          I will try the GCC then. It is a shame that I could not get calldll
                          to work. It was very simple to use. I think I am making a mistake
                          with the argument types but not sure.
                          >
                          Thanks for your help, it is greatly appreciated.
                          >
                          Did you try ctypes?
                          >
                          >>from ctypes import *
                          >>sample=cdll.s ample.sample_
                          >>sample.restyp e=None
                          >>sample.argtyp es=[POINTER(c_int), POINTER(c_int), POINTER(c_doubl e),
                          POINTER(c_doubl e)]
                          >>e1 = c_int(0)
                          >>e2 = c_int(0)
                          >>ain = (c_double*3)(2. 0, 3.0, 4.0)
                          >>aout = (c_double*4)()
                          >>sample(e1, e2, ain, aout)
                          >>aout[:]
                          [6.0, 9.0, 8.0, 12.0]
                          >>e1.value
                          0
                          >>e2.value
                          0
                          >
                          I compile the SAMPLE example with mingw g77 3.4.5:
                          >
                          g77 -shared -o sample.dll sample.for
                          >
                          I had to take out the "INTENT(OUT )"s because g77 didn't like them. And
                          "SAMPLE" became "sample_" in the dll. Also note that argument passing to
                          Fortran subroutines is strictly pass-by-reference. Thus the ain pointer.
                          >
                          Lenard Lindstrom- Hide quoted text -
                          >
                          - Show quoted text -
                          A little bit of googling solved the problem. instead of
                          >>sample = cdll.sample_dll .SAMPLE
                          I used

                          >>sample = windll.sample_d ll.SAMPLE
                          and now it seems to be working without error messages.

                          Thanks a lot.


                          Comment

                          • Lenard Lindstrom

                            #14
                            Re: Calling Fortran from Python

                            Mangabasi wrote:
                            A little bit of googling solved the problem. instead of
                            >
                            >>>sample = cdll.sample_dll .SAMPLE
                            >
                            I used
                            >
                            >
                            >>>sample = windll.sample_d ll.SAMPLE
                            >
                            and now it seems to be working without error messages.
                            >
                            Thanks a lot.
                            >
                            >
                            I remember someone on the ctypes mailing list mentioning that g77 uses
                            the C calling convention for exported functions. Other compilers might
                            default to standard calls. At least with ctypes one can tinker with
                            calling convention and function arguments to make a call work.

                            Lenard

                            Comment

                            Working...