如何为ABAQUS Python代码传递参数?UMAT跨语言传参并行化问题
解决UMAT与Python并行环境下的变量传递问题
这个问题我之前帮同行处理过——用文本文件在Fortran UMAT和Python之间传参,单进程仿真时没问题,但一到并行场景,多个核心同时读写同一个文件,数据混乱、竞争冲突几乎是必然的。下面给你几个更可靠的、原生支持并行的方案,你可以根据数据量和交互需求来选:
1. 命令行参数+标准输出(适合小体量数据)
直接把Fortran里的变量打包成命令行参数传给Python脚本,Python处理完后把结果打印到标准输出,Fortran再捕获这个输出。每个进程独立调用Python,完全不会有资源冲突,非常适合传递少量数值型参数。
Fortran端代码示例
! 假设要传递的变量是a, b, c,最终接收Python返回的result character(len=256) :: cmd real :: a, b, c, result a = 1.0 b = 2.0 c = 3.0 ! 构造命令行,把数值转成字符串传入(注意路径和参数的空格) write(cmd, '(A, F8.2, A, F8.2, A, F8.2)') & 'abaqus cae noGUI="c:\temp\pycode.py" ', a, ' ', b, ' ', c ! Fortran 2008+推荐用execute_command_line,能直接捕获输出 character(len=128) :: output_str integer :: exit_code call execute_command_line(trim(cmd), output_unit=output_str, exitstat=exit_code) ! 解析Python返回的结果(假设Python只打印了一个浮点数) read(output_str, *) result print *, 'Python返回结果:', result
Python端代码示例(pycode.py)
import sys # 从命令行获取参数(sys.argv[0]是脚本名,后面的才是传入的变量) if len(sys.argv) < 4: print(0.0) # 异常情况返回默认值 sys.exit(1) a = float(sys.argv[1]) b = float(sys.argv[2]) c = float(sys.argv[3]) # 这里写你的业务逻辑,比如计算加权和 result = a*0.2 + b*0.3 + c*0.5 # 把结果打印到标准输出,让Fortran捕获 print(result)
2. 共享内存(适合大量数据,低延迟)
如果需要传递数组、矩阵这类大数据,命令行参数就不太现实了,这时候可以用共享内存——Fortran创建一块内存区域,Python直接读写这块内存,完全绕开文件。并行时每个进程创建自己的唯一共享内存段(比如用进程ID命名),就不会冲突。
Fortran端示例(Linux/Unix用POSIX共享内存,Windows需替换为WinAPI)
use, intrinsic :: iso_c_binding implicit none interface function shm_open(name, flags, mode) bind(c) import :: c_int, c_char integer(c_int) :: shm_open character(kind=c_char), intent(in) :: name(*) integer(c_int), value :: flags, mode end function shm_open function ftruncate(fd, length) bind(c) import :: c_int, c_long integer(c_int) :: ftruncate integer(c_int), value :: fd integer(c_long), value :: length end function ftruncate function mmap(addr, length, prot, flags, fd, offset) bind(c) import :: c_ptr, c_size_t, c_int, c_long type(c_ptr) :: mmap type(c_ptr), value :: addr integer(c_size_t), value :: length integer(c_int), value :: prot, flags, fd integer(c_long), value :: offset end function mmap function munmap(addr, length) bind(c) import :: c_ptr, c_size_t, c_int integer(c_int) :: munmap type(c_ptr), value :: addr integer(c_size_t), value :: length end function munmap function shm_unlink(name) bind(c) import :: c_int, c_char integer(c_int) :: shm_unlink character(kind=c_char), intent(in) :: name(*) end function shm_unlink end interface integer(c_int) :: shm_fd, status character(len=32) :: shm_name real(c_float), pointer :: shared_data(:) type(c_ptr) :: c_ptr ! 用进程ID生成唯一的共享内存名称(避免并行时冲突) write(shm_name, '(A, I8)') "/umat_shm_", this_image() ! 创建共享内存段,大小为4个float(比如传递3个输入+1个输出) shm_fd = shm_open(trim(shm_name)//c_null_char, & int(z'0001', c_int)+int(z'0002', c_int)+int(z'0002', c_int), & ! IPC_CREAT+IPC_EXCL+O_RDWR int(z'0666', c_int)) call ftruncate(shm_fd, 4_c_size_t*sizeof(real(c_float))) ! 映射到Fortran内存 c_ptr = mmap(c_null_ptr, 4_c_size_t*sizeof(real(c_float)), & int(z'01', c_int)+int(z'02', c_int), int(z'01', c_int), & ! PROT_READ+PROT_WRITE, MAP_SHARED shm_fd, 0_c_long) call c_f_pointer(c_ptr, shared_data, [4]) ! 写入输入数据 shared_data(1) = 1.0_c_float shared_data(2) = 2.0_c_float shared_data(3) = 3.0_c_float ! 调用Python脚本,传入共享内存名称 call SYSTEM('abaqus cae noGUI="c:\temp\pycode.py" '//trim(shm_name)) ! 读取Python修改后的输出数据 print *, 'Python返回结果:', shared_data(4) ! 清理资源 call munmap(c_ptr, 4_c_size_t*sizeof(real(c_float))) call shm_unlink(trim(shm_name)//c_null_char)
Python端代码示例
import sys import os import mmap import struct shm_name = sys.argv[1] # 打开共享内存段 shm_fd = os.open(shm_name, os.O_RDWR) mm = mmap.mmap(shm_fd, 0) # 读取4个float(每个4字节,共16字节) data_bytes = mm.read(16) a, b, c, _ = struct.unpack('ffff', data_bytes) # 业务逻辑:计算三者乘积 result = a * b * c # 把结果写回第4个位置(偏移12字节) mm.seek(12) mm.write(struct.pack('f', result)) # 清理 mm.close() os.close(shm_fd)
3. 管道通信(适合双向多次交互)
如果UMAT和Python需要多次来回传递数据,管道通信是更好的选择。每个进程创建自己的管道,Fortran和Python通过标准输入输出交互,完全独立,并行时不会互相干扰。
Fortran端示例(POSIX管道,Windows需调整为CreatePipe)
use, intrinsic :: iso_c_binding implicit none interface function pipe(fd) bind(c) import :: c_int integer(c_int) :: pipe integer(c_int), intent(out) :: fd(2) end function pipe function fork() bind(c) import :: c_int integer(c_int) :: fork end function fork function dup2(oldfd, newfd) bind(c) import :: c_int integer(c_int) :: dup2 integer(c_int), value :: oldfd, newfd end function dup2 function execlp(file, arg0, arg1, arg2, arg3) bind(c) import :: c_char, c_int integer(c_int) :: execlp character(kind=c_char), intent(in) :: file(*), arg0(*), arg1(*), arg2(*), arg3(*) end function execlp function waitpid(pid, status, options) bind(c) import :: c_int integer(c_int) :: waitpid integer(c_int), value :: pid, options integer(c_int), intent(out) :: status end function waitpid end interface integer(c_int) :: pipefd(2), pid, status real(c_float) :: send_data(3), recv_data ! 创建管道(pipefd(1)是写端,pipefd(0)是读端) status = pipe(pipefd) pid = fork() if (pid == 0_c_int) then ! 子进程:重定向标准输入输出到管道,然后执行Python脚本 call dup2(pipefd(0), 0_c_int) call dup2(pipefd(1), 1_c_int) call close(pipefd(0)) call close(pipefd(1)) ! 启动Python脚本 call execlp('abaqus'//c_null_char, & 'abaqus'//c_null_char, 'cae'//c_null_char, & 'noGUI="c:\temp\pycode.py"'//c_null_char, c_null_char) else ! 父进程(UMAT):发送数据到Python send_data = [1.0_c_float, 2.0_c_float, 3.0_c_float] status = write(pipefd(1), send_data, size(send_data)*sizeof(real(c_float))) ! 接收Python返回的数据 status = read(pipefd(0), recv_data, sizeof(recv_data)) print *, 'Python返回结果:', recv_data ! 清理 call close(pipefd(0)) call close(pipefd(1)) call waitpid(pid, status, 0_c_int) end if
Python端代码示例
import sys import struct # 从标准输入读取3个float(12字节) input_bytes = sys.stdin.read(12) a, b, c = struct.unpack('fff', input_bytes) # 业务逻辑:计算平均值 result = (a + b + c) / 3 # 把结果写回标准输出 sys.stdout.write(struct.pack('f', result)) sys.stdout.flush() # 必须刷新,否则Fortran可能读不到数据
关键注意事项
- 并行唯一性:不管用哪种方案,一定要给每个进程的资源(共享内存名称、管道标识等)加上唯一后缀,比如用
this_image()(Fortran并行)或者os.getpid()(Python)生成的进程ID,避免不同进程互相干扰。 - 跨平台兼容:如果是Windows环境,POSIX相关的API(比如
shm_open、fork)要替换成Windows API对应的函数,或者用跨平台库(比如MPI的共享内存模块)。 - ABAQUS环境:确保Python脚本在ABAQUS的Python环境中能正常运行,必要时在脚本开头指定ABAQUS的Python路径。
内容的提问来源于stack exchange,提问作者RKM
相关产品推荐
相关产品推荐

