Open In Colab # Show3DVolume – Quick Demo 3D volume viewer with interactive orthogonal slices and WebGL ray-cast volume rendering. Synthetic gold nanoparticle tomographic reconstruction with faceted shape, twin boundaries, and lattice fringes.

[1]:
# Install in Google Colab
try:
    import google.colab
    !pip install -q -i https://test.pypi.org/simple/ --extra-index-url https://pypi.org/simple/ quantem-widget
except ImportError:
    pass  # Not in Colab, skip
[2]:
try:
    %load_ext autoreload
    %autoreload 2
    %env ANYWIDGET_HMR=1
except Exception:
    pass  # autoreload unavailable (Colab Python 3.12+)
env: ANYWIDGET_HMR=1
[3]:
import numpy as np
import torch
import quantem.widget
from quantem.widget import Show3DVolume
device = torch.device("mps" if torch.backends.mps.is_available() else "cuda" if torch.cuda.is_available() else "cpu")
def make_gold_nanoparticle(n=96):
    """Realistic HAADF-STEM tomographic reconstruction of a multiply-twinned gold nanoparticle."""
    coords = torch.arange(n, dtype=torch.float32, device=device)
    z, y, x = torch.meshgrid(coords, coords, coords, indexing="ij")
    cz, cy, cx = n / 2, n / 2, n / 2
    ax, ay, az = torch.abs(x - cx), torch.abs(y - cy), torch.abs(z - cz)
    # Truncated octahedron shape (faceted, common for FCC gold nanoparticles)
    # Blend of L1 norm (octahedron) and Linf norm (cube) → truncated octahedron
    l1 = ax + ay + az
    linf = torch.maximum(torch.maximum(ax, ay), az)
    shape_dist = torch.maximum(l1 / 1.6, linf)
    R = n * 0.37
    particle = 1.0 / (1 + torch.exp((shape_dist - R) * 1.2))  # smooth boundary
    # Z-contrast density: core slightly brighter (bimetallic Au@Pd-like)
    r = torch.sqrt((x - cx) ** 2 + (y - cy) ** 2 + (z - cz) ** 2)
    core_weight = 1.0 / (1 + torch.exp((r - R * 0.45) * 0.6))
    density = 0.65 + 0.35 * core_weight
    # Lattice fringes (111 planes, ~2.35 A spacing for Au)
    d111 = 3.8  # spacing in voxels
    fringes = 0.12 * (
        torch.cos(2 * np.pi * (x + y + z) / (d111 * np.sqrt(3)))
        + 0.5 * torch.cos(2 * np.pi * (x - y + z) / (d111 * np.sqrt(3)))
    )
    # Twin boundary (planar mirror defect at ~54.7 deg — common five-fold twin)
    twin1 = 0.18 * torch.exp(-((x - cx) * 0.707 + (y - cy) * 0.707) ** 2 / 2.0)
    twin2 = 0.12 * torch.exp(-((x - cx) * 0.707 - (z - cz) * 0.707) ** 2 / 2.0)
    # Stacking fault (planar defect)
    sf = 0.10 * torch.exp(-((z - cz) + 0.3 * (x - cx)) ** 2 / 1.5)
    volume = particle * (density + fringes + twin1 + twin2 + sf)
    # Internal voids (vacancy clusters — common in real tomograms)
    for dx, dy, dz, vr in [(10, -6, 4, 3.0), (-8, 8, -5, 2.5), (5, -3, -12, 2.0)]:
        d = torch.sqrt((x - cx - dx) ** 2 + (y - cy - dy) ** 2 + (z - cz - dz) ** 2)
        volume = volume - 0.5 * particle * torch.exp(-(d ** 2) / (2 * vr ** 2))
    # Satellite particles on the surface (smaller Au clusters)
    for sx, sy, sz, sr in [
        (R * 0.85, 0, R * 0.5, 3.5),
        (-R * 0.7, R * 0.6, 0, 2.8),
        (0, -R * 0.8, -R * 0.5, 3.0),
    ]:
        d = torch.sqrt((x - cx - sx) ** 2 + (y - cy - sy) ** 2 + (z - cz - sz) ** 2)
        volume = volume + 0.8 / (1 + torch.exp((d - sr) * 2.0))
    # Realistic reconstruction noise (Poisson-like — use NumPy, torch.poisson unreliable on MPS)
    vol_np = volume.cpu().numpy()
    vol_np += np.random.normal(0, 0.015, vol_np.shape)
    vol_np = np.clip(vol_np, 0, None)
    return vol_np.astype(np.float32)
volume = make_gold_nanoparticle()
print(f"Generators ready (device={device})")
Show3DVolume(volume, title="Gold Nanoparticle — Tomographic Reconstruction", cmap="inferno")
print(f"quantem.widget {quantem.widget.__version__}")
Generators ready (device=mps)
quantem.widget 0.4.0a3

Inspect Widget State#

[4]:
w = Show3DVolume(volume, title="Gold Nanoparticle", cmap="inferno")
w.summary()
Gold Nanoparticle
════════════════════════════════
Volume:   96×96×96
Slices:   Z=48  Y=48  X=48
Data:     min=0  max=1.645  mean=0.1681
Display:  inferno | manual contrast | linear