如何使用 ctype 将字符串数组从 fortran dll 传递到 python

问题描述 投票:0回答:1

我想使用 ctype 读取带有 fortran dll 的文件。

我的文件结构是:

AX

BX

… .

4.0 5.0 6.9

1.2 8.0 7.0

… … …

为了读取文件,我有 PATH 传递给 dll fortran 并从 Ax、BX 等获取字符数组,并从数字获取浮点数组。

我在获取字符串数组时遇到问题。

Python代码:

import ctypes
import numpy as np
from numpy.ctypeslib import ndpointer
import os


def Import_DLL():         
    
    PATH = os.path.dirname(os.path.realpath(__file__))
    Lib = ctypes.CDLL(os.path.join(PATH,"./DLL_read.dll"))
    return Lib


def Decla_Arg():           
    
    Lib.open_file.argtypes = [ctypes.c_int, ctypes.c_char_p,ctypes.c_int]
    Lib.open_file.restype = None

    Lib.get_char_col.argtypes = [ctypes.c_int, ctypes.POINTER(ctypes.c_int), ndpointer(dtype=np.dtype('a16'))]
    Lib.get_char_col.restype = None

    Lib.get_float.argtypes = [ctypes.c_int, ctypes.c_int, ndpointer(dtype=ctypes.c_float)]
    Lib.get_float.restype = None


def open_file(FicWxx,PATH):
    Lib.open_file(FicWxx,PATH.encode("utf-8"),len(PATH))
    return

def get_char_col(FicWxx,nliais):
    z=[' ' for i in range(nliais)]
    #z=[]
    elem=np.asarray(z, dtype = np.dtype('a16'))
    nliais = ctypes.c_int(nliais)
    Lib.get_char_col(FicWxx, nliais, elem)
    return elem

def get_res_type(FicWxx, nliais):
   
    param=np.zeros(shape=(3 , nliais),dtype=ctypes.c_float)
    nliais = ctypes.c_int(nliais)
    Lib.get_float(FicWxx, nliais,param)
    return param

# --------------  ___main___  --------------------------------
if __name__ == "__main__":

    Lib=Import_DLL()
    Decla_Arg()
    nliais=3
    FicWxx = 15
    PATH ="......\\test.txt"
    open_file(FicWxx,PATH)

    elem = get_char_col(FicWxx, nliais)
    print("elem =", elem)
  
    param = get_res_type(FicWxx, nliais)
    print("param =", param)




    

FORTRAN 代码:

            
      module read_file
          USE iso_fortran_env
          USE,INTRINSIC :: ISO_C_BINDING
          implicit none
          
          
      contains
      
          subroutine OPEN_FILE(FicWxx,path_cptr,lenpath_cptr)  BIND(C)
              !DEC$ ATTRIBUTES DLLEXPORT :: OPEN_FILE
              integer (KIND=C_INT)         , intent(in) ,value     :: FicWxx
              type(c_ptr), value :: path_cptr
              integer(c_int), value :: lenpath_cptr
              character(len=lenpath_cptr,kind=c_char), pointer :: PATH
              logical  :: lexist
              
              call c_f_pointer(path_cptr, PATH)                                             
              
              
              inquire(file=trim(PATH),exist=lexist)
              if(.not.lexist) then
                  stop
              else
                  open(FicWxx,file=trim(PATH))  
              end if
              
          end subroutine OPEN_FILE
      
!--------------------------- read file   ----------------------------------------
      
          
          subroutine GET_Char_COL(FicWxx,numel,Py_Elem ) BIND(C) 
              !DEC$ ATTRIBUTES DLLEXPORT :: GET_Char_COL

              integer (KIND=C_INT)       ,value            , intent(in)    :: FicWxx
              integer (KIND=C_INT)                         , intent(in)    :: numel
              type(c_ptr)                , value               :: Py_Elem
              character(KIND=C_char,len=16) ,dimension(:)     ,pointer   :: Elem  
              
              integer                                                        :: n
              
              call c_f_pointer(Py_Elem,Elem)
              
              do n = 1, numel
                 read(FicWxx,*)Elem(n)
             end do 
          end subroutine GET_Char_COL
              
       !     
          subroutine GET_FLOAT(FicWxx,numel,param) BIND(C)
              !DEC$ ATTRIBUTES DLLEXPORT :: GET_FLOAT
      
              integer, parameter                                       :: Ncol=3
              integer (KIND=C_INT)   ,value              , intent(in)  :: FicWxx
              integer (KIND=C_INT)   ,value              , intent(in)  :: numel
              real  (KIND=C_FLOAT),dimension(numel,Ncol), intent(out)  :: param
              
              integer                                                  :: n

              do n = 1, numel
                read(FicWxx,*) param(n,:)
              end do
              
          end subroutine GET_FLOAT
        
      end module read_file
      
   

我用 IFORT intel 编译器编译我的代码:

$ ifort -c main.f90
$ ifort -dll -exe:DLL_read.dll main.obj

当我运行Python代码时,出现错误:OSError:异常:当我使用函数“get_char_col”时堆栈溢出

PS:如果我有一个没有字符串的文件,则代码可以很好地检索浮点数组。

谢谢您的帮助

python string dll fortran ctypes
1个回答
0
投票

经过多次尝试和错误,我终于找到了解决问题的方法。我分享的解决方案可能对其他人有帮助

subroutine GET_Char_COL(FicWxx,numel,Py_Elem ) BIND(C) 
          !DEC$ ATTRIBUTES DLLEXPORT :: GET_Char_COL

          integer (KIND=C_INT)       ,value            , intent(in)    :: FicWxx
          integer (KIND=C_INT)                         , intent(in)    :: numel
          type(c_ptr)                , value               :: Py_Elem
          character(KIND=C_char,len=16) ,dimension(:)     ,pointer   :: Elem  
          
          integer                                                        :: n
          
          call c_f_pointer(Py_Elem,Elem,[numel])  ! numel is Rank-one array .The size must be equal to the rank of Py_Elem 
          
          do n = 1, numel
             read(FicWxx,*)Elem(n)
         end do 
      end subroutine GET_Char_COL
© www.soinside.com 2019 - 2024. All rights reserved.