目录
步骤一:将每个时间步下的节点坐标和应力值导出为一个csv文件
前言
因课题需要,想得到Ansys瞬态仿真中每时每刻的应力最大值,以及最大应力值出现的位置(xyz坐标)。
初步在Mechanical中尝试,点击一个应力结果,右侧表格中能够显示每个时间步下的最大应力值,但是却不知道这个值出现的位置。
再次尝试,在项目树中的应力结果处右键,导出为文本文件。
打开导出的文件后发现,虽然有每个节点的坐标和应力值,但是这个文件是局限于一个时间步下的,仍然达不到我想导出每个时间步下的最大应力值和坐标的要求。

初步想法
既然【导出为文本文件】可以导出单一时间步下的坐标和应力值,那么我在每个时间步上都导出这样一个文件,岂不是可以通过简单的排序筛选等方法直接找到每个时间步文件的最大应力值和坐标了?之后再将每一个时间步下的文件汇总整理,不久可以满足我的要求了?
当然,这种手动的方法在时间步较少的时候可以使用,但是我的仿真时间步太多了,这样一点一点的操作显然不现实。有没有通过写一个自动化脚本,全自动的实现这一流程?当然有!
查阅资料
查阅资料,找到了“PyAnsys”这个玩意中的“ansys.dpf.core”这个python库。官网介绍如下:
数据处理框架(DPF)为数值模拟用户和工程师提供了一个工具箱,用于访问和转换模拟数据。DPF 可以访问 Ansys 求解器结果文件以及多种中性文件格式。
官网文档连接:https://dpf.docs.pyansys.com/version/stable/getting_started/index.html
也就是说,这个库可以允许python代码直接读取仿真结果的.rst文件。这就非常好办了,我只需要利用这个库读取结果文件每个时间步下的最大应力值,之后再用代码将这些值汇总在一起就可以搞定了。
实施方案
首先安装这个库。
pip install ansys-dpf-core
鉴于本人python水平有限,遂求助Chat GPT,告诉它我的需求,让它辅助我写代码。
方案分两步走,首先让代码读取仿真结果,让其将每个时间步下的节点的坐标和应力数据导出。接着,再用代码遍历所有导出的文件,找到兴趣范围内最大的应力值及其xyz坐标。
步骤一:将每个时间步下的节点坐标和应力值导出为一个csv文件
GPT给我的代码如下。使用代码时,注意设置好自己的rst文件路径,以及导出csv文件的路径。不知道路径的,可以通过图片中的方法打开rst输出文件夹:

