Core Module

The core module provides fundamental constants and operators for NV center simulation.

Physical Constants

Physical constants and unit conversions for NV center simulation.

Unit Convention

This library uses practical laboratory units for the API:
  • Frequencies: GHz, MHz, kHz (not Hz)

  • Magnetic fields: mT (not Tesla)

  • Lengths: µm, nm (not meters)

Internally, all values are converted to rad/s for the Hamiltonian.

Why rad/s?

The Hamiltonian H has units of energy. In quantum mechanics we work with ℏ=1, so that energy = frequency × 2π.

E = ℏω = ω (for ℏ=1)

Therefore, the Hamiltonian matrix elements are in rad/s.

Example

>>> from sim.core.constants import GHZ, MHZ, MT
>>> D = 2.87 * GHZ  # ZFS in rad/s
>>> B = 10 * MT     # 10 mT in Tesla
sim.core.constants.GHZ = 6283185307.179586

D = 2.87 * GHZ

Type:

1 GHz in rad/s. Usage

sim.core.constants.MHZ = 6283185.307179586

A = 2.14 * MHZ

Type:

1 MHz in rad/s. Usage

sim.core.constants.KHZ = 6283.185307179586

1 kHz in rad/s.

sim.core.constants.HZ = 6.283185307179586

1 Hz in rad/s.

sim.core.constants.MT = 0.001

B = 10 * MT

Type:

1 millitesla in Tesla. Usage

sim.core.constants.UT = 1e-06

1 microtesla in Tesla.

sim.core.constants.GAUSS = 0.0001

1 Gauss in Tesla (CGS unit, sometimes still used).

sim.core.constants.UM = 1e-06

1 micrometer in meters.

sim.core.constants.NM = 1e-09

1 nanometer in meters.

sim.core.constants.ANGSTROM = 1e-10

1 Ångström in meters.

sim.core.constants.HBAR = 1.054571817e-34

Reduced Planck constant ℏ = h/(2π) in J·s.

sim.core.constants.H_PLANCK = 6.62607015e-34

Planck constant h in J·s.

sim.core.constants.MU_B = 9.274010078e-24

Bohr magneton μ_B = eℏ/(2m_e) in J/T.

sim.core.constants.MU_N = 5.050783746e-27

Nuclear magneton μ_N = eℏ/(2m_p) in J/T.

sim.core.constants.KB = 1.380649e-23

Boltzmann constant k_B in J/K.

sim.core.constants.E_CHARGE = 1.602176634e-19

Elementary charge e in Coulomb.

sim.core.constants.G_E = 2.0028

Electron g-factor for NV center (close to free electron g≈2.002).

sim.core.constants.G_N14 = 0.4038

N14 nuclear g-factor.

sim.core.constants.G_C13 = 1.4048

C13 nuclear g-factor.

sim.core.constants.GAMMA_E = 176128235979.76355

Electron gyromagnetic ratio γ_e in rad/(s·T).

For a magnetic field B, the Larmor frequency is:

ω_L = γ_e * B

At B = 1 mT:

ω_L = 1.761e11 * 1e-3 = 1.761e8 rad/s ≈ 28 MHz

sim.core.constants.GAMMA_N14 = 19339664.153330963

N14 nuclear gyromagnetic ratio in rad/(s·T).

sim.core.constants.GAMMA_C13 = 67281724.1272891

C13 nuclear gyromagnetic ratio in rad/(s·T).

sim.core.constants.D_GS = 18032741831.605415

2.87 GHz (in rad/s).

This is the energy difference between ms=0 and ms=±1.

Type:

ZFS D-parameter in ground state

sim.core.constants.D_ES = 8922123136.195013

1.42 GHz (in rad/s).

Type:

ZFS D-parameter in excited state

sim.core.constants.A_PARALLEL_N14 = -13446016.557364315

-2.14 MHz (in rad/s).

Type:

Parallel hyperfine coupling for N14

sim.core.constants.A_PERP_N14 = -16964600.329384882

-2.70 MHz (in rad/s).

Type:

Perpendicular hyperfine coupling for N14

sim.core.constants.P_N14 = -31415926.53589793

-5.0 MHz (in rad/s).

Type:

N14 quadrupole parameter

sim.core.constants.ghz_to_rads(freq_ghz)[source]

