从模块获取尺寸时,f2py 编译失败

问题描述 投票:0回答:1

下面的 Fortran 代码无法使用 f2py 使用命令进行编译

f2py -m ggchemlib -c --fcompiler=gfortran --f90flags="-fdefault-real-8 -fdefault-double-8" --opt="-O5" test.f90

错误信息是

/tmp/tmpb4kqj9_4/src.linux-x86_64-3.10/ggchemlibmodule.c:292:16: error: ‘nmole’ undeclared (first use in this function)
  292 |   sat_Dims[0]=(nmole);
      |                ^~~~~

问题似乎是在子程序 SUPERSAT 中声明变量 Sat 的方式,其中 Sat 的维度取自数据模块。 这是测试。f90:

module CHEMISTRY
  integer :: NMOLE
end module CHEMISTRY

program main
  use CHEMISTRY,ONLY: NMOLE
  implicit none
  real*8 :: T
  NMOLE = 20
  T = 1000.0
  call CHECK_MELTING(T)
end program main

subroutine CHECK_MELTING(T)
  use CHEMISTRY,ONLY: NMOLE
  implicit none
  integer,parameter :: qp = selected_real_kind ( 33, 4931 )
  real*8,intent(in) :: T
  real(kind=qp) :: Sat(NMOLE)
  call SUPERSAT(T,Sat)
end subroutine CHECK_MELTING

subroutine SUPERSAT(T,Sat)
  use CHEMISTRY,ONLY: NMOLE
  implicit none
  integer,parameter :: qp = selected_real_kind ( 33, 4931 )
  real*8,intent(in) :: T
  real(kind=qp),intent(out) :: Sat(NMOLE)
  Sat(1:NMOLE) = 0.q0
end subroutine SUPERSAT

有没有简单的方法可以解决这个问题?

以下修改可行,但这对我来说不是一个可行的解决方案,因为我想将大型 Fortran 代码移植到 Python,其中始终使用从模块获取变量的维度。

module CHEMISTRY
  integer :: NMOLE
end module CHEMISTRY

program main
  use CHEMISTRY,ONLY: NMOLE
  implicit none
  real*8 :: T
  NMOLE = 20
  T = 1000.0
  call CHECK_MELTING(T)
end program main

subroutine CHECK_MELTING(T)
  use CHEMISTRY,ONLY: NMOLE
  implicit none
  integer,parameter :: qp = selected_real_kind ( 33, 4931 )
  real*8,intent(in) :: T
  real(kind=qp) :: Sat(NMOLE)
  call SUPERSAT(NMOLE,T,Sat)
end subroutine CHECK_MELTING

subroutine SUPERSAT(NMOLE,T,Sat)
  implicit none
  integer,parameter :: qp = selected_real_kind ( 33, 4931 )
  integer,intent(in) :: NMOLE
  real*8,intent(in) :: T
  real(kind=qp),intent(out) :: Sat(NMOLE)
  Sat(1:NMOLE) = 0.q0
end subroutine SUPERSAT
python fortran f2py
1个回答
0
投票

您的 Fortran 代码需要多种解决方法:

  1. F2PY的局限性;
  2. 返回
    np.float128
    类型的数组 (
    long double
    );

mapfile.txt

{'real': {'10': "long_double"}, 'integer': {'c_int': "int"}}

240616-testb.f90

module CHEMISTRY
  use iso_c_binding
  implicit none
  integer(C_INT), bind(C) :: NMOLE      ! bind to `extern int nmole`
  data NMOLE/10/                        ! python can't call main    
end module CHEMISTRY

program main
  use CHEMISTRY,ONLY: NMOLE
  implicit none
  real*8 :: T
  print *, NMOLE
  NMOLE = 20
  T = 1000.0
  call CHECK_MELTING(T)
end program main

subroutine CHECK_MELTING(T)
  use CHEMISTRY,ONLY: NMOLE
  implicit none
  integer,parameter :: qp = selected_real_kind ( 18, 4931 )     ! np.float128
  real*8,intent(in) :: T
  real(kind=qp) :: Sat(NMOLE)
  call SUPERSAT(T,Sat)
  print *, NMOLE, T, Sat
  print *, 'qp=', qp, digits(Sat(1)), epsilon(Sat(1)), huge(Sat(1))
end subroutine CHECK_MELTING

subroutine SUPERSAT(T,Sat)
  use CHEMISTRY,ONLY: NMOLE
  ! Workaround F2PY limitations
  !f2py usercode '''extern int nmole;'''
  implicit none
  integer,parameter :: qp = selected_real_kind ( 18, 4931 )     ! np.float128
  real*8,intent(in) :: T
  real(kind=qp),intent(out) :: Sat(NMOLE)
  Sat(1:NMOLE) = 1.23456789_qp
end subroutine SUPERSAT

结果:

$ python3.11 -m numpy.f2py --f2cmap mapfile.txt -m ggchemlib -c 240616-testb.f90 
...
$ python3.11 -c "import ggchemlib; s=ggchemlib.supersat(1000.); print(s.dtype, s)"
float128 [1.23456789 1.23456789 1.23456789 1.23456789 1.23456789 1.23456789
 1.23456789 1.23456789 1.23456789 1.23456789]
© www.soinside.com 2019 - 2024. All rights reserved.