:SimVascular 几何管线二次开发——从影像到批量 case 生成)
虚拟器官插件开发教程9SimVascular 几何管线二次开发——从影像到批量 case版本声明块工具/软件SimVascular 主程序 2025.06.21Ubuntu debSimTK FRs 分发BSD 许可svMorphMITsvMultiPhysicsBSD-3无原生 Windows语言/环境SimVascular 内嵌 Python 3bashXML 输入文件本文目标把影像→中心线→表面模型→体网格→求解器输入整条几何管线拆成可编程部件封装出可追溯的批量 case 生成器插件模板一句话结论SimVascular 的几何管线由sv包的pathplanningsv.pathplanning.Path中心线存.vtp→modelingsv.modeling.Modeler依赖 Path→meshing后端 TetGen/MeshSim/MMGGUI 右键 “Export Mesh Complete” 产出mesh-complete目录三级串成MITK/VTK/ITK/GDCM 是构建期 externalsExternals/CMake/SvExtOptions.cmake而不是可独立安装的插件本篇的批量 case 生成器实跑 4 条件去重后生成 3 个 case 目录第 4 条与第 1 条同条件被条件哈希幂等跳过这就是第 14 篇万级虚拟筛分管线的几何入口。〇、本篇要解决的认知问题SimVascular 的影像分割到底靠什么MITK/ITK 是它的插件还是构建依赖中心线Path、Vessel Segmenter、Modeler 三者的依赖顺序和文件形态是什么Meshing Tool 有哪三个网格后端mesh-complete目录里装的是什么svMorph 和 svVascularize 分别补什么位许可证各是什么插件工程怎么把几何→网格→case.xml模板化成可批量、可追溯的生成器一、机制解析1.1 管线全景数据流决定 API 分层DICOM 影像 ──sv.segmentation──▶ 分割体积(VTK image) │ Path Planning Tool ────┤ 交互式布点 sv.pathplanning.Path ▼ 中心线 .vtp一条血管一条 Path Vessel Segmenter ──────┤ 依赖 Path 逐截面圈轮廓没 Path 寸步难行 sv.modeling.Modeler ▼ 管腔表面 .vtpsurface.vtp 族 Meshing Tool ──────────┤ 后端 TetGen / MeshSim / MMG Export Mesh Complete ▼ mesh-complete/体网格 .vtu 边界标记 CFD/FSI/EP 配置 ───────┤ GUI 生成 .sjb/XMLEP 只在这一层文件里GUI 无 EP 面板 ▼ svmultiphysics case.xml或 svFSI .inp第 3 篇讲过sv包 9 子模块dmg/geometry/imaging/meshing/modeling/pathplanning/segmentation/simulation/vmtk与内嵌 Python 的取捨本篇把中间四环打通成可编程管线——这是患者特异批量仿真的插件模板也是心脏/血管两栖模块第 17 篇 cardiotox 的 3D 端的入口。1.2 生态位纠偏没有MITK 插件这回事常见误传“SimVascular 通过插件加载 MITK/ITK 做分割”。不成立MITK、VTK、ITK、GDCM 在Externals/CMake/SvExtOptions.cmake里登记为构建外部依赖MITK 配 with Python ON编译进发行版运行时不存在装个 MITK 插件的操作。分割能力暴露在sv.segmentation与 GUI 的 Image Segmenter。做插件时你要链的是svAPI 和 VTK 对象不是外部件。扩展名地图同样要纠偏真实扩展名是.vtp表面/中心线、.vtu体网格/结果、.svpre/.insvSolver 三件套、.inpsvFSI、.xmlsvMultiPhysics、.jsonsvZeroDSolver、.sjbCFD job、.dat/.csv。网上流传的.vsmt、.stm、.stp、.svmg均不是SimVascular 扩展名调研未查到任何官方出处——别按它们写文件解析器。官方引用口径仍是 Updegrove et al., Ann Biomed Eng 45:525 (2017)doi:10.1007/s10439-016-1762-8。1.3 几何编辑与合成svMorph 与 svVascularizesvMorphGitHub 组织仓库MIT 许可对.vtpSimVascular 标准输出的 VTK XML PolyData做形态学编辑沿中心线缩放/平移截面、轮廓插值改形。两种入口CLI 与 Python 脚本典型参数形态如--cline Input.vtp centerline path.vtp中心线驱动截面变换具体参数清单以官方 README 为准。插件价值患者队列的几何变异研究血管半径 ±20% 敏感性不需要回 GUI 重分割。svVascularizePython从中心线树合成血管几何——没有影像、只有拓扑/参数时造出管腔表面。做理想化虚拟人群或算法回归测试的黄金数据源。许可证视角铁律 3主程序 BSD、svMorph MIT、svMultiPhysics/svZeroDSolver BSD-3、svFSI “MIT-like”——整条 SimVascular 路线可商用这与 openCARP 的 Academic PL 形成对照第 7 篇但注意svMultiPhysics 无原生 Windows需 WSL。1.4 为什么case 模板化是插件的分水岭GUI 一次一例插件一万个条件。模板化的三要素输入快照每个 case 一份 JSON记录全部语义参数与软件版本——出问题时能回答这台机器那天到底算了什么条件哈希把语义参数规范化后取摘要做目录名重复条件自动跳过任务队列可以随便重启、随便补跑这就是幂等与断点续跑的地基铁律 10渲染求解器输入case.xml/.inp 模板只留占位符参数注入集中一处杜绝改一份漏三份。为什么顺序难以倒置中心线定义了沿血管坐标的截面族表面重建和边界层网格都消费这个坐标——先网格后中心线的工具链在 SimVascular 里不存在这决定了插件的失败模式也呈链式影像质量差→分割阈值要重调→Path 在弯曲段打滑→表面出现褶皱纹理→网格负体积。批量生成器必须逐级断言分割体非空、Path 点数≥阈值、表面水密、网格有界非 NaN任何一级失败就把原因写进 manifest缺记录的 case 不允许进入筛选报告。EP 配置位置更要心里有数在求解器输入文件层cepModel_*注册表第 7 篇GUI 里没有那个面板GUI 里找不到电生理设置不是 bug是分层。同理CFD job 参数落.sjbSVPROJECT/Simulations/JOBNAME.sjb插件不要试图去解析 GUI 工程文件替代生成.xml/.inp。二、完整代码与逐行剖析2.1svAPI 驱动几何对象官方示例形态运行于内嵌 Pythonimportsv# 内嵌 Python 环境外部已装 Python 包不可用取舍见第 3 篇importvtk# sv API 大量返回 VTK 对象——显式 import vtk 是官方示例的固定动作# 造一个圆截面Path Planning 的最小积木GUI 里等价于手动放 contourcircle_segsv.segmentation.Circle(radius1.0,center[1.0,1.0,1.0],normal[1.0,0.0,0.0])# 沿路径插值出中心线对象类名首字母大写是 sv 包命名规范sv.pathplanning.Path# Path 的 add_contour/cut 等成员方法清单以官方文档 GitHub 源 readme.md 为准#文档站 *.html 为 JS 动态装载正文源文件在 simvascular.github.io 仓库 documentation/ 下要点入口用Python Shell终端——新版 GUI 的 Python Console 已在 2026-03-31 文档变更中移除第 3 篇详述看到旧教程里菜单打开 Python Console要能识别为过时内容。2.2 批量 case 生成器mesh-complete XML 模板渲染已实跑# -*- coding: utf-8 -*-几何-网格-case.xml 批量生成器插件模板的最小可用骨架 纯标准库即可运行求解器输入 XML 为简化示意字段以 SimVascular 官方为准。 importhashlib,json,os,shutilfromstringimportTemplate CASE_XMLTemplate(?xml version1.0 encodingUTF-8? Simulation Output_Dir_Nameoutput_${case_id}/Output_Dir_Name Structural_Dynamic_Preferences Dynamic typeFalse/ /Structural_Dynamic_Preferences Electrophysiology_Preferences !-- EP 配置在求解器输入文件层GUI 无 EP 面板模型名用内建注册表 -- CEP_Model_Name${cep_model}/CEP_Model_Name !-- cepModel_AP/FN/BO/TTP 之一 -- Stimulus_x${stim_x}/Stimulus_x !-- 起搏点坐标可换 Purkinje 刺激文件 -- /Electrophysiology_Preferences Coupling_Laws !-- 3D-0Doutlet 列表与 rcrt.dat 由 sv.simulation.ROMParameters 生成第 10 篇 -- BC_List${outlet_list}/BC_List Rom_Filercrt.dat/Rom_File /Coupling_Laws Initial_Condition t${t0} restart1/ /Simulation )defcondition_hash(params):铁律10条件哈希做幂等键——同参数重复生成不覆盖、可断点续跑 注意 grid_i 这类序号必须排除在哈希之外否则同条件不同序号会被误判为新条件core{k:vfork,vinparams.items()ifnotk.startswith(grid_)andk!_hash}blobjson.dumps(core,sort_keysTrue).encode(utf-8)returnhashlib.sha256(blob).hexdigest()[:16]defbuild_case(root,case_id,params,dry_run_meshTrue):cdiros.path.join(root,case_id)ifos.path.exists(cdir):# 幂等已存在即跳过批量可续跑returncdir,Falsemdiros.path.join(cdir,mesh-complete)os.makedirs(mdir)# 真实工程里这里放 GUI Export Mesh Complete 或 sv.meshing 导出的网格# 生成器只放占位文件来源说明防止看似成功实则空壳的假交付withopen(os.path.join(mdir,README.source.txt),w,encodingutf-8)asfh:fh.write(mesh placeholder: replace with Meshing Tool export (TetGen/MeshSim/MMG backend)\n)ifdry_run_mesh:open(os.path.join(mdir,mesh-complete.nodes.vtu),w).write(% placeholder vtu\n)xmlCASE_XML.substitute(case_idcase_id,cep_modelparams[cep_model],stim_xparams[stim_x],outlet_listparams[outlets],t0params.get(t0,0.0))withopen(os.path.join(cdir,case.xml),w,encodingutf-8)asfh:fh.write(xml)withopen(os.path.join(cdir,inputs.json),w,encodingutf-8)asfh:# 输入快照json.dump({case:case_id,hash:params[_hash],params:params,sv_version:2025.06.21},fh,ensure_asciiFalse,indent2)returncdir,Truedefbatch_generate(root,grid):os.makedirs(root,exist_okTrue)manifestos.path.join(root,manifest.csv)made0withopen(manifest,w,encodingutf-8)asmf:mf.write(case_id,cond_hash,cep_model,stim_x\n)fori,(model,stim,outlets)inenumerate(grid):p{cep_model:model,stim_x:stim,outlets:outlets,grid_i:i}p[_hash]condition_hash(p)cidfcase_{p[_hash]}_,createdbuild_case(root,cid,p)madecreated mf.write(f{cid},{p[_hash]},{model},{stim}\n)returnmade,manifest grid[(cepModel_TTP,-30.0 10.0 5.0,outlet_0),(cepModel_AP,-30.0 10.0 5.0,outlet_0),(cepModel_TTP,-28.0 12.0 5.0,outlet_0,outlet_1),(cepModel_TTP,-30.0 10.0 5.0,outlet_0)]# 与第1条同条件→测试幂等rootcases_outshutil.rmtree(root,ignore_errorsTrue)made,mfbatch_generate(root,grid)print(f生成 case 数{made}/ 网格点{len(grid)}同条件重复项应被幂等跳过)实跑输出Python 3.10 复验生成 case 数3 / 网格点 4同条件重复项应被幂等跳过 cases_out/ manifest.csv case_5a441a5c8950524c/ case.xml inputs.json mesh-complete/{mesh-complete.nodes.vtu, README.source.txt} case_44ac8c2b2ac56888/ cepModel_AP 变体 case_59b5eb7bbae78e1e/ 起搏点/双出口变体逐行要害condition_hash哈希对象是语义参数模型名、起搏点、出口清单不是字典全集——序号、时间戳、机器路径一旦混入幂等即失效练习 2 会让你亲手验证。build_case的占位网格策略宁可放README.source.txt声明此处须替换为真实导出也不让空壳目录伪装成可算 case——批量管线里假成功比报错贵一百倍。XML 模板同时预埋了两个接口CEP_Model_Name第 7 篇注册表与rcrt.dat第 10 篇 0D 边界——几何层生成的目录结构就是物理层插件的装载槽。真实批量场景的网格来源二选一GUI 预导出一批mesh-complete或用sv.meshing/svMorph 派生变异几何后导出生成器只负责配对与渲染。求解产物的目录形态要提前设计进采集器并行运行时结果写进新建的4-procs这类目录核数进名字1-procs是单进程批处理聚合必须按*-procs通配扫描而不是写死单进程路径重启号restart序列.vtu如result_002.vtu与.dat历史文件histor.dat等是两套时间轴PV/流量曲线取.dat、场量取.vtu。2.3 svMorph 形态变异 CLI 形态示意参数以官方 README 为准# svMorphMIT以中心线为轴对 .vtp 表面做截面缩放 → 血管半径敏感性研究svmorph ScaleSection Input patient_lumen.vtp\--clineInput centerline patient_cl.vtp\--factor1.2# 半径×1.2 的变异几何示意参数名以官方仓库为准# 输出仍是 .vtp——回灌 2.2 的生成器即得变异几何×同参数的批量矩阵三、常见报错与排查在扩展管理器里找 “MITK 插件”。根因把构建 externals 当运行时插件。解法分割直接用 Image Segmenter /sv.segmentation改源码编译才碰SvExtOptions.cmake。Vessel Segmenter 无法开始圈轮廓。根因它依赖 Path 中心线先行1.1 图。解法Path Planning Tool 沿血管布点存.vtp后再进 Vessel Segmenter脚本路线sv.pathplanning.Path→sv.modeling。网格边界标记丢失/出口对不上名。现象case.xml 里outlet_0在求解器报BC 引用的面不存在。根因导出时未走 GUI 右键“Export Mesh Complete”该动作保证 mesh-complete 目录含边界区域信息或后端切换后区域编号漂移TetGen/MeshSim/MMG 三后端产物形态不同。解法以 mesh-complete 为准重建 BC 名映射批量生成器里做网格面名 ⊇ BC 引用名断言。Windows 上svmultiphysics case.xml直接闪退/不存在。根因svMultiPhysics无原生 Windows 支持。解法WSLUbuntu 24 deb 同版本线或 Linux 服务器官方 HPC 通道 SimVascular Supercomputing Gateway。按.vsmt/.svmg写文件监视器永远等不到事件。根因这些扩展名不属于 SimVascular官方未查到。解法监视.vtp/.vtu/.xml/.inp/.json/.dat真实扩展名族。四、动手练习把 2.2 的 grid 复制一份改outletsoutlet_1重跑batch_generate不 rmtree判定标准生成 case 数4 / 网格点 8且新增 4 目录条件不同→全部新建。故意把grid_i放进condition_hash的 core 字典再重跑同 grid判定标准第一次跑就输出生成 case 数4幂等被序号破坏的现场复现然后改回来。用 GUI 走完一个真实算例影像→Path→Vessel Segmenter→Meshing Tool→Export Mesh Complete把你的 mesh-complete 文件清单与 2.2 占位目录逐项对照写出哪些文件必须由真实导出提供的清单≥3 项即合格。五、小结与下一篇预告几何管线的插件化关键不在会不会点 GUI而在三点依赖顺序Path→Segmenter→Modeler→mesh-complete任何逆向拼装都是给自己挖坑、真实文件形态.vtp/.vtu/.xml/.inp/.json/.dat家族顺带纠掉.vsmt/.svmg一类查无实据的传闻扩展名、条件哈希驱动的批量可追溯快照-幂等-断点续跑三件套。第 3 篇搭的内嵌 Python 环境在此兑现为生产力同一段生成器代码夜里可以喂两百个患者特异 case。第 7 篇的 EP 注册表通过case.xml的Electrophysiology_Preferences挂上求解器几何层与物理层的接缝就此对齐。下一篇第 10 篇进入耦合深水区兴奋-收缩怎么接、CMM 与 ALE 两条 FSI 路径怎么选、add_rcr(Rp,C,Rd)与ChamberElastanceInductor们如何把 0D 循环边界接进 3D——压力-容积环将是插件的器官生理输出接口。本篇认知问题回显FAQQ1SimVascular 的影像分割是 MITK/ITK 插件吗A不是。MITK、VTK、ITK、GDCM 是构建期 externals登记在 Externals/CMake/SvExtOptions.cmakeMITK 带 Python 编译随发行版内嵌运行时没有独立MITK 插件可装。分割能力经 GUI Image Segmenter 与sv.segmentation使用。Q2SimVascular 中心线用什么类与文件格式和 Vessel Segmenter 什么关系AGUI 的 Path Planning Tool 对应sv.pathplanning.Path中心线存.vtpVTK PolyDataVessel Segmenter 逐截面圈轮廓依赖已建 Path之后由sv.modeling.Modeler重建管腔表面。顺序是先 Path 后分割缺 Path 时 Vessel Segmenter 无法开工。Q3SimVascular 体网格怎么生成mesh-complete 目录是什么AMeshing Tool 提供 TetGen、MeshSim、MMG 三个后端生成体网格.vtuGUI 右键 “Export Mesh Complete” 导出 mesh-complete 目录内含体网格与带边界标记的导出结果供求解器输入按出口名outlet_0 等引用边界条件。Q4svMorph 和 svVascularize 各做什么许可证是什么AsvMorph 对 SimVascular 标准输出 .vtp 做中心线驱动的形态编辑截面缩放/改形CLI 参数形如 --clineMIT 许可服务几何变异/队列敏感性svVascularize 从中心线树合成无影像的管腔几何适合回归测试与理想化虚拟人群。Q5怎么把几何管线封装成可批量的插件模板A三件套输入快照每 case 一个 inputs.json 存参数软件版本、条件哈希目录名语义参数 JSON 规范化后 sha256 截 16 位重复条件幂等跳过、Template 渲染求解器输入case.xmlEP 用内建注册表 cepModel_TTP 等写在输入文件层GUI 无面板。实测 4 条件去重生成 3 case即高通量虚拟筛分管线的几何入口。