Wrap C struct with array member for access in python: SWIG? cython? ctypes?

后端 未结 5 1167
囚心锁ツ
囚心锁ツ 2021-02-03 10:19

I want to access a C function that returns a struct containing double arrays (where the lengths of these arrays is given by other int members of the struct) from python. The dec

5条回答
  •  渐次进展
    2021-02-03 10:48

    Using SWIG requires a typemap for the entire struct. Tyepmaps for only the pointer members are not enough, since they don't have the context to know what size to initialize the NumPy arrays with. I managed to get what I wanted with the following typemaps (which was basically copy & paste from numpy.i and adapt to my needs, probably not very robust):

    %typemap (in,numinputs=0) element * (element temp) {
      $1 = &temp;
    }
    
    %typemap (argout) element * {
      /* weight */
      {
        npy_intp dims[1] = { $1->ngi };
        PyObject * array = PyArray_SimpleNewFromData(1, dims, NPY_DOUBLE, (void*)($1->weight));
        if (!array) SWIG_fail;
        $result = SWIG_Python_AppendOutput($result,array);
      }
      /* l */
      {
        npy_intp dims[2] = { $1->ngi, $1->dim };
        PyObject * array = PyArray_SimpleNewFromData(2, dims, NPY_DOUBLE, (void*)($1->l));
        if (!array) SWIG_fail;
        $result = SWIG_Python_AppendOutput($result,array);
      }
      /* n */
      {
        npy_intp dims[2] = { $1->ngi, $1->vertices };
        PyObject * array = PyArray_SimpleNewFromData(2, dims, NPY_DOUBLE, (void*)($1->n));
        if (!array) SWIG_fail;
        $result = SWIG_Python_AppendOutput($result,array);
      }
      /* dn */
      {
        npy_intp dims[3] = { $1->ngi, $1->vertices, $1->dim };
        PyObject * array = PyArray_SimpleNewFromData(3, dims, NPY_DOUBLE, (void*)($1->dn));
        if (!array) SWIG_fail;
        $result = SWIG_Python_AppendOutput($result,array);
      }
    }
    

    This works different from the C function in that it returns a tuple of NumPy arrays with the data I want, which is more convenient than having to extract it from the element object later. The first typemap furthermore eliminates the need to pass in an object of type element. Hence I can hide the element struct entirely from the python user.

    The python interface finally looks like this:

    weight, l, n, dn = get_element(dim, vertices, quadrature_degree, polynomial_degree)
    

提交回复
热议问题