如何在Fortran子程序中将输入变量声明为常量参数?
问题描述
我有一段Fortran代码,在模块内定义了如下常量:
real(RealExt), parameter :: grav_acc = 9.80665 real(RealExt), parameter :: r_gas_dry = 287.026 real(RealExt), parameter :: cp_air_dry = 1.005e+03 real(RealExt), parameter :: pi = 4.0*atan(1.0) real(RealExt), parameter :: seconds_per_day = 8.6400e+04
其中类型RealExt定义为:
INTEGER, PARAMETER :: RealExt=SELECTED_REAL_KIND(15, 307)
我正尝试用CFFI将该Fortran代码与Python对接,实现Python输入值传入Fortran子程序并执行计算。当前核心问题是Fortran的parameter属性限制:我希望将Python传入的常量值(如重力加速度、行星自转速率等)在Fortran子程序中作为常量使用,但parameter要求值在编译时已知,无法直接通过如下方式实现:
subroutine runes(g, rd, cp_rd, sec_per_day) implicit none real(RealExt), intent(in) :: g, rd, cp_rd, pi_, sec_per_day real(RealExt), parameter :: grav_acc = g real(RealExt), parameter :: r_gas_dry = rd real(RealExt), parameter :: cp_air_dry = cp_rd real(RealExt), parameter :: pi = pi_ real(RealExt), parameter :: seconds_per_day = sec_per_day . . .
请问是否有可行的解决方法?能否将传入子程序的值声明为常量?
可行解决方案
使用模块变量替代
parameter,在子程序入口赋值
将原模块中的parameter常量改为普通模块变量,在子程序接收Python传入的值后,先为这些模块变量赋值,后续计算代码直接使用模块变量即可。这种方式既保留了原有变量名的使用习惯,又满足运行时传入值的需求。示例代码:
! 模块定义 module constants_mod INTEGER, PARAMETER :: RealExt=SELECTED_REAL_KIND(15, 307) real(RealExt) :: grav_acc, r_gas_dry, cp_air_dry, pi, seconds_per_day end module constants_mod ! 子程序实现 subroutine runes(g, rd, cp_rd, pi_, sec_per_day) use constants_mod implicit none real(RealExt), intent(in) :: g, rd, cp_rd, pi_, sec_per_day ! 为模块变量赋值 grav_acc = g r_gas_dry = rd cp_air_dry = cp_rd pi = pi_ seconds_per_day = sec_per_day ! 后续计算直接调用模块变量,与原parameter写法一致 ! ... 计算代码 ... end subroutine runes添加
protected属性限制模块变量修改
若担心后续代码误修改这些变量,可给模块变量加上protected属性,确保仅能在指定的初始化子程序中赋值,其他代码只能读取,模拟常量的不可修改特性。示例代码:
module constants_mod INTEGER, PARAMETER :: RealExt=SELECTED_REAL_KIND(15, 307) real(RealExt), protected :: grav_acc, r_gas_dry, cp_air_dry, pi, seconds_per_day contains subroutine init_constants(g, rd, cp_rd, pi_, sec_per_day) real(RealExt), intent(in) :: g, rd, cp_rd, pi_, sec_per_day grav_acc = g r_gas_dry = rd cp_air_dry = cp_rd pi = pi_ seconds_per_day = sec_per_day end subroutine init_constants end module constants_mod ! 主调用子程序 subroutine runes(g, rd, cp_rd, pi_, sec_per_day) use constants_mod implicit none real(RealExt), intent(in) :: g, rd, cp_rd, pi_, sec_per_day call init_constants(g, rd, cp_rd, pi_, sec_per_day) ! 后续代码仅能读取变量,无法修改 ! ... 计算代码 ... end subroutine runes使用
associate块临时绑定变量别名
若不想修改原有模块结构,可在子程序内部用associate块将传入的参数绑定为习惯的常量名称,块内可直接使用这些别名,代码可读性与原parameter写法一致,且无需额外存储变量。示例代码:
subroutine runes(g, rd, cp_rd, pi_, sec_per_day) implicit none INTEGER, PARAMETER :: RealExt=SELECTED_REAL_KIND(15, 307) real(RealExt), intent(in) :: g, rd, cp_rd, pi_, sec_per_day associate( & grav_acc => g, & r_gas_dry => rd, & cp_air_dry => cp_rd, & pi => pi_, & seconds_per_day => sec_per_day & ) ! 块内grav_acc等别名等价于传入参数,仅可读取 ! ... 计算代码 ... end associate end subroutine runes
内容的提问来源于stack exchange,提问作者Senku02
相关产品推荐
相关产品推荐

