Skip to content

Electrometry

The electrometry subpackage computes local electric fields from gate-bias voltages and screened disorder charges, and evaluates the resulting ODMR frequency shifts across a 2-D scan area.


SpinDefectSim.electrometry.efield

Low-level E-field building blocks.


E_gate_bias

from SpinDefectSim.electrometry.efield import E_gate_bias

def E_gate_bias(
    r_obs_xyz: tuple,
    E0=(0, 0, 0),
    grad=None,
) -> np.ndarray

Return the gate-bias electric field (uniform + optional linear gradient) at a single observation point.

Parameters:

Name Type Description
r_obs_xyz (x, y, z) Observation point (m)
E0 array_like (3,) Uniform field components (Ex, Ey, Ez) in V/m
grad np.ndarray (2,2) \| None In-plane gradient tensor [[∂Ex/∂x, ∂Ex/∂y], [∂Ey/∂x, ∂Ey/∂y]] in V/m²

Returns: np.ndarray shape (3,) in V/m

Example:

from SpinDefectSim.electrometry.efield import E_gate_bias
import numpy as np

E = E_gate_bias((0, 0, 0.34e-9), E0=(0, 0, 2e6))
# → array([0., 0., 2e6]) V/m


E_disorder_point_charges

from SpinDefectSim.electrometry.efield import E_disorder_point_charges

def E_disorder_point_charges(
    r_obs_xyz: tuple,
    charges_xyzq: np.ndarray,
    *,
    epsilon_eff: float,
    screening_model: Optional[str],
    lambda_screen: float,
    d_gate: float,
    n_images: int,
    r_min: float = 0.2e-9,
) -> np.ndarray

Compute the E-field at a single observation point due to a set of static point charges, using the selected screened Coulomb model.

Parameters:

Name Type Description
r_obs_xyz (x, y, z) Observation point (m)
charges_xyzq np.ndarray (M, 4) Charge positions and values [x, y, z, q] in SI units
epsilon_eff float Effective dielectric constant
screening_model str \| None None (bare 1/r), "yukawa", or "dual_gate"
lambda_screen float Yukawa screening length (m)
d_gate float Dual-gate separation (m)
n_images int Number of image-charge terms
r_min float Minimum distance regulariser (m)

Returns: np.ndarray shape (3,) in V/m


apply_dielectric_transmission

from SpinDefectSim.electrometry.efield import apply_dielectric_transmission

def apply_dielectric_transmission(
    E: np.ndarray,
    eps_layer: float,
    eps_host: float,
) -> np.ndarray

Scale an E-field by the quasi-static planar dielectric transmission factor:

\[\eta = \frac{2\,\varepsilon_\text{layer}}{\varepsilon_\text{layer} + \varepsilon_\text{host}}\]

Parameters:

Name Type Description
E np.ndarray Input E-field, any shape ending in (..., 3)
eps_layer float Dielectric constant of the layer
eps_host float Dielectric constant of the host

Returns: np.ndarray same shape as E


ElectricFieldBuilder

from SpinDefectSim.electrometry.efield import ElectricFieldBuilder

Combines gate-bias and disorder charge contributions into a single total() call. Inherits PhysicalParams.

Constructor

ElectricFieldBuilder(defaults: Optional[Defaults] = None)

total

def total(
    defect_xyz: tuple,
    *,
    E0_gate=(0, 0, 0),
    gate_grad=None,
    disorder_xyzq=None,
) -> tuple[np.ndarray, dict]

Compute the total E-field at defect_xyz.

Parameters:

Name Type Description
defect_xyz (x, y, z) Defect position (m)
E0_gate array_like (3,) Uniform gate field (V/m)
gate_grad np.ndarray \| None Gate-field gradient tensor
disorder_xyzq np.ndarray (M, 4) \| None Disorder charges

Returns: (E_tot, components) where E_tot is a (3,) array (V/m) and components is a dict with keys "gate" and "disorder".


SpinDefectSim.electrometry.electrometry

ElectrometryExperiment

