工程师平台
Abaqus 实战2026-09-07

导入成功、看得到 Ductile Damage、就是不删单元

韧性损伤是 Abaqus 里最常被"填对了却不失效"的一块。JSON 导进去没报错,材料编辑器里 Ductile Damage 也在,可分析跑完单元一个没删、载荷位移曲线一路往上不回头。绝大多数情况下 问题不在数值,而在结构:损伤起始和损伤演化是两个独立对象,只写前者, Abaqus 只会记录一个损伤变量,不会让材料软化,也不会删单元。这篇把damage.ductile 的三列讲清楚,把插件源码里那几条校验说明白,再把 "不报错但结果错"的五种情况一次列完。
起始和演化必须都写
只有 damage.ductile 而没有它下面的 evolution,材料只会累积损伤变量,不会软化、不会删单元。
三列的顺序是固定的
fractureStrain、stressTriaxiality、strainRate,插件按这个顺序读,写反了不报错但物理全乱。
演化值不能为 0
fractureStrain 允许 0,但 evolution 里的位移或能量必须严格大于 0 —— 源码里这两处校验用的是不同参数。

01先分清起始和演化:为什么填了不断

Abaqus 的延性金属损伤是分两步走的。第一步叫损伤起始(damage initiation),它只回答 一个问题:什么时候开始坏。第二步叫损伤演化(damage evolution),它回答 另一个问题:开始坏之后怎么坏下去。两者在 Abaqus 内部是两个独立的关键字, 插件的 JSON 也就跟着分成两层。

"damage": {
  "ductile": {
    "table": [
      [0.35, -0.33, 0.001],
      [0.25,  0.00, 0.001],
      [0.18,  0.33, 0.001]
    ],
    "evolution": {
      "type": "DISPLACEMENT",
      "value": 0.5,
      "softening": "LINEAR"
    }
  }
}

外层的 table 是起始准则,内层的 evolution 是演化规律。只写外层不写内层,导入依然成功,材料里也确实多了一条 Ductile Damage, 但 Abaqus 拿到的只是一个"何时开始"的判据,没有"之后怎么退化"的规律,于是 SDEG 这个损伤变量会一路涨到 1 附近然后停住,单元刚度不降、不删除。你在结果里看不到断裂, 只能在场变量里看到一片损伤区。

这是最高频的坑,而且不报任何错
这一条是韧性损伤最高频的坑,而且它不会报任何错。 如果你的模型"导入成功、看得到 Ductile Damage、就是不断", 先去 JSON 里数一遍有没有 evolution

顺带说一句:损伤是叠在塑性之上的,材料必须已经有 plastic 块。 塑性表本身的坑(应变不从 0 开始、应力不单调、名义应力当真应力用)在塑性表那六种报错真应力真应变换算两篇里已经拆过,这里不重复。

02ductile 的三列:字段名、顺序、以及各自的含义

插件读 damage.ductile 时要求的字段是固定的三个,顺序也是固定的。 源码里这一行写得很直白:

_rows(sub, ('fractureStrain', 'stressTriaxiality', 'strainRate'), 'damage.ductile')
字段名含义取值范围
第 1 列fractureStrain该应力状态下的等效塑性断裂应变≥ 0(0 合法)
第 2 列stressTriaxiality应力三轴度,静水压力除以 Mises 应力再取负号的那个量可正可负
第 3 列strainRate等效塑性应变率≥ 0
第 4 列(温度)只在你多写一列时才存在按你的温标
三列的名字和顺序取自 materialImporterKernel.py 的 _addDamage(),不是约定俗成

第 4 列是隐式的:插件并不要求你显式声明温度相关,而是按表宽推断。 源码里这一句是关键:

tempDep = spec.get('temperatureDependency', width > len(columns))

意思是,如果你没写 temperatureDependency,而每行给了 4 个数(比声明的 3 列多), 插件就认为第 4 列是温度。这个设计很方便,但也意味着多打一个数就会被当成温度, 而不是报错。温度列的完整规则在温度相关表怎么排那篇里。

关于三轴度:它是 Abaqus 里用来区分"拉、剪、压"三种应力状态的标量。纯剪切附近它在 0 左右,单轴拉伸大约 1/3,缺口和三向拉应力区会更高。同一种材料在三向拉应力下能承受的 塑性应变要小得多,所以这张表的物理趋势应该是三轴度越高、断裂应变越小

03拿示例库里那组演示值当参照

插件自带的 materials_sample.json 里有一组韧性损伤的完整写法, 挂在 Steel_Q345 上。下面这些数值是示例库里的演示值, 用来说明格式和趋势,不是标准值、也不是某炉钢的实测值 —— 真做项目要用自己的试验数据。

fractureStrainstressTriaxialitystrainRate大致对应的应力状态
0.35-0.330.001偏压
0.250.000.001纯剪附近
0.180.330.001单轴拉伸
来自插件示例库 materials_sample.json 的 Steel_Q345,演示值