Convert frequency from GHz to rad/s.

Parameters:

freq_ghz (float) – Frequency in GHz

Returns:

Frequency in rad/s

Return type:

float

Examples

>>> ghz_to_rads(2.87)  # ZFS
18032327871.53...
sim.core.constants.mhz_to_rads(freq_mhz)[source]

Convert frequency from MHz to rad/s.

Parameters:

freq_mhz (float) – Frequency in MHz

Returns:

Frequency in rad/s

Return type:

float

sim.core.constants.rads_to_ghz(omega)[source]

Convert rad/s back to GHz.

Parameters:

omega (float) – Angular frequency in rad/s

Returns:

Frequency in GHz

Return type:

float

sim.core.constants.rads_to_mhz(omega)[source]

Convert rad/s back to MHz.

Parameters:

omega (float) – Angular frequency in rad/s

Returns:

Frequency in MHz

Return type:

float

sim.core.constants.mt_to_tesla(field_mt)[source]

Convert magnetic field from mT to Tesla.

Parameters:

field_mt (float) – Magnetic field in mT

Returns:

Magnetic field in Tesla

Return type:

float

sim.core.constants.zeeman_splitting_mhz(B_mt, g=2.0028)[source]

Calculate the Zeeman splitting in MHz for a given B-field.

The splitting between ms=+1 and ms=-1 is:

Δf = 2 * γ * B / (2π) = 2 * g * μ_B * B / h

Parameters:
  • B_mt (float) – Magnetic field in mT

  • g (float) – g-factor (default: 2.0028 for NV)

Returns:

Splitting in MHz

Return type:

float

Examples

>>> zeeman_splitting_mhz(10)  # 10 mT
560.6...  # approximately 56 MHz/mT * 10 mT

Unit Conversions

The library uses practical laboratory units for the API:

  • Frequencies: GHz, MHz, kHz

  • Magnetic fields: mT

  • Lengths: μm, nm

Internally, all values are converted to rad/s (with ℏ=1).

from sim.core.constants import GHZ, MHZ, MT

D = 2.87 * GHZ    # ZFS in rad/s
B = 10 * MT       # 10 mT in Tesla
A = 2.14 * MHZ    # Hyperfine in rad/s

Available Constants

Unit Conversions:

  • GHZ: 1 GHz in rad/s (≈ 6.28×10⁹)

  • MHZ: 1 MHz in rad/s (≈ 6.28×10⁶)

  • KHZ: 1 kHz in rad/s

  • MT: 1 mT in Tesla (10⁻³)

Fundamental Constants:

  • HBAR: Reduced Planck constant (1.055×10⁻³⁴ J·s)

  • MU_B: Bohr magneton (9.274×10⁻²⁴ J/T)

  • KB: Boltzmann constant (1.381×10⁻²³ J/K)

NV-Specific:

  • D_GS: Ground state ZFS (2.87 GHz)

  • D_ES: Excited state ZFS (1.42 GHz)

  • GAMMA_E: Electron gyromagnetic ratio

  • A_PARALLEL_N14, A_PERP_N14: N14 hyperfine couplings

  • P_N14: N14 quadrupole parameter

Spin Operators

Spin-1 operators for NV center simulation.

This module provides the spin-1 matrices required for describing the electron spin (S=1) and N14 nuclear spin (I=1) in the NV center.

Physical Background

The NV center ground state is a spin triplet (S=1) with states |ms=+1>, |ms=0>, |ms=-1>. The spin operators satisfy the standard commutation relations:

[Sx, Sy] = i*Sz (and cyclic permutations) S² = S(S+1) = 2 for S=1

Basis Convention

All matrices are represented in the {|+1>, |0>, |-1>} basis, where Sz is diagonal with eigenvalues +1, 0, -1 on the diagonal.

18-Dimensional Hilbert Space

The full NV center Hilbert space is the tensor product:

|ψ> = |g/e> ⊗ |ms> ⊗ |mI>

  • |g/e>: Ground/Excited state (2 dim)

  • |ms>: Electron spin ms ∈ {+1, 0, -1} (3 dim)

  • |mI>: N14 nuclear spin mI ∈ {+1, 0, -1} (3 dim)

Total: 2 × 3 × 3 = 18 dimensions

The basis states are ordered as:

