f2py在Fortran的Python回调函数中使用数组

时间:2015-11-30 18:55:03

标签: python fortran f2py

我使用Fortran来补充Python,并且在一些方法中我使用Python方法作为Fortran子例程中的回调。一切似乎都有效,直到我将数组提供给回调函数,如下所示。

String Gson::toJson(Object src)

尝试使用f2py(使用gfortran)进行编译时,这是一些输出:

RECURSIVE SUBROUTINE RECURSIVE_CURVE_SUBDIVISION(CPW, N, TOL, FUNC1)
    IMPLICIT NONE

    !F2PY INTENT(IN) CPW, N, TOL
    !F2PY DEPEND(N) CPW
    !F2PY (CALLBACK) FUNC1

    INTEGER, INTENT(IN) :: N
    DOUBLE PRECISION, INTENT(IN) :: CPW(0:N, 0:3), TOL

    INTEGER :: I
    DOUBLE PRECISION :: QP(0:N, 0:2), LP, LC, TEMP, &
                        AW(0:N, 0:3), BW(0:N, 0:3), V(0:2)

    EXTERNAL :: FUNC1

    DO I = 0, N
        QP(I, :) = CPW(I, 0:2) / CPW(I, 3)
    END DO
    LP = 0.0D0
    DO I = 0, N - 1
        V = QP(I + 1, :) - QP(I, :)
        CALL NORM(V, TEMP)
        LP = LP + TEMP
    END DO
    V = QP(N, :) - QP(0, :)
    CALL NORM(V, LC)
    IF (ABS(LP - LC) .LE. TOL) THEN
        CALL FUNC1(CPW, QP, LC, LP) !<-- here is the problem
        ! CALL FUNC1(LC, LP) !<-- this works
        ! CALL FUNC1(CPW=CPW, QP=QP, LC=LC, LP=LP)
        ! Added bonus if anyone can figure out how to use keyword arguements in
        ! the callback. For cleanliness, I'm trying to use func1(**kwargs) in Python.
    ELSE
        CALL SPLIT_BEZIER_CURVE(CPW, N, 0.50D0, AW, BW)
        CALL RECURSIVE_CURVE_SUBDIVISION(AW, N, TOL / 2.0D0, FUNC1)
        CALL RECURSIVE_CURVE_SUBDIVISION(BW, N, TOL / 2.0D0, FUNC1)
    END IF
END SUBROUTINE RECURSIVE_CURVE_SUBDIVISION

该模块本身就可以很好地编译gfortran。我在想!我在F2PY部分没有足够的信息,但我还没弄明白我还缺少什么。

非常感谢任何提示。

更新1:

所以我注意到我可以返回1 x n数组,但是m x n返回虚假结果。例如,我可以执行CALL FUNC1(V)并返回1 x 3阵列V并将其打印到屏幕上(回调函数FUNC1只打印到屏幕以供现在测试)。当我用CP代替V时,它会给出上面显示的警告并且不会编译,所以它与数组的形状有关吗?

我不记得我在哪里看到这个,但是如果我修改子程序顶部附近的语句:

warning C4244: '=' : conversion from 'npy_intp' to 'npy_int', possible loss of data
warning C4244: '=' : conversion from 'npy_intp' to 'npy_int', possible loss of data
warning C4244: '+=' : conversion from 'Py_ssize_t' to 'int', possible loss of data
warning C4244: '+=' : conversion from 'Py_ssize_t' to 'int', possible loss of data
warning C4244: '=' : conversion from 'Py_ssize_t' to 'int', possible loss of data
warning C4244: '=' : conversion from 'Py_ssize_t' to 'int', possible loss of data
warning C4244: '=' : conversion from 'Py_ssize_t' to 'int', possible loss of data
error C2065: 'n' : undeclared identifier
error C2065: 'n' : undeclared identifier

它将编译并运行,但回调的输出(只是将数组打印到屏幕)是假的。它是一个浮动,每次迭代都有不同程度的变化。某种分段错误?

1 个答案:

答案 0 :(得分:2)

当你调用函数时你必须传递N,以便它知道数组有多大(你不必在Python中处理这个参数,但它需要在C级别)。所以将呼叫更改为

CALL FUNC1(CPW, QP, LC, LP,N)

如果那样做,但查看生成的.pyf签名文件(f2py -m thingy -h thingy.pyf thingy.f90)相关部分(它是自动生成的签名)是

python module recursive_curve_subdivision__user__routines 
    interface recursive_curve_subdivision_user_interface 
        subroutine func1(cpw,qp) ! in :thingy:thingy.f90:recursive_curve_subdivision:unknown_interface
            double precision dimension(n + 1,4),intent(in),depend(n) :: cpw
            double precision dimension(n + 1,3) :: qp
        end subroutine func1
    end interface recursive_curve_subdivision_user_interface
end python module recursive_curve_subdivision__user__routines

(请注意,为了简单起见,我使用一个略微缩减的函数调用仅使用两个参数进行了测试,因此它与您的代码完全不匹配)。 您会注意到,对于所有数组大小,它取决于N,但您永远不会传递N。如果你确实添加N作为参数,它知道大小,并且Python的打印工作正常。