3. 谱系建模基础
仿真数据的可追溯性,本质上要回答三个问题:这份数据是什么、它是怎么产生的、谁对它负责。W3C PROV 模型正是围绕这三个问题建立的一套通用谱系表达规范。它把谱系世界抽象为三类核心要素——实体(Entity)、活动(Activity)、代理(Agent),再通过一组标准关系把它们连接起来。理解这三要素及其映射方法,是后续所有谱系建模工作的语法基础。
三要素的定义与边界
实体(Entity)指在谱系中需要被追踪的“物”,它可以是物理对象,也可以是数字对象。在仿真场景中,实体通常包括:几何模型文件、网格文件、材料参数表、边界条件配置、求解器输入卡、结果数据文件(如 .odb、.h5、.vtk)、后处理图表、仿真报告等。实体的关键特征是有身份、有版本、有内容。同一个逻辑对象的不同版本应视为不同实体,例如 mesh_v1.msh 与 mesh_v2.msh 是两个实体,而不是一个实体的两次修改。
活动(Activity)指在一段时间内发生、消耗或产生实体的“过程”。仿真中的典型活动包括:几何清理、网格划分、材料参数标定、求解计算、结果提取、模型校核、报告生成等。活动具有时间属性(开始、结束)、执行状态(成功、失败、中断)和参数配置。活动是谱系中“变化发生的地方”——没有活动,实体之间就不会产生因果联系。
代理(Agent)指对活动或实体负有责任的主体,可以是人、团队、组织,也可以是软件工具或自动化脚本。仿真场景中常见的代理包括:仿真工程师、CAE 主管、网格划分工具(如 ANSA)、求解器(如 Abaqus/Standard)、后处理脚本、自动化调度平台等。代理的关键作用是归属与问责:当结果出现异常时,能够沿谱系回溯到“谁在什么工具环境下执行了哪一步”。
PROV 的核心关系
三要素本身只是名词,真正让谱系“活起来”的是它们之间的关系。W3C PROV 定义了若干标准关系,其中与仿真最相关的是以下几类:
- used:活动使用了某个实体。例如“求解计算 used 网格文件”。
- wasGeneratedBy:实体由某个活动产生。例如“结果文件 wasGeneratedBy 求解计算”。
- wasDerivedFrom:实体派生自另一个实体。例如“结果文件 wasDerivedFrom 网格文件”。
- wasAttributedTo:实体归属于某个代理。例如“结果文件 wasAttributedTo 仿真工程师”。
- wasAssociatedWith:活动与代理关联。例如“求解计算 wasAssociatedWith 求解器”。
- actedOnBehalfOf:代理代表另一代理行动。例如“自动化脚本 actedOnBehalfOf 仿真团队”。
这些关系构成了谱系图的基本边。需要注意的是,wasDerivedFrom 是实体到实体的直接派生关系,而 used 和 wasGeneratedBy 是实体与活动之间的连接。在建模时,应优先使用活动作为“中转站”,而不是把所有关系都简化为实体之间的派生,否则会丢失“过程信息”,导致谱系无法回答“怎么产生的”。
仿真场景中的映射方法
把 PROV 映射到仿真场景,核心工作是建立一张映射表:把仿真资产、操作、角色分别归入实体、活动、代理,并确定它们之间的关系类型。下面给出一个典型的结构静力分析案例的映射示例。
| 仿真对象/操作/角色 | PROV 类型 | 说明 |
|---|---|---|
几何模型 bracket.step | Entity | 输入实体,有版本号 |
网格文件 mesh_v2.msh | Entity | 由网格划分活动产生 |
材料参数 steel_AISI1045.json | Entity | 输入实体,含弹性模量、泊松比 |
求解输入卡 job_static.inp | Entity | 包含边界条件与载荷 |
结果文件 job_static.odb | Entity | 求解活动输出 |
| 网格划分 | Activity | used 几何模型,wasGeneratedBy 网格文件 |
| 求解计算 | Activity | used 网格、材料、输入卡,wasGeneratedBy 结果文件 |
| 仿真工程师 张三 | Agent | wasAssociatedWith 求解计算 |
| Abaqus 2023 | Agent | wasAssociatedWith 求解计算 |
映射完成后,可以用 PROV-N 或 PROV-JSON 表达。以下是一个简化的 PROV-JSON 片段,展示“求解计算”这一活动的谱系记录:
{
"activity": {
"solve_static": {
"prov:startTime": "2024-05-12T09:20:00",
"prov:endTime": "2024-05-12T10:05:00",
"prov:type": "simulation:solver_run"
}
},
"entity": {
"mesh_v2": { "prov:type": "simulation:mesh" },
"mat_steel": { "prov:type": "simulation:material" },
"job_inp": { "prov:type": "simulation:input_deck" },
"result_odb": { "prov:type": "simulation:result" }
},
"agent": {
"engineer_zhang": { "prov:type": "prov:Person" },
"abaqus_2023": { "prov:type": "prov:SoftwareAgent" }
},
"used": {
"solve_static": ["mesh_v2", "mat_steel", "job_inp"]
},
"wasGeneratedBy": {
"result_odb": "solve_static"
},
"wasAssociatedWith": {
"solve_static": ["engineer_zhang", "abaqus_2023"]
},
"wasAttributedTo": {
"result_odb": "engineer_zhang"
}
}
这段记录表达的信息是:工程师张三使用 Abaqus 2023,在 2024-05-12 09:20 至 10:05 之间执行了一次静力求解活动,该活动使用了网格、材料和输入卡三个实体,并产生了结果文件。当后续发现结果异常时,可以沿 result_odb → solve_static → mesh_v2 / mat_steel / job_inp 回溯,快速定位是网格质量问题、材料参数错误还是输入卡设置不当。
建模时的三个关键判断
第一,实体粒度要一致。如果网格文件按整体建模,就不要在另一处把某个局部网格单独作为实体,否则谱系会出现“同一对象两种身份”的混乱。建议在项目开始前约定实体粒度:文件级、数据集级还是字段级。仿真场景通常以文件级为主,关键参数可下沉到字段级。
第二,活动要记录参数与状态。仅记录“执行了求解”是不够的。活动应携带关键参数(如求解器版本、时间步长、收敛容差)和执行状态(成功/失败/中断)。失败的活动同样有价值——它解释了为什么某个结果文件不存在,或者为什么后续活动被阻塞。
第三,代理要区分人与工具。人和软件工具都是代理,但它们的责任性质不同。人承担决策责任,工具承担执行责任。在 wasAssociatedWith 中同时记录两者,可以在追溯时区分“是工具版本问题”还是“是人为设置问题”。
上图把一次典型结构静力分析的谱系关系完整呈现出来:左侧实体列是“物”,中间活动列是“过程”,右侧代理列是“责任主体”。蓝色箭头表示活动消耗实体,绿色箭头表示活动产生实体,紫色箭头表示活动与代理的关联,橙色虚线表示实体归属与派生。读图时可以从结果文件出发,沿绿色箭头反向找到求解活动,再沿蓝色箭头找到输入实体,沿紫色箭头找到执行者,从而完成一次完整的谱系追溯。
掌握三要素与核心关系后,下一步需要解决的是“如何把这种映射落到具体的数据结构和工具链中”。这涉及标识符设计、版本管理、关系存储以及查询接口,是谱系建模从概念走向工程实现的关键环节。