3

ctypes を使用して Python から Fortran 関数を呼び出そうとしています。サブルーチンと関数 (両方とも同じ機能) から結果を取得しようとしましたが、サブルーチンがうまく機能しているにもかかわらず、関数から期待される出力を取得できません。問題は、サブルーチンの代わりに Fortran 関数を使用するライブラリがたくさんあることです。Fortran 関数と ctypes に問題はありますか?

Fortran コードの一部:

MODULE Vector
! Public types
 TYPE VectorType
    PRIVATE
    DOUBLE PRECISION, DIMENSION(3):: components = 0.0d0
 END TYPE VectorType
!---------------------------------------------------------------------    
 CONTAINS 
!---------------------------------------------------------------------
 SUBROUTINE newVect(this,vectorIn)
 TYPE (VectorType),       INTENT(OUT):: this
 DOUBLE PRECISION, DIMENSION(3), INTENT(IN)::vectorIn

   this%components = (/vectorIn(1), vectorIn(2), vectorIn(3)/)

 END SUBROUTINE newVect
!---------------------------------------------------------------------
 SUBROUTINE subVect(this,vectorOut)

 TYPE(VectorType), INTENT (OUT):: vectorOut
 TYPE(VectorType), INTENT (IN) :: this

   vectorOut%components = this%components

 END SUBROUTINE subVect
!----------------------------------------------------------------------
 TYPE(VectorType) FUNCTION getVect(this) RESULT(vectorOut)

 TYPE(VectorType), INTENT (IN) :: this

   vectorOut%components = this%components

  END FUNCTION getVect
!--------------------------------------------------------------------
END MODULE Vector

私が使用しているPythonコードは次のとおりです。

import ctypes
import numpy as np

class _VectorType(ctypes.Structure):
    _fields_ = [('components',  ctypes.c_double*3)]


lib_gen_ctypes = '/local/scratch/jfreixa/lib/lib_ctypes_vector.so'

try_ctypes = ctypes.CDLL(lib_gen_ctypes,ctypes.RTLD_GLOBAL)

class vector(object):

    _ctypes_newVect = try_ctypes['Vector.newVect_']
    _ctypes_subVect = try_ctypes['Vector._subVect_']
    _ctypes_getVect = try_ctypes['Vector.getVect_']

    vector_pointer = ctypes.POINTER(_VectorType)

    _ctypes_getVect.argtypes = [vector_pointer,]
    _ctypes_getVect.restype  = _VectorType


    def __init__(self,*args):
        self._vector = _VectorType()
        self._newVect(*args)

    def _newVect(self,vectIn):
        pdb.set_trace()
        c_vect = (ctypes.c_double*3)(*vectIn)
        self._ctypes_newVect(self._vector,c_vect)

    def subVect(self):
        pdb.set_trace()
        c_vect =  _VectorType()
        self._ctypes_subVect(ctypes.byref(self._vector),ctypes.byref(c_vect))
        print c_vect.components[:]
        return np.array(c_vect.components[:])

    def getVect(self):
        pdb.set_trace()
        c_vect = self._ctypes_getVect(ctypes.byref(self._vector))
        vect = self._ctypes_getVect(self.vector_pointer.from_address(ctypes.addressof(c_vect)))
        print vect.components[:]
        return np.array(vect.components[:])

関数については、多くのことを試しましたが、正しい結果が得られませんでした。プログラムの一部を実行するには、次を試してください。

import pyctp.vector
newVect = pyctp.vector.vector((1.0,2.0,3.0))
newVect.subVect()
newVect.getVect()

サブルーチン呼び出しは期待されるベクトルを返しますが、関数呼び出しはヌル ベクトルまたはガベージでいっぱいのベクトルを返します。

4

1 に答える 1

5

まず、Python から見えるようにするすべてのプロシージャと型に bind(C) 属性を配置する必要があります。すべての Fortran 型は iso_c_binding から取得する必要があります。たとえば、real(c_double)代わりに使用double precisionすると、C と相互運用可能な型であることが確実になります。

MODULE Vector
use iso_c_binding
! Public types
TYPE,bind(C) :: VectorType
    real(c_double), DIMENSION(3):: components = 0.0d0
END TYPE VectorType

CONTAINS

!---------------------------------------------------------------------
SUBROUTINE newVect(this,vectorIn) bind(c,name="newVect")
   TYPE (VectorType),       INTENT(OUT):: this
   real(c_double), DIMENSION(3), INTENT(IN)::vectorIn

   this%components = (/vectorIn(1), vectorIn(2), vectorIn(3)/)

END SUBROUTINE newVect
!---------------------------------------------------------------------
SUBROUTINE subVect(this,vectorOut) bind(c,name="subVect")
   TYPE(VectorType), INTENT (OUT):: vectorOut
   TYPE(VectorType), INTENT (IN) :: this

   vectorOut%components = this%components

END SUBROUTINE subVect
!----------------------------------------------------------------------
TYPE(VectorType) FUNCTION getVect(this) RESULT(vectorOut) bind(c,name="getVect")

TYPE(VectorType), INTENT (IN) :: this

    vectorOut%components = this%components

END FUNCTION getVect
!--------------------------------------------------------------------
END MODULE Vector

次に、Python ですべての引数を参照として渡します。

import ctypes
import numpy as np

class _VectorType(ctypes.Structure):
    _fields_ = [('components',  ctypes.c_double*3)]

lib_gen_ctypes = 'lib_ctypes_vector.so'
try_ctypes = ctypes.CDLL(lib_gen_ctypes,ctypes.RTLD_GLOBAL)

class vector(object):

    _ctypes_newVect = try_ctypes['newVect']
    _ctypes_subVect = try_ctypes['subVect']
    _ctypes_getVect = try_ctypes['getVect']

    vector_pointer = ctypes.POINTER(_VectorType)

    _ctypes_getVect.argtypes = [vector_pointer,]
    _ctypes_getVect.restype  = _VectorType

    def __init__(self,*args):
        self._vector = _VectorType()
        self._newVect(*args)

    def _newVect(self,vectIn):
        c_vect = (ctypes.c_double*3)(*vectIn)
        self._ctypes_newVect(ctypes.byref(self._vector),ctypes.byref(c_vect))

    def subVect(self):
        c_vect =  _VectorType()
        self._ctypes_subVect(ctypes.byref(self._vector),ctypes.byref(c_vect))
        return np.array(c_vect.components[:])

    def getVect(self):
        c_vect = self._ctypes_getVect(ctypes.byref(self._vector))
        return np.array(vect.components[:])

getVect からの結果は既に VectorType であるため、そのコンポーネントに直接アクセスできます。

于 2015-09-22T15:10:43.773 に答える