# 本脚本:
# 1) 使用 ansys-dpf-core 打开 ANSYS .rst 结果文件
# 2) 对每个时间步计算节点 von-mises 应力
# 3) 按 node_id 将 von-mises 与节点坐标合并
# 4) 保存为 timestep_001.csv、timestep_002.csv …
import os
import numpy as np
import pandas as pd
from ansys.dpf import core as dpf
from ansys.dpf.core import operators as ops
# -----------------------------
# 用户设置——按需修改
# ⚠请在这里设置你的rst文件路径和csv输出路径,比如
# rst_path = r'D:\Simulation\Sim01\Sim01_files\dp0\SYS-1\MECH\file.rst'
# -----------------------------
rst_path = r'rst/file.rst'
output_dir = r"timesteps_csv/"
# -----------------------------
os.makedirs(output_dir, exist_ok=True)
print("正在打开结果文件:", rst_path)
ds = dpf.DataSources(rst_path)
model = dpf.Model(ds)
# 时间支持
tfreq = model.metadata.time_freq_support
n_sets = tfreq.n_sets if tfreq is not None else 0
print("检测到的时间集数量:", n_sets)
# 一次性准备网格坐标表(网格节点是静态的)
mesh = model.metadata.meshed_region
# coords_field:包含所有节点坐标的场
coords_field = mesh.nodes.coordinates_field
coords_ids = list(coords_field.scoping.ids)
# 坐标数据可能是扁平列表或已是 (N,3)
coords_arr = np.array(coords_field.data)
# 尝试将坐标 reshape 成 (N,3)
try:
if coords_arr.ndim == 1:
coords_arr = coords_arr.reshape(-1, 3)
elif coords_arr.ndim == 2 and coords_arr.shape[1] == 3:
pass
else:
# 回退:尝试推断形状
coords_arr = coords_arr.reshape(len(coords_ids), 3)
except Exception:
raise RuntimeError("无法将坐标数组 reshape 为 (n_nodes,3).")
coords_df = pd.DataFrame({
"node_id": coords_ids,
"x": coords_arr[:, 0],
"y": coords_arr[:, 1],
"z": coords_arr[:, 2],
})
print(f"节点坐标表已准备:共 {len(coords_df)} 个节点.")
# 循环时间集
# 若 tfreq 返回 0 集,仍尝试一次(某些结果文件行为不同)
time_indices = list(range(1, n_sets + 1)) if n_sets > 0 else [1]
for time_idx in time_indices:
print(f"正在处理时间步 {time_idx} …")
try:
# 创建应力读取算子
s_op = model.results.stress()
# 请求节点结果(确保位于节点)
try:
s_op.inputs.requested_location.connect("Nodal")
except Exception:
# 容错回退
try:
s_op.inputs.requested_location.connect("nodal")
except Exception:
pass
# 设置时间范围(按索引选择时间集)
s_op.inputs.time_scoping.connect(time_idx)
# 从应力算子创建 von-mises 算子
vm_op = ops.invariant.von_mises_eqv_fc(s_op)
# 获取包含 von-mises 场的场容器
vm_fc = vm_op.outputs.fields_container()
if len(vm_fc) == 0:
print(f" 警告:时间集 {time_idx} 未返回 von-mises 场,已跳过.")
continue
# 通常 vm_fc[0] 就是我们请求时间的场
vm_field = vm_fc[0]
vm_ids = list(vm_field.scoping.ids)
vm_data = np.array(vm_field.data)
# 确保 vm_data 为与 vm_ids 对应的一维数组
if vm_data.ndim > 1:
vm_data = vm_data.reshape(-1)
if len(vm_ids) != vm_data.shape[0]:
# 防御:若尺寸不匹配,打印尺寸并跳过
print(f" 警告:vm_ids 长度 ({len(vm_ids)}) != vm_data 长度 ({vm_data.shape[0]}). 尝试用可用对继续.")
# 最后手段:截断或填充
minlen = min(len(vm_ids), vm_data.shape[0])
vm_ids = vm_ids[:minlen]
vm_data = vm_data[:minlen]
vm_df = pd.DataFrame({
"node_id": vm_ids,
"von_mises": vm_data
})
# 按 node_id 内连接坐标表与 vm 表(仅保留有 vm 值的节点)
merged = pd.merge(vm_df, coords_df, on="node_id", how="inner")
if merged.empty:
print(f" 警告:时间集 {time_idx} 合并后数据框为空(无重叠节点 id),已跳过.")
continue
# 可选:重排列顺序
merged = merged[["node_id", "x", "y", "z", "von_mises"]]
# 带 BOM 的 utf-8-sig 编码,帮助 Windows 下 Excel 正确打开
outname = os.path.join(output_dir, f"timestep_{time_idx:03d}.csv")
merged.to_csv(outname, index=False, encoding="utf-8-sig")
print(f" 已保存 {len(merged)} 个节点 -> {outname}")
except Exception as ex:
print(f" 处理时间步 {time_idx} 时出错: {ex}")
# 此处不抛出异常,允许继续处理其他时间步
continue
print("全部完成,CSV 文件位于:", output_dir)
运行代码。运行过程比较慢,主要看你的仿真时间步有多少,越多耗时越久。代码运行中,可以看到在你设置的csv输出文件夹中的csv文件在慢慢变多。

看到终端输出完成之后,这一步就结束了。你已经得到了每个时间步下的节点坐标和应力值数据。

