f2py无法修改inout数组且出现数组拷贝性能问题如何解决
问题根因定位
- 参数声明不符合f2py语义:你给待修改数组
phi声明的intent(in, overwrite)是非法组合,overwrite修饰符必须配合intent(inout)使用才能告知f2py直接修改输入数组的原始内存;另外你给rhs、Mx等只读参数添加了无意义的inplace修饰符,反而触发f2py不必要的内存检查逻辑。 - Python侧参数传递错误:numpy数组的
.data是底层内存缓冲区对象,不是ndarray本身,f2py无法将缓冲区的修改关联同步到原ndarray,导致上层看到的数组没有变化。 - 视图属性触发强制拷贝:你的输入数组
OWNDATA=False属于切片视图,且你没有给f2py声明数组维度和输入边界参数的依赖关系,f2py默认会将不符合预期形状/所有权的数组拷贝为临时数组,所有修改都作用在临时数组上,自然不会回写到原数组。
修复方案
第一步:修改Fortran代码的f2py声明
对每个数组补充正确的intent和维度依赖声明:
! phi是唯一需要修改的数组,声明为inout+overwrite,明确维度依赖 REAL*8 phi(iphilo0:iphihi0, iphilo1:iphihi1, 0:nphicomp-1) cf2py intent(inout, overwrite) phi cf2py depend(iphilo0, iphihi0, iphilo1, iphihi1, nphicomp) phi ! 只读数组删除inplace修饰,只留intent(in),补充维度依赖 REAL*8 rhs(irhslo0:irhshi0, irhslo1:irhshi1, 0:nrhscomp-1) cf2py intent(in) rhs cf2py depend(irhslo0, irhshi0, irhslo1, irhshi1, nrhscomp) rhs ! Mx、My、Mz、Dinv按照同样规则修改,补充对应维度的depend声明即可
第二步:修改Python侧调用代码
删除所有.data后缀,直接传递ndarray本身:
GS.poissonop_gsrb(phi,phi.box.LoEnd()[0],phi.box.LoEnd()[1],phi.box.HiEnd()[0], phi.box.HiEnd()[1], rhs,rhs.box.LoEnd()[0],rhs.box.LoEnd()[1],rhs.box.HiEnd()[0], rhs.box.HiEnd()[1], Mx,Mx.box.LoEnd()[0],Mx.box.LoEnd()[1],Mx.box.HiEnd()[0], Mx.box.HiEnd()[1], My,My.box.LoEnd()[0],My.box.LoEnd()[1],My.box.HiEnd()[0], My.box.HiEnd()[1], Mz,Mz.box.LoEnd()[0],Mz.box.LoEnd()[1],Mz.box.HiEnd()[0], Mz.box.HiEnd()[1], DInv,DInv.box.LoEnd()[0],DInv.box.LoEnd()[1],DInv.box.HiEnd()[0], DInv.box.HiEnd()[1], L[0], L[1],H[0], H[1], whichPass, )
第三步:可选优化避免拷贝
如果仍有拷贝提示,可以对输入数组提前做一次F序拷贝获得所有权,再传入接口:
phi = np.asarray(phi, order='F') rhs = np.asarray(rhs, order='F') # 其他数组同理处理
编译时可添加额外参数-DF2PY_ASSUME_CONTIGUOUS=1,跳过f2py的连续性检查,进一步降低开销。
内容的提问来源于stack exchange,提问作者user3646557
相关产品推荐
相关产品推荐

