how to passing arrays of strings from fortran dll to python with ctype

Question:

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

Asked By: didie

||

Answers:

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
Answered By: didie
Categories: questions Tags: , , , ,
Answers are sorted by their score. The answer accepted by the question owner as the best is marked with
at the top-right corner.