步骤二:汇总整理数据并可视化
有了这些csv文件,下面就是基本的数据处理操作了。GPT给我的代码如下。操作时,注意设置好刚刚导出的csv文件路径,以及最后汇总的csv文件路径。汇总的csv中,每一列分别是时间步、x坐标、y坐标、z坐标、应力值。
需要说明的是,由于课题设定的工况,我只对这些csv文件中特定范围内的节点坐标进行搜索。可通过代码中的x_min, x_max, y_min, y_max进行设置(注意单位,我这里是米)。
此外,我并不关心找出的每个节点的y坐标。所以在最后生成的三维图中,x轴是节点的x坐标位置,y轴是节点的z坐标位置,z轴是节点的应力值,点的颜色从蓝到红分别是仿真开始到仿真结束。
如果我设置的输出和你想要的不符,请自行修改代码或自行求助AI,这一步对表格数据的处理非常基础,我觉得大部分AI都可以胜任这项工作。
# 绘制 x=coord_x, y=coord_z, z=stress
# 点按时间步顺序着色
# 在 XY 平面添加圆
import os
import pandas as pd
import numpy as np
import matplotlib.pyplot as plt
from matplotlib import cm
# -----------------------------
# 用户设置
# -----------------------------
csv_dir = r"timesteps_csv/"
out_csv = r"max_stress_per_timestep.csv"
# 坐标轴范围
x_min, x_max = -62.983E-3, -47.983E-3
y_min, y_max = -7.5E-3, 7.5E-3
# 圆参数
circle_radius = 7.5E-3
circle_center = ((x_min + x_max) / 2, (y_min + y_max) / 2)
circle_z = 0.0
# -----------------------------
# 收集时间步文件
files = sorted([f for f in os.listdir(csv_dir) if f.startswith("timestep_") and f.endswith(".csv")])
if not files:
raise RuntimeError("在文件夹中未找到 timestep CSV 文件: " + csv_dir)
points = []
print("正在处理", len(files), "个时间步 CSV 文件 ...")
for f in files:
timestep = int(f.split("_")[1].split(".")[0])
path = os.path.join(csv_dir, f)
df = pd.read_csv(path)
# 按 x 和 z 过滤(z 在此对应后续 Y 轴)
filtered = df[(df["x"] >= x_min) & (df["x"] <= x_max) &
(df["z"] >= y_min) & (df["z"] <= y_max)]
if filtered.empty:
print(f" 时间步 {timestep:03d}: 无节点在过滤范围内,已跳过.")
continue
# 查找最大应力点
max_row = filtered.loc[filtered["von_mises"].idxmax()]
points.append((timestep, max_row["x"], max_row["y"], max_row["z"], max_row["von_mises"]))
print(f" 时间步 {timestep:03d}: 最大应力={max_row['von_mises']:.3f} 位于 (x={max_row['x']:.2f}, y={max_row['y']:.2f}, z={max_row['z']:.2f})")
# 转换为 DataFrame
points_df = pd.DataFrame(points, columns=["timestep", "x", "y", "z", "stress"])
# 保存输出文件
points_df.to_csv(out_csv, index=False)
if points_df.empty:
raise RuntimeError("在给定范围内未找到最大应力点.")
# -----------------------------
# 可视化
# -----------------------------
fig = plt.figure(figsize=(10, 8))
ax = fig.add_subplot(111, projection="3d")
# 按时间步着色
norm = plt.Normalize(points_df["timestep"].min(), points_df["timestep"].max())
cmap = cm.get_cmap("jet")
colors = cmap(norm(points_df["timestep"].values))
sc = ax.scatter(points_df["x"], points_df["z"], points_df["stress"],
c=colors, s=50, marker="o")
# 添加显示时间步映射的颜色条
sm = cm.ScalarMappable(cmap=cmap, norm=norm)
sm.set_array([])
cbar = plt.colorbar(sm, ax=ax, shrink=0.6)
cbar.set_label("时间步")
# 设置轴标签
ax.set_xlabel("X (coord_x)")
ax.set_ylabel("Y (coord_z)")
ax.set_zlabel("应力 (von Mises)")
# 设置轴范围
ax.set_xlim([x_min, x_max])
ax.set_ylim([y_min, y_max])
# z 轴自动
# 在 XY 平面 z=0 处画圆
theta = np.linspace(0, 2*np.pi, 200)
xc = circle_center[0] + circle_radius * np.cos(theta)
yc = circle_center[1] + circle_radius * np.sin(theta)
zc = np.full_like(xc, circle_z)
ax.plot(xc, yc, zc, color="black", linewidth=2, label="参考圆")
ax.legend()
ax.set_title("最大应力点(按时序着色)及参考圆")
plt.show()
汇总后的csv文件形式如下:

可视化结果如图所示(这里图片的数据和上面csv的数据不同,并且后期做了美化修改。仅供示意参考):

总结
借助 PyAnsys 的 DPF 模块,把 Ansys 瞬态结构仿真结果中每个时间步的最大 von-Mises 应力及其出现位置(xyz)全自动地提取出来并可视化。具体方案:①循环所有时间步,把节点坐标与 von-Mises 应力拼成 CSV(timestep_001.csv …);②再次循环这些 CSV,在指定 xyz 区域内找每步最大应力点,汇总成 max_stress_per_timestep.csv 并用 Matplotlib 画 3D 散点图(x=coord_x,y=coord_z,z=stress,颜色=时间步),全程无需打开 Mechanical,Python 一键完成。
* 作者水平有限,内容仅供参考。如有错误欢迎评论指出。
892



被折叠的 条评论
为什么被折叠?



