svVascularize (svv) is an open-source, user-friendly toolkit that algorithmically grows physiologically realistic vascular trees when imaging data are unavailable or incomplete.
Capabilities:
Biofabrication & 3D printing — export watertight VTP/STL meshes ready for extrusion-based printing, FRESH/SWIFT bioprinting, or sacrificial templating. Radii, bifurcation angles, and tapering rules are tunable to match printer resolution and biomaterial rheology.
Patient-specific cardiovascular modelling — fill in unresolved distal vasculature to close boundary conditions for 0D, 1D, or full 3D SimVascular flow simulations. Trees can be constrained to an anatomical mask or grown freely inside an organ ROI.
Design-space exploration — generate thousands of candidate networks in minutes, enabling optimisation loops for perfusion homogeneity, wall shear stress, or material usage.
The core engine is modern Python with cython acceleration, delivering < 1 min generation times for networks exceeding 10 000 segments. Every release ships wheels for Windows, macOS, and Linux, so a quick pip install svv gets you started immediately.
Try svVascularize in your browser
This runs the real svv API in a temporary cloud session via
Binder and renders the resulting tree here in 3D.
The first launch can take a couple minutes.
Not started
Python (svv)
# This cell runs on Binder (real Python + real svv).
import json
import numpy as np
import pyvista as pv
from IPython.display import Javascript, display
from svv.domain.domain import Domain
from svv.tree.tree import Tree
def _set_status(text: str) -> None:
display(Javascript(f"svvPlaygroundSetStatus({json.dumps(str(text))});"))
def _tree_to_lines(tree: Tree):
# Use the TreeData node ids (cols 18/19) to preserve connectivity.
data = np.asarray(tree.data, dtype=float)
points = []
node_index = {}
edges = []
for row in data:
a_raw = row[18]
b_raw = row[19]
a_key = ("id", int(a_raw)) if np.isfinite(a_raw) else ("pt", tuple(np.round(row[0:3], 12)))
b_key = ("id", int(b_raw)) if np.isfinite(b_raw) else ("pt", tuple(np.round(row[3:6], 12)))
ia = node_index.get(a_key)
if ia is None:
ia = len(points)
node_index[a_key] = ia
points.append([float(x) for x in row[0:3]])
ib = node_index.get(b_key)
if ib is None:
ib = len(points)
node_index[b_key] = ib
points.append([float(x) for x in row[3:6]])
if ia != ib:
edges.append([ia, ib])
return points, edges
_set_status("Building domain…")
surface = pv.Cube(x_length=1.0, y_length=1.0, z_length=1.0)
dom = Domain(surface)
dom.set_random_seed(0)
dom.create()
dom.solve()
dom.build()
_set_status("Growing tree…")
t = Tree()
t.set_domain(dom)
t.set_root()
t.n_add(80)
points, edges = _tree_to_lines(t)
display(Javascript("playground_clear?.();"))
display(Javascript("render_domain?.('box', 0.5);"))
display(Javascript(f"render_lines?.({json.dumps(points)}, {json.dumps(edges)});"))
_set_status(f"Ready — segments: {int(t.data.shape[0])}, nodes: {len(points)}")
3D Preview
Tip: Click the cell’s run button (or press Shift+Enter) to execute. Change t.n_add(…) and re-run to grow a larger/smaller tree.
Simulation Workflows
The svv.simulation.Simulation container turns generated trees and forests into ready-to-run
solver input. It automates mesh generation, boundary extraction, and svFSI configuration so you can move from a
synthetic network to a 3-D CFD job without leaving Python.
3D CFD: build watertight tet meshes, optional boundary layers, extract wall/outlet faces,
and emit svFSI XML plus surface/volume mesh files.
Multi-tree support: forests are handled tree-by-tree, letting you select which networks to
mesh and export.
Reduced-order: direct helpers in svv.simulation.fluid.rom export matching 0-D
circuits today, with 1-D parameter generation available for coupling work.
Need details? The 3-D pipeline and Simulation API pages walk through every step, from
build_meshes() to writing solver files.