:环境盘点与许可——统一安装器、Zentitle2 三层级与“先探测后编码”清单法)
AFT二次开发教程02环境盘点与许可——统一安装器、Zentitle2 三层级与“先探测后编码”清单法版本与事实声明产品与版本AFT Fathom 15 / AFT Impulse 122026-09 官方文档门户公告四产品由单一 Datacor Flow Simulation 安装器交付。旧版帮助文档Fathom 13 / Impulse 10仍在线用于机制细节。语言/环境Python 3.x 标准库os/glob/winreg/jsonWindows 桌面环境。本文目标读完能在 30 分钟内产出一份本机 AFT 环境清单 JSON并据此决定该买/该用哪个授权层级。铁律 3先探测后编码在本篇首次落地本文不写任何 AFT 可执行文件的具体文件名只写探测方法。许可条款与价格以 Datacor 官方渠道为准本文所有路径均为探测目标而非断言。一句话结论AFT 自 2026-09 版起由统一安装器交付支持静默安装、授权走Zentitle2的Core/Pro/Enterprise三层级Pro 解锁 Goal Seeking/Extended Transients/Slurries/PulsationEnterprise 解锁Local License ServerLLS与metered API functionality而席位在应用崩溃时不会正常归还并可能被标记为orphaned服务端 2 小时兜底释放——因此批量平台的第一个模块必须是环境探测层先把安装痕迹、授权层级、备份配置探测成机器可读清单。〇、本篇要解决的认知问题Q1统一安装器到底改变了什么安装后机器上会留下哪些可探测的痕迹Q2Zentitle2的 Core / Pro / Enterprise 三层级分别解锁哪些能力二次开发必须上 Enterprise 吗Q3完全气隙air-gapped的工业现场AFT 靠什么授权LLS 是什么形态Q4为什么同事强杀了 AFT 进程会导致别人打不开软件orphaned seat 的机制是什么Q5怎么把环境盘点变成一次可重复、可入库存档的动作而不是每次靠记忆一、机制解析2.1 统一安装器改变了什么官方安装文档说得很直白自2026 年 9 月版本起Fathom、Arrow、Impulse、xStream由同一个 Datacor Flow Simulation 安装器交付取代原先四个独立安装器。要点变化点旧世界四安装器新世界统一安装器对二次开发的意义下载/升级四份安装包各自排期一份安装包安装时勾选产品环境更一致回归测试基线更稳底层四产品各自维护共享架构基础built on a shared architectural foundation同族产品的数据契约更可能对齐升级方式各自卸载重装就地升级update in place无需先卸载升级脚本可以简化企业部署—支持静默安装脚本silent installation scripts批量平台可以纳入 CI 或镜像化交付为什么这对你重要统一安装器 静默安装意味着你的批量水力分析平台第一次可以写进环境的可复现声明里——“本项目在 Fathom 15 Impulse 12 环境下验证安装方式为静默安装”。没有这句话你的批跑结果永远无法被合规/审计接受。2.2 Zentitle2 三层级你真正需要哪一层现授权平台是Zentitle2由Nalpeiron提供。官方定义了三层┌───────────────────────────────────────────────────────────┐ │ Enterprise ← 气隙站点 计量式 API │ │ Local License Server (LLS) │ │ metered API functionality │ ├───────────────────────────────────────────────────────────┤ │ Pro ← 高级物理特性 │ │ Goal Seeking / Extended Transients / Slurries / Pulsation│ ├───────────────────────────────────────────────────────────┤ │ Core ← 基础应用无高级特性 │ └───────────────────────────────────────────────────────────┘ 期限2 Week Trial / 1 Year / 3 Year 权益 Entitlement Tier Term Number of Seats关键判断经验法则本系列 90% 的自动化内容AFT Transfer 批量改参、Excel Export Manager 取数、Start Batch Run 批跑、Fathom→Impulse 衔接、Force File 交付在 Core 层就能做——因为它们是 GUI/文件通道不是高级物理特性。只有在两种情况才需要往上买你的模型用了GSCGoal Seek Control目标求解与控制或XTSExtended Time Simulation扩展时间模拟等 Pro 特性例如求让某节点压力等于目标值的泵转速这类反算——那批跑必须在 Pro你的现场是气隙网络无互联网、无云——必须 Enterprise 用 LLS你要用厂商的metered API——必须 Enterprise且 API 的用法以厂商提供的文档为准官方公开资料未给出技术细节铁律 2。2.3 LLS气隙现场的授权形态官方描述Local License Server (LLS)是给完全隔离于互联网的气隙网络用的它是一个Docker 应用部署在你的内网服务器上终端机上配置为从内网 LLS 实例签出/归还席位。LLS 本身需要先通过在环境内外传递证书的过程完成初始激活然后载入在订阅期限内有效的权益。还有两种激活方式Online Activation标准联网激活防火墙白名单主机名https://datacor.license.nalpeiron.ioTemporary Offline Activation临时离线激活把席位暂时锁定到某台机器 1 周适合短期出差无网不适合长期气隙那种情况用 LLS且需要公司License Admin提供专用激活码。为什么这对你重要如果你在炼厂/化工厂的内网做自动化你的批量任务很可能跑在气隙环境。那么你的平台文档里必须写清授权依赖 LLS 内网服务器 hostname并且批跑脚本不能假设有外网。2.4 席位池与 orphaned seat真实运维坑官方原文的机制链Entitlement 是一池席位a pool of seats登录并打开应用时签出一个 seat正常关闭应用时归还如果软件崩溃或被任务管理器强杀席位不会正常归还通常同一账号、同一机器重新打开再正常关闭可以释放否则服务端有2 小时 checkout interval作为安全兜底自动释放这段时间内席位仍算被占用超过签出期即视为orphaned孤立仍显示最后签出信息但如果池里其他席位都被占用下一个用户会重置这个孤立席位以更新信息重新签出。这是本系列铁律 8 的根因任何驱动 AFT 应用的批量代码必须做超时 try/finally 正常关闭 残留进程清理三步。否则你半夜批跑挂死早上不仅任务没跑完还把公司席位池的 seat 全锁死两小时以上——这比任务失败更讨人厌。2.5 备份文件与本地化纪律模型文件保存时AFT 会级联滚动备份AFT Fathom.bakF-001、...bakF-002……Arrow 为bakA-、Impulse 为bakI-、xStream 为bakX-默认最多保留 3 份可在User Options的Number of Backup Files Created调整也可开自动定时保存。官方同时给了一条必须当纪律执行的建议不要在网络盘/共享服务器/云同步目录里直接打开-编辑-保存模型文件VPN 断线尤危险。正确做法下载到本地 → 本地编辑保存 → 再上传铁律 7。二、完整代码与逐行剖析代码 2-1probe_env.py环境探测 → 清单 JSON只依赖标准库。它做三件事找安装目录、找卸载注册项、找开始菜单快捷方式并把结果写成机器可读的 JSON。# -*- coding: utf-8 -*- probe_env.py —— AFT 环境探测只依赖标准库 不写死任何可执行文件名只输出探测到的路径供后续脚本引用铁律3。 运行 python probe_env.py --out aft_env.json python probe_env.py --selftest importargparseimportglobimportjsonimportosimportsys# 探测目标均为候选不构成断言官方文档曾出现 C:\AFT Products 作为默认安装根INSTALL_ROOTS[rC:\AFT Products,rC:\Program Files\AFT Products,rC:\Program Files (x86)\AFT Products]UNINSTALL_KEYS[rSOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall,rSOFTWARE\WOW6432Node\Microsoft\Windows\CurrentVersion\Uninstall,]NAME_HINTS(fathom,impulse,arrow,xstream,aft,datacor)deffind_install_dirs():返回存在的安装根与其中的可执行文件候选。found{}forrootinINSTALL_ROOTS:ifos.path.isdir(root):exes[]forpatin(**/*.exe,):exes[pforpinglob.glob(os.path.join(root,pat),recursiveTrue)]found[root]sorted(exes)[:50]# 截断防超大目录拖慢returnfounddeffind_uninstall_entries():扫描注册表卸载项找名字含关键词的条目。用 winreg 时容错。entries[]try:importwinreg# Windows 限定非 Windows 时优雅降级exceptImportError:return[{note:winreg 不可用非 Windows 环境跳过注册表扫描}]forhive,pathin[(winreg.HKEY_LOCAL_MACHINE,k)forkinUNINSTALL_KEYS]:try:withwinreg.OpenKey(hive,path)askey:sub0whileTrue:try:namewinreg.EnumKey(key,sub)exceptOSError:breaksub1try:withwinreg.OpenKey(key,name)assk:dispwinreg.QueryValueEx(sk,DisplayName)[0]ifany(hinstr(disp).lower()forhinNAME_HINTS):loctry:locwinreg.QueryValueEx(sk,InstallLocation)[0]exceptOSError:passentries.append({display_name:str(disp),install_location:str(loc),reg_key:f{path}\\{name}})exceptOSError:continueexceptOSError:continuereturnentriesdeffind_shortcuts():找开始菜单里名字含关键词的 .lnk快捷方式指向真实 exe。roots[os.path.join(os.environ.get(ProgramData,rC:\ProgramData),rMicrosoft\Windows\Start Menu\Programs),os.path.join(os.environ.get(APPDATA,),rMicrosoft\Windows\Start Menu\Programs),]hits[]forrinroots:ifrandos.path.isdir(r):forpinglob.glob(os.path.join(r,**/*.lnk),recursiveTrue):ifany(hinos.path.basename(p).lower()forhinNAME_HINTS):hits.append(p)returnsorted(hits)defbuild_report():return{probed_at:runtime,# 时间戳交给调用方补避免脚本非确定性install_dirs:find_install_dirs(),uninstall_entries:find_uninstall_entries(),shortcuts:find_shortcuts(),backup_extension_patterns:[*.bakF-001,*.bakA-001,*.bakI-001,*.bakX-001],model_extensions:[.fth,.aro,.imp,.xtr],activation_host:https://datacor.license.nalpeiron.io,}defselftest():自检结构正确 不含任何写死的可执行文件名。repbuild_report()assertset(rep){install_dirs,uninstall_entries,shortcuts,model_extensions,activation_host},rep.keys()assertrep[model_extensions][.fth,.aro,.imp,.xtr]blobjson.dumps(rep,ensure_asciiFalse).lower()forbadin(fathom.exe,impulse.exe,aftsolver.exe):assertbadnotinblob,f不应写死可执行文件名{bad}# 铁律3print(SELFTEST OK环境报告结构正确且未内置任何硬编码可执行文件名。)defmain():apargparse.ArgumentParser()ap.add_argument(--out,defaultaft_env.json)ap.add_argument(--selftest,actionstore_true)aap.parse_args()ifa.selftest:selftest()return0importdatetime repbuild_report()rep[probed_at]datetime.datetime.now().isoformat(timespecseconds)withopen(a.out,w,encodingutf-8)asf:json.dump(rep,f,ensure_asciiFalse,indent2)print(f已写出环境清单{a.out})print(f 安装根命中{len(rep[install_dirs])}个f卸载项{len(rep[uninstall_entries])}条快捷方式{len(rep[shortcuts])}个)return0if__name____main__:sys.exit(main())逐行剖析INSTALL_ROOTS是候选列表不是断言。官方 Quick Start 里出现过C:\AFT Products\AFT Fathom\...这样的默认路径所以我们把它列为第一优先探测点但脚本设计成目录存在才记录——这就是铁律 3 的代码化探测而不是断言。winreg用try/except ImportError包起来是为了让这段代码在非 Windows 机器比如你的 Linux 构建机也能跑——环境探测脚本经常要在 CI 里跑。find_install_dirs里[:50]截断是真实工程经验安装根下可能有成千上万个示例文件、帮助文件、库文件不截断会拖慢甚至撑爆 JSON。selftest()里那句assert bad not in blob是本篇的灵魂用自动化测试守住先探测后编码铁律——如果哪天有人图省事把Fathom.exe写死进脚本自检立刻失败。输出里显式带上activation_host来自官方授权文档是为了让这份清单直接能当气隙/防火墙申请单的附件交给 IT。代码 2-2license_router.py授权层级选型# -*- coding: utf-8 -*-license_router.py —— 按需求反推最低授权层级defpick_tier(uses_gsc_or_xts:bool,air_gapped:bool,needs_vendor_api:bool)-dict:经验法则通道型自动化 Core 够高级物理特性要 Pro气隙/厂商API 要 Enterprise。tier,whyCore,[]ifuses_gsc_or_xts:tierProwhy.append(模型用了 Goal Seeking 或 Extended Transients 等 Pro 高级特性)ifair_gappedorneeds_vendor_api:tierEnterpriseifair_gapped:why.append(气隙现场需 Local License Server (LLS) 部署在内网)ifneeds_vendor_api:why.append(需用 metered API functionality用法以厂商文档为准)ifnotwhy:why.append(仅用 AFT Transfer / Excel Export Manager / Start Batch Run 等通道Core 足够)return{tier:tier,reasons:why}defselftest():assertpick_tier(False,False,False)[tier]Coreassertpick_tier(True,False,False)[tier]Proassertpick_tier(True,True,True)[tier]Enterprise# 取最高print(SELFTEST OK三层级判定与取最高规则正确。)if__name____main__:selftest()forargsin[(False,False,False),(True,False,False),(False,True,False)]:print(args,-,pick_tier(*args))反直觉点很多人以为做自动化就必须 Enterprise。按官方层级定义纯通道型自动化在 Core 就能完成——Enterprise 加的是LLS与metered APIPro 加的是GSC/XTS/Slurries/Pulsation。把这条写进你的采购申请能省掉一大笔不必要的升级费用。三、常见报错与排查报错 2-1批量脚本半夜挂死第二天同事报软件打不开提示席位被占用。现象任务未完成且全公司共用的授权打不开。根因脚本强杀/崩溃导致席位未正常归还进入最长 2 小时的 checkout interval期间席位仍算被占用甚至已成 orphaned。解法给脚本加铁律 8 三步法——超时熔断 try/finally 正常关闭 残留进程清理出事后同账号同机重开再正常关闭通常可立即释放。报错 2-2气隙内网机器怎么都激活不上报连不上授权服务器。现象激活界面转圈或报网络错误。根因默认用的是联网激活需放行https://datacor.license.nalpeiron.io气隙网络根本出不去。解法走Local License ServerLLSDocker 部署在内网服务器或用Temporary Offline Activation需 License Admin 给激活码仅 1 周不适合长期。报错 2-3脚本里写死了C:\Program Files\AFT\Fathom.exe换台机器就找不到文件。现象换机器/升级版本后 FileNotFoundError。根因违反铁律 3把本机实体当成了常量。解法改成本篇probe_env.py的探测法从探测结果动态取路径所有本机相关常量进 JSON 清单而不是进代码。报错 2-4模型放在 OneDrive 同步目录里改某天打开提示Cant find [TOOLBOX PREFERENCES] heading。现象模型损坏、文件名带冲突副本。根因云同步/网络盘在保存瞬间断连会损坏模型文件官方明示。解法遵守铁律 7——本地编辑保存再上传已损坏时用同目录.bakF-001改名.fth抢救备份默认保留 3 份。报错 2-5以为多买几个席位就能并发批跑更快。现象并发批跑反而更慢、还互相抢 Excel 文件。根因席位池是签出制且批跑手册层面是顺序运行的并发还需处理文件锁。解法单机老老实实顺序批跑Start Batch Run 本身就是顺序的、且可后台运行真要并行就上多机 每机独立的工作目录与输出目录。四、动手练习练习 1环境清单在装有 AFT 的机器上跑python probe_env.py --out aft_env.json。判定生成的 JSON 里model_extensions恰为四个预期扩展名install_dirs至少命中 1 个安装根文件可被json.load解析。练习 2铁律自检跑python probe_env.py --selftest。判定输出SELFTEST OK随后手动在脚本里故意加一行print(fathom.exe)重跑自检。判定自检必须失败证明守门有效然后撤销这行。练习 3授权选型用license_router.py判定①纯批跑取数②模型用了 XTS 液位变化③气隙 需厂商 API。判定三次判定分别得到 Core / Pro / Enterprise且理由行非空。练习 4备份抢救演练找一个测试模型把.bakF-001或对应产品的.bakX-001复制改名回原扩展名并打开。判定能正常打开且内容为上一保存版本记录从损坏到恢复耗时。五、小结与下一篇预告本篇把环境与许可摸清了统一安装器 静默安装给了可复现的环境声明Zentitle2 的Core/Pro/Enterprise三层级告诉我们通道型自动化 Core 就够气隙现场靠LLS崩溃会让席位进入 2 小时 checkout interval 并可能 orphaned所以铁律 8 三步法不是洁癖而是刚需。我们还拿到了第一份机器可读的AFT 环境清单 JSON它将是第 20 篇平台环境探测层的雏形。第 03 篇《第一个可运行的自动化算例》我们把五条通道里最常用的三件套Scenario Manager Start Batch Run Excel Export Manager串成一条最小闭环——建三个泵配置场景、批跑、把结果落进 Excel 指定单元格、再用 pandas 读回并核对单位产出你后续所有批量的手工基准线。FAQ与第〇节一一对应Q1AFT 统一安装器改变了什么A自 2026-09 版起 Fathom、Arrow、Impulse、xStream 由单一 Datacor Flow Simulation 安装器交付安装时勾选所需产品、支持就地升级与静默安装脚本四产品共享同一架构基础对二次开发的意义是环境更一致、可写入可复现的环境声明。Q2Zentitle2 的 Core / Pro / Enterprise 分别解锁什么ACore 是基础应用Pro 增加 Goal Seeking、Extended Transients、Slurries、Pulsation 高级特性Enterprise 增加用于气隙站点的 Local License Server (LLS) 与 metered API functionality。期限有 2 周试用、1 年、3 年权益 Entitlement Tier Term Seats。Q3气隙网络里 AFT 怎么授权A用 Local License Server (LLS)——一个部署在内网服务器上的 Docker 应用终端机从内网 LLS 签出/归还席位LLS 需先通过环境内外传递证书完成初始激活并载入订阅期内的权益。短期离线可用 Temporary Offline Activation锁机 1 周需 License Admin 给激活码但它不适合长期气隙。Q4为什么强杀 AFT 进程会导致别人打不开软件A因为应用打开时从席位池签出一个 seat、正常关闭才归还崩溃或被任务管理器强杀时不会正常归还同账号同机器重开再正常关闭通常可释放否则服务端有 2 小时 checkout interval 兜底释放之后席位被视为 orphaned池满时下一个用户会重置它。Q5怎么让环境盘点可重复、可存档A写一个只依赖标准库的探测脚本如 probe_env.py枚举安装根目录、注册表卸载项、开始菜单快捷方式输出为机器可读 JSON并内置自检断言确保不写死可执行文件名把这份 JSON 连同授权层级、激活方式、备份文件命名规则一并入库成为后续所有脚本的引用源。