|0> = |g, +1, +1> |1> = |g, +1, 0> |2> = |g, +1, -1> |3> = |g, 0, +1> … |17> = |e, -1, -1>

class sim.core.operators.Spin1Ops(Sx, Sy, Sz, Sp, Sm, I)[source]

Bases: object

Container for spin-1 operators.

Parameters:
Sx

Spin-x operator (3×3 complex)

Type:

np.ndarray

Sy

Spin-y operator (3×3 complex)

Type:

np.ndarray

Sz

Spin-z operator (3×3 complex, diagonal)

Type:

np.ndarray

Sp

Raising operator S+ = Sx + i*Sy

Type:

np.ndarray

Sm

Lowering operator S- = Sx - i*Sy

Type:

np.ndarray

I

Identity matrix (3×3)

Type:

np.ndarray

Sx: ndarray
Sy: ndarray
Sz: ndarray
Sp: ndarray
Sm: ndarray
I: ndarray
__init__(Sx, Sy, Sz, Sp, Sm, I)
Parameters:
Return type:

None

sim.core.operators.spin1_operators()[source]

Create spin-1 operators in the {|+1>, |0>, |-1>} basis.

The matrices satisfy:
  • [Sx, Sy] = i*Sz (and cyclic permutations)

  • S² = Sx² + Sy² + Sz² = 2*I (for S=1)

  • Sz|m> = m|m> for m ∈ {+1, 0, -1}

Returns:

Dataclass containing Sx, Sy, Sz, S+, S-, and identity matrix

Return type:

Spin1Ops

Examples

>>> ops = spin1_operators()
>>> np.allclose(ops.Sx @ ops.Sy - ops.Sy @ ops.Sx, 1j * ops.Sz)
True
>>> np.linalg.eigvalsh(ops.Sz)
array([-1.,  0.,  1.])
sim.core.operators.extend_to_18x18(H_3x3)[source]

Extend a 3×3 electron spin Hamiltonian to the full 18×18 space.

The operator acts on the electron spin in BOTH manifolds (ground and excited) and leaves the nuclear spin unchanged.

Mathematically:

H_18 = I_2 ⊗ H_3 ⊗ I_3

where:
  • I_2: Identity on |g/e> (2×2)

  • H_3: Electron spin operator (3×3)

  • I_3: Identity on |mI> (3×3)

Parameters:

H_3x3 (np.ndarray) – 3×3 Hamiltonian in the electron spin subspace

Returns:

18×18 Hamiltonian in the full Hilbert space

Return type:

np.ndarray

Notes

This extension is correct for terms like ZFS and Zeeman that act only on the electron spin and are identical in both electronic states (g and e).

Examples

>>> from sim.hamiltonian.terms import ZFS
>>> zfs = ZFS(D=2.87)
>>> H_3 = zfs._build_3x3()
>>> H_18 = extend_to_18x18(H_3)
>>> H_18.shape
(18, 18)
sim.core.operators.extend_electron_only(H_3x3, manifold='ground')[source]

Extend 3×3 to 18×18, acting only on ONE electronic manifold.

Unlike extend_to_18x18(), this operator acts ONLY on the ground state (|g>) OR the excited state (|e>), not both.

This is needed for terms that differ between g and e, e.g., different ZFS parameters in the excited state.

Parameters:
  • H_3x3 (np.ndarray) – 3×3 electron spin Hamiltonian

  • manifold (str) – “ground” for |g> manifold (indices 0-8) “excited” for |e> manifold (indices 9-17)

Returns:

18×18 Hamiltonian acting only on the chosen manifold

Return type:

np.ndarray

Examples

>>> # ZFS only in ground state
>>> H_gs = extend_electron_only(H_zfs_3x3, manifold="ground")
>>> # Different ZFS in excited state
>>> H_es = extend_electron_only(H_zfs_excited_3x3, manifold="excited")
>>> H_total = H_gs + H_es

Spin-1 Operators

The spin1_operators() function returns a container with all standard spin-1 operators:

from sim.core.operators import spin1_operators

ops = spin1_operators()
Sx = ops.Sx  # 3×3 spin-x matrix
Sy = ops.Sy  # 3×3 spin-y matrix
Sz = ops.Sz  # 3×3 spin-z matrix
Sp = ops.Sp  # Raising operator S+
Sm = ops.Sm  # Lowering operator S-

