⭐ If you find this project helpful, please drop us a star! It helps us get discovered by the community and is by far the most useful thing you can do for an early-stage open-source project.
Open-source computational lithography benchmarking and workflow toolkit for advanced EUV/curvilinear mask processes.
Website: openlithohub.com | Docs: docs.openlithohub.com | Playground: HuggingFace Space
中文版 / Chinese Version — kept in sync with this English README; if the two diverge, this English version is authoritative.
OpenLithoHub is an open-source computational lithography benchmarking and workflow toolkit — ILT, OPC, mask optimization, and EUV stochastic defect prediction with honest self-measurement.
EUV Stochastic Defect Prediction — BayesianStochasticModel validated across 4 pattern types × 3 nodes, cross-checked against independent MC simulation:
| Pattern | EUV N3 FP | EUV N7 FP | ArF 45nm FP | Calibration MAE |
|---|---|---|---|---|
| line/space | 11.4% | 2.9% | 0.07% | < 0.016 |
| contact | 4.1% | 6.0% | 7.9% | < 0.014 |
| elbow | 1.0% | 1.9% | 1.7% | < 0.003 |
| dense logic | ~0% | 0% | 0% | < 0.001 |
Dose-response is monotonically decreasing (19.4× from 10→100 ph/nm²), matching published √(1/dose) EUV shot-noise scaling. Full tables and methodology: BENCHMARKS.md.
- Unified dataset access — LithoBench, LithoSim, GAN-OPC, ICCAD'16, ASAP7, FreePDK45, ORFS-routed RISC-V layouts
- Standardized metrics — EPE, L2, PV Band, shot count, stochastic robustness, imec defect rates, hotspot detection
- Bayesian stochastic model — per-pixel failure probability, LER, LWR heatmaps via Poisson-MC or MC-Dropout
- Manufacturing compliance — MRC/DRC rule checking as hard-fail gates
- OASIS / GDSII workflow — end-to-end tensor→fab-ready mask (manhattan & curvilinear)
- Model-agnostic evaluation — plug any OPC/ILT model via minimal interface
- Optional physics plugins — DiffNano (EM solvers) and DiffCFD (litho + spin-coat) as opt-in extras
Honesty boundaries: All benchmarks use synthetic 64×64 layouts. No foundry validation, no production tapeout. CPU-only timing. See BENCHMARKS.md for full methodology.
┌─────────────────────────────────────────────────────────────────────────┐
│ OpenLithoHub │
├─────────────┬──────────────┬──────────────┬───────────┬─────────────────┤
│ Data Layer │ Benchmark │ Workflow │ Vis & UX │ CLI │
│ LithoBench │ EPE/PVBand │ Tiling/Stitch│ Paper figs│ eval / optimize │
│ LithoSim │ MRC/DRC │ Contour Ext. │ Jupyter │ leaderboard │
│ Transforms │ Stochastic │ OASIS Export │ EDA bridge│ simulate / synth│
│ Dummy gen. │ Shot Count │ B-spline Fit │ │ hackathon/export│
└─────────────┴──────────────┴──────────────┴───────────┴─────────────────┘
pip install --pre openlithohub # Core (metrics + CLI)
pip install --pre 'openlithohub[all]' # Everything (data, workflow, models, jupyter)From source: git clone https://github.com/OpenLithoHub/OpenLithoHub.git && pip install -e ".[dev]"
Docker: docker run --rm ghcr.io/openlithohub/openlithohub:latest eval run ...
Available extras
data, workflow, models, jupyter, export, docs, dev,
diffnano (EM solvers), diffcfd (litho + spin-coat), plugins (= both),
all. Combine: 'openlithohub[data,workflow]'.
DiffNano and DiffCFD are early-stage research plugins with no third-party validation.
From source (development):
git clone https://github.com/OpenLithoHub/OpenLithoHub.git
cd OpenLithoHub
pip install -e ".[dev]"Docker (zero-config, GPU-ready):
Pre-built images are published to GitHub Container Registry on every release:
# CPU
docker run --rm -v "$PWD":/data ghcr.io/openlithohub/openlithohub:latest \
eval run --model dummy-identity --dataset lithobench --data-root /data/lithobench
# GPU (requires nvidia-container-toolkit on the host)
docker run --rm --gpus all -v "$PWD":/data ghcr.io/openlithohub/openlithohub:latest \
optimize run --input /data/design.oas --model neural-ilt --output /data/optimized.oasTagged versions are also available (e.g. ghcr.io/openlithohub/openlithohub:0.1).
OpenLithoHub's forward lithography model serves as the coupling layer that connects upstream design solvers (EM, CFD) to downstream manufacturability:
from diff_surrogate import CoDesignWorkflow, CoupledLoss
from openlithohub.simulators import HopkinsSimulator, SimulatorConfig
# Lithography forward function feeds printability gradients back to design
def litho_coupling(merged_outputs):
design_mask = merged_outputs["design"]["mask"]
sim = HopkinsSimulator(SimulatorConfig(pixel_size_nm=1.0))
result = sim.simulate(design_mask)
merged_outputs["litho"] = {"aerial": result.aerial}
return merged_outputs
wf = CoDesignWorkflow(
design_params=torch.rand(64, 64),
forward_fns={"design": design_forward},
loss_fn=combined_loss,
coupling_fn=litho_coupling,
)Install openlithohub[plugins] to use DiffNano/DiffCFD solvers as co-design partners.
openlithohub eval run \
--model dummy-identity \
--dataset lithobench \
--data-root ./data/lithobench \
--format tableOutput:
┌──────────────────┬────────────────┐
│ Metric │ Value │
├──────────────────┼────────────────┤
│ epe_mean_nm │ 0.0000 │
│ epe_max_nm │ 0.0000 │
│ mrc_violation_rate│ 0.0000 │
│ mrc_passed │ 1.0000 │
└──────────────────┴────────────────┘
openlithohub optimize run \
--input design.oas \
--model your-model \
--writer mbmw \
--node 3nm-euv \
--drc-check \
--output optimized.oasopenlithohub flow run design.gds \
--pdk asap7 --layer metal1 \
--node 45nm --tile-nm 2000 \
--drc --mrc \
--output report.jsonAccepts a standalone GDS / OAS / DEF file or an ORFS product directory. Per-PDK layer maps are configurable (asap7, freepdk45, orfs_asap7, sky130, or a custom JSON file). The report aggregates tile-level EPE, PV Band, DRC, and MRC into a single JSON summary.
# Default: CTR (constant-threshold resist), threshold=0.225 — comparable numbers
openlithohub simulate run mask.npy --resist-diffusion-nm 0.0
# Opt-in: CAR with Gaussian acid diffusion — more realistic but NON-COMPARABLE
openlithohub simulate run mask.npy --resist-diffusion-nm 20.0The scored default remains CTR without diffusion, threshold = 0.225. Enabling acid diffusion (or any plugin EM/resist backend) produces non-comparable numbers and is disabled for leaderboard submission.
For fab-side schedulers (Slurm / LSF) or legacy C++/Perl pipelines that
cannot embed Python, run the FastAPI engine and drive it with curl:
pip install "openlithohub[server]"
openlithohub serve --port 8000 &
curl -X POST http://localhost:8000/v1/optimize \
-F "layout=@design.oas" \
-F "model=your-model" \
-F "writer=mbmw" \
-o optimized.oasModels stay resident in-process; repeat requests skip weight loading.
Open http://localhost:8000/docs in a browser for the auto-generated
Swagger UI: every endpoint is documented with its JSON schema and can
be exercised interactively (file upload included), no client code needed.
The object-oriented façade — Mask, LitheEngine, Report — is the
shortest path from a layout file to scored results:
from openlithohub import Mask, LitheEngine
mask = Mask.from_oasis("design.oas", layer="1:0", pixel_size_nm=1.0)
engine = LitheEngine(model="neural-ilt", node="3nm-euv")
optimized = engine.optimize(mask)
report = engine.evaluate(optimized, target=mask)
print(report.epe_mean_nm, report.pvband_mean_nm, report.drc_violations)
optimized.to_oasis("optimized.oas")The functional API stays available for fine-grained control:
import torch
from openlithohub.benchmark.metrics import compute_epe, compute_pvband
from openlithohub.benchmark.compliance import check_mrc, check_drc
predicted = torch.load("predicted_mask.pt")
target = torch.load("target_mask.pt")
# Edge Placement Error
epe = compute_epe(predicted, target, pixel_size_nm=1.0)
print(f"EPE mean: {epe['epe_mean_nm']:.2f} nm")
# Process Variation Band
pvb = compute_pvband(predicted, defocus_range_nm=20.0)
print(f"PV Band: {pvb['pvband_mean_nm']:.2f} nm")
# Manufacturing compliance
mrc = check_mrc(predicted, min_width_nm=40.0, min_spacing_nm=40.0)
print(f"MRC passed: {mrc.passed} ({mrc.violation_count} violations)")import torch
from openlithohub.models.base import LithographyModel, PredictionResult
from openlithohub.models.registry import registry
@registry.register
class MyOPCModel(LithographyModel):
NAME = "my-opc"
SUPPORTS_CURVILINEAR = True
def predict(self, design: torch.Tensor, **kwargs) -> PredictionResult:
mask = my_optimization_algorithm(design)
return PredictionResult(mask=mask)from openlithohub.vis import plot_contours
# Vector PDF, IEEE column-width, colorblind-safe palette
plot_contours(target, predicted, save_path="fig.pdf", style="ieee")from openlithohub.data import generate_dummy_layout
mask = generate_dummy_layout(size=256, seed=0) # numpy + torch only, no KLayoutfrom openlithohub.workflow import BridgeRules, emit_bridge_bundle
emit_bridge_bundle(
"optimized.oas",
BridgeRules(min_width_nm=40.0, min_spacing_nm=40.0),
)
# Writes optimized.svrf, optimized.rs, optimized.bridge.mdThe notebooks/quickstart.ipynb tutorial runs end-to-end on Colab's stock
runtime — install, generate a layout, score it, and produce a paper-ready
figure in three minutes.
Notebook last cold-run-verified against PyPI
0.1.0a2on 2026-05-21.
For plugging your own model into the harness, use the BYOM tutorial — it
walks through subclassing LithographyModel, running the standard metric
suite, and formatting a leaderboard submission.
| Layer | Module | Description |
|---|---|---|
| API facade | openlithohub.api |
OO entry points (Mask, LitheEngine, Report) re-exported at the package root |
| Data | openlithohub.data |
Unified adapters for LithoBench (.npy), LithoSim (HuggingFace), GAN-OPC (paired PNGs), ICCAD'16 hotspot (OASIS via klayout) |
| Benchmark | openlithohub.benchmark |
EPE (mask & wafer-sim), L2 wafer error, PV Band, shot count, stochastic robustness + per-class defect rates, hotspot detection, MRC/DRC compliance |
| Models | openlithohub.models |
Abstract LithographyModel interface (NAME class variable) + decorator-based registry |
| Simulators | openlithohub.simulators |
Forward model registry (register_simulator), Hopkins/SOCS built-in, Calibre/Tachyon commercial adapters (with mock mode), plugin EM backends (RCWA/FDTD/FDFD) |
| Workflow | openlithohub.workflow |
Layout parsing (OASIS / GDSII / DEF / LEF), tiling, contour extraction (manhattan/curvilinear), OASIS / GDSII export, process-window OPC, OpenAccess layer-purpose helper |
| Inference | openlithohub.inference |
Shared-weight multi-process inference (multiproc_predict), CompiledCache for torch.compile artifacts |
| Plugins | openlithohub.plugins |
Optional DiffNano (EM + resist) and DiffCFD (litho + spin-coat + joint optimisation) backends |
| Constants | openlithohub._constants |
Single source of truth for optical, resist, EUV 3D-mask, and plugin default values |
| CLI | openlithohub.cli |
eval, optimize, leaderboard, simulate, flow, synth, hackathon, export command groups via Typer |
OpenLithoHub supports optional physics backends via the plugin system. None are required for the core install.
| Plugin | What it adds | Install extra |
|---|---|---|
| DiffNano | Rigorous EM simulators (RCWA / FDTD / FDFD) + calibratable resist model (acid diffusion, PEB, development contrast) — registered as diffnano_rcwa, diffnano_fdtd2d, diffnano_fdfd2d backends |
[diffnano] |
| DiffCFD | Differentiable steady-state CFD — Dill/Mack lithography solver, Meyerhofer spin-coating solver, and joint process optimization (optimize_joint_process) |
[diffcfd] |
pip install --pre 'openlithohub[plugins]' # installs bothCaveats:
- Both plugins are early-stage research with no external users or third-party validation. Do not use for production decisions.
- Plugin EM/resist backends produce non-comparable metric values. Built-in
Hopkins + CTR (threshold
0.225) remains the only path for leaderboard submission. - Optionality is justified by unvalidated status, install footprint, and independent iteration cadence — not by dependency weight (all are PyTorch-native).
| Metric | Description | Reference |
|---|---|---|
| EPE | Edge Placement Error — distance between predicted and target contour edges | Standard |
| PV Band | Process Variation Band — resist contour variation across dose/focus window | Standard |
| Shot Count | Mask write time proxy for MBMW and VSB writers | Industry |
| Stochastic Robustness | Monte Carlo photon noise simulation for bridge/break probability | EUV-specific |
| MRC | Minimum width/spacing rule check (hard-fail) | EasyMRC |
| Curvilinear MRC | Minimum curvature radius + minimum feature area for post-ILT curvilinear shapes (MBMW writability) | EUV-specific |
| DRC | Design Rule Check: area, notch, width, spacing | OpenDRC |
Diffusion resist: EPE and PV Band can optionally run through the CAR acid-diffusion model (
--resist-diffusion-nm). The scored default remains CTR at threshold0.225; enabling diffusion produces non-comparable numbers and is disabled for leaderboard submission. Absolute wafer prediction still needs user-calibrated, foundry-confidential parameters — the framework is benchmark-relative, not absolute-predictive.
| Dataset | Format | Process Node | Task | Source |
|---|---|---|---|---|
| LithoBench | NumPy .npy | 45nm | Mask optimization | NeurIPS'23 |
| LithoSim | HuggingFace Parquet | Sub-28nm | Mask optimization | NeurIPS'25 |
| GAN-OPC | Paired PNGs | — | AI-OPC training | TCAD'20 |
| ICCAD'16 Problem C | OASIS + CSV | N7 EUV | Hotspot detection | ICCAD'16 |
| ASAP7 standard cells | GDSII (klayout) | 7nm predictive | PDK-aware OPC | The-OpenROAD-Project/asap7 |
| FreePDK45 + NanGate OCL | GDSII (klayout) | 45nm predictive | PDK-aware OPC | mflowgen/freepdk-45nm |
| ORFS-routed ASAP7 | GDSII (klayout) | 7nm | RISC-V tile-cut hotspots | OpenROAD-flow-scripts |
All numbers are obtained by running bundled benchmark scripts on real hardware. No data has been estimated, extrapolated, or "reasonably assumed." See
docs/benchmarks.mdfor methodology, forward model configuration, and per-pattern breakdowns.
Eight hand-crafted 64×64 layouts (square, h-line, line/space, T, L, cross,
contacts, dense lines) at 8 nm/px, graded with a single shared
HopkinsSimulator (wavelength / NA / threshold identical for every row).
| Model | EPE mean (nm) | Wafer EPE (nm) | L2 (px) | PVB mean (nm) | MRC pass |
|---|---|---|---|---|---|
dummy-identity |
0.000 | 4.529 | 299.9 | 18.340 | 88% |
rule-based-opc |
4.242 | 7.786 | 356.4 | 16.000 | 88% |
levelset-ilt (200 iter) |
0.322 | 4.482 | 294.9 | 18.516 | 75% |
openilt (MOSAIC L2+PVB) |
0.000 | 4.529 | 299.9 | 18.340 | 88% |
neural-ilt (v0.1 seed) |
0.000 | 4.529 | 299.9 | 18.340 | 88% |
levelset-iltis the only model that improves wafer L2 (294.9 vs identity's 299.9), at the cost of a lower MRC pass rate (75%) — the gradient-descent mask creates narrow features that violatemin_width_nm=40.openiltandneural-iltconverge to identity on these simple patterns — their forward model already reproduces the target without modification. They diverge on real layouts with non-trivial corner rounding.rule-based-opcintentionally deviates from the target mask (mask-EPE rises to 4.242 nm) but reduces PVB (16.0 vs 18.3 nm) — the expected bias-OPC trade-off.dummy-identityis a floor, not a competitor — mask-EPE is zero by construction (design == target) but wafer-EPE and L2 are nonzero due to diffraction.
Real EUV layout (1.9 µm × 1.5 µm, 475×375 px at 4 nm/px) from Yang2016_ICCAD16Bench. EPE/L2 columns omitted — the dataset ships no reference OPC mask.
| Model | PVB mean (nm) | PVB max (nm) | MRC viol rate |
|---|---|---|---|
dummy-identity |
14.82 | 64.0 | 15.93% |
rule-based-opc |
12.39 | 32.0 | 14.89% |
levelset-ilt |
10.49 | 32.0 | 0.97% |
openilt |
14.82 | 64.0 | 15.93% |
neural-ilt (v0.1) |
0.00 | 0.0 | 0% |
gan-opc (v0.1) |
10.97 | 48.0 | 8.48% |
gan-opc (v0.2) |
11.76 | 64.0 | 5.99% |
levelset-iltachieves the best PVB (10.49 nm) with near-zero MRC violations (0.97%) — same ranking as synthetic-8.neural-iltv0.1 shows a degenerate result (zero PVB, zero violations) because weights trained on synthetic 64-px tiles produce a near-blank mask on the 475×375 grid — this is an out-of-distribution failure, not a competitive score.gan-opcv0.2 vs v0.1: MRC violations drop 29% (8.48%→5.99%) but PVB rises 7% (10.97→11.76 nm), reflecting the Hopkins-in-the-loop trade-off.
Comparing OpenLithoHub's reimplementations against original paper results. Non-strict same-condition comparison, for reference only — test layouts, process nodes, and evaluation methodologies differ. All paper numbers are from ICCAD 2013 contest benchmarks (10 clips, 32 nm M1, 1024 nm × 1024 nm, 1 nm/px); OpenLithoHub numbers are from ICCAD16 testcase1 (7 nm EUV, 475 × 375 px, 4 nm/px) — a fundamentally different benchmark.
| Method | Source | Reported (ICCAD13) | OpenLithoHub reimpl. (ICCAD16) | Caveats |
|---|---|---|---|---|
| MOSAIC (SGD, L2+PVB) | Gao et al., DAC 2014 (DOI 6881379) | PVB avg ≈ 56 890 nm², TAT ≈ 1703 s | PVB 14.82 nm (identity) | OpenILT converges to identity on clean patterns; ICCAD13 vs ICCAD16 metrics not directly comparable |
| Neural-ILT (U-Net) | Jiang et al., ICCAD 2020 (DOI 3415704) | L2 avg 38 504 nm², TAT ≈ 11 s (GPU) | N/A (degenerate on ICCAD16) | v0.1 trained on synthetic only; paper uses 2048×2048 masks on GPU |
| GAN-OPC (PGAN-OPC) | Yang et al., DAC 2018 / TCAD 2020 (DOI 3196056) | L2 avg 39 949 nm², TAT ≈ 371 s | PVB 10.97 nm, MRC viol 8.48% | Paper reports L2 (nm²); we report PVB (nm) — different metrics and layouts |
| curvyILT | Yang & Ren, ISPD 2025 / arXiv 2411.07311 | MSE avg 25 991 nm², 2.11 s/clip (RTX A6000) | — (not yet integrated) | External GPU tool; best published academic SOTA on ICCAD13 |
All timing measured with perf_counter_ns, gc.disable() during sampling,
100 samples (forward models / metrics) or 20 samples (full model predictions),
median and P99 reported. CPU only (no GPU).
| Benchmark | Grid | Median | P99 | Device |
|---|---|---|---|---|
forward_gaussian |
64×64 | 238 µs | 549 µs | AMD 5600G CPU |
forward_gaussian |
256×256 | 804 µs | 1.2 ms | AMD 5600G CPU |
forward_hopkins |
64×64 | 2.1 ms | 2.7 ms | AMD 5600G CPU |
forward_hopkins |
256×256 | 6.5 ms | 9.5 ms | AMD 5600G CPU |
metric_epe |
64×64 | 541 µs | 941 µs | AMD 5600G CPU |
metric_pvband |
64×64 | 1.4 ms | 3.6 ms | AMD 5600G CPU |
metric_epe |
256×256 | 2.0 ms | 4.1 ms | AMD 5600G CPU |
metric_pvband |
256×256 | 6.7 ms | 7.5 ms | AMD 5600G CPU |
model_dummy-identity |
64×64 | 4 µs | 106 µs | AMD 5600G CPU |
model_rule-based-opc |
64×64 | 632 µs | 1.3 ms | AMD 5600G CPU |
model_levelset-ilt (10 iter) |
64×64 | 17.9 ms | 20.7 ms | AMD 5600G CPU |
- Hopkins is ~8× slower than Gaussian (2.1 ms vs 238 µs at 64×64) — the SOCS SVD decomposition is the bottleneck.
levelset-ilt10 iterations takes ~18 ms per 64×64 tile; 200 iterations would scale to ~360 ms. This is consistent with the iterative gradient-descent nature of the algorithm.- GPU timing is not reported — OpenLithoHub's models run on CPU by default. Neural-ILT (Jiang et al., ICCAD 2020) reports ~11 s on GPU for the same task; direct comparison is not meaningful without matching hardware.
Surrogate-ILT uses an on-the-fly trained surrogate forward model and reports 10–50× speedup relative to the full-physics Hopkins forward model — this is an internal relative measurement, not a wall-clock comparison with external tools.
Hardware: AMD Ryzen 5 5600G (6C/12T), 13 GB DDR4, SATA SSD, Ubuntu 24.04 (kernel 6.8.0)
Software: CPython 3.10.12, PyTorch 2.12.0+cpu, OpenLithoHub 4c3a699 (main)
# Model quality (synthetic-8):
python3 scripts/generate_baselines.py --synthetic --limit 8 --output baselines/
# Model quality (ICCAD16 testcase1):
openlithohub eval run --model levelset-ilt --dataset iccad16 \
--data-root data/iccad16 --node 7nm --pixel-nm 4.0
# Performance timing:
python3 scripts/benchmark_performance.py --json results_timing.json
# Generate comparison charts:
python3 scripts/plot_benchmarks.py --input baselines/results.json --output docs/images/Methodology: Synthetic-8 numbers are averaged across 8 patterns per model,
single run. ICCAD16 is a single testcase, single run. No statistical sampling
across seeds. Timing benchmarks use perf_counter_ns, gc.disable() during
measurement, and report median / P95 / P99 over 100 samples (forward models)
or 20 samples (full model predictions).
All test data is obtained by actually running the above commands on the above hardware, without any subjective estimation. Readers can reproduce the results by running the same commands.
python scripts/plot_benchmarks.py \
--input baselines/results.json \
--output docs/images/Charts use transparent-background SVG with neutral-gray (#888) axis labels for readability in both light and dark GitHub themes.
OpenLithoHub ships two differentiable forward models, both written in pure PyTorch so the entire ILT loop is end-to-end auto-differentiable:
| Model | Module | Notes |
|---|---|---|
| Gaussian PSF | openlithohub._utils.forward_model.simulate_aerial_image |
Single-Gaussian convolution; cheap default for tests and small grids |
| Hopkins SOCS | openlithohub._utils.hopkins.simulate_aerial_image_hopkins |
Partial-coherent imaging via SVD-truncated Sum-Of-Coherent-Systems; supports circular / annular / dipole illumination |
| Thick mask forward model | openlithohub._utils.forward_model.simulate_aerial_image_thick_mask |
Multi-layer thick-mask diffraction model for 3D mask effects (O7.1) |
| DiffNano RCWA/FDTD/FDFD | openlithohub.plugins.diffnano_em (opt-in) |
Rigorous EM solvers via the DiffNano plugin; registered as diffnano_rcwa, diffnano_fdtd2d, diffnano_fdfd2d backends |
Built-in Hopkins remains the default and the only comparable path for leaderboard numbers. Plugin EM backends are opt-in and produce non-comparable scores.
schwarz_tiled_ilt() in openlithohub._utils.tiling implements alternating Schwarz domain decomposition for large-layout ILT. Adjacent tiles exchange overlap boundary data at each iteration, with convergence monitoring (residual norm). This replaces naive independent tiling with a solver that enforces inter-tile consistency:
from openlithohub._utils.tiling import schwarz_tiled_ilt
result = schwarz_tiled_ilt(
mask, tile_size=512, overlap=64, max_schwarz_iter=10, tol=1e-4,
)Differentiable dilate/erode/open/close via structured-element max-pool soft approximations, usable as differentiable MRC/DRC proxies in the ILT autograd graph:
from openlithohub._utils.morphology import soft_dilate, soft_erode, soft_opening, soft_closing
# Differentiable morphological operations
opened = soft_opening(mask, kernel_size=3, temperature=0.1)
width_violation = soft_erode(mask, kernel_size=3).clamp(min=0).mean() # proxy for min-width penaltyThe LevelSetILTModel and warm_start_ilt() support initializing ILT from a prior OPC result (rule-based, neural, or external), avoiding cold-start convergence issues:
from openlithohub._utils.warm_start import warm_start_ilt
result = warm_start_ilt(
initial_mask=prior_opc_mask, # from rule-based or neural OPC
target=target_mask,
iterations=100,
forward_model="hopkins",
)tiling_residual_report() quantifies inter-tile boundary consistency after tiling/stitching, reporting overlap L2 norm, max discontinuity, and per-tile residual maps:
from openlithohub._utils.tiling import tiling_residual_report
report = tiling_residual_report(stitched_mask, tile_size=512, overlap=64)
print(f"Overlap L2: {report['overlap_l2']:.4f}, Max discontinuity: {report['max_disc']:.2f} nm")simulate_aerial_image_born() in openlithohub._utils.forward_model extends the Hopkins Gaussian PSF forward model with higher-order Born scattering terms for thick-mask effects. This captures edge diffraction and sidewall scattering that the thin-mask (Hopkins-only) model misses:
from openlithohub._utils.forward_model import simulate_aerial_image_born
aerial = simulate_aerial_image_born(
mask, sigma_nm=20.0, born_order=2, # Hopkins + 2nd-order correction
)Switch LevelSetILTModel to Hopkins:
from openlithohub._utils import HopkinsParams
from openlithohub.models.levelset_ilt import LevelSetILTModel
model = LevelSetILTModel(
iterations=200,
forward_model="hopkins",
hopkins_params=HopkinsParams(
wavelength_nm=193.0, na=1.35, sigma=0.7, num_kernels=24, pixel_size_nm=2.0,
),
)Differentiable stochastic metrics — edge error and LCDU (local CD uniformity) — with CVaR (Conditional Value-at-Risk) and quantile risk measures. Enables stochastic process window evaluation that directly optimizes worst-case yield instead of nominal performance:
from openlithohub._utils.stochastic_ilt import StochasticILTLoss
stochastic_loss = StochasticILTLoss(
edge_weight=1.0,
lcdu_weight=0.5,
risk_measure="cvar", # or "quantile"
alpha=0.05, # tail fraction for CVaR
)
loss = stochastic_loss(predicted_contour, target_contour)PosteriorWarmStart uses a conditional VAE (CVAE) to sample diverse multi-candidate initializations from the learned posterior over OPC solutions. BatchILTScheduler performs batch refinement and selection across candidates, picking the best mask by a composite score (EPE + MRC + PVB):
from openlithohub._utils.posterior_warm_start import PosteriorWarmStart, BatchILTScheduler
warm_start = PosteriorWarmStart(latent_dim=64, n_candidates=8)
candidates = warm_start.sample(target_mask, n=8) # diverse initial masks
scheduler = BatchILTScheduler(iterations=200, forward_model="hopkins")
best_mask = scheduler.refine_and_select(candidates, target=target_mask)TileParallelProcessor enables GPU batch-parallel Schwarz tiling for full-chip ILT. SchwarzTilingSolver runs iterative Schwarz convergence with all tiles processed simultaneously on GPU, achieving near-linear scaling for large layouts:
from openlithohub._utils.tiling_gpu import TileParallelProcessor, SchwarzTilingSolver
processor = TileParallelProcessor(tile_size=512, overlap=64, device="cuda")
solver = SchwarzTilingSolver(max_iter=10, tol=1e-4)
result = solver.solve(mask, processor=processor)
# All tiles batched on GPU, overlap exchange at each Schwarz iterationPhysicalResistModel implements a differentiable CAR (chemically amplified resist) pipeline: acid generation from aerial image exposure, Gaussian acid diffusion during PEB, quencher kinetics, and sigmoid development. GradientFidelityGate verifies that the differentiable surrogate stays faithful to a high-fidelity resist simulation:
from openlithohub._utils.resist_physical import PhysicalResistModel, GradientFidelityGate
resist = PhysicalResistModel(
acid_generation_rate=0.8,
diffusion_length_nm=20.0,
quencher_concentration=0.3,
development_contrast=10.0,
)
resist_contour = resist(aerial_image)
# Verify surrogate fidelity
gate = GradientFidelityGate(atol=1e-3, rtol=1e-2)
fidelity_report = gate.check(resist, high_fidelity_resist, sample_input)GRPOWarmStart applies Group Relative Policy Optimization (GRPO) fine-tuning on the CVAE posterior, producing higher-quality and more diverse warm-start candidates than the V8 posterior sampler. StyleConditioning injects layer-purpose awareness (metal, via, cut) into the VAE encoder via LayerPurpose embeddings, so the generative model adapts its initialization strategy per mask layer:
from openlithohub.models.grpo_warm_start import GRPOWarmStart, GRPOConfig, StyleConditioning
from openlithohub._constants import LayerPurpose
config = GRPOConfig(
latent_dim=64,
grpo_steps=50,
group_size=8,
clip_ratio=0.2,
style_conditioning=StyleConditioning(layer_purpose=LayerPurpose.METAL),
)
warm_start = GRPOWarmStart(config)
candidates = warm_start.sample(target_mask, n=8)Reference: arXiv:2602.19027 (clean-room implementation).
StochasticAcceptanceGate replaces the deterministic pass/fail MRC check with a conformal-calibrated stochastic process window. StochasticSampler draws photon-noise and dose/focus perturbation samples; ThroughFocusCoverageCalibrator fits a conformal prediction band so the acceptance probability is statistically calibrated. ProcessWindowPlotter produces through-focus coverage visualizations:
from openlithohub.benchmark.metrics.coverage_gate import (
StochasticSampler,
ThroughFocusCoverageCalibrator,
StochasticAcceptanceGate,
ProcessWindowPlotter,
)
sampler = StochasticSampler(n_samples=512, dose_sigma=0.02, focus_range_nm=40.0)
calibrator = ThroughFocusCoverageCalibrator(alpha=0.05) # 95% conformal band
gate = StochasticAcceptanceGate(sampler=sampler, calibrator=calibrator)
result = gate.evaluate(predicted_mask, target_mask)
print(f"Coverage probability: {result.coverage_prob:.3f}, Accepted: {result.accepted}")
ProcessWindowPlotter().plot(result, save_path="process_window.pdf")Reference: arXiv:2402.01960.
GPUTileBatchProcessor wraps GPU batch-parallel Schwarz tiling in a reproducible benchmark harness. ICCAD13Benchmark provides the ICCAD'13 contest end-to-end pipeline (10 clips, gauges, scoring). TilingResidualRegression fits a lightweight regression model that predicts tiling residual from tile geometry, enabling adaptive overlap selection:
from openlithohub.workflow.gpu_tiling_benchmark import (
GPUTileBatchProcessor,
ICCAD13Benchmark,
TilingResidualRegression,
)
processor = GPUTileBatchProcessor(tile_size=1024, overlap=128, device="cuda")
benchmark = ICCAD13Benchmark(processor=processor, data_root="data/iccad13")
results = benchmark.run(model="levelset-ilt")
print(f"Median L2: {results['l2_median_nm2']:.0f} nm2, TAT: {results['tat_s']:.1f} s")
regression = TilingResidualRegression()
regression.fit(tile geometries, measured_residuals)
predicted_residual = regression.predict(new_tile_geometry)References: arXiv:2411.07311, Light: Sci. Appl. 2025-07.
| Claim | Code | Tests | Data | Status |
|---|---|---|---|---|
Schwarz domain decomposition tiling (schwarz_tiled_ilt) |
openlithohub/workflow/tiling.py |
tests/test_workflow/test_schwarz_born.py (5 tests) |
Internal | Verified |
Born scattering forward correction (simulate_aerial_image_born) |
openlithohub/_utils/forward_model.py |
tests/test_workflow/test_schwarz_born.py (4 tests) |
Internal | Verified |
| Hopkins SOCS forward model | openlithohub/_utils/hopkins.py |
tests/test_utils/test_hopkins.py |
docs/benchmarks.md (measured timing) |
Verified |
| EPE / PV Band / MRC / DRC metrics | openlithohub/benchmark/metrics/ |
tests/test_benchmark/test_metrics.py |
Baseline tables in README | Verified |
| LevelSet-ILT model | openlithohub/models/levelset_ilt.py |
tests/test_models/test_levelset_ilt.py |
Synthetic-8 and ICCAD16 tables | Verified |
GAN-OPC model (GanOpcModel) |
openlithohub/models/gan_opc.py |
tests/test_models/test_gan_opc.py |
ICCAD16 table | Aspirational — generator-only, no GAN discriminator, predictions near-random without pretrained weights |
Neural-ILT model (NeuralILTModel) |
openlithohub/models/neural_ilt.py |
tests/test_models/test_neural_ilt.py |
ICCAD16 table | Aspirational — NOT paper-faithful re-implementation of Jiang2020; differentiable ILT correction layer unimplemented; degenerate on out-of-distribution inputs |
Layout-MAE (LayoutMAE) |
openlithohub/models/layout_mae.py |
tests/test_models/test_layout_mae.py |
N/A | Aspirational — ViT-S MAE prototype with no pretrained weights, no fine-tune adapter, no Hub release |
| Stochastic-aware ILT (O8.1) | openlithohub/_utils/stochastic_ilt.py |
tests/test_utils/test_stochastic_ilt.py |
Internal | Verified |
| Posterior warm-start (O8.2) | openlithohub/_utils/posterior_warm_start.py |
tests/test_utils/test_posterior_warm_start.py |
Internal | Verified |
| GPU full-chip tiling (O8.3) | openlithohub/_utils/tiling_gpu.py |
tests/test_utils/test_tiling_gpu.py |
Internal | Verified |
| Physical resist model (O8.4) | openlithohub/_utils/resist_physical.py |
tests/test_utils/test_resist_physical.py |
Internal | Verified |
| GRPO generative warm start (O9.1) | openlithohub/models/grpo_warm_start.py |
tests/test_models/test_grpo_warm_start.py |
Internal | Verified |
| GPU tile-batch benchmark (O9.2) | openlithohub/workflow/gpu_tiling_benchmark.py |
tests/test_workflow/test_gpu_tiling_benchmark.py |
Internal | Verified |
| Stochastic ILT coverage gate (O9.3) | openlithohub/benchmark/metrics/coverage_gate.py |
tests/test_benchmark/test_coverage_gate.py |
Internal | Verified |
| Dependency | Version |
|---|---|
| Python | 3.10+ (< 3.13) |
| PyTorch | 2.12+ |
Sister projects: DiffCFD (differentiable CFD, optional plugin), DiffNano (nanophotonics, optional plugin), diff-surrogate (shared surrogate framework).
OpenLithoHub ships adapters for Calibre nmOPC and ASML Brion Tachyon. Both fall back to a deterministic mock when the commercial toolchain is not installed, so tests pass on any machine:
from openlithohub.simulators import CalibreSimulator, TachyonSimulator
from openlithohub.simulators import SimulatorConfig
# Calibre nmOPC (requires calibre on PATH; mock_mode=True otherwise)
calibre = CalibreSimulator(SimulatorConfig(pixel_size_nm=4.0, mock_mode=True))
result = calibre.simulate(mask_tensor)
# ASML Brion Tachyon (requires TACHYON_HOME; mock_mode=True otherwise)
tachyon = TachyonSimulator(SimulatorConfig(pixel_size_nm=4.0, mock_mode=True))
result = tachyon.simulate(mask_tensor)# Run tests
pytest tests/ -v
# Lint
ruff check src/ tests/
# Type check
mypy src/
# Format
ruff format src/ tests/
# Check plugin infrastructure health
make check-pluginsFor production-scale scoring, multiproc_predict distributes tiles across
worker processes with shared model weights via SharedMemory:
from openlithohub.inference import multiproc_predict
from openlithohub.models import get_model
model = get_model("neural-ilt")
tiles = [mask_tile_1, mask_tile_2, mask_tile_3, mask_tile_4]
results = multiproc_predict(model, tiles, n_workers=2)- Milestone 1: Unified data adapters, EPE metric,
evalCLI - Milestone 2: MRC compliance, Manhattan contour extraction, tiling, shot count
- Milestone 3: OASIS workflow, PV Band, stochastic robustness, DRC, B-spline fitting,
optimizeCLI - Milestone 4: Public leaderboard, MkDocs documentation site, CI/CD for docs
- Milestone 5: Web playground (HuggingFace Spaces)
- Milestone 6: Real ILT models (LevelSet-ILT, Neural-ILT U-Net), DTCO process nodes, resist simulation, model hub, Jupyter integration, PyPI/Docker CI/CD
- Milestone 7: Paper-ready visualization, dummy layout generator, EDA bridge templates, Colab quickstart
- Milestone 8: Multi-stage KLayout Docker, AI-engineer terminology guide, Auto-Leaderboard CI, community charter (Discord), v0.1 launch announcement
- Milestone 9: PDK-aware synthetic layout generator, vendor-neutral simulator hook API, EUV 3D-mask shadow proxy, Monte Carlo failure metric, Mini-Hackathon (2026-Q3), RFC 0001 (Layout-MAE) + RFC 0002 (Layout Tokens)
- Milestone 10: Real PDK rollout — ASAP7 standard cells, FreePDK45 + NanGate OCL, ORFS-routed RISC-V mock-alu (issue #4)
- Milestone 11: Standard MRC rule-deck schema (RFC 0003), measured-source / Zernike-pupil I/O, Calibre/CSV gauge parser,
openlithohub exportCLI (ONNX / TorchScript / TensorRT-ready),--compileon by default, first PyPI release (openlithohub-0.1.0a2) - Milestone 12: Opt-in diffusion resist (
--resist-diffusion-nm),openlithohub flow runclosed-loop CLI (design→litho→DFM), configurable per-PDK layer maps, optional DiffNano/DiffCFD plugin ecosystem - Milestone 13: Thick mask forward model (O7.1), differentiable morphological operators (O7.2), warm-start ILT interface (O7.3), tiling residual quantification (O7.4)
- Milestone 14: Stochastic-aware ILT (O8.1), posterior warm-start with conditional VAE (O8.2), GPU batch-parallel Schwarz tiling (O8.3), physical resist model with gradient fidelity gate (O8.4)
- Milestone 15: GRPO generative warm start with style-aware conditioning (O9.1), GPU tile-batch benchmark with ICCAD13 pipeline (O9.2), stochastic ILT coverage gate with conformal calibration (O9.3)
Note: Milestones above reflect feature integration completeness (adapters, CLI commands, CI pipelines), not industrial validation. The alpha version (
0.1.0a2) runs on synthetic layouts — real industrial-scale benchmarking is planned for the v1.0 milestone.
What it is: An open-source computational lithography benchmarking and workflow toolkit — ILT, OPC, mask optimization, and process window analysis with honest self-measurement.
Where it leads:
- Open ILT benchmark with honest baselines: The only open-source project providing standardized ILT benchmarks with SARIF export, morphological MRC, tile-consistency metrics, and stochastic-aware loss. Commercial tools (Calibre MML, cuLitho) are closed-source with no public benchmarks.
- Variation-aware ILT: CVaR and quantile risk measures integrated directly into ILT loss — stochastic-aware optimization that goes beyond deterministic nominal-point optimization.
- Full-chip tiling with Schwarz decomposition: GPU batch-parallel Schwarz tiling for full-chip ILT with tile-consistency residual quantification.
- Physical resist model: Acid generation → diffusion → quencher neutralization → sigmoid development — fully differentiable for end-to-end mask-to-resist optimization.
Where it lags (honest assessment):
- Scale: Benchmark subsets, tile-level, GPU stitching. Orders of magnitude behind Calibre MML and cuLitho (full-chip, GPU production-grade).
- Validation: Self-tests + numerical cross-validation against LithoBench/ICCAD13 references. No fab validation, no production tapeout.
- Maturity: Research prototype. No foundry integration, no PDK sign-off flow.
Bottom line: Uniquely positioned as the honest open-source lithography benchmark — what it lacks in scale it compensates with transparency, reproducibility, and methodological currency (2024-2026 stochastic ILT, conformal UQ, physical resist). Not a replacement for production OPC tools, but a research and benchmarking platform they don't provide.
| Project | Venue | Role in Ecosystem |
|---|---|---|
| LithoSim | NeurIPS'25 | Sub-28nm industrial dataset |
| LithoBench | NeurIPS'23 | 45nm evaluation framework |
| TorchLitho 2.0 | ASICON'25 | Differentiable lithography simulator |
| curvyILT | NVIDIA arXiv'24 | GPU-accelerated curvilinear ILT |
| EasyMRC | TODAES'25 | MRC reference implementation |
| ILT challenges survey | Light: Sci. Appl. 2025 | Comprehensive survey of ILT challenges and solutions |
| B-spline + Delaunay curvilinear mask | arXiv:2504.11962, 2025 | Curvilinear mask optimization via B-spline and Delaunay triangulation |
| Full-chip EUV curvilinear mask optimization | Light: Advanced Manufacturing, 2026, doi:10.37188/lam.2026.049 | Full-chip EUV curvilinear mask optimization |
| Schwarz Neural Inference | arXiv:2504.00510 v2, 2026-02 | Local→global domain decomposition operator learning — applicable to ILT solver acceleration |
| ML4PS optical diffraction convolution | NeurIPS 2025 | ML for physical simulation: optical diffraction convolution |
| DiffNano | — | Optional plugin: PyTorch-native nanophotonics (RCWA / FDTD / FDFD + calibratable resist). Early-stage research, no third-party validation. |
| DiffCFD | — | Optional plugin: PyTorch-native steady-state CFD for lithography (Dill/Mack solver, spin-coating solver, joint process optimization). Early-stage research, no third-party validation. |
See CONTRIBUTING.md for guidelines.
A Discord server for OpenLithoHub is launching 2026-Q3 — channels for model discussion, physics simulation, help, and showcase. The place to debate model design, reproducibility, and benchmarks.
Want to be notified when the invite goes live? Open an issue with the
community label
or watch this repo. Charter, channel structure, etiquette, and onboarding
flow are documented in docs/community.md.
📣 Read the launch announcement: v0.1 release post — includes paste-ready copy for X / LinkedIn / 知乎 / HuggingFace Forum.
🏆 Mini-hackathon launching 2026-Q3 — charter & rules. EPE target, frozen test split, hard MRC/DRC gate, separate leaderboard track.
OpenLithoHub is a purely academic, open-source project for fundamental research in computational physics and machine learning. It relies solely on publicly available datasets and published algorithms. It does not contain, nor does it seek to reverse-engineer, any proprietary commercial EDA tools or export-controlled manufacturing processes.
Plugin validation: DiffNano and DiffCFD are optional plugins that self-describe as early-stage personal research projects with no external users and no third-party validation. Do not rely on them for production decisions.
Leaderboard comparability: The scored default is CTR (constant-threshold resist)
without diffusion, at threshold 0.225. Enabling acid diffusion (--resist-diffusion-nm > 0)
or switching to a plugin EM/resist backend produces non-comparable metric values
and is disabled for leaderboard submission.
OpenLithoHub uses a layered licensing model:
- Code — Apache License 2.0
- Documentation — CC-BY-SA 4.0
- Datasets — each dataset retains its original license; OpenLithoHub ships only adapters, not data. See DATA-LICENSES.md.
- Third-party components — see NOTICE.
You may freely use OpenLithoHub commercially under the open-source license
(attribution and the NOTICE file are the only requirements). For commercial
licensing options without attribution or with
SLA-backed support, see COMMERCIAL-USE.md.
To cite OpenLithoHub in academic work, see CITATION.cff. Contributors: please review CONTRIBUTING.md and the Contributor License Agreement. Security issues: SECURITY.md.
