Skip to content

SpinDefectSim

A Python library for simulating optically detected magnetic resonance (ODMR) experiments with spin-defect centres.

SpinDefectSim provides a complete framework for modelling spin-defect quantum sensors — from single-spin Hamiltonians to inhomogeneous ensembles, from DC electrometry to AC magnetometry with Ramsey and Hahn-echo pulse protocols.


What this library does

Module What it models
spin Spin Hamiltonians, nuclear hyperfine, ODMR spectra, echo signals, optical contrast
sensing Sensing experiments, pulse sequences (Ramsey / Hahn-echo / XY8), SNR
ensemble Ensemble of defects with local E- and B-fields, parameter sweeps
electrometry E-field from gate bias and screened disorder charges
magnetometry Stray B-field from 2-D magnetization via Biot-Savart
coulomb Screened Coulomb kernels (bare / Yukawa / dual-gate image charge)

Supported defect types

Five built-in presets are included; any custom defect can be defined with a single dataclass:

Preset name Host Spin S D₀ (GHz) d⊥ (Hz / (V/m))
vb_minus hBN 1 3.46 0.35
nv_minus diamond 1 2.87 0.17
v_sic 4H-SiC 1 1.28 0.10
p1 diamond ½ 0 0
cr_gaN GaN 3/2 1.80 0

A five-minute example

import numpy as np
import SpinDefectSim as sds

# ── 1. Pick a defect ─────────────────────────────────────────────────────
defect = sds.SpinDefect("vb_minus", B_mT=2.0)

# ── 2. ODMR transition frequencies ───────────────────────────────────────
freqs = defect.transition_frequencies()
print(f"Transitions: {freqs / 1e9} GHz")

# ── 3. CW ODMR spectrum ───────────────────────────────────────────────────
from SpinDefectSim.spin.spectra import PL_model

f_axis = np.linspace(3.3e9, 3.6e9, 400)
pl = PL_model(f_axis, freqs, linewidth_Hz=5e6, contrast=0.02)

# ── 4. Build an ensemble ─────────────────────────────────────────────────
ens = sds.DefectEnsemble(N_def=500, R_patch=300e-9)
ens.generate_defects()
ens.compute_efields(E0_gate=(0, 0, 2e6))   # 2 MV/m gate field

# ── 5. Run a sensing experiment ───────────────────────────────────────────
exp = ens.to_experiment(sensing="E")
tau_s, S_w, S_no, dS, tau_opt, dS_peak = exp.ramsey()
print(f"Optimal τ = {tau_opt * 1e9:.0f} ns, peak ΔS = {dS_peak:.4f}")

Design principles

  • Physical defaults are sensible. All parameters have a single configurable Defaults object that you can override globally or per-object.
  • Progressive complexity. Use SpinDefect for a single spin, DefectEnsemble for an ensemble, or build from raw functions in spin.hamiltonian directly.
  • No side-effects. All computations are pure functions or lazy-cached properties. Re-running with different parameters is safe.
  • Plotting helpers included. Objects that inherit PlottingMixin expose quick_plot() and save_fig() so you can visualise results with one line.

Next steps