Properties:

  • Basis: {|+1⟩, |0⟩, |-1⟩}

  • Sz is diagonal with eigenvalues +1, 0, -1

  • [Sx, Sy] = iSz (and cyclic)

  • S² = 2𝟙 (for S=1)

Extending to 18×18

Operators can be extended to the full 18-dimensional Hilbert space:

from sim.core.operators import extend_to_18x18, extend_electron_only

# Acts on both g and e manifolds
H_18 = extend_to_18x18(H_3x3)

# Acts only on ground state
H_g = extend_electron_only(H_3x3, manifold="ground")

# Acts only on excited state
H_e = extend_electron_only(H_3x3, manifold="excited")

Nuclear Operators

Nuclear spin operators for NV center simulation.

This module provides spin-1/2 operators for C13 nuclear spins and utility functions for building tensor products in the extended Hilbert space.

Hilbert Space Structure

The full NV center Hilbert space is:

|ψ⟩ = |g/e⟩ ⊗ |ms⟩ ⊗ |mI_N14⟩

Dimensions: 2 × 3 × 3 = 18

When including a C13 nuclear spin (I=1/2), this extends to:

|ψ⟩ = |g/e⟩ ⊗ |ms⟩ ⊗ |mI_N14⟩ ⊗ |mI_C13⟩

Dimensions: 2 × 3 × 3 × 2 = 36

However, for computational efficiency, C13 coupling is often treated in a block-diagonal approximation within the 18D space.

Spin-1/2 Operators

The Pauli matrices σ are related to spin operators by:

Ix = σx/2, Iy = σy/2, Iz = σz/2

The operators satisfy [Ii, Ij] = iε_ijk Ik.

class sim.core.nuclear_operators.SpinHalfOps(Ix, Iy, Iz, Ip, Im, I)[source]

Bases: object

Container for spin-1/2 operators.

Parameters:
Ix

Spin-x operator (2×2 complex)

Type:

np.ndarray

Iy

Spin-y operator (2×2 complex)

Type:

np.ndarray

Iz

Spin-z operator (2×2 complex, diagonal)

Type:

np.ndarray

Ip

Raising operator I+ = Ix + i*Iy

Type:

np.ndarray

Im

Lowering operator I- = Ix - i*Iy

Type:

np.ndarray

I

Identity matrix (2×2)

Type:

np.ndarray

Examples

>>> ops = spin_half_operators()
>>> np.allclose(ops.Ix @ ops.Iy - ops.Iy @ ops.Ix, 0.5j * ops.Iz)
True
>>> np.linalg.eigvalsh(ops.Iz)
array([-0.5,  0.5])
Ix: ndarray
Iy: ndarray
Iz: ndarray
Ip: ndarray
Im: ndarray
I: ndarray
__init__(Ix, Iy, Iz, Ip, Im, I)
Parameters:
Return type:

None

sim.core.nuclear_operators.spin_half_operators()[source]

Create spin-1/2 operators in the {|+1/2⟩, |-1/2⟩} basis.

The matrices are:

Ix = (1/2) * σx = (1/2) * [[0, 1], [1, 0]] Iy = (1/2) * σy = (1/2) * [[0, -i], [i, 0]] Iz = (1/2) * σz = (1/2) * [[1, 0], [0, -1]]

Returns:

Dataclass containing Ix, Iy, Iz, I+, I-, and identity

Return type:

SpinHalfOps

Examples

>>> ops = spin_half_operators()
>>> # Check commutation relation [Ix, Iy] = i*Iz/2
>>> comm = ops.Ix @ ops.Iy - ops.Iy @ ops.Ix
>>> np.allclose(comm, 0.5j * ops.Iz)
True
>>> # Check I² = I(I+1) = 3/4 for I=1/2
>>> I_squared = ops.Ix @ ops.Ix + ops.Iy @ ops.Iy + ops.Iz @ ops.Iz
>>> np.allclose(I_squared, 0.75 * ops.I)
True
sim.core.nuclear_operators.extend_9x9_to_18x18(H_9x9)[source]

Extend 9×9 matrix (electron ⊗ N14) to 18×18 full space.

The 9×9 operator acts on |ms⟩ ⊗ |mI_N14⟩ and is embedded in the full space as acting identically on both g and e manifolds.

Mathematically:

