下面的 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
您的 Fortran 代码需要多种解决方法:
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]