I want to read a file with a fortran dll using ctype.
the structure of my file is:
AX
BX
… .
4.0 5.0 6.9
1.2 8.0 7.0
… … …
for read the file , i have PATH to pass to dll fortran and get a character array from Ax,BX,… and float array from the number.
i have problem with get string array .
python code:
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 code :
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
i compile my code with IFORT intel compiler:
$ ifort -c main.f90
$ ifort -dll -exe:DLL_read.dll main.obj
when I run the python code, i get error: OSError: exception: stack overflow when i use function" get_char_col"
PS: if I have a file without the string , the code works well to retrieve the float array.
Thank you for your help
After several trials and errors I finally managed to find a solution to my problem. I share the solution it might help someone else
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