仅在内部使用派生类型的 F2PY 包装过程
F2PY wrap procedure that uses derived types only internally
很多地方都说F2PY不“支持派生类型”,但是我不清楚这是否意味着
- 派生类型不能用作由
F2PY
- 派生类型甚至可能不会在我想用 F2PY 包装的程序内部使用
对于我的用例来说,第一点是不便,第二点是破坏交易的因素。
例如,考虑这个计算向量和的模块:
module derived_types
implicit none
public :: point, add
type :: point
real :: x
real :: y
end type point
contains
type(point) function add(p1, p2)
type(point), intent(in) :: p1
type(point), intent(in) :: p2
add%x = p1%x + p2%x
add%y = p1%y + p2%y
end function add
end module derived_types
module expose
use derived_types, only: point, add
implicit none
contains
subroutine vector_sum(x1, y1, x2, y2, x3, y3)
real, intent(in) :: x1, y1, x2, y2
real, intent(out) :: x3, y3
type(point) :: p1, p2, p3
p1 = point(x1, y1)
p2 = point(x2, y2)
p3 = add(p1, p2)
x3 = p3%x
y3 = p3%y
end subroutine vector_sum
end module expose
子例程 vector_sum
应暴露给 Python。派生类型 point
不能在 Python 和 Fortran 之间传递。
这作为普通 Fortran 程序(添加了适当的程序块)但 F2PY 失败:
f2py -c ff.f90 only: vector_sum
running build
running config_cc
unifing config_cc, config, build_clib, build_ext, build commands --compiler options
running config_fc
unifing config_fc, config, build_clib, build_ext, build commands --fcompiler options
running build_src
build_src
building extension "untitled" sources
f2py options: ['only:', 'vector_sum', ':']
f2py:> /tmp/tmpjdq8b9dq/src.linux-x86_64-3.8/untitledmodule.c
creating /tmp/tmpjdq8b9dq/src.linux-x86_64-3.8
Reading fortran codes...
Reading file 'ff.f90' (format:free)
Line #7 in ff.f90:"type :: point "
analyzeline: No name/args pattern found for line.
Post-processing...
Block: untitled
Block: derived_types
Block: unknown_type
Block: expose
Block: vector_sum
Block: run
Post-processing (stage 2)...
Block: untitled
Block: unknown_interface
Block: derived_types
Block: unknown_type
Block: expose
Block: vector_sum
Block: run
Building modules...
Building module "untitled"...
Constructing F90 module support for "derived_types"...
Variables: point add
getctype: No C-type found in "{'attrspec': ['public']}", assuming void.
Traceback (most recent call last):
File "/home/me/.pyenv/versions/anaconda3-2020.11/lib/python3.8/site-packages/numpy/f2py/f90mod_rules.py", line 143, in buildhooks
at = capi_maps.c2capi_map[ct]
KeyError: 'void'
这样的事情完全可以使用 F2PY 来完成吗?
您可以使用单个过程,在其中定义派生类型,也可以使用包含的过程。
这是一种快速而肮脏的方法,仅适用于较小的问题。
示例实现如下
! file: a.f90
subroutine vector_sum(x1, y1, x2, y2, x3, y3)
real, intent(in) :: x1, y1, x2, y2
real, intent(out) :: x3, y3
type point
real :: x(2)
end type
type(point) :: p1, p2, p3
p1%x = [x1, y1]
p2%x = [x2, y2]
p3 = add(p1, p2)
x3 = p3%x(1)
y3 = p3%x(2)
contains
type(point) function add(p1, p2)
type(point), intent(in) :: p1
type(point), intent(in) :: p2
add%x = p1%x + p2%x
end function
end subroutine
编译
$ f2py -c a.f90 -m amod
在python
中的用法
>>> import amod
>>> amod.vector_sum(1, 2, 3, 4)
(4.0, 6.0)
经过一些修改,我认为首先将定义所有派生类型的代码编译到静态库中可能是最简单的,即:
libff.f90
包含:
module derived_types
implicit none
public :: point, add
type :: point
real :: x
real :: y
end type point
contains
type(point) function add(p1, p2)
type(point), intent(in) :: p1
type(point), intent(in) :: p2
add%x = p1%x + p2%x
add%y = p1%y + p2%y
end function add
end module derived_types
用 gfortran -free -c libff.f90
编译生成 libff.o
。
然后使用预编译模块的派生类型的代码可以在链接库时使用F2PY编译,即:
ff.f90
包含:
module expose
use derived_types, only: point, add
implicit none
contains
subroutine vector_sum(x1, y1, x2, y2, x3, y3)
real, intent(in) :: x1, y1, x2, y2
real, intent(out) :: x3, y3
type(point) :: p1, p2, p3
p1 = point(x1, y1)
p2 = point(x2, y2)
p3 = add(p1, p2)
x3 = p3%x
y3 = p3%y
end subroutine vector_sum
end module expose
在使用 F2PY 与 f2py -c ff.f90 libff.o -m ff
构建 Python 扩展后,我们可以将其导入 Python 与 from ff.expose import vector_sum
。
经验教训:将派生类型的定义放入预编译库中,然后使用 F2PY 仅编译使用这些类型的代码。
很多地方都说F2PY不“支持派生类型”,但是我不清楚这是否意味着
- 派生类型不能用作由 F2PY
- 派生类型甚至可能不会在我想用 F2PY 包装的程序内部使用
对于我的用例来说,第一点是不便,第二点是破坏交易的因素。
例如,考虑这个计算向量和的模块:
module derived_types
implicit none
public :: point, add
type :: point
real :: x
real :: y
end type point
contains
type(point) function add(p1, p2)
type(point), intent(in) :: p1
type(point), intent(in) :: p2
add%x = p1%x + p2%x
add%y = p1%y + p2%y
end function add
end module derived_types
module expose
use derived_types, only: point, add
implicit none
contains
subroutine vector_sum(x1, y1, x2, y2, x3, y3)
real, intent(in) :: x1, y1, x2, y2
real, intent(out) :: x3, y3
type(point) :: p1, p2, p3
p1 = point(x1, y1)
p2 = point(x2, y2)
p3 = add(p1, p2)
x3 = p3%x
y3 = p3%y
end subroutine vector_sum
end module expose
子例程 vector_sum
应暴露给 Python。派生类型 point
不能在 Python 和 Fortran 之间传递。
这作为普通 Fortran 程序(添加了适当的程序块)但 F2PY 失败:
f2py -c ff.f90 only: vector_sum
running build
running config_cc
unifing config_cc, config, build_clib, build_ext, build commands --compiler options
running config_fc
unifing config_fc, config, build_clib, build_ext, build commands --fcompiler options
running build_src
build_src
building extension "untitled" sources
f2py options: ['only:', 'vector_sum', ':']
f2py:> /tmp/tmpjdq8b9dq/src.linux-x86_64-3.8/untitledmodule.c
creating /tmp/tmpjdq8b9dq/src.linux-x86_64-3.8
Reading fortran codes...
Reading file 'ff.f90' (format:free)
Line #7 in ff.f90:"type :: point "
analyzeline: No name/args pattern found for line.
Post-processing...
Block: untitled
Block: derived_types
Block: unknown_type
Block: expose
Block: vector_sum
Block: run
Post-processing (stage 2)...
Block: untitled
Block: unknown_interface
Block: derived_types
Block: unknown_type
Block: expose
Block: vector_sum
Block: run
Building modules...
Building module "untitled"...
Constructing F90 module support for "derived_types"...
Variables: point add
getctype: No C-type found in "{'attrspec': ['public']}", assuming void.
Traceback (most recent call last):
File "/home/me/.pyenv/versions/anaconda3-2020.11/lib/python3.8/site-packages/numpy/f2py/f90mod_rules.py", line 143, in buildhooks
at = capi_maps.c2capi_map[ct]
KeyError: 'void'
这样的事情完全可以使用 F2PY 来完成吗?
您可以使用单个过程,在其中定义派生类型,也可以使用包含的过程。 这是一种快速而肮脏的方法,仅适用于较小的问题。
示例实现如下
! file: a.f90
subroutine vector_sum(x1, y1, x2, y2, x3, y3)
real, intent(in) :: x1, y1, x2, y2
real, intent(out) :: x3, y3
type point
real :: x(2)
end type
type(point) :: p1, p2, p3
p1%x = [x1, y1]
p2%x = [x2, y2]
p3 = add(p1, p2)
x3 = p3%x(1)
y3 = p3%x(2)
contains
type(point) function add(p1, p2)
type(point), intent(in) :: p1
type(point), intent(in) :: p2
add%x = p1%x + p2%x
end function
end subroutine
编译
$ f2py -c a.f90 -m amod
在python
中的用法>>> import amod
>>> amod.vector_sum(1, 2, 3, 4)
(4.0, 6.0)
经过一些修改,我认为首先将定义所有派生类型的代码编译到静态库中可能是最简单的,即:
libff.f90
包含:
module derived_types
implicit none
public :: point, add
type :: point
real :: x
real :: y
end type point
contains
type(point) function add(p1, p2)
type(point), intent(in) :: p1
type(point), intent(in) :: p2
add%x = p1%x + p2%x
add%y = p1%y + p2%y
end function add
end module derived_types
用 gfortran -free -c libff.f90
编译生成 libff.o
。
然后使用预编译模块的派生类型的代码可以在链接库时使用F2PY编译,即:
ff.f90
包含:
module expose
use derived_types, only: point, add
implicit none
contains
subroutine vector_sum(x1, y1, x2, y2, x3, y3)
real, intent(in) :: x1, y1, x2, y2
real, intent(out) :: x3, y3
type(point) :: p1, p2, p3
p1 = point(x1, y1)
p2 = point(x2, y2)
p3 = add(p1, p2)
x3 = p3%x
y3 = p3%y
end subroutine vector_sum
end module expose
在使用 F2PY 与 f2py -c ff.f90 libff.o -m ff
构建 Python 扩展后,我们可以将其导入 Python 与 from ff.expose import vector_sum
。
经验教训:将派生类型的定义放入预编译库中,然后使用 F2PY 仅编译使用这些类型的代码。