API — nefi.instances¶
Generated by scripts/gen_api_docs.py — do not edit by hand. Index
nefi.instances¶
Strong exemplar instances. Importing this package registers every instance.
nefi.instances.base¶
Instance protocol: a self-contained, registered exemplar inverse problem.
class Instance(cfg: Any | Mapping | None = None, **overrides: Any)¶
Base class for registered instances. Subclass, set name and Config, implement hooks.
baselines(self) -> dict[str, Callable[[Measurement], tuple[InverseProblem, Curriculum]]]— Optional: name -> builder returning (problem, curriculum) for baseline methods.build_problem(self, measurement: Measurement) -> InverseProblembuild_problem_measurement_shape(self, field_shape: Sequence[int]) -> tuple[int, ...] | None— Measurement shape at native resolution (default: ask a throwaway problem's operator).config_dict(self) -> dictdata_generator(self) -> DataGeneratordefault_curriculum(self) -> Curriculumdefault_scene_class(self) -> str | None— Scene class used whenrun/make_measurementget none (cfg.sceneif set).domain(self) -> Domainevaluate(self, result: Result, gt: Mapping[str, torch.Tensor]) -> dict[str, float]make_measurement(self, seed: int = 0, scene_class: str | None = None, gt: Mapping[str, torch.Tensor] | None = None) -> tuple[dict[str, torch.Tensor], Measurement]metrics(self) -> dict[str, Callable]refine(self, result: Result, measurement: Measurement, **kw: Any)— Edge refinement of a reconstruction ofmeasurement: a short second optimization under the same operator and data with a level-set (piecewise-constant) prior, phase values from the instance configuration (nefi.solve.refine.REFINE_DEFAULTSor arefine_defaultsattribute).run(self, seed: int = 0, device: str = 'auto', scene_class: str | None = None, curriculum: Curriculum | None = None, callbacks: Sequence = (), **solver_kw) -> R...scene_generator(self) -> SceneGenerator
class RunOutput(result: Result, metrics: dict[str, float], gt: dict[str, torch.Tensor] | None, measurement: Measurement, extra: dict[str, Any] = <factory>)¶
RunOutput(result: 'Result', metrics: 'dict[str, float]', gt: 'dict[str, torch.Tensor] | None', measurement: 'Measurement', extra: 'dict[str, Any]' =
nefi.instances.ct3d¶
ct3d — 3-D parallel-beam sparse-view CT (rotation about z) with a differentiable Radon stack.
class CT3D(cfg: Any = None, preset: str | None = None, **overrides: Any)¶
3-D sparse-view parallel-beam CT instance (see module docstring).
angles(self) -> torch.Tensorbaselines(self) -> dict[str, Callable[[Measurement], tuple[InverseProblem, Curriculum]]]build_problem(self, measurement: Measurement) -> InverseProblembuild_problem_measurement_shape(self, field_shape)data_generator(self) -> DataGeneratordefault_curriculum(self) -> Curriculumdomain(self) -> Domainfbp(self, measurement: Measurement, filter: str | None = None) -> torch.Tensor— Slice-wise filtered back-projection ofmeasurementon the native grid.field(self) -> NeuralFieldheads(self) -> Headslosses(self) -> LossSetmeasurement_image(self, measurement: Measurement) -> torch.Tensor— Compact 2-D view: the sinogram(n_views, n_det)of the most structured slice.metrics(self) -> dict[str, Callable]operator(self, domain: Domain | None = None, det_per_pixel: float | None = None)scene_generator(self) -> SceneGenerator
class CT3DConfig(n: int = 64, n_z: int = 32, extent: float = 1.0, height: float = 1.0, n_views: int = 30, angle_range: float = 180.0, det_per_pixel: float = 1.0, samples_per...¶
Configuration of the :class:CT3D instance (every number is a field).
def make_problem(seed: int = 0, scene: str | None = None, **cfg: Any) -> tuple[InverseProblem, dict[str, torch.Tensor], Measurement]¶
Convenience: (problem, gt, measurement) for docs and tests.
def run(cfg: CT3DConfig | dict | None = None, seed: int = 0, **kw: Any)¶
End-to-end demo (generate → invert → evaluate); returns a RunOutput.
nefi.instances.ct3d.radon3d¶
Differentiable 3-D parallel-beam Radon transform (rotation about z) and slice-wise FBP.
class Radon3DOperator(domain: Domain, n_views: int = 20, field: str = 'mu', angles: torch.Tensor | Sequence[float] | None = None, angle_range: float = 3.141592653589793, det_per_...¶
Parallel-beam CT about the z axis: μ (n, n, n_z) ↦ sinograms (V, n_det, n_z).
adjoint(self, sinogram: torch.Tensor) -> torch.Tensor— Exact adjointRᵀ yof this discretization (autograd VJP; the operator is linear).at_resolution(self, shape: Sequence[int]) -> Radon3DOperatorbackproject(self, sinogram: torch.Tensor) -> torch.Tensor— Pixel-driven back-projection ≈Rᵀ y(independent discretization).dt(property) — Physical ray step Δt.extra_repr(self) -> strfbp(self, sinogram: torch.Tensor, filter: str = 'ramp', circle: bool = False)— Slice-wise filtered back-projection onto this operator's grid.forward(self, fields: Fields) -> torch.Tensorn_views(property)output_shape(self, shape: Sequence[int]) -> tuple[int, ...]tau(property) — Physical detector bin width.
def backproject3d(sinogram: torch.Tensor, angles: torch.Tensor, n: int | None = None, width: float = 1.0, samples_per_pixel: float = 1.0) -> torch.Tensor¶
Pixel-driven back-projection of a sinogram stack, scaled to approximate Rᵀ.
def fbp3d(sinogram: torch.Tensor, angles: torch.Tensor | Sequence[float], filter: str = 'ramp', *, n: int | None = None, width: float = 1.0, circle: bool = False) -> ...¶
Slice-wise filtered back-projection f(·, z) ≈ (π/V) Σ_θ q_θ(x cos θ + y sin θ, z).
nefi.instances.ct3d.scenes¶
Procedural 3-D CT phantoms (normalized coordinates, inside the scanner cylinder, in [0, 1]).
class CT3DScenes(domain: Domain, render_factor: int = 2)¶
Attenuation volumes for 3-D parallel-beam CT (rotation axis z).
blobs(self, rng: np.random.Generator) -> Painter3Dellipsoids(self, rng: np.random.Generator) -> Painter3Dpiecewise(self, rng: np.random.Generator) -> Painter3Dsample(self, rng, cls=None, shape=None)
nefi.instances.current_density¶
current_density — NV-magnetometry current imaging: sheet current from its stray field B_z.
class BiotSavartDataGenerator(operator: Operator, noise_std: float = 0.0, relative: bool = True, dtype: torch.dtype = torch.float64, device: str | torch.device = 'cpu', supersample: int ...¶
g on a fine grid → direct Biot–Savart B_z at the native pixels (float64) + noise.
generate(self, gt_fields, rng: np.random.Generator, noise_std=None, target_shape=None)
class CurrentDensity(cfg: Any | Mapping | None = None, **overrides: Any)¶
NV magnetometry current-density imaging (stream-function parameterization).
baselines(self)build_problem(self, measurement: Measurement) -> InverseProblembuild_problem_measurement_shape(self, field_shape)data_generator(self) -> BiotSavartDataGeneratordefault_curriculum(self) -> Curriculumdomain(self) -> Domainevaluate(self, result: Result, gt: Mapping[str, torch.Tensor]) -> dict[str, float]field(self) -> NeuralFieldfourier_reconstruction(self, measurement: Measurement) -> torch.Tensor— Classical regularized k-space inversion of the measuredB_z(stream function).heads(self) -> Headslosses(self, tv: float | None = None) -> LossSetmake_measurement(self, seed=0, scene_class=None, gt=None)metrics(self) -> dict[str, Callable]mu0(property)operator(self, domain: Domain | None = None) -> CurrentDensityOperatorscene_generator(self) -> SceneGenerator
class CurrentDensityConfig(n: int = 64, pixel: float = 0.1, z0: float = 0.2, nv_layer: float = 0.0, length_unit: str = 'um', current_unit: str = 'mA', field_unit: str = 'uT', pad_fact...¶
NV current-imaging instance configuration (every number used by the pipeline).
def current_metrics(pred_g: torch.Tensor, gt_g: torch.Tensor, spacing, pred_bz: torch.Tensor | None = None, gt_bz: torch.Tensor | None = None) -> dict[str, float]¶
PSNR / relative error of K = ∇×g (central differences, both components) and of B_z.
def make_problem(seed: int = 0, scene_class: str | None = None, **cfg)¶
Convenience: (problem, gt, measurement) for docs, tests and notebooks.
def run(cfg: CurrentDensityConfig | dict | None = None, seed: int = 0, **kw)¶
End-to-end demo: generate → invert → evaluate. Returns (Result, metrics).
nefi.instances.current_density.scenes¶
Current-density scenes for NV magnetometry: wires, loops and branching current networks.
class CurrentScenes(domain: Domain, current: Sequence[float] = (0.5, 1.5), width: Sequence[float] = (0.2, 0.3), margin: float = 0.15, loop_radius: Sequence[float] = (0.08, 0.2)...¶
Stream-function scenes (see module docstring). Lengths in domain units.
components(self, rng: np.random.Generator, cls: str) -> list[dict]— Sample the scene's current paths: dicts withkind, geometry,Iandw.render(self, comps: list[dict], shape: Sequence[int] | None = None) -> torch.Tensor— Stream functiong(float64) on the gridshape.sample(self, rng, cls=None, shape=None)
nefi.instances.darcy_flow¶
darcy_flow — permeability recovery from steady pressure data (subsurface flow).
class DarcyConfig(n: int = 32, length: float = 1.0, viscosity: float = 1.0, bc: str = 'neumann', n_configs: int = 6, well_radius: float = 0.3, well_rate: float = 1.0, well_an...¶
Darcy-flow instance configuration (every number used by the pipeline).
class DarcyFlow(cfg: Any | Mapping | None = None, **overrides: Any)¶
Steady Darcy flow: log-permeability from sparse pressure gauges, several well patterns.
baselines(self)build_problem(self, measurement: Measurement) -> InverseProblembuild_problem_measurement_shape(self, field_shape)data_generator(self) -> SupersampledObservationGeneratordefault_curriculum(self) -> Curriculumdomain(self) -> Domainfield(self) -> NeuralFieldheads(self) -> Headslosses(self, tv: float | None = None) -> LossSetmake_measurement(self, seed=0, scene_class=None, gt=None)metrics(self) -> dict[str, Callable]observation_weights(self, shape: tuple[int, ...]) -> torch.Tensor— Sensor weights at gridshape(exact native-cell footprints).operator(self, domain: Domain | None = None, **overrides) -> DarcyOperatorscene_generator(self) -> SceneGeneratorsensors(self) -> torch.Tensor—(n_configs, n, n)native sensor mask (deterministic unlesssensor_jitter > 0).wells(self) -> list[list[tuple[float, float, float]]]
def make_problem(seed: int = 0, scene_class: str | None = None, **cfg)¶
Convenience: (problem, gt, measurement) for docs, tests and notebooks.
def run(cfg: DarcyConfig | dict | None = None, seed: int = 0, **kw)¶
End-to-end demo: generate → invert → evaluate. Returns (Result, metrics).
nefi.instances.darcy_flow.operator¶
Steady single-phase Darcy flow: log-permeability → pressure at sparse sensors.
class DarcyOperator(domain: Domain, wells: Sequence[Sequence[Well]], *, sensors: torch.Tensor | None = None, obs_shape: Sequence[int] | None = None, field: str = 'log_k', sigma...¶
{log_k} → p (n_configs, *obs_shape): steady Darcy pressure per well configuration.
output_shape(self, shape: Sequence[int]) -> tuple[int, ...]post(self, u: torch.Tensor, sigma: torch.Tensor, fields) -> torch.Tensor
def sensor_mask(domain: Domain, wells: Sequence[Sequence[Well]], n_sensors: int = 6, exclusion: float = 1.5, jitter: float = 0.0, rng=None) -> torch.Tensor¶
(n_configs, *grid) pressure-sensor mask on a regular n_sensors × n_sensors lattice.
def well_configurations(domain: Domain, n_configs: int, radius: float = 0.35, rate: float = 1.0, angle0: float = 0.3) -> list[list[Well]]¶
Injector/producer pairs on a circle, rotated over half a turn.
def wells_rhs(domain: Domain, wells: Sequence[Sequence[Well]], viscosity: float = 1.0, spread: str = 'linear') -> torch.Tensor¶
(n_configs, *grid) source density μ Σ Q δ(x − x_w) (cloud-in-cell point sources).
nefi.instances.darcy_flow.scenes¶
Darcy-flow ground-truth permeability fields (log-permeability Y = log k).
class DarcyScenes(domain: Domain, mean: float = 0.0, std: float = 0.8, corr_length: float = 0.15, n_modes: int = 128, channel_contrast: float = 2.5, channel_bg_std: float = 0...¶
Log-permeability scenes (see module docstring).
sample(self, rng, cls=None, shape=None)
def high_k_iou(pred, gt, n_std: float = 1.0) -> float¶
IoU of the high-permeability region Y > mean(Y_gt) + n_std·std(Y_gt) (flow paths).
nefi.instances.deconvolution¶
deconvolution — 2-D image deblurring with Gaussian / motion / disk PSFs.
class Deconvolution(cfg: Any | Mapping | None = None, **overrides: Any)¶
2-D image deblurring instance (see module docstring).
baselines(self) -> dict[str, Callable[[Measurement], tuple[InverseProblem, Curriculum]]]blur(self, domain: Domain | None = None) -> FFTConvolution— Blur operator in image units (no count scaling).build_problem(self, measurement: Measurement, losses: LossSet | None = None) -> InverseProblembuild_problem_measurement_shape(self, field_shape)data_generator(self) -> DataGeneratordefault_curriculum(self) -> Curriculumdomain(self) -> Domainfield(self) -> NeuralFieldheads(self) -> Headslosses(self, l2: float = 0.0) -> LossSetmeasurement_image(self, measurement: Measurement) -> torch.Tensor— Measurement in image units (counts → intensity for Poisson data).metrics(self) -> dict[str, Callable]noise_level(self, measurement: Measurement) -> float— Noise std in image units (known Gaussian std, or√λ / peakfor Poisson counts).operator(self, domain: Domain | None = None) -> Operator— Inversion operator: blur, timespeak_countsplus background for Poisson data.psf_fn(self) -> KernelFnscene_generator(self) -> SceneGeneratorwiener(self, measurement: Measurement) -> torch.Tensor— Closed-form Wiener reconstruction ofmeasurement(image units, clipped ≥ 0).wiener_reconstruction(self, measurement: Measurement) -> tuple[torch.Tensor, float]— Closed-form Wiener reconstruction (image units, ≥ 0) and the SNR used.
class DeconvolutionConfig(n: int = 64, extent: float = 1.0, scene: str = 'phantom', psf: str = 'gaussian', psf_sigma: float = 0.02, motion_length: float = 0.1, motion_angle: float = ...¶
Configuration of the :class:Deconvolution instance (all numbers are config fields).
def make_problem(n: int = 64, seed: int = 0, scene: str | None = None, **cfg) -> tuple[InverseProblem, dict[str, torch.Tensor], Measurement]¶
Convenience: (problem, gt, measurement) for docs and tests.
def run(cfg: DeconvolutionConfig | dict | None = None, seed: int = 0, **kw)¶
End-to-end demo (generate → invert → evaluate); returns a RunOutput.
nefi.instances.deconvolution.data¶
Inverse-crime-safe blur data generation with Gaussian or Poisson (photon-count) noise.
class BlurDataGenerator(operator: Operator, noise: str = 'gaussian', noise_std: float = 0.01, peak_counts: float = 200.0, background_counts: float = 0.0, relative: bool = True, dty...¶
Blur on a finer grid in float64, area-average to the detector grid, then add noise.
generate(self, gt_fields: dict[str, torch.Tensor], rng: np.random.Generator, noise_std: float | None = None, target_shape: Sequence[int] | None = None) -> Measurement
nefi.instances.deconvolution.phantoms¶
Procedural 2-D phantom primitives shared by the imaging instances.
class Painter(background: float = 0.0, clip: tuple[float | None, float | None] | None = (0.0, 1.0))¶
Accumulates primitives into a scene: additive terms and painted (overwriting) regions.
add(self, value: float, fn: Callable) -> Painterpaint(self, value: float, fn: Callable) -> Painter
def disk(x, y, cx: float, cy: float, r: float) -> torch.Tensor¶
def ellipse(x, y, cx: float, cy: float, a: float, b: float, theta: float = 0.0) -> torch.Tensor¶
Indicator of an ellipse with semi-axes a, b rotated by theta (radians).
def gaussian(x, y, cx: float, cy: float, sx: float, sy: float | None = None, theta: float = 0.0) -> torch.Tensor¶
Unit-peak anisotropic Gaussian.
def point_max(fn: SceneFn, domain: Domain, render_factor: int = 4, normalized: bool = False)¶
Maximum of the point-sampled rendering sub-grid (grid-independent normalization).
def rectangle(x, y, cx: float, cy: float, w: float, h: float, theta: float = 0.0) -> torch.Tensor¶
Indicator of a w × h rectangle centered at (cx, cy) rotated by theta.
def render(fn: SceneFn, domain: Domain, shape: Sequence[int] | None = None, render_factor: int = 4, normalized: bool = False) -> torch.Tensor¶
Cell-averaged rendering of a continuous 2-D scene (float64).
def uniform(rng: np.random.Generator, lo: float, hi: float) -> float¶
nefi.instances.deconvolution.psf¶
Point-spread functions as kernel functions of the grid spacing (rebuilt at every resolution).
def disk_psf(radius: float, supersample: int = 8) -> KernelFn¶
Uniform out-of-focus (pillbox) blur of physical radius, anti-aliased per pixel.
def gaussian_psf(sigma: float | Sequence[float]) -> KernelFn¶
Gaussian blur with physical standard deviation sigma (isotropic or per axis).
def make_psf(kind: str, sigma: float = 0.02, motion_length: float = 0.1, motion_angle: float = 30.0, disk_radius: float = 0.04) -> KernelFn¶
PSF kernel function by name: "gaussian" | "motion" | "disk".
def motion_psf(length: float, angle_deg: float = 0.0, samples_per_cell: int = 8) -> KernelFn¶
Linear motion blur: a uniform line segment of physical length at angle_deg.
nefi.instances.deconvolution.scenes¶
Ground-truth scene classes for image deblurring (cell-averaged, resolution-consistent).
class DeconvolutionScenes(domain: Domain, dot_cells: float = 0.7, render_factor: int = 4)¶
Scene classes (values in [0, 1], zero-ish background):
phantom(self, rng: np.random.Generator) -> Paintersample(self, rng, cls=None, shape=None)smooth(self, rng: np.random.Generator) -> Paintersparse_dots(self, rng: np.random.Generator) -> Painter
nefi.instances.deconvolution.wiener¶
Classical Wiener deconvolution — the closed-form reference reconstruction.
def wiener(measurement: Measurement | torch.Tensor, psf: torch.Tensor | FFTConvolution, snr: float = 100.0, pad: int | None = None, clip: tuple[float | None, float | N...¶
Wiener filter X = conj(H) Y / (|H|² + 1/snr) (Wiener 1949; e.g. Gonzalez & Woods §5.8).
def wiener_discrepancy(measurement: Measurement | torch.Tensor, psf: FFTConvolution, noise_std: float, tau: float = 1.0, snrs: torch.Tensor | None = None, **kw) -> tuple[torch.Ten...¶
Wiener filter with the SNR chosen by Morozov's discrepancy principle.
nefi.instances.deconvolution3d¶
deconvolution3d — fluorescence-microscopy z-stack deblurring with an anisotropic 3-D PSF.
class Deconvolution3D(cfg: Any = None, preset: str | None = None, **overrides: Any)¶
3-D widefield fluorescence deconvolution instance (see module docstring).
baselines(self) -> dict[str, Callable[[Measurement], tuple[InverseProblem, Curriculum]]]blur(self, domain: Domain | None = None) -> FFTConvolution— The PSF convolution in image units (no count scaling).build_problem(self, measurement: Measurement) -> InverseProblembuild_problem_measurement_shape(self, field_shape)data_generator(self) -> DataGeneratordefault_curriculum(self) -> Curriculumdomain(self) -> Domainfield(self) -> NeuralFieldheads(self) -> Headslosses(self) -> LossSetmeasurement_image(self, measurement: Measurement) -> torch.Tensor— Compact 2-D view: the z-slice (image units) with the largest in-slice variance.measurement_stack(self, measurement: Measurement) -> torch.Tensor— Measurement in image units (counts → intensity for Poisson data).metrics(self) -> dict[str, Callable]noise_level(self, measurement: Measurement) -> float— Noise std in image units (known Gaussian std, or√λ / peakfor Poisson counts).operator(self, domain: Domain | None = None) -> Operator— Inversion operator: blur, timespeak_countsplus background for Poisson data.psf_sigma(self) -> tuple[float, float, float]— Physical PSF standard deviations(σ_xy, σ_xy, σ_z)in µm.richardson_lucy(self, measurement: Measurement, n_iter: int | None = None) -> torch.Tensor— Richardson–Lucy reconstruction (rl_itersEM iterations) in image units.scene_generator(self) -> SceneGeneratorwiener(self, measurement: Measurement) -> torch.Tensor— Closed-form 3-D Wiener reconstruction ofmeasurement.wiener_reconstruction(self, measurement: Measurement) -> tuple[torch.Tensor, float]— Closed-form 3-D Wiener reconstruction (image units, ≥ 0) and the SNR used.
class Deconvolution3DConfig(n: int = 64, n_z: int = 32, pixel_size: float = 0.1, z_step: float = 0.2, scene: str = 'filaments', render_factor: int = 2, filament_sigma: tuple[float, flo...¶
Configuration of the :class:Deconvolution3D instance (every number is a field).
def make_problem(seed: int = 0, scene: str | None = None, **cfg: Any) -> tuple[InverseProblem, dict[str, torch.Tensor], Measurement]¶
Convenience: (problem, gt, measurement) for docs and tests.
def run(cfg: Deconvolution3DConfig | dict | None = None, seed: int = 0, **kw: Any)¶
End-to-end demo (generate → invert → evaluate); returns a RunOutput.
nefi.instances.deconvolution3d.classical¶
Classical 3-D deconvolution references: Wiener filtering and Richardson–Lucy.
def richardson_lucy(counts: torch.Tensor, blur: FFTConvolution, n_iter: int = 40, gain: float = 1.0, background: float = 0.0, x0: torch.Tensor | None = None, eps: float = 1e-08...¶
Richardson–Lucy deconvolution of (photon-count or intensity) data.
def wiener3d(image: torch.Tensor, psf: FFTConvolution | torch.Tensor, snr: float = 100.0, pad: tuple[int, ...] | None = None, clip: tuple[float | None, float | None] | N...¶
Wiener deconvolution of a 1-/2-/3-D image (image in image units).
def wiener3d_discrepancy(image: torch.Tensor, psf: FFTConvolution, noise_std: float, tau: float = 1.0, snrs: torch.Tensor | None = None, **kw) -> tuple[torch.Tensor, float]¶
Wiener filter with the SNR chosen by Morozov's discrepancy principle.
nefi.instances.deconvolution3d.scenes¶
Fluorescence-microscopy ground-truth volumes (physical µm coordinates, intensities ~[0, 1]).
class Deconvolution3DScenes(domain: Domain, render_factor: int = 2, filament_sigma: tuple[float, float] = (0.06, 0.09), puncta_sigma: tuple[float, float] = (0.04, 0.07), membrane_width...¶
Z-stack scene classes (fluorophore density, zero-ish background):
cells(self, rng: np.random.Generator)filaments(self, rng: np.random.Generator)puncta(self, rng: np.random.Generator)sample(self, rng, cls=None, shape=None)
nefi.instances.diffraction_tomography¶
diffraction_tomography — 2-D Born / Rytov inversion of a weak scattering contrast.
class DiffractionTomography(cfg: Any | Mapping | None = None, **overrides: Any)¶
Born diffraction tomography instance (see module docstring).
backpropagation(self, measurement: Measurement, domain: Domain | None = None)— Filtered backpropagation reconstruction ofχ(closed form).baselines(self)build_problem(self, measurement: Measurement) -> InverseProblembuild_problem_measurement_shape(self, field_shape)data_generator(self) -> DataGeneratordefault_curriculum(self, lr_mult: float = 1.0) -> Curriculumdomain(self) -> Domainfield(self) -> NeuralFieldheads(self) -> Headslosses(self) -> LossSetmetrics(self) -> dict[str, Callable]operator(self, domain: Domain | None = None) -> BornOperatorscene_generator(self) -> SceneGenerator
class DiffractionTomographyConfig(n: int = 32, extent: float = 4.0, wavelength: float = 1.0, background_index: float = 1.0, scene: str = 'blobs', contrast: float = 0.02, n_angles: int = 16, ...¶
Configuration (defaults = CPU smoke preset: 32², 16 angles, 64 receivers).
class DiffractionTomographyScenes(domain: Domain, contrast: float)¶
Weak-contrast phantoms χ(x) (analytic, any resolution).
sample(self, rng: np.random.Generator, cls: str | None = None, shape=None)
def make_problem(seed: int = 0, **cfg)¶
Convenience: (problem, gt, measurement).
def run(cfg=None, seed: int = 0, **kw)¶
End-to-end demo (DESIGN §3.10): (result, metrics).
nefi.instances.dot3d¶
dot3d — continuous-wave diffuse optical tomography: absorption from surface reflectance.
class DOT3D(cfg: Any = None, preset: str | None = None, **overrides: Any)¶
CW diffuse optical tomography instance (see module docstring).
A(property) — Robin boundary factor from the refractive index (Groenhuis fit).D(property) — Diffusion coefficient1/(3 μ_s')(mm).background_prediction(self) -> torch.Tensor— Readings of the homogeneous background slab (inversion operator, float64, cached).baselines(self) -> dict[str, Callable[[Measurement], tuple[InverseProblem, Curriculum]]]build_problem(self, measurement: Measurement) -> InverseProblembuild_problem_measurement_shape(self, field_shape)data_generator(self) -> DOTDataGeneratordefault_curriculum(self) -> Curriculumdepths(self) -> torch.Tensor— Cell-center depths (mm) of the native grid.detectors(self) -> tuple[torch.Tensor, float]— Detector centers(n_dx, n_dy, 2)and pixel size (mm).domain(self) -> Domainevaluate(self, result: Result, gt: Mapping[str, torch.Tensor]) -> dict[str, float]field(self) -> NeuralFieldheads(self) -> Headsinclusion_mask(self, mua: torch.Tensor) -> torch.Tensor— Half-maximum inclusion mask{e > iou_fraction · max e}of the absorption excesse = [μ_a − μ_bg]_+(contrast independent: DOT under-recovers contrast by design).inclusion_metrics(self, pred: torch.Tensor, gt: torch.Tensor) -> dict[str, float]— Inclusion localization, depth and contrast recovery (half-maximum masks).losses(self) -> LossSetmeasurement_image(self, measurement: Measurement) -> torch.Tensor— Compact 2-D view: source-averaged Rytov datalog(y / y₀)(%, observed pairs), withy₀the homogeneous-background reading (1 for calibrated data) — the inclusions' shadow.metrics(self) -> dict[str, Callable]observation_mask(self) -> torch.Tensor—(n_sources, n_dx, n_dy)mask of the observed source–detector pairs.operator(self, domain: Domain | None = None, tol: float | None = None)scene_generator(self) -> SceneGeneratorsensitivity(self, problem: InverseProblem | None = None, **kw: Any) -> torch.Tensor— Depth-resolved sensitivity‖∂y/∂μ_a(x)‖of the observed data at the background (:func:nefi.diagnostics.sensitivity_map: stochastic output probes by default, one adjoint solve each;exact=Truecomputes every column, one solve per voxel).sources(self) -> torch.Tensor— Source positions(n_sources, 3): a grid on the top face, depth1/μ_s'.
class DOT3DConfig(extent: tuple[float, float, float] = (40.0, 40.0, 20.0), grid: tuple[int, int, int] = (32, 32, 16), musp: float = 1.0, refractive_index: float = 1.4, mua_ba...¶
Configuration of the :class:DOT3D instance (every number is a field; lengths in mm, coefficients in mm⁻¹).
def make_problem(seed: int = 0, scene: str | None = None, **cfg: Any) -> tuple[InverseProblem, dict[str, torch.Tensor], Measurement]¶
Convenience: (problem, gt, measurement) for docs and tests.
def run(cfg: DOT3DConfig | dict | None = None, seed: int = 0, **kw: Any)¶
End-to-end demo (generate → invert → evaluate); returns a RunOutput.
nefi.instances.dot3d.data¶
DOT data generation (fine-grid physics, multiplicative noise, source–detector mask) and the relative-residual data loss.
class DOTDataGenerator(operator: Operator, noise_std: float = 0.01, min_separation: float = 6.0, supersample: int = 2, fidelity_tag: str = 'dot-fv-robin-2x-float64', dtype: torch....¶
Fine-grid CW DOT data with multiplicative (shot-noise-like) Gaussian noise.
generate(self, gt_fields: dict[str, torch.Tensor], rng: np.random.Generator, noise_std: float | None = None, target_shape: Sequence[int] | None = None) -> Measurement
class RelativeResidualMSE(floor: float = 1e-06, name: str | None = None)¶
mean_obs [(pred − obs) / |obs|]² — the relative (per-entry normalized) residual.
forward(self, ctx: Context) -> torch.Tensor
def separation_mask(sources: torch.Tensor, detectors: torch.Tensor, min_separation: float) -> torch.Tensor¶
(n_sources, n_dx, n_dy) mask of source–detector pairs with a lateral separation of at least min_separation (the diffusion approximation fails close to the source, and the huge near-source dynamic range would dominate any fit).
nefi.instances.dot3d.operator¶
Continuous-wave diffuse optical tomography (DOT) forward model on a 3-D slab.
class DiffuseOpticalOperator(domain: Domain, sources: torch.Tensor | Sequence[Sequence[float]], detectors: torch.Tensor, detector_size: float, *, D: float, A: float, field: str = 'mu_a'...¶
CW DOT: absorption μ_a(x) → top-face exitance at detector footprints for every source.
coefficient(self, fields: Fields) -> torch.Tensor— The (known, homogeneous) diffusion coefficient on the grid.detector_shape(property)extra_repr(self) -> strfluence(self, mua: torch.Tensor) -> torch.Tensor— Full fluenceΦ(n_sources, *grid)for an absorption map (diagnostics).kappa_value(self, fields: Fields, ref: torch.Tensor) -> torch.Tensor—κ = μ_a + κ_b(unknown absorption + Robin boundary sink).n_sources(property)output_shape(self, shape: Sequence[int]) -> tuple[int, ...]post(self, u: torch.Tensor, sigma: torch.Tensor, fields: Fields) -> torch.Tensorreadout(self, u: torch.Tensor) -> torch.Tensor— Top-face exitanceK_b Φ[..., 0]averaged over the detector footprints.reference_readout(self, device=None, dtype=None) -> torch.Tensor— Readings of the homogeneous reference slab (μ_a = reference_mua), cached; the solve bypasses the warm-start state of the optimization loop.required_fields(self) -> tuple[str, ...]
def boundary_conductance(h: float, D: float, A: float) -> float¶
Series conductance K_b = 1 / (2A + h / 2D) of a boundary face (flux K_b Φ_0).
def detector_layout(domain: Domain, n: Sequence[int], span: float = 0.8) -> tuple[torch.Tensor, float]¶
Detector centers (n_dx, n_dy, 2) covering the central span fraction of the top face and the detector pitch (square pixels, one per layout cell).
def grid_positions(n: Sequence[int], lo: Sequence[float], hi: Sequence[float]) -> torch.Tensor¶
Cell centers of a regular n[0] × n[1] layout over [lo, hi] → (n0, n1, 2).
def robin_A(refractive_index: float) -> float¶
Boundary mismatch factor A = (1 + R_eff) / (1 − R_eff) with the Groenhuis et al. (1983) fit R_eff = −1.440 n⁻² + 0.710 n⁻¹ + 0.668 + 0.0636 n (n = 1.4 → A ≈ 3.25; n = 1 → A ≈ 1).
def robin_sink(domain: Domain, D: float, A: float, dtype=torch.float64) -> torch.Tensor¶
Volumetric sink κ_b = Σ_faces K_b / h of the boundary cells (Robin on all six faces).
nefi.instances.dot3d.scenes¶
Absorbing inclusions in a scattering slab (physical mm coordinates, μ_a in mm⁻¹).
class DOT3DScenes(domain: Domain, mua_background: float = 0.01, inclusion_mua: tuple[float, float] = (0.03, 0.05), radius: tuple[float, float] = (3.0, 5.0), depth_single: tup...¶
Absorption maps μ_a(x, y, z) of a slab (depth = last axis, top face at z = 0).
draw(self, rng: np.random.Generator, cls: str | None = None) -> list[Inclusion]— Draw the inclusions of one scene (grid independent).render(self, inclusions: list[Inclusion], shape=None) -> torch.Tensorsample(self, rng, cls=None, shape=None)
class Inclusion(center: tuple[float, float, float], radius: float, mua: float)¶
One spherical absorber: physical center (x, y, depth), radius and μ_a.
depth(property)
nefi.instances.eit¶
eit — electrical impedance tomography: conductivity from boundary voltages.
class EIT(cfg: Any | Mapping | None = None, **overrides: Any)¶
Electrical impedance tomography (continuum or gap electrode model).
baselines(self)build_problem(self, measurement: Measurement) -> InverseProblembuild_problem_measurement_shape(self, field_shape)data_generator(self) -> SupersampledObservationGeneratordefault_curriculum(self) -> Curriculumdifference_data(self, measurement: Measurement) -> torch.Tensor— Boundary signature of the inclusions (difference EIT): per observed strip cell, the RMS over the current patterns ofV − V_bgin % of the RMS boundary voltage, whereV_bgis the prediction for the homogeneous bodyσ ≡ σ_bg;NaNoff the observed strip.domain(self) -> Domainfield(self) -> NeuralFieldheads(self) -> Headslosses(self, tv: float | None = None) -> LossSetmake_measurement(self, seed=0, scene_class=None, gt=None)measurement_image(self, measurement: Measurement) -> tuple[torch.Tensor, str]— Compact measurement view for the viewers (:mod:nefi.viz): :meth:difference_data.metrics(self) -> dict[str, Callable]observation_weights(self, shape: tuple[int, ...]) -> torch.Tensor— Boundary length observed per strip cell at gridshape(mask => 0).operator(self, domain: Domain | None = None, **overrides) -> EITOperatorscene_generator(self) -> SceneGenerator
class EITConfig(n: int = 32, half_width: float = 1.0, sigma_bg: float = 1.0, sigma_min: float = 0.05, sigma_max: float = 20.0, n_patterns: int = 8, amplitude: float = 1.0, ...¶
EIT instance configuration (every number used by the pipeline).
def make_problem(seed: int = 0, scene_class: str | None = None, **cfg)¶
Convenience: (problem, gt, measurement) for docs, tests and notebooks.
def run(cfg: EITConfig | dict | None = None, seed: int = 0, **kw)¶
End-to-end demo: generate → invert → evaluate. Returns (Result, metrics).
nefi.instances.eit.operator¶
Continuum-model EIT forward operator: conductivity → boundary potentials for current patterns.
class EITBoundary(rhs: torch.Tensor, offset: torch.Tensor, weights: torch.Tensor, faces: dict[str, np.ndarray])¶
Boundary data of the EIT model on one grid.
class EITOperator(domain: Domain, n_patterns: int = 8, *, amplitude: float = 1.0, electrodes: int = 0, coverage: float = 0.5, obs_shape: Sequence[int] | None = None, field: s...¶
Continuum / gap-model EIT: {σ} → V (n_patterns, *obs_shape), strip = boundary traces.
face_traces(self, u: torch.Tensor, sigma: torch.Tensor) -> torch.Tensor—(n_patterns, n_faces)boundary tracesu + (h_n/2) j/σon this operator's grid.observation_weights(property) —(*obs_shape)observed boundary length per strip cell (mask => 0).output_shape(self, shape: Sequence[int]) -> tuple[int, ...]post(self, u: torch.Tensor, sigma: torch.Tensor, fields) -> torch.Tensor
def boundary_faces(domain: Domain) -> dict[str, np.ndarray]¶
Boundary faces of a 2-D rectangular grid in counter-clockwise arc-length order.
def eit_boundary(domain: Domain, n_patterns: int, amplitude: float = 1.0, electrodes: int = 0, coverage: float = 0.5, dtype: torch.dtype = torch.float64) -> EITBoundary¶
Right-hand sides, trace offsets and observation weights of the EIT model on domain.
def face_interpolation(src: dict[str, np.ndarray], dst: dict[str, np.ndarray]) -> tuple[np.ndarray, np.ndarray, np.ndarray, np.ndarray]¶
Periodic linear interpolation in arc length from src to dst boundary-face centres.
nefi.instances.eit.scenes¶
EIT ground-truth scenes: homogeneous background with elliptical inclusions.
class EITScenes(domain: Domain, sigma_bg: float = 1.0, contrast: Sequence[float] = (3.0, 6.0), high_contrast: Sequence[float] = (10.0, 20.0), radius: Sequence[float] = (0.1...¶
Background σ_bg plus elliptical inclusions (see module docstring).
inclusions(self, rng: np.random.Generator, cls: str) -> list[dict]— Sample inclusion parameters (independent of the rendering resolution).render(self, inclusions: list[dict], shape: Sequence[int] | None = None) -> torch.Tensor— σ on the gridshape(float64), area-weighted at inclusion boundaries.sample(self, rng, cls=None, shape=None)
def inclusion_iou(pred, gt, sigma_bg: float = 1.0, fraction: float = 0.5) -> float¶
IoU of the recovered inclusion support (half-maximum, sign-aware, log-contrast).
nefi.instances.holography¶
holography — multi-distance inline (Gabor) holography phase retrieval.
class Holography(cfg: Any | Mapping | None = None, **overrides: Any)¶
Multi-distance inline holography instance (see module docstring).
baselines(self)build_problem(self, measurement: Measurement) -> InverseProblembuild_problem_measurement_shape(self, field_shape)data_generator(self) -> DataGeneratordefault_curriculum(self, lr_mult: float = 1.0) -> Curriculumdomain(self) -> Domainfield(self) -> NeuralFieldgerchberg_saxton(self, measurement: Measurement, domain: Domain | None = None)— Multi-distance Gerchberg–Saxton phase (closed-form-style baseline).heads(self) -> Headslosses(self) -> LossSetmetrics(self) -> dict[str, Callable]operator(self, domain: Domain | None = None) -> HolographyOperatorscene_generator(self) -> SceneGeneratorviz_hints(property) — Display hints (:mod:nefi.viz.hints): with the :class:~nefi.fields.ZeroMeanhead the phase and the phantoms share one gauge, so the viewer'szero_meandisplay transform (the fallback forzero_mean=False) is switched off.
class HolographyConfig(n: int = 32, pixel_size: float = 1.0, wavelength: float = 0.5, distances: tuple[float, ...] = (10.0, 25.0, 50.0), scene: str = 'smooth_phase', phase_amplitu...¶
Configuration (defaults = CPU smoke preset: 32², 3 distances).
class HolographyScenes(domain: Domain, amplitude: float, zero_mean: bool = True)¶
Phase phantoms φ(x) in rad (analytic, any resolution).
sample(self, rng: np.random.Generator, cls: str | None = None, shape=None)
def make_problem(seed: int = 0, **cfg)¶
Convenience: (problem, gt, measurement).
def run(cfg=None, seed: int = 0, **kw)¶
End-to-end demo (DESIGN §3.10): (result, metrics).
nefi.instances.nv_relaxometry¶
nv_relaxometry — NeTMY: sparse spin-density recovery from NV-center relaxometry spectra.
class NVRelaxometry(cfg: Any | Mapping | None = None, **overrides: Any)¶
NeTMY NV-relaxometry instance (arXiv 2605.13988).
band_center(property)baselines(self) -> dict[str, Callable[[Measurement], tuple[InverseProblem, Curriculum]]]—grid(Tikhonov, F2),grid_f1,f1(NeTMY under F1),f2(NeTMY, F2).build_grid_problem(self, measurement: Measurement, mode: str = 'F2') -> tuple[InverseProblem, Curriculum]— Tikhonov free-density baseline (NeTMY App. E.2): grid ρ ≥ 0 (softplus) + ℓ2 + TV.build_problem(self, measurement: Measurement, mode: str | None = None, field=None, seed: int | None = None) -> InverseProblem— NeTMY problem formeasurementunder inversion operatormode("F2" | "F1").build_problem_measurement_shape(self, field_shape: Sequence[int]) -> tuple[int, ...]compare(self, seed: int = 0, scene_class: str | None = None, methods: Sequence[str] = ('netmy', 'f1', 'grid', 'grid_f1'), device: str = 'auto', step_scale: float = ...— Run several methods on the same F3-generated sample (NeTMY Tab. 1 in one call).data_generator(self) -> NVDataGenerator— F3 (default) or F2/F1 (matched-operator) data generator with relative noise.default_curriculum(self) -> Curriculum— Tab. 6: 32² (3000 steps, η) → 64² (7000 steps, η/2), cosine to 0.01η, β reset.direct_simulator(self) -> NVDirectSimulator— Source-side direct simulator F3 (NeTMY Eq. 11), float64.domain(self) -> Domainevaluate(self, result: Result, gt: Mapping[str, torch.Tensor]) -> dict[str, float]— Density metrics onresult.fields["rho"](scale-corrected) + Larmor MAE on support.field(self, seed: int | None = None) -> NeuralField— Coordinate MLP with annealed Fourier features (Tab. 5, Eq. 27).frequencies(self, dtype: torch.dtype = torch.float32) -> torch.Tensorheads(self) -> Heads—ρ= gated softplus (Eq. 5);ω_L= support-masked bounded head (Eq. 26).kernels(self) -> DipolarKernelslog_eps(self, measurement: Measurement | None = None) -> float— Additive constant of the log-MSE (Eq. 19): paper 1e-10, or the noise floor of N̂.losses(self, measurement: Measurement | None = None) -> LossSet— NeTMY objective Eq. (6), Tab. 7 weights (log_mse= D,noise_map= R_nm, ...).metrics(self) -> dict[str, Callable]— GMSD, Hungarian F1, SWD (primary) + density MSE, masked SSIM (App. E.3).operator(self, mode: str | None = None, domain: Domain | None = None) -> NVOperator— Inversion operatorF2/F1(NeTMY Eq. 2) ondomain(default native).postprocess(self) -> listrun(self, seed: int = 0, device: str = 'auto', scene_class: str | None = None, curriculum: Curriculum | None = None, callbacks: Sequence = (), **solver_kw: Any)...— Generate one sample (F3 + noise), invert it with NeTMY and evaluate (Algorithm 1).scene_generator(self) -> NVScenes
class NVRelaxometryConfig(n: int = 64, spacing: float = 20.0, z0: float = 20.0, gamma: float = 0.5, larmor_band: tuple[float, float] = (1.5, 2.5), freq_range: tuple[float, float] = (...¶
Configuration of the NV-relaxometry instance; defaults follow NeTMY.
def build_problem(measurement: Measurement, mode: str = 'F2', cfg: NVRelaxometryConfig | Mapping | None = None, **overrides: Any) -> InverseProblem¶
NeTMY :class:InverseProblem for measurement under mode ("F2" | "F1").
def default_curriculum(cfg: NVRelaxometryConfig | Mapping | None = None, **overrides) -> Curriculum¶
Tab. 6 curriculum for cfg.
def make_problem(seed: int = 0, scene: str | None = None, mode: str = 'F2', **cfg: Any) -> tuple[InverseProblem, dict[str, torch.Tensor], Measurement]¶
Convenience: (problem, gt, measurement) for docs, tests and notebooks.
def run(cfg: NVRelaxometryConfig | Mapping | None = None, seed: int = 0, **run_kw: Any) -> tuple[Result, dict[str, float]]¶
End-to-end demo (DESIGN §3.10): generate (F3) → invert (NeTMY) → evaluate.
nefi.instances.nv_relaxometry.data¶
Measurement generation for NV relaxometry (NeTMY App. E.1).
class NVDataGenerator(operator, noise_std: float = 0.01, relative: bool = True, dtype: torch.dtype = torch.float64, device: str | torch.device = 'cpu', fidelity_tag: str | None =...¶
Data generator with noise relative to max(S) − min(S) of each clean spectrum.
add_noise(self, clean: torch.Tensor, rng: np.random.Generator, noise_std: float | None = None) -> tuple[torch.Tensor, float]generate(self, gt_fields: dict[str, torch.Tensor], rng: np.random.Generator, noise_std: float | None = None, target_shape=None) -> Measurement
def downsample_spectrum(measurement: Measurement, shape) -> Measurement¶
Area-average the spatial dims of a (n_freq, H, W) spectrum to shape = (h, w).
nefi.instances.nv_relaxometry.losses¶
NeTMY-specific loss terms (App. D.4) and noise-map helpers.
class DirectDensityLoss(field: str = 'rho', freq_axis: int = 0, eps: float = 1e-12, name: str | None = None)¶
Direct-density proxy R_ds = MSE(ρ² / mean ρ², N_obs / mean N_obs) (NeTMY App. D.4).
forward(self, ctx: Context) -> torch.Tensor
def noise_map(spectrum: torch.Tensor, freq_axis: int = 0) -> torch.Tensor¶
Frequency-summed noise map N(r; S) = Σ_{ω∈W} S(ω, r) (NeTMY §3.2, App. B.1).
def normalized_noise_map(spectrum: torch.Tensor, how: str = 'max', freq_axis: int = 0, eps: float = 1e-30) -> torch.Tensor¶
N̂ = N / max N (how="max", Eq. 19) or N / mean N (how="mean", R_nm).
nefi.instances.nv_relaxometry.operator¶
NV relaxometry forward operators F1 / F2 (FFT-factorized) and F3 (direct, source-side).
class NVDirectSimulator(domain: Domain, freqs: torch.Tensor | Sequence[float], z0: float = 20.0, gamma: float = 0.5, units: str = 'normalized', length_scale: float = 1e-09, nv_axis...¶
Source-side direct simulator F3 (NeTMY Eq. 11), float64, no FFT factorization.
extra_repr(self) -> strforward(self, fields: Fields) -> torch.Tensorn_freq(property)output_shape(self, shape: Sequence[int]) -> tuple[int, ...]required_fields(self) -> tuple[str, ...]
class NVOperator(domain: Domain, freqs: torch.Tensor | Sequence[float], z0: float = 20.0, gamma: float = 0.5, mode: str = 'F2', units: str = 'normalized', length_scale: floa...¶
FFT-factorized NV relaxometry operator (NeTMY Eq. 2): {rho, omega_L} -> S(ω, r).
at_resolution(self, shape: Sequence[int]) -> NVOperatorextra_repr(self) -> strfidelity_tag(property) — Physics/discretization tag for the benchmark inverse-crime guard ("F2-fft").forward(self, fields: Fields) -> torch.Tensorkernel(self, shape: Sequence[int] | None = None, device=None, dtype=None) -> torch.Tensor— The sampled convolution kernel (PorG_zz) for a field grid ofshape.lorentzian(self, omega_L: torch.Tensor) -> torch.Tensor—L(ω; ω_L(r))at the readout pixels, shape(n_freq, *omega_L.shape).n_freq(property)output_shape(self, shape: Sequence[int]) -> tuple[int, ...]required_fields(self) -> tuple[str, ...]spatial_response(self, fields: Fields) -> torch.Tensor— Frequency-independent spatial factor:P ∗ ρ(F2) or(G_zz ∗ ρ)²(F1).
nefi.instances.nv_relaxometry.physics¶
NV-relaxometry physics: dipolar Green tensor, tensor power kernels and the Lorentzian.
class DipolarKernels(z0: float = 20.0, units: str = 'normalized', length_scale: float = 1e-09, nv_axis: tuple[float, float, float] = (0.0, 0.0, 1.0))¶
Dipolar kernels for an NV array at standoff z0 (NeTMY Eq. 1-2, App. A).
channel(self, offsets: torch.Tensor, a: str | int) -> torch.Tensor— Single channelG_nv,afora ∈ {x, y, z}.channel_fn(self, a: str | int) -> KernelFn—(spacing, shape, device, dtype) -> G_nv,asampled on the offset grid.channels(self, offsets: torch.Tensor) -> torch.Tensor— NV-projected channelsG_nv,a(R) = Σ_i n_i G_ia(R), shape(..., 3)(a = x, y, z).nv(self, offsets: torch.Tensor) -> torch.Tensor— Scalar NV-axis kernelG_nn(R) = Σ_a n_a G_nv,a(R)(G_zzfor n = z; F1).nv_fn(self) -> KernelFn—(spacing, shape, device, dtype) -> G_nn(G_zz) sampled on the offset grid.peak(property) — Peak of|G_zz|for a z-aligned NV in the chosen units (1when normalized).power(self, offsets: torch.Tensor) -> torch.Tensor— Tensor power kernelP(R) = Σ_a |G_nv,a(R)|²(NeTMY Eq. 2 F2, Eq. 11).power_fn(self) -> KernelFn—(spacing, shape, device, dtype) -> Psampled on :func:kernel_offsets.
def channel_kernel_fn(a: str | int, z0: float, units: str = 'normalized', length_scale: float = 1e-09, nv_axis: Sequence[float] = (0.0, 0.0, 1.0)) -> KernelFn¶
Kernel callable for a single channel G_az (a ∈ {x, y, z}; App. A.1, Fig. 6).
def dipolar_green_tensor(R: torch.Tensor, prefactor: float = 1.0000000000000001e-07) -> torch.Tensor¶
Dipolar Green tensor G_ia(R) = c (3 R_i R_a − |R|² δ_ia) / |R|⁵ (NeTMY Eq. 1).
def frequency_grid(lo: float = 1.0, hi: float = 3.0, n: int = 50, dtype: torch.dtype = torch.float32) -> torch.Tensor¶
Uniform readout frequency grid W (NeTMY App. E.1: 50 frequencies).
def gzz_kernel_fn(z0: float, units: str = 'normalized', length_scale: float = 1e-09, nv_axis: Sequence[float] = (0.0, 0.0, 1.0)) -> KernelFn¶
Kernel callable for the F1 NV-axis kernel G_nv = Σ_a n_a G_az (G_zz, Eq. 2).
def lorentzian(omega: torch.Tensor | float, omega_L: torch.Tensor | float, gamma: float) -> torch.Tensor¶
Lorentzian spectral response L(ω; ω_L) = γ² / ((ω − ω_L)² + γ²) (NeTMY Eq. 13).
def power_kernel_fn(z0: float, units: str = 'normalized', length_scale: float = 1e-09, nv_axis: Sequence[float] = (0.0, 0.0, 1.0)) -> KernelFn¶
Kernel callable for the F2 tensor power kernel P = Σ_a |G_az|² (NeTMY Eq. 2).
nefi.instances.nv_relaxometry.scenes¶
Sparse spin-source scenes for NV relaxometry (NeTMY App. E.1).
class NVScenes(domain: Domain, z0: float = 20.0, larmor_band: Sequence[float] = (1.5, 2.5), background_larmor: float | None = None, amp_range: Sequence[float] = (0.5, 1.0)...¶
Ground-truth {"rho", "omega_L"} scenes with sparse point sources (NeTMY App. E.1).
check_class(self, cls: str | None) -> strrender(self, sources: Mapping, shape: Sequence[int] | None = None) -> dict— Rasterizesources(from :meth:sample_sources) on a grid ofshape.sample(self, rng: np.random.Generator, cls: str | None = None, shape: Sequence[int] | None = None) -> dict[str, torch.Tensor]sample_sources(self, rng: np.random.Generator, cls: str | None = None) -> dict— Sample source positions (physical), amplitudes and Larmor frequencies forcls.
def normalize_class(cls: str) -> str¶
Canonical "<count>/<separation>" form (accepts _, - or / separators).
nefi.instances.photoacoustic3d¶
photoacoustic3d — 3-D photoacoustic tomography (PAT) from a planar sensor array.
class Photoacoustic3D(cfg: Any = None, preset: str | None = None, **overrides: Any)¶
3-D planar-array photoacoustic tomography instance (see module docstring).
baselines(self) -> dict[str, Callable[[Measurement], tuple[InverseProblem, Curriculum]]]build_problem(self, measurement: Measurement) -> InverseProblembuild_problem_measurement_shape(self, field_shape)data_generator(self) -> DataGeneratordefault_curriculum(self) -> Curriculumdomain(self) -> Domainfield(self) -> NeuralFieldheads(self) -> Headslosses(self) -> LossSetmetrics(self) -> dict[str, Callable]n_t(property)operator(self, domain: Domain | None = None, order: int | None = None) -> SensorBandwidth— Inversion operator: the wave solver followed by the sensors' bandwidth.scene_generator(self) -> SceneGeneratorsensors(self) -> torch.Tensor— Sensor positions(n_sx · n_sy, 3): a regular grid on the top face.time_reversal(self, measurement: Measurement, mode: str | None = None) -> torch.Tensor— Time-reversal (or adjoint) reconstruction on the native grid, clipped to≥ 0.wave_operator(self, domain: Domain | None = None, order: int | None = None) -> WaveInitialConditionOperator— The bare wave solver (ideal point sensors).
class Photoacoustic3DConfig(extent: tuple[float, float, float] = (12.0, 12.0, 8.0), grid: tuple[int, int, int] = (48, 48, 32), sound_speed: float = 1.5, sensor_grid: tuple[int, int] = ...¶
Configuration of the :class:Photoacoustic3D instance (every number is a field; mm, µs).
def make_problem(seed: int = 0, scene: str | None = None, **cfg: Any) -> tuple[InverseProblem, dict[str, torch.Tensor], Measurement]¶
Convenience: (problem, gt, measurement) for docs and tests.
def run(cfg: Photoacoustic3DConfig | dict | None = None, seed: int = 0, **kw: Any)¶
End-to-end demo (generate → invert → evaluate); returns a RunOutput.
nefi.instances.photoacoustic3d.scenes¶
Initial-pressure (absorbed-energy) phantoms for 3-D photoacoustic tomography (physical mm).
class PAT3DScenes(domain: Domain, vessel_radius: tuple[float, float] = (0.3, 0.6), sphere_radius: tuple[float, float] = (0.6, 1.5), edge_width: float = 0.15, depth_range: tup...¶
Initial pressure p0(x, y, z) ≥ 0 (arbitrary units, ≲ 1; depth = last axis).
sample(self, rng, cls=None, shape=None)spheres(self, rng: np.random.Generator) -> Painter3Dvessels(self, rng: np.random.Generator) -> Painter3D
nefi.instances.photoacoustic3d.sensor¶
Finite sensor bandwidth: a zero-phase Gaussian low-pass of the pressure traces.
class SensorBandwidth(inner: Operator, dt_obs: float, f_cutoff: float | None)¶
Wraps a trace operator (…, n_t) with the sensors' low-pass response.
at_resolution(self, shape: Sequence[int]) -> SensorBandwidthextra_repr(self) -> strforward(self, fields: Fields) -> torch.Tensoroutput_shape(self, shape: Sequence[int]) -> tuple[int, ...] | Nonerequired_fields(self) -> tuple[str, ...]
def gaussian_lowpass(traces: torch.Tensor, dt: float, f_cutoff: float | None) -> torch.Tensor¶
Zero-phase Gaussian low-pass exp(−½ (f/f_c)²) along the last axis (sample step dt).
nefi.instances.poisson_source¶
poisson_source — PDE-constrained source recovery for the Poisson equation (elliptic).
class PoissonSource(cfg: Any | Mapping | None = None, **overrides: Any)¶
Elliptic source-recovery instance (see module docstring).
baselines(self) -> dict[str, Callable[[Measurement], tuple[InverseProblem, Curriculum]]]build_problem(self, measurement: Measurement) -> InverseProblembuild_problem_measurement_shape(self, field_shape)data_generator(self) -> DataGeneratordefault_curriculum(self) -> Curriculumdomain(self) -> Domainfield(self) -> NeuralFieldheads(self) -> Headslosses(self) -> LossSetmetrics(self) -> dict[str, Callable]operator(self, domain: Domain | None = None) -> PoissonOperatorscene_generator(self) -> SceneGenerator
class PoissonSourceConfig(n: int = 64, extent: float = 1.0, conductivity: float = 1.0, spectrum: str = 'continuous', scene: str = 'blobs', point_cells: float = 0.8, obs_mode: str = '...¶
Configuration of the :class:PoissonSource instance (all numbers are config fields).
def make_problem(n: int = 64, seed: int = 0, scene: str | None = None, **cfg) -> tuple[InverseProblem, dict[str, torch.Tensor], Measurement]¶
Convenience: (problem, gt, measurement) for docs and tests.
def run(cfg: PoissonSourceConfig | dict | None = None, seed: int = 0, **kw)¶
End-to-end demo (generate → invert → evaluate); returns a RunOutput.
nefi.instances.poisson_source.data¶
Sparse / boundary observation data for the Poisson source problem, and masked downsampling.
class PoissonDataGenerator(operator: Operator, noise_std: float = 0.01, obs_mode: str = 'random', obs_fraction: float = 0.1, boundary_width: int = 3, relative: bool = True, dtype: tor...¶
Finite-difference solve on a finer grid (float64), area-average, sample a mask, add noise.
generate(self, gt_fields: dict[str, torch.Tensor], rng: np.random.Generator, noise_std: float | None = None, target_shape: Sequence[int] | None = None) -> Measurement
def masked_downsample(measurement: Measurement, shape: Sequence[int]) -> Measurement¶
Mask-aware area downsampling for coarse curriculum stages.
def observation_mask(shape: Sequence[int], rng: np.random.Generator, mode: str = 'random', fraction: float = 0.1, boundary_width: int = 3) -> torch.Tensor¶
Binary observation mask: a random pixel subset, a boundary strip, or everything.
nefi.instances.poisson_source.operator¶
Differentiable spectral Poisson solver (discrete sine transforms via torch.fft).
class FDPoissonOperator(domain: Domain, field: str = 'f', conductivity: float = 1.0)¶
Non-differentiable finite-difference Poisson solver used by the data generator.
at_resolution(self, shape: Sequence[int]) -> FDPoissonOperatorforward(self, fields: Fields) -> torch.Tensoroutput_shape(self, shape: Sequence[int]) -> tuple[int, ...]
class PoissonOperator(domain: Domain, field: str = 'f', conductivity: float = 1.0, spectrum: str = 'continuous')¶
Source-to-potential map f ↦ u = (-κ Δ)^{-1} f (Dirichlet), spectral and differentiable.
at_resolution(self, shape: Sequence[int]) -> PoissonOperatoreigenvalues(self, device=None, dtype=None) -> torch.Tensor— Eigenvaluesλof-κΔon the operator's grid, shapedomain.shape.forward(self, fields: Fields) -> torch.Tensorlaplacian(self, u: torch.Tensor) -> torch.Tensor— Spectral-κΔu(the inverse map), for residual checks.output_shape(self, shape: Sequence[int]) -> tuple[int, ...]
def dst1(x: torch.Tensor, dim: int = -1) -> torch.Tensor¶
Unnormalized DST-I X_k = Σ_n x_n sin(π (n + 1)(k + 1) / (N + 1)) along dim.
def dst2(x: torch.Tensor, dim: int = -1) -> torch.Tensor¶
Unnormalized DST-II X_k = Σ_n x_n sin(π (n + ½)(k + 1) / N) along dim.
def fd_poisson_solve(f: np.ndarray, spacing: Sequence[float], conductivity: float = 1.0) -> np.ndarray¶
Finite-difference solve of -κΔu = f (float64, scipy sparse direct solver).
def idst1(X: torch.Tensor, dim: int = -1) -> torch.Tensor¶
Inverse of :func:dst1 (DST-I is an involution up to 2 / (N + 1)).
def idst2(X: torch.Tensor, dim: int = -1) -> torch.Tensor¶
Inverse of :func:dst2 along dim (a scaled DST-III).
nefi.instances.poisson_source.scenes¶
Non-negative source fields for the Poisson source problem (cell-averaged, grid-consistent).
class SourceScenes(domain: Domain, point_cells: float = 0.8, render_factor: int = 4)¶
Source classes (field "f", maximum ≈ 1):
blobs(self, rng: np.random.Generator) -> Painterpoints(self, rng: np.random.Generator) -> Paintersample(self, rng, cls=None, shape=None)smooth(self, rng: np.random.Generator) -> Painter
nefi.instances.reaction_diffusion¶
reaction_diffusion — recover a spatially varying Gray–Scott feed rate F(x) from snapshots.
class ReactionDiffusion(cfg: Any | Mapping | None = None, **overrides: Any)¶
Gray–Scott feed-rate inversion instance (see module docstring).
baselines(self)build_problem(self, measurement: Measurement) -> InverseProblembuild_problem_measurement_shape(self, field_shape)data_generator(self) -> DataGeneratordefault_curriculum(self, lr_mult: float = 1.0) -> Curriculumdomain(self) -> Domainfield(self) -> NeuralFieldheads(self) -> Headsinitial_model(self) -> torch.Tensorlosses(self) -> LossSetmetrics(self) -> dict[str, Callable]operator(self, domain: Domain | None = None, substeps: int = 1) -> ReactionDiffusionOperatorscene_generator(self) -> SceneGenerator
class ReactionDiffusionConfig(n: int = 32, extent: float = 0.64, scene: str = 'blobs', F_background: float = 0.045, F_amplitude: float = 0.015, F_min: float = 0.02, F_max: float = 0.07, ...¶
Configuration (defaults = CPU smoke preset: 32², 4 snapshots of u and v, 100 steps).
class ReactionDiffusionScenes(domain: Domain, cfg: ReactionDiffusionConfig)¶
Feed-rate fields F(x) (analytic, any resolution).
sample(self, rng: np.random.Generator, cls: str | None = None, shape=None)
def make_problem(seed: int = 0, **cfg)¶
Convenience: (problem, gt, measurement).
def run(cfg=None, seed: int = 0, **kw)¶
End-to-end demo (DESIGN §3.10): (result, metrics).
nefi.instances.sparse_view_ct¶
sparse_view_ct — parallel-beam CT from a few views with a differentiable Radon transform.
class SparseViewCT(cfg: Any | Mapping | None = None, **overrides: Any)¶
Sparse-view parallel-beam CT instance (see module docstring).
angles(self) -> torch.Tensorbaselines(self) -> dict[str, Callable[[Measurement], tuple[InverseProblem, Curriculum]]]build_problem(self, measurement: Measurement) -> InverseProblembuild_problem_measurement_shape(self, field_shape)data_generator(self) -> DataGeneratordefault_curriculum(self) -> Curriculumdomain(self) -> Domainfbp(self, measurement: Measurement, filter: str | None = None) -> torch.Tensor— Filtered back-projection ofmeasurementon the native grid.field(self) -> NeuralFieldheads(self) -> Headslosses(self) -> LossSetmetrics(self) -> dict[str, Callable]operator(self, domain: Domain | None = None) -> RadonOperatorscene_generator(self) -> SceneGenerator
class SparseViewCTConfig(n: int = 64, extent: float = 1.0, n_views: int = 20, angle_range: float = 180.0, det_per_pixel: float = 1.0, samples_per_pixel: float = 1.0, scene: str = 's...¶
Configuration of the :class:SparseViewCT instance (all numbers are config fields).
def make_problem(n: int = 64, seed: int = 0, scene: str | None = None, **cfg) -> tuple[InverseProblem, dict[str, torch.Tensor], Measurement]¶
Convenience: (problem, gt, measurement) for docs and tests.
def run(cfg: SparseViewCTConfig | dict | None = None, seed: int = 0, **kw)¶
End-to-end demo (generate → invert → evaluate); returns a RunOutput.
nefi.instances.sparse_view_ct.radon¶
Differentiable parallel-beam Radon transform, back-projection and filtered back-projection.
class RadonOperator(domain: Domain, n_views: int = 20, field: str = 'mu', angles: torch.Tensor | Sequence[float] | None = None, angle_range: float = 3.141592653589793, det_per_...¶
Parallel-beam Radon transform μ ↦ sinogram (n_views, n_det) (differentiable, linear).
adjoint(self, sinogram: torch.Tensor) -> torch.Tensor— Exact adjointRᵀ yof this discretization (autograd VJP; the operator is linear).at_resolution(self, shape: Sequence[int]) -> RadonOperatorbackproject(self, sinogram: torch.Tensor) -> torch.Tensor— Pixel-driven back-projection ≈Rᵀ y(independent discretization).dt(property) — Physical ray step Δt.fbp(self, sinogram: torch.Tensor, filter: str = 'ramp', circle: bool = False)— Filtered back-projection onto this operator's grid.forward(self, fields: Fields) -> torch.Tensorn_views(property)output_shape(self, shape: Sequence[int]) -> tuple[int, ...]tau(property) — Physical detector bin width.
def backproject(sinogram: torch.Tensor, angles: torch.Tensor, n: int | None = None, width: float = 1.0, samples_per_pixel: float = 1.0) -> torch.Tensor¶
Pixel-driven back-projection, scaled to approximate the adjoint of :class:RadonOperator.
def fbp(sinogram: torch.Tensor, angles: torch.Tensor | Sequence[float], filter: str = 'ramp', *, n: int | None = None, width: float = 1.0, circle: bool = False) -> ...¶
Filtered back-projection f ≈ (π / V) Σ_θ q_θ(x cos θ + y sin θ), q = (h ⊛ p) / τ.
def ramp_filter(sinogram: torch.Tensor, filter: str = 'ramp', pad_factor: int = 2) -> torch.Tensor¶
Convolve each projection with the Kak-Slaney ramp at unit bin spacing (± window).
def uniform_angles(n_views: int, angle_range: float = 3.141592653589793) -> torch.Tensor¶
n_views equispaced angles in [0, angle_range) (radians, float64).
nefi.instances.sparse_view_ct.scenes¶
Procedural CT phantoms (normalized coordinates, inside the field of view, values in [0, 1]).
class CTScenes(domain: Domain, render_factor: int = 4)¶
Attenuation phantoms for sparse-view CT.
blobs(self, rng: np.random.Generator) -> Painterpiecewise(self, rng: np.random.Generator) -> Paintersample(self, rng, cls=None, shape=None)shepp(self, rng: np.random.Generator) -> Painter
nefi.instances.thermal_tomography¶
thermal_tomography — NeFTY: 3-D inverse heat conduction from pulsed-thermography surface frames.
class ThermalTomography(cfg: Any = None, preset: str | None = None, **overrides: Any)¶
NeFTY thermal tomography (pulsed thermography, 3-D inverse heat conduction).
baselines(self) -> dict[str, Callable[[Measurement], tuple[InverseProblem, Curriculum]]]— Baselines on the same measurement.boundary_conditions(self) -> tuple[str, ...]build_problem(self, measurement: Measurement) -> InverseProblembuild_problem_measurement_shape(self, field_shape: Sequence[int]) -> tuple[int, ...]data_generator(self) -> DataGeneratordefault_curriculum(self) -> Curriculum— Single stage (paper): Adam, step decay ×0.1 / 1000, annealing over the firstanneal_steps(Tab. 5);n_stages > 1gives a coarse-to-fine curriculum.domain(self) -> Domainevaluate(self, result: Result, gt: Mapping[str, torch.Tensor], measurement: Measurement | None = None) -> dict[str, float]— Volumetric metrics, App. H projections and — given the measurement — the surface-fit PSNR of the recovered field's re-simulation next to that of the initial uniform field (the data-fit-paradox diagnostic, NeFTY §5.2 / App. G.2).field(self) -> NeuralField— NeFTY neural diffusivity field (App. D.1, Tab. 5).heads(self) -> Headsinitial_condition(self)— Post-flash temperature (App. A.5): Gaussian (synthetic) or near-uniform flash (PVC).losses(self) -> LossSet— Surface MSE + isotropic TV (Eq. 22: lateral periodic differences, zero δz on the last slice, physical spacing).make_measurement(self, seed: int = 0, scene_class: str | None = None, gt: Mapping[str, torch.Tensor] | None = None) -> tuple[dict[str, torch.Tensor], Measurement]— Draw a scene, simulate it with the explicit float64 simulator (optionally on asim_supersample× finer grid), add noise.metrics(self) -> dict[str, Callable]— Volumetric metrics of NeFTY App. E.2 / G.5 on the diffusivity field.obs_frames(self) -> tuple[int, ...]operator(self, domain: Domain | None = None, **overrides: Any) -> HeatOperator— The inversion operator (implicit Euler + Jacobi/CG + discrete adjoint).projection_metrics(self, alpha: torch.Tensor, gt: torch.Tensor, gt_mask: torch.Tensor | None = None) -> dict[str, float]— App. H projections evaluated against the ground truth: 2-D footprint IoU / Dice and 2.5-D depth AbsRel / RMSE / δ<1.25 on the correctly detected pixels.run(self, seed: int = 0, device: str = 'auto', scene_class: str | None = None, curriculum: Curriculum | None = None, callbacks: Sequence = (), **solver_kw: Any)...— Generate → invert → evaluate (with the surface-fit diagnostics).scene_generator(self) -> ThermalScenessimulator(self, domain: Domain | None = None) -> ExplicitHeatSimulator— The independent data simulator (explicit, substepped, float64; App. E.1).surface_metrics(self, pred: torch.Tensor, measurement: Measurement, reference: torch.Tensor | None = None) -> dict[str, float]— Surface-fit MSE / PSNR of re-simulated frames against the observed frames (App. G.2); PSNR uses the observed data range.uniform_prediction(self, value: float | None = None, dtype=torch.float64) -> torch.Tensor— Frames predicted by the inversion operator for a uniform field (the initial iterate).
class ThermalTomographyConfig(extent: tuple[float, ...] = (10.0, 10.0, 1.0), grid: tuple[int, ...] = (64, 64, 16), dt: float = 0.05, n_frames: int = 100, first_frame: int = 1, frame_stri...¶
NeFTY configuration; defaults reproduce NeFTY Tab. 5 / App. A.5 / E.1 (see the docs page docs/instances/thermal_tomography.md for the field-by-field mapping).
def surface_downsample(measurement: Measurement, field_shape: Sequence[int]) -> Measurement¶
Measurement at a coarse curriculum stage: surface frames area-averaged laterally.
nefi.instances.thermal_tomography.pinn¶
Soft-constrained PINN baseline for thermal tomography (NeFTY Eq. 4, §3.3, App. C / F.1).
class InitialConditionLoss(initial: Callable[[Domain], torch.Tensor], normalize: bool = True, name=None)¶
mean (T_φ(x, 0) − T0(x))² on the cell centres of the current grid (NeFTY Eq. 4).
forward(self, ctx: Context) -> torch.Tensor
class NormalizedSurfaceMSE(scale: float = 100.0, name: str | None = None)¶
mean (T_φ|_Γ − T̂)² / scale² — the PINN data term in the same dimensionless units as the residual and initial-condition penalties.
forward(self, ctx: Context) -> torch.Tensor
class PDEResidualLoss(n_points: int = 24576, normalize: bool = True, name: str | None = None)¶
mean r² with r = ∂_t T_φ − α_θ ΔT_φ − ∇α_θ·∇T_φ at random collocation points (NeFTY Eq. 4 / App. C.1, Eq. 19). Space is sampled uniformly in the slab, time in (0, t_end]; derivatives are taken by autograd in physical units.
forward(self, ctx: Context) -> torch.Tensor
class SoftPINNSurface(domain: Domain, frame_times: Sequence[float], t_end: float, tnet: TemperatureNet, field: str = 'alpha')¶
The PINN's "forward model": T_φ read off at the observed surface and frame times.
at_resolution(self, shape: Sequence[int]) -> SoftPINNSurfaceforward(self, fields: Fields) -> torch.Tensornormalize(self, x_phys: torch.Tensor, t: torch.Tensor) -> torch.Tensor— Physical(…, ndim)coordinates and times(…)→ normalized(…, ndim + 1).output_shape(self, shape: Sequence[int]) -> tuple[int, ...]temperature(self, x_phys: torch.Tensor, t: torch.Tensor) -> torch.Tensor
class TemperatureNet(ndim: int, hidden: int = 128, depth: int = 5, n_octaves: int = 0, scale: float = 100.0)¶
T_φ(x, t): tanh MLP on (optionally Fourier-encoded) normalized space-time coordinates.
forward(self, xt: torch.Tensor) -> torch.Tensor—xt:(..., ndim + 1)normalized(x, [y,] z, t)→ temperature(...).
nefi.instances.thermal_tomography.projection¶
Projections of a reconstructed 3-D diffusivity to 2-D defect masks and 2.5-D depth maps.
def bulk_profile(alpha: torch.Tensor, alpha_base: float | torch.Tensor | None = None) -> torch.Tensor¶
Bulk (defect-free) diffusivity broadcast to alpha's shape.
def defect_mask_2d(alpha: torch.Tensor, alpha_base: float | torch.Tensor | None = None, k: float = 2.0, min_sigma: float = 0.001, return_info: bool = False, mad_of: str = 'sig...¶
2-D defect mask from a 3-D diffusivity (NeFTY App. H.3).
def depth_map_25d(alpha: torch.Tensor, alpha_base: float | torch.Tensor | None = None, mask2d: torch.Tensor | None = None, depth_coords: Sequence[float] | torch.Tensor | None...¶
2.5-D defect depth map (NeFTY App. H.3).
def gt_depth_map(defect_mask: torch.Tensor, depth_coords: Sequence[float] | torch.Tensor | None = None, thickness: float | None = None, reduce: str = 'median') -> torch.Tensor¶
Ground-truth 2.5-D depth labels from a 3-D defect mask (same reduction as the prediction).
def mad_sigma(x: torch.Tensor) -> torch.Tensor¶
Robust standard deviation 1.4826 · median(|x − median(x)|).
nefi.instances.thermal_tomography.realdata¶
Real pulsed-thermography data: loading, ambient shift, physical ↔ unitless scaling (NeFTY App. A.5 / H).
class PhysicalScales(alpha_phys: float, L0: float, thickness: float, t_total: float, lateral_size: tuple[float, float] | None = None)¶
Dimensional scales of a specimen and its recording (App. A.5, H.2).
extent(self) -> tuple[float, float, float]fourier_number(property) —Fo = α_phys · t_total / L0²— the unitless bulk diffusivityα_sim.physical_alpha(self, alpha_sim: float | torch.Tensor)physical_length(self, x_sim: float | torch.Tensor)physical_time(self, t_sim: float) -> floatunitless_alpha(self, alpha_phys: float | torch.Tensor | None = None)unitless_length(self, x_phys: float) -> floatunitless_time(self, t_phys: float) -> float
def config_for_frames(measurement: Measurement, scales: PhysicalScales, *, nz: int = 16, base: dict[str, Any] | None = None, **overrides: Any) -> dict[str, Any]¶
Config overrides for :class:ThermalTomography matching a real measurement.
def load_frames(path: str | Path, key: str | None = None, dtype=torch.float32) -> torch.Tensor¶
Load a surface temperature sequence (n_t, H, W) from a local file or directory.
def measurement_from_frames(frames: torch.Tensor, *, dt: float, t_ambient: float | torch.Tensor | None = None, pre_flash_frames: int = 0, first_frame: int = 1, frame_stride: int = 1, c...¶
Ambient-shift, crop, subsample and package recorded frames as a :class:Measurement.
def physical_depth_map(depth_sim: torch.Tensor, scales: PhysicalScales, unit: str = 'mm')¶
Convert a unitless depth map (fraction of L0) to physical units.
def pvc_overrides(scales: PhysicalScales, *, robin_h: float = 0.0, lateral: str = 'neumann', alpha_contrast: float = 50.0, flash_width_z: float | None = None) -> dict[str, Any]¶
The three PVC adaptations of App. H.2 as config overrides.
nefi.instances.thermal_tomography.scenes¶
Synthetic subsurface-defect scenes for pulsed-thermography tomography (NeFTY App. E.1).
class DefectSpec(kind: str, center: tuple[float, ...], radii: tuple[float, ...], half_thickness: float, angle: float, alpha: float)¶
One buried defect (physical units).
class SceneSpec(cls: str, layer_bounds: tuple[float, ...], layer_alpha: tuple[float, ...], defects: list[DefectSpec] = <factory>)¶
Parameters of one sample: scene class, bulk strata and defects.
to_dict(self) -> dict
class ThermalScenes(domain: Domain, alpha_base_range: Sequence[float] = (0.1, 0.2), alpha_defect_range: Sequence[float] = (0.005, 0.015), n_defects: Sequence[int] = (1, 4), n_l...¶
Scene generator with classes "homogeneous" and "layered" (NeFTY App. E.1).
draw(self, rng: np.random.Generator, cls: str | None = None) -> SceneSpec— Draw the scene parameters (the number of random draws does not depend onshape).rasterize(self, spec: SceneSpec, shape: Sequence[int] | None = None) -> tuple[dict[str, torch.Tensor], dict]— Evaluate a scene on the cell centres ofshape(default: the domain's grid).sample(self, rng: np.random.Generator, cls: str | None = None, shape: Sequence[int] | None = None) -> dict[str, torch.Tensor]— Ground-truth fields{"alpha": (*shape)}for one random scene.sample_with_meta(self, rng: np.random.Generator, cls: str | None = None, shape: Sequence[int] | None = None) -> tuple[dict[str, torch.Tensor], dict]— Like :meth:samplebut also returns the bulk field, defect mask and parameters.thickness(property)
nefi.instances.toy1d¶
toy1d — recover a 1-D non-negative signal from its blurred, noisy observation.
class Toy1D(cfg: Any | Mapping | None = None, **overrides: Any)¶
baselines(self)build_problem(self, measurement: Measurement) -> InverseProblembuild_problem_measurement_shape(self, field_shape)data_generator(self) -> DataGeneratordefault_curriculum(self) -> Curriculumdomain(self) -> Domainfield(self) -> NeuralFieldmetrics(self) -> dict[str, Callable]operator(self, domain: Domain | None = None) -> FFTConvolutionscene_generator(self) -> SceneGenerator
class Toy1DConfig(n: int = 128, sigma: float = 0.02, noise_std: float = 0.01, scene: str = 'bumps', supersample: int = 4, hidden: int = 64, depth: int = 4, n_octaves: int = 6...¶
Toy1DConfig(n: 'int' = 128, sigma: 'float' = 0.02, noise_std: 'float' = 0.01, scene: 'str' = 'bumps', supersample: 'int' = 4, hidden: 'int' = 64, depth: 'int' = 4, n_octaves: 'int' = 6, steps: 'tuple[int, int]' = (300, 600), lr: 'float' = 0.01, tv: 'float' = 0.0001, l1: 'float' = 0.0)
class Toy1DScenes(domain: Domain)¶
sample(self, rng, cls=None, shape=None)
def make_problem(n: int = 128, seed: int = 0, **cfg) -> tuple[InverseProblem, dict[str, torch.Tensor], Measurement]¶
Convenience: (problem, gt, measurement) for docs and tests.
nefi.instances.wave_fwi¶
wave_fwi — acoustic full-waveform inversion (FWI) of a 2-D sound-speed map.
class TraceDataGenerator(operator, trace_mask: torch.Tensor | None = None, **kw)¶
:class:~nefi.bench.DataGenerator with an optional trace mask (near-offset mute).
generate(self, gt_fields, rng, noise_std=None, target_shape=None) -> Measurement
class WaveFWI(cfg: Any | Mapping | None = None, **overrides: Any)¶
Acoustic FWI instance (see module docstring).
acquisition(self) -> tuple[torch.Tensor, torch.Tensor]—(sources, receivers)physical positions (km).baselines(self)build_problem(self, measurement: Measurement) -> InverseProblembuild_problem_measurement_shape(self, field_shape)data_generator(self) -> DataGeneratordefault_curriculum(self, lr_mult: float = 1.0) -> Curriculumdomain(self) -> Domainfield(self) -> NeuralFieldheads(self) -> Headsinitial_model(self) -> torch.Tensor— The uniform starting modelc_backgroundon the native grid.losses(self) -> LossSetmetrics(self) -> dict[str, Callable]n_t(property)offset_mask(self) -> torch.Tensor | None— Near-offset mute:(n_sources, n_receivers, 1)with 0 where the source–receiver distance is belowmin_offset(Nonewhen nothing is muted).operator(self, domain: Domain | None = None, order: int | None = None) -> WaveOperatorscene_generator(self) -> SceneGenerator
class WaveFWIConfig(n: int = 24, extent: float = 1.0, scene: str = 'smooth_anomaly', c_background: float = 2.0, c_min: float = 1.5, c_max: float = 2.5, anomaly: float = 0.4, ge...¶
Configuration (defaults = CPU smoke / gallery preset: 24², surround acquisition with 6 sources and 32 receivers, near offsets < 0.3 km muted, 150 + 250 steps).
class WaveFWIScenes(domain: Domain, cfg: WaveFWIConfig)¶
Analytic sound-speed models (evaluated at any resolution; km/s).
sample(self, rng: np.random.Generator, cls: str | None = None, shape=None)
def make_problem(seed: int = 0, **cfg) -> tuple[InverseProblem, dict[str, torch.Tensor], Measurement]¶
Convenience: (problem, gt, measurement) for docs and tests.
def run(cfg: dict | WaveFWIConfig | None = None, seed: int = 0, **kw)¶
End-to-end demo (DESIGN §3.10): generate → invert → evaluate → (result, metrics).
nefi.instances.wave_fwi.losses¶
Band-limited trace misfit for multiscale (frequency-continuation) full-waveform inversion.
class BandLimitedMSE(f_max: float | None, dt: float, taper: float = 0.3, relative: bool = True, name: str | None = None)¶
(Relative) MSE between low-pass filtered predicted and observed traces.
extra_repr(self) -> strforward(self, ctx: Context) -> torch.Tensor
def lowpass(x: torch.Tensor, dt: float, f_max: float, taper: float = 0.3) -> torch.Tensor¶
Zero-phase low-pass filter along the last (time) axis with a cosine roll-off.