f2py 在 Fortran 的 Python 回调函数中使用数组
f2py use arrays in Python callback function in Fortran
我使用 Fortran 来补充 Python,并且在一些方法中我使用 Python 方法作为 Fortran 子例程中的回调。一切似乎都正常,直到我将一个数组输入回调函数,如下所示。
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
这是尝试使用 f2py(使用 gfortran)编译时的一些输出:
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
该模块本身与 gfortran 编译得很好。我想我在 !F2PY 部分中没有足够的信息,但还没有弄清楚我缺少什么。
非常感谢任何提示。
更新 1:
所以我注意到我可以 return 一个 1 x n 的数组,但是一个 m x n returns 的虚假结果。例如,我可以执行 CALL FUNC1(V) 并且它 returns 1 x 3 数组 V 并将其打印到屏幕上(回调函数 FUNC1 现在只是打印到屏幕上进行测试)。当我用 CP 代替 V 时,它给出了上面显示的警告并且不会编译,所以它与数组的形状有关?
我不记得是在哪里看到的,但是如果我将子程序顶部附近的语句修改为:
!F2PY INTENT(IN) N, CPW, TOL
!F2PY DEPEND(N) CPW
!F2PY (CALLBACK) FUNC1
!F2PY CALL FUNC1(CP)
EXTERNAL :: FUNC1
它将编译并且 运行,但是回调的输出(只是将数组打印到屏幕上)是伪造的。它是一个单一的浮点数,每次迭代的幅度变化很大。某种分段错误?
你必须在调用函数时传递 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 的打印工作正常。
我使用 Fortran 来补充 Python,并且在一些方法中我使用 Python 方法作为 Fortran 子例程中的回调。一切似乎都正常,直到我将一个数组输入回调函数,如下所示。
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
这是尝试使用 f2py(使用 gfortran)编译时的一些输出:
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
该模块本身与 gfortran 编译得很好。我想我在 !F2PY 部分中没有足够的信息,但还没有弄清楚我缺少什么。
非常感谢任何提示。
更新 1:
所以我注意到我可以 return 一个 1 x n 的数组,但是一个 m x n returns 的虚假结果。例如,我可以执行 CALL FUNC1(V) 并且它 returns 1 x 3 数组 V 并将其打印到屏幕上(回调函数 FUNC1 现在只是打印到屏幕上进行测试)。当我用 CP 代替 V 时,它给出了上面显示的警告并且不会编译,所以它与数组的形状有关?
我不记得是在哪里看到的,但是如果我将子程序顶部附近的语句修改为:
!F2PY INTENT(IN) N, CPW, TOL
!F2PY DEPEND(N) CPW
!F2PY (CALLBACK) FUNC1
!F2PY CALL FUNC1(CP)
EXTERNAL :: FUNC1
它将编译并且 运行,但是回调的输出(只是将数组打印到屏幕上)是伪造的。它是一个单一的浮点数,每次迭代的幅度变化很大。某种分段错误?
你必须在调用函数时传递 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 的打印工作正常。