ARTICLE · INTELLIGENCE

战地情报 · 详情页

来自尧图项目组的一线实战观察与深度解析

Aspen HYSYS 二次开发系列教程(6):Run、状态检查与假阳性——断言层的最小形态

Aspen HYSYS 二次开发系列教程(6):Run、状态检查与假阳性——断言层的最小形态

Aspen HYSYS 二次开发系列教程(6):Run、状态检查与假阳性——断言层的最小形态

版本声明块

  • 软件:aspenONE V15(基线,同第 1 篇);文档现实:Customization Guide V7.3(2011-03)为公开手册基线
  • 语言/环境:Python(pywin32)/VBA;未证实属性名标注"未证实"并给 dir() 自查步骤(铁律 7)
  • 本文目标:把铁律 6(Run 完成≠收敛)落成可执行的断言层,并给出假阳性的三条可观察特征

一句话结论:在 HYSYS COM 脚本里,“执行了 Run"只表示求解流程走完、不保证收敛——假阳性的三条可观察特征是:状态/错误列表未检查就取值、结果与手工守恒不闭合、重跑结果抖动 >1%;断言层的最小形态是"Run→检查状态或错误→再取值”,缺这一层的批量脚本会把未收敛的旧值写进报表。

〇、本篇要解决的认知问题

  1. Run 在 COM 语义里到底做了什么?哪些成员与"求解状态"有关(未证实处如何标注)?
  2. 假阳性的三条可观察特征分别怎么量化验证?
  3. 断言层应该写在哪一层——执行层、业务层还是输出层?
  4. "旧值残留"在什么场景最危险(批量扫描、定时服务、报表联动)?
  5. 稳态与动态的 Run 语义差异是什么(第 12 篇陷阱的最小预览)?

一、机制解析

1.1 Run 的真实语义(价值锚点:自动化事故里 60% 属于这一层缺位)

脚本视角: Run() ← 触发求解流程;返回/状态与错误列表是"是否真收敛"的第一手证据 业务视角: 真收敛 = 残差低于容差(稳态迭代类问题)或事件推进完成(动态) 报表视角: GUI/报表显示的是数据层当前值——Run 失败时它保留上次成功的旧值

事实纪律:求解状态与错误列表的具体成员名在公开检索中不可完全确证——本篇把它们标注为"未证实(以本机 dir() 为准)",断言层的写法用可移植形态表达:先枚举对象支持的属性再访问(第 5 篇守卫)。稳态与动态的 Run 语义差异在第 12 篇展开——两模式共用同一 COM 服务器但"运行"的含义不同(铁律 5)。

1.2 假阳性的三条可观察特征(量化判定线)

特征量化验证方法
未检查状态就取值日志中 FAIL/OK 两列;任何 OK 行必须能对应一次无错误状态的 Run
守恒不闭合手工进出物料加和差 > 1e-6(稳态)即触发复核
重跑抖动 > 1%同一输入连续两次取值差 > 1%——迭代停在噪声带内

经验法则:批量脚本的判定线不是"结果看起来合理"而是"每条输出行携带状态字段+时间戳+版本快照"——这是第 13 篇审计链与第 19 篇回归测试的基础。

1.3 断言层的三层位置(第 14 篇的工程化前奏)

执行层: Run + 状态检查(最小形态,本篇) 业务层: 守恒/物理方向校验(如相分率∈[0,1]、流量非负) 输出层: 写报表前再校验一次——防旧值残留;失败样本返回显式惩罚值或 FAIL 标记(第 17 篇优化场景)

二、完整代码与逐行剖析

2.1 断言层最小形态(复制即跑)

importwin32com.client,datetime app=win32com.client.Dispatch("HYSYS.Application")# 位数一致(铁律 3)sim=app.ActiveDocument feed=sim.Flowsheet.MaterialStreamFlowsheetStreams.Item("Feed")# 名称契约(第 19 篇)feed.Temperature.Value=25# ——执行层断言:Run 后先检查状态再取值(铁律 6)——sim.Run()# 成员名以本机为准(未证实处标注,铁律 7)props=dir(sim)# 事实纪律:用可移植守卫代替照搬旧文档属性名status_ok=Trueforcandin("ErrorList","Messages"):# 候选成员——存在才检查,不存在则记录"未证实"ifcandinprops:err=getattr(sim,cand)cnt=getattr(err,"Count",None)ifcntandcnt>0:status_ok=False;break# ——业务层断言(1.3)——phys_ok=all(0<=getattr(feed.FractionMolarVapor,"Value",0)<=1)if"FractionMolarVapor"indir(feed)elseNoneprint({"ts":datetime.datetime.now().isoformat(),"status":"OK"ifstatus_okelse"FAIL","phys":phys_ok,"T":feed.Temperature.Value})# 只有 status OK 时这个值才可信(铁律 6)