from SpinDefectSim.electrometry.electrometry import ElectrometryExperiment

Computes ODMR observables at one point or across a 2-D scan grid from a known distribution of static charges and/or gate bias.

Inherits: PhysicalParams


Constructor

ElectrometryExperiment(
    charges_xyzq: np.ndarray,
    defaults: Optional[Defaults] = None,
    *,
    z_defect: Optional[float] = None,
    E0_gate=(0, 0, 0),
    gate_grad=None,
    epsilon_eff: Optional[float] = None,
    screening_model: Optional[str] = None,
    lambda_screen: Optional[float] = None,
    d_gate: Optional[float] = None,
    n_images: Optional[int] = None,
    bias_B_T=None,
)

Parameters:

Name Type Description
charges_xyzq np.ndarray (M, 4) Disorder charges [x, y, z, q] in SI units
defaults Defaults \| None Global defaults
z_defect float \| None Defect height above the charge plane (m); uses defaults.z_defect if None
E0_gate array_like (3,) Uniform gate-bias field (V/m)
gate_grad np.ndarray \| None Gate-field gradient tensor (V/m²)
epsilon_eff float \| None Effective dielectric (overrides defaults.epsilon_eff)
screening_model str \| None None, "yukawa", or "dual_gate"
lambda_screen float \| None Yukawa length (m)
d_gate float \| None Gate separation (m)
n_images int \| None Image-charge sum length
bias_B_T array_like (3,) \| None Bias B-field vector (T) to use when computing ODMR frequencies

E_field

def E_field(
    x_obs: float,
    y_obs: float,
    z_obs: Optional[float] = None,
) -> np.ndarray

Total E-field at a single observation point.

Parameters:

Name Type Description
x_obs float x position (m)
y_obs float y position (m)
z_obs float \| None z position (m); if None, uses self.z_defect

Returns: np.ndarray shape (3,) in V/m


transition_frequencies

def transition_frequencies(
    x_obs: float,
    y_obs: float,
    z_obs: Optional[float] = None,
) -> np.ndarray

ODMR transition frequencies at a single point.

Returns: np.ndarray float64, shape (2S,), sorted ascending, in Hz


E_field_map

def E_field_map(
    x_obs: np.ndarray,
    y_obs: np.ndarray,
    z_obs: Optional[float] = None,
) -> np.ndarray

Compute the total E-field on a 2-D grid. x_obs and y_obs define 1-D coordinate arrays; the result is computed on their outer product mesh.

Parameters:

Name Type Description
x_obs np.ndarray 1-D x coordinates (m)
y_obs np.ndarray 1-D y coordinates (m)
z_obs float \| None z height (m)

Returns: np.ndarray shape (Ny, Nx, 3) in V/m


E_z_map

def E_z_map(
    x_obs: np.ndarray,
    y_obs: np.ndarray,
    z_obs: Optional[float] = None,
) -> np.ndarray

Ez component on a 2-D grid.

Returns: np.ndarray shape (Ny, Nx) in V/m


transition_frequency_map

def transition_frequency_map(
    x_obs: np.ndarray,
    y_obs: np.ndarray,
    z_obs: Optional[float] = None,
) -> np.ndarray

ODMR transition frequencies on a 2-D scan grid.

Returns: np.ndarray shape (Ny, Nx, 2S) in Hz

Example:

import numpy as np
from SpinDefectSim.electrometry.electrometry import ElectrometryExperiment

# Single trapped electron charge
charges = np.array([[0., 0., 0., 1.6e-19]])

exp = ElectrometryExperiment(
    charges_xyzq=charges,
    z_defect=0.34e-9,
    screening_model="dual_gate",
    d_gate=15e-9,
)

x = np.linspace(-100e-9, 100e-9, 50)
y = np.linspace(-100e-9, 100e-9, 50)
freq_map = exp.transition_frequency_map(x, y)

# Frequency of the lower transition, in GHz
lower_freq_GHz = freq_map[:, :, 0] / 1e9