值得学的不是这三个数,而是它们的排布方式:三轴度从 -0.33 单调升到 0.33, 断裂应变从 0.35 单调降到 0.18,应变率一列保持同一个值。这就是一张最小可用的韧性损伤表 —— 三轴度覆盖了压、剪、拉三个点,趋势符合物理,应变率维度先不展开。

同一个材料的 evolution 写的是 typeDISPLACEMENTvalue 为 0.5、softeningLINEAR。 这个 0.5 的单位是长度,在毫米制里就是 0.5 mm,含义是"从开始损伤到完全失效, 等效塑性位移走 0.5 mm"。它的单位问题下面单独讲。

这个材料在示例库里的塑性表是 345 / 420 / 480 / 520 配 0 / 0.02 / 0.06 / 0.15, 也是演示值。想核对整份 JSON 的字段层级, 对着 JSON 字段说明看一遍最快。

04evolution 的两种写法,以及那个不允许为 0 的校验

演化子块有两种类型,插件按 type 决定去读哪个字段名。源码里是一行三元表达式:

etype  = _constant(spec.get('type'), DISPLACEMENT)
column = 'fractureEnergy' if etype == ENERGY else 'displacementAtFailure'
type插件要读的字段量纲对网格的敏感度
DISPLACEMENT(默认)displacementAtFailure长度
ENERGYfractureEnergy能量 / 面积

两种写法都还接受一个通用的 value 作为兜底字段名 —— 但顺序有讲究: 插件先找 table 或者当前 type 对应的正式字段名,两者都没有时才回头去找 value。所以"value": 0.5"displacementAtFailure": 0.5效果一样(示例库用的是前者),但如果你 type 写了 ENERGY、字段名却填成displacementAtFailure,插件会抱怨缺 value —— 一条指向兜底字段的报错,真正的病根是字段名和 type 不配套。

type 不写就是 DISPLACEMENT,这个默认值是插件给的 (源码里无条件调用了一次常量解析)。但 softeningdegradation 不一样:源码里是写了这个键才传, 不写就整个参数不传给 Abaqus,用的是 Abaqus 自己那一端的默认值。 想明确控制这两项,就显式写出来,别依赖"应该是默认那个吧"。

allowZero 那一个参数,决定了报错串里的形容词
起始表里的 fractureStrain 允许为 0, 但 evolution 里的位移或能量必须严格大于 0。 源码里这两处调用的是同一个校验函数,区别只在一个参数: 起始表那次带了 allowZero=True,evolution 那次没带。
# 起始表:允许 0
_checkColumn(table, 0, ..., 'fractureStrain', allowZero=True)

# 演化:不允许 0
_checkColumn(table, 0, ..., column)

所以你如果把演化值写成 0(比如想表达"一到就断"),会拿到这样一条报错:

damage.ductile.evolution: displacementAtFailure must be positive, got 0

而在起始表里把断裂应变写成 0,是合法的 —— 那表示这个应力状态下材料一进入塑性就开始损伤。 如果你写了负数,报错串里的形容词会换成另一个:

damage.ductile: fractureStrain must be non-negative, got -0.2

这两条串的差别(positivenon-negative)就是那个allowZero 参数的直接产物。看到哪一个,就知道插件在校验哪一层。

05演化值的单位:为什么位移型换个网格结果就变

displacementAtFailure 的量纲是长度。这件事有两个后果, 都很容易吃亏。

  1. 它跟着你的单位制走。整套模型按毫米—吨—秒建的,这个 0.5 就是 0.5 mm; 按米—千克—秒建的,0.5 就是 0.5 m,差了一千倍。单位制怎么自洽,单位制那篇里有完整的换算表。
  2. 和网格尺寸耦合。等效塑性位移等于损伤区的等效塑性应变乘以单元特征长度, 所以同一个 0.5 mm,在 1 mm 网格上和在 0.2 mm 网格上代表的应变量完全不同。 网格一细,结构就"变脆"。

这就是 ENERGY 型存在的理由。fractureEnergy 是单位面积的断裂能, Abaqus 内部会用它除以单元特征长度反算出位移,于是网格细化时结果收敛, 而不是一路变脆。代价是你得有断裂能这个量 —— 它通常来自断裂力学试验, 比试验测个断后位移麻烦。

选位移还是选能量,取决于你会不会改网格
实践上的取舍:做参数研究、要换网格比结果的,用 ENERGY; 只在一个固定网格上标定曲线、不打算改网格的,用 DISPLACEMENT 更省事。 示例库里 Steel_Q345 用位移、Al_6061_T6 用能量, 正好把两种都演示了一遍,后者在Johnson-Cook 那篇里讲。

06不报错但结果错的五种情况

上面那些报错串好办 —— 插件会拦。真正麻烦的是插件拦不住、Abaqus 也不吭声的这五种。

情况插件会拦吗实际后果
漏了 evolution不会只累积损伤变量,材料不软化、单元不删
表只有一行不会三轴度插值退化成常数,拉压剪都用同一个断裂应变
三轴度那列没排序不会插值按你给的顺序连线,可能连出反向段
三列写反了顺序不会数都是合法数,但被当成完全不同的物理量
多打一个数不会被当成温度列,静默变成温度相关表

