在Fortran和Python之间共享变量
在Fortran和Python之间共享变量
在Fortran工程中与Python共享标量变量和数组变量,可以通过以下几种方法实现。我将介绍最常用的几种方法,包括使用Python的字典作为中介。
1. 使用f2py (NumPy的Fortran接口)
这是最直接的方法,f2py允许Fortran和Python之间直接共享内存。
Fortran端代码 (shared_vars.f90
)
module shared_varsimplicit nonereal(8) :: scalar_varreal(8), allocatable :: array_var(:,:)containssubroutine init_array(n, m)integer, intent(in) :: n, mallocate(array_var(n, m))array_var = 0.0d0end subroutine init_arraysubroutine print_vars()print *, "Scalar var:", scalar_varprint *, "Array var:"print *, array_varend subroutine print_vars
end module shared_vars
Python端代码
import numpy as np
import f2py_wrapper # 这是编译后的模块# 编译Fortran代码
# 命令行执行: f2py -c -m f2py_wrapper shared_vars.f90# 创建字典作为中介
var_dict = {'scalar': 3.14,'array': np.array([[1.0, 2.0], [3.0, 4.0]], dtype=np.float64)
}# 传递变量给Fortran
f2py_wrapper.shared_vars.scalar_var = var_dict['scalar']
f2py_wrapper.shared_vars.init_array(*var_dict['array'].shape)
f2py_wrapper.shared_vars.array_var[:,:] = var_dict['array']# 调用Fortran打印
f2py_wrapper.shared_vars.print_vars()# 修改Fortran中的变量
f2py_wrapper.shared_vars.scalar_var = 6.28
f2py_wrapper.shared_vars.array_var[0,0] = 10.0# 从Fortran获取更新后的值
var_dict['scalar'] = f2py_wrapper.shared_vars.scalar_var
var_dict['array'] = f2py_wrapper.shared_vars.array_var.copy()print("Updated Python dict:", var_dict)
2. 使用ctypes库
这种方法提供了更底层的控制。
Fortran端代码 (ctypes_shared.f90
)
module ctypes_shareduse, intrinsic :: iso_c_bindingimplicit nonereal(c_double), bind(C) :: c_scalar_vartype(c_ptr), bind(C) :: c_array_ptrinteger(c_int), bind(C) :: c_array_sizecontainssubroutine print_shared_vars() bind(C)use, intrinsic :: iso_c_bindingreal(c_double), pointer :: f_array(:)print *, "Scalar var:", c_scalar_varif (c_associated(c_array_ptr)) thencall c_f_pointer(c_array_ptr, f_array, [c_array_size])print *, "Array var:"print *, f_arrayelseprint *, "Array not allocated"end ifend subroutine print_shared_vars
end module ctypes_shared
Python端代码
import ctypes
import numpy as np
from numpy.ctypeslib import ndpointer# 加载共享库
lib = ctypes.CDLL('./ctypes_shared.so') # 需要先编译Fortran代码# 设置参数和返回类型
lib.print_shared_vars.argtypes = None
lib.print_shared_vars.restype = None# 创建字典
var_dict = {'scalar': ctypes.c_double(3.14),'array': np.array([1.0, 2.0, 3.0, 4.0], dtype=np.float64)
}# 设置标量变量
lib.c_scalar_var = var_dict['scalar']# 设置数组变量
array_ptr = var_dict['array'].ctypes.data_as(ctypes.POINTER(ctypes.c_double))
lib.c_array_ptr = array_ptr
lib.c_array_size = ctypes.c_int(len(var_dict['array']))# 调用Fortran打印
lib.print_shared_vars()# 修改Fortran中的变量
lib.c_scalar_var = 6.28
var_dict['array'][0] = 10.0 # 直接修改,因为内存是共享的# 再次打印
lib.print_shared_vars()# 更新字典中的标量值
var_dict['scalar'] = lib.c_scalar_var
3. 使用Python的字典作为中介的完整示例
下面是一个更完整的示例,展示如何通过字典在两个方向传递数据:
import numpy as npdef fortran_to_dict(fortran_module):"""将Fortran模块中的变量提取到字典"""var_dict = {}# 获取标量变量if hasattr(fortran_module, 'scalar_var'):var_dict['scalar'] = fortran_module.scalar_var# 获取数组变量if hasattr(fortran_module, 'array_var'):var_dict['array'] = fortran_module.array_var.copy()return var_dictdef dict_to_fortran(var_dict, fortran_module):"""将字典中的变量传递到Fortran模块"""# 设置标量变量if 'scalar' in var_dict:fortran_module.scalar_var = var_dict['scalar']# 设置数组变量if 'array' in var_dict:arr = var_dict['array']if not hasattr(fortran_module, 'array_var') or \fortran_module.array_var.shape != arr.shape:fortran_module.init_array(*arr.shape)fortran_module.array_var[:,:] = arr# 使用示例
var_dict = {'scalar': 3.14,'array': np.array([[1.0, 2.0], [3.0, 4.0]], dtype=np.float64)
}# 传递到Fortran
dict_to_fortran(var_dict, f2py_wrapper.shared_vars)# 从Fortran获取
updated_dict = fortran_to_dict(f2py_wrapper.shared_vars)
编译说明
对于上述方法,需要先编译Fortran代码:
-
f2py方法:
f2py -c -m f2py_wrapper shared_vars.f90
-
ctypes方法:
gfortran -shared -fPIC -o ctypes_shared.so ctypes_shared.f90
注意事项
- 内存管理:数组在Fortran和Python之间共享时,要注意内存分配和释放
- 数据类型匹配:确保两端的变量类型一致
- 数组顺序:Fortran是列优先,Python/NumPy默认是行优先
- 线程安全:如果涉及多线程,需要确保同步
以上方法提供了灵活的方式在Fortran和Python之间共享数据,通过Python字典作为中介可以更好地组织和管理这些共享变量。