3. Python基础快速回顾
CAE二次开发并不要求你成为Python语言专家,但要求你对几类核心语法有“能读、能改、能写”的熟练度。本节不追求语言完备性,而是围绕一个真实场景——用脚本批量修改Abaqus/Ansys模型的材料参数并输出结果——来回顾数据类型、控制流、函数、模块、文件操作与异常处理。学完本节,你应当能独立写出一个几十行、可运行、可复用的参数扫描脚本。
一、数据类型:CAE脚本里真正高频的只有几种
CAE脚本处理的对象高度集中:节点编号、单元编号、坐标、材料参数、路径字符串、结果列表。因此最常用的类型是:int(编号、计数)、float(模量、泊松比、载荷)、str(文件路径、集合名、材料名)、list/tuple(节点列表、参数序列)、dict(名称到值的映射,如材料参数表)。
需要特别注意的是可变与不可变的区别。list 是可变对象,赋值时传递的是引用,这在批量修改参数时极易踩坑:
base = [210000.0, 0.3] # 钢的弹性模量与泊松比
steel = base # 这是引用,不是拷贝
steel[0] = 200000.0
print(base) # 输出 [200000.0, 0.3],base 被意外修改
# 正确做法:显式拷贝
steel = base.copy()
steel[0] = 200000.0
print(base) # 输出 [210000.0, 0.3]
dict 在CAE中常用于组织参数集,例如把材料名映射到参数字典,遍历时既清晰又便于扩展:
materials = {
"Steel": {"E": 210000.0, "nu": 0.30, "rho": 7.85e-9},
"Alu": {"E": 70000.0, "nu": 0.33, "rho": 2.70e-9},
"Rubber": {"E": 10.0, "nu": 0.49, "rho": 1.10e-9},
}
单位一致性是CAE脚本的隐形陷阱。上例中密度用 t/mm³、模量用 MPa,属于 mm-t-s 一致单位制;若混用 m 与 mm,结果会差 10⁹ 倍。脚本中应把单位约定写在注释里并全程遵守。
二、控制流:批量扫描的骨架
CAE脚本的控制流几乎都围绕“遍历参数组合 + 条件判断”展开。for 循环遍历参数列表,if 判断筛选有效工况,while 一般只在迭代求解或收敛判断中出现。下面是一个典型的双层参数扫描骨架:
thickness_list = [1.0, 2.0, 3.0] # mm
load_list = [500.0, 1000.0] # N
for t in thickness_list:
for F in load_list:
if t <= 0 or F <= 0:
continue # 跳过非法工况
case_name = f"t{t}_F{int(F)}"
print("准备计算工况:", case_name)
这里用到了 f-string 拼接工况名,这是生成文件名、集合名、输出目录名最实用的方式。continue 用于跳过非法组合,break 用于提前终止(例如检测到模型不收敛时放弃当前参数组)。列表推导式在提取结果时非常高效,例如从结果列表中筛出安全工况:
results = [("t1.0_F500", 120.5), ("t2.0_F1000", 310.2), ("t3.0_F1000", 180.7)]
safe = [name for name, stress in results if stress < 250.0]
print(safe) # ['t1.0_F500', 't3.0_F1000']
三、函数:把“一次能跑”变成“反复能用”
函数是脚本可维护性的分界线。建议把“改参数—提交计算—读结果”拆成独立函数,每个函数只做一件事。参数用关键字形式调用,可读性远高于位置参数:
def build_case_name(thickness, load):
return f"t{thickness}_F{int(load)}"
def is_safe(stress, allow=250.0):
return stress < allow
name = build_case_name(thickness=2.0, load=1000.0)
print(name, is_safe(310.2)) # t2.0_F1000 False
默认参数 allow=250.0 让函数在多数情况下可直接调用,特殊材料再显式传入许用值。注意不要用可变对象(如 list)作默认参数,否则多次调用会共享同一对象,这是Python的经典陷阱。
四、模块与文件操作:脚本与外部世界的接口
模块分两类:标准库(os、sys、csv、json、math)和CAE平台API(abaqus、odbAccess、ansys相关模块)。标准库负责文件与数据,平台API负责建模与求解。文件操作推荐用 with 语句,确保异常时也能正确关闭:
import csv, os
os.makedirs("results", exist_ok=True) # 目录已存在也不报错
with open("results/summary.csv", "w", newline="", encoding="utf-8") as f:
writer = csv.writer(f)
writer.writerow(["case", "max_stress_MPa", "safe"])
for name, stress in results:
writer.writerow([name, stress, is_safe(stress)])
读取参数表时同理,用 csv.reader 逐行解析,把字符串转成 float 后再参与计算。路径拼接优先用 os.path.join 或 pathlib.Path,避免手写反斜杠在不同系统上出错。
五、异常处理:让批量任务不因单个工况崩溃
批量计算最怕“跑到第17个工况报错退出,前16个结果也没保存”。异常处理的目标是隔离故障、记录原因、继续执行:
log = []
for t in thickness_list:
for F in load_list:
case = build_case_name(t, F)
try:
stress = run_simulation(t, F) # 假设的求解函数
log.append((case, stress, "OK"))
except ZeroDivisionError as e:
log.append((case, None, f"参数错误: {e}"))
except Exception as e:
log.append((case, None, f"求解失败: {type(e).__name__}"))
finally:
print(f"{case} 处理结束")
捕获异常时应尽量具体,先捕获可预期的错误(如除零、文件不存在),再用 Exception 兜底并记录异常类型。finally 适合做清理或进度提示。切忌用裸 except 吞掉所有错误而不记录,那会让排障变得极其困难。