第二条值得展开。只给一行表,语法上完全合法,Abaqus 也照跑, 但你实际上是在说"这个材料在任何应力状态下的断裂应变都一样"。 对韧性金属来说这几乎总是错的 —— 缺口根部和光滑试棒的断裂应变能差好几倍。 要么老实给三个以上三轴度点,要么心里清楚自己在用一个各向应力状态无关的粗模型。

第三条的表现很隐蔽:假设你给的三轴度顺序是 0.33 / -0.33 / 0,插件不会重排, Abaqus 就按这个顺序理解分段线性关系,插出来的曲线会在中间折回去。提交前按第 2 列升序排一遍,这是一分钟的事。

第四条容易发生在从别人的 inp 里抄数的时候 —— 不同前处理器导出的列顺序不一致。 判断方法很简单:断裂应变那一列应该都是正的小数(0.05 到 2 之间居多), 三轴度那一列应该有负数或跨零。如果第 1 列出现了负数,插件会直接报错, 这反倒帮你抓住了写反的情况。

07提交前照着过一遍

  1. 材料里已经有 plastic 块,且塑性表第一行应变是 0、应力单调不降。
  2. damage.ductile.table 每行三个数,顺序是断裂应变、三轴度、应变率。
  3. 第 1 列没有负数;第 2 列已按升序排好;不多不少正好三个数(除非你确实要温度列)。
  4. 三轴度至少覆盖三个点,把压、剪、拉都带上,断裂应变随三轴度单调下降。
  5. evolution 子块存在,且里面的位移或能量大于 0
  6. 演化值的单位和整套模型的单位制一致;如果后面要改网格,优先用 ENERGY
  7. 导入后在材料编辑器里确认 Ductile Damage 下面挂着 Damage Evolution, 而不是只有一条起始准则。要是材料整个没生效,先看材料没生效那篇
一个不用跑分析就能做的确认
最后一条的检查方法:在 Property 模块双击材料,展开 Mechanical 下的 Damage for Ductile Metals,Suboptions 里应该能点开 Damage Evolution。点不开,就是漏了。

常见问题

damage.ductile 填好了导入也成功,为什么单元一个都不删?

九成是漏了 evolution 子块。损伤起始只告诉 Abaqus 什么时候开始坏,损伤演化才决定怎么退化和什么时候删单元。只写起始不会报错,材料编辑器里也能看到 Ductile Damage,但分析结果里只会有损伤变量升高,看不到断裂。检查方法是在 Property 模块双击材料,展开 Damage for Ductile Metals,看 Suboptions 里能不能点开 Damage Evolution。

fractureStrain 写 0 会报错吗?

不会。插件校验这一列时带了 allowZero=True,所以 0 是合法值,含义是该应力状态下材料一进入塑性就开始损伤。但负数会被拦,报错串是 damage.ductile: fractureStrain must be non-negative, got -0.2 这种形式。注意 evolution 里的位移或能量不一样,那一处校验没带 allowZero,写 0 会报 must be positive。

DISPLACEMENT 和 ENERGY 该选哪个?

DISPLACEMENT 型填的是等效塑性位移,量纲是长度,和网格尺寸耦合,网格一细结构就变脆。ENERGY 型填的是单位面积断裂能,Abaqus 会用单元特征长度换算,网格细化时结果收敛。如果要做网格敏感性研究或者后面会改网格,用 ENERGY;如果只在一个固定网格上标定曲线,DISPLACEMENT 更省事,因为断后位移比断裂能容易测。

我的表每行写了 4 个数,为什么变成温度相关了?

这是插件的表宽推断规则。源码里 tempDep 的默认值是表宽大于声明列数,也就是说 damage.ductile 声明了三列,你给 4 个数,插件就认为第 4 列是温度,不会报错。想避免误触发,要么严格给三个数,要么显式写 temperatureDependency 说明你的意图。

只给一行 ductile 表可以吗?

语法上可以,物理上通常不合适。只有一行意味着三轴度插值退化成常数,拉伸、剪切、三向拉应力区都用同一个断裂应变。韧性金属在缺口根部和光滑试棒上的断裂应变能差好几倍,所以建议至少给三个三轴度点,把偏压、纯剪附近、单轴拉伸覆盖到,并保证断裂应变随三轴度单调下降。

stressTriaxiality 那一列需要自己排序吗?

需要。插件不会替你重排,Abaqus 按你给的行顺序理解分段线性关系。如果三轴度那列的顺序是乱的,插出来的曲线会在中间折回去,结果不可靠而且不报错。提交前按第 2 列升序排一遍。

这一步可以不自己做

材料编辑器里展开 Damage for Ductile Metals,Suboptions 里点不开 Damage Evolution —— 这一眼就是"填了不断"的全部原因,比翻一遍数值快得多。

在线材料库需要 Abaqus 2023 或更高版本;2022 及更早只能用本地 JSON 材料库。