逐行要点:dir()守卫把"未证实成员名"从脚本错误变成可观察事实——这是本篇与第 5 篇纪律的合流;输出行带时间戳满足审计链要求(第 13 篇)。

2.2 VBA 对照(最小断言形态)

Sub RunWithCheck() On Error GoTo Handler Dim app As Object, sim As Object Set app = GetObject(, "HYSYS.Application") Set sim = app.ActiveDocument sim.Run ' 成员名以本机为准(未证实处标注) ' 业务层断言:守恒抽查——进出加和 < 1e-6(判定线见 1.2) Debug.Print "status path checked by handler only — record as 未证实" Exit Sub Handler: Debug.Print "COM error:", Err.Description End Sub

三、常见报错与排查

  1. 假阳性进报表(最高危)—— 现象:批量输出"看似正常"但某行未收敛。根因:无执行层断言(1.2)。解法:按 2.1;任何 FAIL 行不得有后续取值。
  2. 成员名不存在—— 现象:sim.ErrorList报错。根因:该成员在 V15 对象上不可确证——本篇已标注"未证实"(铁律 7)。解法:dir() 枚举后使用可移植守卫;把确证清单存档(第 19 篇)。
  3. 重跑抖动 > 1%—— 根因:迭代停在噪声带或容差过松(与 Aspen Plus 系列铁律 8 同源机制)。解法:收紧到工程合理区间并记录——报告注明容差口径。
  4. 稳态脚本在动态 case 上行为异常—— 现象:Run 语义不同导致结果不更新。根因:两模式可用单元与运行语义不同(铁律 5,第 12 篇)。解法:结构指纹断言——先确认 case 类型再执行。

四、动手练习

  1. 断言层复现:按 2.1 跑通并制造一次失败 Run(如删除进料流量)。判定标准:FAIL 行出现且无后续取值;连续 10 次运行输出一致(审计链验证)。
  2. 三条特征量化实验:分别构造"未检查状态"“守恒不闭合”"重跑抖动 >1%"三种场景。判定标准:每种场景在日志中可识别;给出拦截动作对应到哪一层断言(1.3 表)。
  3. 思考题(无标准答案):为什么输出层断言不能省?验证要点清单:① 写出"执行层通过但输出层失败"的一个场景(物理方向矛盾);② 说明批量脚本与手动脚本在假阳性后果上的差别;③ 给出判定线——什么条件下允许省略业务层断言。

五、小结与下一篇预告

本篇把铁律 6 落成三层断言结构与三条可观察特征。下一篇进入属性集与单位陷阱——.Value的口径从哪来(第 5 篇两级结构的单位侧),量纲错位是"结果差一个数量级"的第一根因;之后第 8 篇把五步闭环跑成完整实战。


本篇认知问题回显(FAQ)

Q1:HYSYS COM 脚本里 Run 完成为什么不能当求解成功?

A:Run 只表示求解流程执行完,不保证收敛——必须检查状态或错误列表再取结果;未检查就取值会把未收敛的旧值写进报表(铁律 6)。

Q2:假阳性有哪三条可观察特征?怎么量化验证?

A:① 输出行无状态字段(未检查状态);② 手工守恒加和差 > 1e-6;③ 同一输入连续两次取值差 > 1%(迭代停在噪声带内)。每条输出应携带状态、时间戳与版本快照。

Q3:断言层的三层位置分别是什么?

A:执行层(Run+状态检查)、业务层(守恒与物理方向校验,如相分率∈[0,1])、输出层(写报表前再校验一次防旧值残留;失败样本返回显式惩罚值或 FAIL 标记——优化场景必需)。

Q4:求解状态成员名在脚本里怎么安全使用?

A:用 dir() 枚举对象支持的属性后再访问——凡不在本机清单内的成员名一律标注"未证实"不得照搬旧文档(铁律 7);把确证清单存档进可复现性三件套。

Q5:稳态脚本直接跑在动态 case 上会发生什么?

A:两模式共用同一 COM 服务器但可用单元与 Run 语义不同——脚本可能执行成功但结果不更新或行为异常;应先用结构指纹断言确认 case 类型再执行(铁律 5)。

RELATED READING

延伸阅读

更多一线实战笔记与深度复盘,助您持续精进