H_18 = I_2 ⊗ H_9

where I_2 is the identity on |g/e⟩.

Parameters:

H_9x9 (np.ndarray) – 9×9 matrix in electron spin ⊗ N14 nuclear spin space

Returns:

18×18 matrix in full Hilbert space

Return type:

np.ndarray

Notes

This is the correct extension for terms like hyperfine coupling that are identical in ground and excited states.

Examples

>>> H_9 = np.eye(9, dtype=complex)
>>> H_18 = extend_9x9_to_18x18(H_9)
>>> H_18.shape
(18, 18)
>>> np.allclose(H_18[:9, :9], H_9)
True
>>> np.allclose(H_18[9:, 9:], H_9)
True
sim.core.nuclear_operators.extend_9x9_to_18x18_manifold(H_9x9, manifold='ground')[source]

Extend 9×9 matrix to 18×18, acting only on one manifold.

Unlike extend_9x9_to_18x18(), this operator acts ONLY on the ground state OR excited state, not both.

Parameters:
  • H_9x9 (np.ndarray) – 9×9 matrix in electron spin ⊗ N14 space

  • manifold (str) – “ground” for g manifold (indices 0-8) “excited” for e manifold (indices 9-17)

Returns:

18×18 matrix acting only on chosen manifold

Return type:

np.ndarray

Examples

>>> H_9 = np.eye(9, dtype=complex)
>>> H_g = extend_9x9_to_18x18_manifold(H_9, "ground")
>>> np.allclose(H_g[:9, :9], H_9)
True
>>> np.allclose(H_g[9:, 9:], 0)
True
sim.core.nuclear_operators.build_spin_spin_coupling(S_ops, I_ops, A_tensor)[source]

Build spin-spin coupling Hamiltonian H = S·A·I.

Computes the tensor product:

H = Σ_ij A_ij (S_i ⊗ I_j)

Parameters:
  • S_ops (tuple) – Tuple of (Sx, Sy, Sz) electron spin operators (3×3 each)

  • I_ops (tuple) – Tuple of (Ix, Iy, Iz) nuclear spin operators (2×2 or 3×3)

  • A_tensor (np.ndarray) – 3×3 hyperfine coupling tensor in rad/s

Returns:

Coupling Hamiltonian of dimension (3*dim_I) × (3*dim_I)

Return type:

np.ndarray

Notes

The tensor product S_i ⊗ I_j creates a matrix of size (3 × dim_I) × (3 × dim_I).

Examples

>>> from sim.core.operators import spin1_operators
>>> S = spin1_operators()
>>> I = spin_half_operators()
>>> A = np.diag([1e6, 1e6, 2e6])  # Axial tensor
>>> H = build_spin_spin_coupling(
...     (S.Sx, S.Sy, S.Sz),
...     (I.Ix, I.Iy, I.Iz),
...     A
... )
>>> H.shape
(6, 6)
sim.core.nuclear_operators.dipolar_tensor(r_vec, gamma_1, gamma_2)[source]

Compute dipolar coupling tensor between two spins.

The dipolar interaction tensor is:

A_dip = (μ₀/4π) × (γ₁γ₂ℏ²/r³) × (I - 3r̂r̂ᵀ)

In frequency units (rad/s):

A_dip = (μ₀γ₁γ₂ℏ)/(4πr³) × (I - 3r̂r̂ᵀ)

Parameters:
  • r_vec (np.ndarray) – Position vector from spin 1 to spin 2, in meters

  • gamma_1 (float) – Gyromagnetic ratio of spin 1 in rad/(s·T)

  • gamma_2 (float) – Gyromagnetic ratio of spin 2 in rad/(s·T)

Returns:

3×3 dipolar tensor in rad/s

Return type:

np.ndarray

Notes

The tensor is traceless and symmetric.

Examples

>>> from sim.core.constants import GAMMA_E, GAMMA_C13, NM
>>> r = np.array([0.154, 0, 0]) * NM  # C-C bond length
>>> A = dipolar_tensor(r, GAMMA_E, GAMMA_C13)
>>> np.isclose(np.trace(A), 0)  # Traceless
True
>>> np.allclose(A, A.T)  # Symmetric
True

The nuclear operators module provides spin-1/2 operators for C13 and utilities for calculating dipolar hyperfine tensors.