Python API map#

The top-level fdtdx namespace re-exports the principal public API. This page emphasizes the paths exercised by the current examples; specialized parameter transforms, GDS helpers, and field-projection detectors are also available from the top level.

Setup and execution#

fdtdx.auto_grid(wavelength, domain_size, *, ppw=20.0, dl=None, max_voxels=40000000, max_refractive_index=1.0, min_feature_size=None, min_cells_per_feature=3.0, budget_behavior='raise')[source]#

Build a grid for domain_size at wavelength / ppw resolution.

Each axis gets an integer cell count (ceil(length / dl) with a small roundoff guard) and the per-axis spacing is adjusted to length / n — the same adjustment Tidy3D’s uniform grid performs, so a domain of e.g. 0.22um at 40nm becomes 6 cells of 0.0367um instead of a fractional 5.5 cells.

Parameters:
  • wavelength (float) – Free-space wavelength in metres. Used only when dl is not given.

  • domain_size (tuple[float, float, float]) – Physical (Lx, Ly, Lz) extent in metres.

  • ppw (float) – Points per wavelength inside the highest-index material when max_refractive_index is supplied. Defaults to 20.

  • dl (float | None) – Explicit target cell width in metres. Overrides ppw.

  • max_voxels (int) – Voxel budget. Raises when exceeded (instead of an OOM crash later) unless budget_behavior="coarsen".

  • max_refractive_index (float) – Largest refractive index relevant to the scene. The wavelength-derived target spacing is wavelength / (ppw * max_refractive_index). Defaults to 1 so existing free-space behavior is preserved.

  • min_feature_size (float | None) – Optional smallest geometrical feature that must be represented. At least min_cells_per_feature cells are targeted.

  • min_cells_per_feature (float) – Target cells across min_feature_size. Defaults to 3.

  • budget_behavior (Literal['raise', 'coarsen']) – "raise" preserves the requested accuracy and fails before allocation. "coarsen" chooses the finest global spacing that fits max_voxels and emits a warning. This explicit warning is important because global coarsening may under-resolve a requested material wavelength or feature.

Returns:

A QuasiUniformGrid with per-axis spacings adjusted so every axis has an integer cell count.

Raises:

ValueError – If the voxel count exceeds max_voxels.

Return type:

QuasiUniformGrid

fdtdx.auto_boundary_config(pml_layers=10, boundary_types=None, structures=None, domain_size=None, wavelength=None, stabilize_evanescent=False, pml_alpha_fraction=0.2)[source]#

Uniform PML boundary config with per-face overrides and inference.

Defaults to PML on every face — the Tidy3D default. Pass boundary_types to override individual faces, e.g. {"min_x": "periodic", "max_x": "periodic"}.

When structures and domain_size are given, any axis whose extent is completely filled by a structure is inferred as PEC on both faces — the convention the Tidy3D goldens use (z-extent = slab thickness with the slab filling it). Explicit boundary_types always win over inference.

Parameters:
  • pml_layers (int) – PML thickness in cells on every PML face.

  • boundary_types (dict[str, BoundaryType] | None) – Per-face boundary type overrides keyed by "min_x"/"max_x"/"min_y"/"max_y"/"min_z"/"max_z".

  • structures (Sequence[object] | None) – Scene objects (e.g. waveguides, slabs) used to infer PEC faces. Any object whose partial_real_shape fills an axis of domain_size marks that axis PEC.

  • domain_size (tuple[float, float, float] | None) – Physical (Lx, Ly, Lz) extent in metres. Required when structures is given.

  • wavelength (float | None) – Reference free-space wavelength. Required when stabilize_evanescent is enabled.

  • stabilize_evanescent (bool) – Use a complex-frequency-shifted PML suitable for resonators, waveguides, and photonic-crystal terminations with strong evanescent or grazing fields. Material crossing a PML must also be continued with fdtdx.extend_material_to_pml() after geometry parameters are applied.

  • pml_alpha_fraction (float) – CFS strength as a fraction of 2 pi f epsilon_0 at the PML interface. The 0.20 default was selected by a late-time stability sweep of an Ez photonic-crystal surface cavity; smaller values left a growing PML mode.

Returns:

A BoundaryConfig.

Return type:

BoundaryConfig

fdtdx.auto_config(wavelength, domain_size, time, *, ppw=20.0, dl=None, max_voxels=40000000, max_refractive_index=1.0, min_feature_size=None, min_cells_per_feature=3.0, budget_behavior='raise', dtype=<class 'jax.numpy.float32'>, courant_factor=0.99)[source]#

One-call simulation config: auto grid + defaults.

Parameters:
  • wavelength (float) – Free-space wavelength in metres (resolution basis).

  • domain_size (tuple[float, float, float]) – Physical (Lx, Ly, Lz) extent in metres.

  • time (float) – Total simulation time in seconds.

  • ppw (float) – Points per wavelength. Defaults to 20.

  • dl (float | None) – Explicit target cell width in metres. Overrides ppw.

  • max_voxels (int) – Voxel budget (see auto_grid()).

  • max_refractive_index (float) – Highest scene refractive index used to resolve wavelength in material.

  • min_feature_size (float | None) – Optional smallest geometry feature to resolve.

  • min_cells_per_feature (float) – Target cells across the smallest feature.

  • budget_behavior (Literal['raise', 'coarsen']) – Whether an over-budget request raises or explicitly coarsens with a warning.

  • dtype (dtype) – Field dtype. Defaults to float32.

  • courant_factor (float) – Courant safety factor. Defaults to 0.99.

Returns:

A SimulationConfig ready for fdtdx.place_objects(). Pair with auto_boundary_config() for the boundary objects.

Return type:

SimulationConfig

fdtdx.auto_interface_aligned_grid(domain_size, target_spacing, *, interfaces=((), (), ()), center=(0.0, 0.0, 0.0), max_voxels=40000000)[source]#

Build a rectilinear mesh whose cells end exactly at material interfaces.

Each interval between the domain boundary and supplied interface planes is divided into the fewest equal cells whose width does not exceed target_spacing. This removes mesh-origin changes in thin films while keeping the mesh quasi-uniform and the cell count predictable. Interface coordinates are absolute physical coordinates in the same frame as center.

This policy is particularly useful for layered photonics: pass the slab, etch, and substrate planes on their normal axis and let subpixel smoothing handle curved or oblique in-plane boundaries.

Parameters:
  • domain_size (tuple[float, float, float])

  • target_spacing (float | tuple[float, float, float])

  • interfaces (tuple[Sequence[float], Sequence[float], Sequence[float]])

  • center (tuple[float, float, float])

  • max_voxels (int)

Return type:

RectilinearGrid

fdtdx.auto_pml_layers(physical_thickness, spacing)[source]#

Choose a uniform PML cell count that preserves physical thickness.

Refining a mesh must not silently make its absorber thinner. For an anisotropic grid, the smallest spacing controls the uniform layer count, so every face is at least physical_thickness thick (up to the same floating-point guard used by snap_half_integer()).

Parameters:
  • physical_thickness (float)

  • spacing (float | tuple[float, float, float])

Return type:

int

fdtdx.place_objects(object_list, config, constraints, key=None)[source]#

Places simulation objects according to specified constraints and initializes containers.

Parameters:
  • objects (list[SimulationObject]) – List of all simulation objects, including the simulation volume.

  • config (SimulationConfig) – Simulation configuration.

  • constraints (Sequence[Constraint]) – List of positioning/sizing constraints referencing object names.

  • key (jax.Array | None) – JAX random key for initialization. When None (the default) a deterministic key is derived from _DEFAULT_KEY_SEED.

  • object_list (Sequence[SimulationObject])

Returns:

A tuple containing:
  • ObjectContainer with placed simulation objects

  • ArrayContainer with initialized field arrays

  • ParameterContainer with device parameters

  • Updated SimulationConfig

  • Dictionary with additional initialization info

Return type:

tuple[ObjectContainer, ArrayContainer, ParameterContainer, SimulationConfig, dict[str, Any]]

Raises:

ValueError – If constraint resolution fails for one or more objects.

fdtdx.apply_params(arrays, objects, params, key=None, **transform_kwargs)[source]#

Applies parameters to devices and updates source states.

Parameters:
  • arrays (ArrayContainer) – Container with field arrays

  • objects (ObjectContainer) – Container with simulation objects

  • params (ParameterContainer) – Container with device parameters

  • key (jax.Array | None) – JAX random key for source updates. When None (the default) a deterministic key is derived from _DEFAULT_KEY_SEED.

  • **transform_kwargs – Keyword arguments passed to the parameter transformation.

Returns:

A tuple containing:
  • Updated ArrayContainer with applied device parameters

  • Updated ObjectContainer with new source states

  • Dictionary with parameter application info

Return type:

tuple[ArrayContainer, ObjectContainer, dict[str, Any]]

fdtdx.run_fdtd(arrays, objects, config, key=None, stopping_condition=None, show_progress=True, progress_callback=None)[source]#
Parameters:
  • arrays (ArrayContainer)

  • objects (ObjectContainer)

  • config (SimulationConfig)

  • key (Array | None)

  • stopping_condition (StoppingCondition | None)

  • show_progress (bool)

  • progress_callback (Callable[[int, int], None] | None)

Return type:

tuple[Array, ArrayContainer]

Configuration and grid#

class fdtdx.SimulationConfig(*a, **k)[source]#

Configuration settings for FDTD simulations.

This class contains all the parameters needed to configure and run an FDTD simulation, including spatial and temporal discretization, hardware backend, and gradient computation settings.

Return type:

T

property has_symmetry: bool#

Whether any axis requests mirror symmetry.

Returns:

True if at least one entry of symmetry is nonzero, meaning the

domain will be reduced and a PEC/PMC wall placed on the symmetry plane(s).

Return type:

bool

property courant_number: float#

Calculate the Courant number for the simulation.

The Courant number is a dimensionless quantity that determines stability of the FDTD simulation. It represents the ratio of the physical propagation speed to the numerical propagation speed.

Returns:

The Courant number, scaled by the courant_factor and normalized

for 3D simulations.

Return type:

float

property time_step_duration: float#

Calculate the duration of a single time step.

The time step duration is determined by the Courant condition to ensure numerical stability. Realized rectilinear grids use their smallest per-axis spacings. Unresolved uniform grids use their configured scalar spacing; unresolved quasi-uniform grids use their smallest per-axis spacing as a conservative CFL bound.

Returns:

Time step duration in seconds, calculated using the Courant

condition and spatial resolution.

Return type:

float

property time_steps_total: int#

Calculate the total number of time steps for the simulation.

Determines how many discrete time steps are needed to simulate the specified total simulation time, based on the time step duration.

Returns:

Total number of time steps needed to reach the specified

simulation time.

Return type:

int

class fdtdx.GradientConfig(*a, **k)[source]#

Configuration for gradient computation in simulations.

This class handles settings for automatic differentiation, supporting either invertible differentiation with a recorder or checkpointing-based differentiation.

Return type:

T

class fdtdx.UniformGrid(*a, **k)[source]#

Unresolved policy for a uniform rectilinear grid.

UniformGrid is user intent, not the solver mesh itself. It records the physical cell spacing while the final simulation shape may still be unknown. Object placement resolves this policy to a concrete RectilinearGrid once the volume shape is known.

Keeping uniform spacing here avoids a second scalar discretization source on SimulationConfig. Uniform grids and explicitly non-uniform grids both enter the solver through the same realized RectilinearGrid structure.

The grid origin is at the center of the simulation domain. Edge arrays therefore span [-N/2 * spacing, +N/2 * spacing] along each axis, giving the domain symmetric negative and positive coordinates. center shifts this physical center away from the geometric origin when non-zero.

Return type:

T

class fdtdx.QuasiUniformGrid(*a, **k)[source]#

Unresolved policy for a rectilinear grid with independent per-axis spacings.

QuasiUniformGrid generalises UniformGrid to allow different cell widths along x, y, and z while keeping each axis internally uniform. This is sometimes called a quasi-uniform or anisotropic-uniform mesh: the grid is rectilinear and axis-aligned, but the aspect ratio is not 1 : 1 : 1.

Like UniformGrid, this is user intent rather than the solver mesh. Calling resolve() converts the policy to a concrete RectilinearGrid once the simulation shape is known. The resulting grid is centered at center so that coordinates span symmetrically into both negative and positive values along every axis.

Example:

grid = QuasiUniformGrid(dx=10e-9, dy=10e-9, dz=20e-9)
resolved = grid.resolve(shape=(100, 100, 50))
# x, y edges span [-500 nm, +500 nm]; z edges span [-500 nm, +500 nm]
Return type:

T

class fdtdx.RectilinearGrid(*a, **k)[source]#

Realized rectilinear simulation grid described by physical cell edges.

This is the canonical solver-facing grid representation used by fdtdx internals. A uniform grid is represented by equally spaced edge arrays, not by a separate scalar code path. Keeping one realized representation is important for the non-uniform grid migration: placement, PML profiles, mode-solver coordinates, detector weights, and Yee update metrics should all ask the grid for physical distances instead of deriving them from a global resolution value.

The arrays store cell edges in metres. For a grid with nx cells along x, x_edges has shape (nx + 1,) and must be strictly increasing. Cell widths, centers, face areas, and volumes are derived from these arrays.

Notes

This class intentionally does not encode automatic mesh generation policy. Future policy objects such as AutoGrid or QuasiUniformGrid should resolve to RectilinearGrid before the solver runs.

Return type:

T

Scene and materials#

API

Role

SimulationVolume

defines the finite physical domain

Material

permittivity, permeability, conductivity, and dispersion

UniformMaterialObject

axis-aligned material region

Cylinder, Sphere

curved primitives with optional subpixel smoothing

ExtrudedPolygon

extruded 2D polygon; useful for PIC geometry

Device

parameterized material region for inverse design

BoundaryConfig

per-face boundary policy

class fdtdx.Material(*a, **k)[source]#

Represents an electromagnetic material with specific electrical and magnetic properties.

This class stores the fundamental electromagnetic properties of a material for use in electromagnetic simulations. Supports both isotropic and anisotropic materials.

Note

All material properties are stored internally as 9-tuples (xx, xy, xz, yx, yy, yz, zx, zy, zz components). Scalar inputs are automatically broadcast to all diagonal components.

Return type:

T

class fdtdx.SimulationVolume(*a, **k)[source]#

Background material for the entire simulation volume.

Defines the default material properties for the simulation background. Usually represents air/vacuum with εᵣ=1.0 and μᵣ=1.0.

Return type:

T

class fdtdx.UniformMaterialObject(*a, **k)[source]#
Return type:

T

class fdtdx.ExtrudedPolygon(*a, **k)[source]#

A polygon object specified by a list of vertices.

The vertices must be given in a coordinate system centered at the origin, i.e. (0, 0) corresponds to the center of the object’s bounding box. The polygon is placed so that its center coincides with the center of the grid region allocated to this object.

The cross-section size is automatically inferred from the vertex bounding box for the two axes perpendicular to axis, so partial_real_shape does not need to be specified for those axes. The extrusion axis size must still be determined by a constraint or an explicit partial_real_shape entry.

Return type:

T

Sources#

All sources carry a WaveCharacter, direction/polarization information where applicable, a temporal profile, and placement inherited from SimulationObject.

API

Spatial model

PointDipoleSource

local electric dipole

UniformPlaneSource

finite uniform linearly polarized plane

GaussianPlaneSource

finite Gaussian beam

ModePlaneSource

eigenmode on a cross-section

TFSFPlaneSourceRegion

total-field/scattered-field box

class fdtdx.WaveCharacter(*a, **k)[source]#

Class describing a wavelength/period/frequency in free space. Importantly, the wave characteristic conversion is based on a free space wave when using the wavelength (For conversion, a refractive index of 1 is used).

Return type:

T

class fdtdx.UniformPlaneSource(*a, **k)[source]#
Return type:

T

class fdtdx.ModePlaneSource(*a, **k)[source]#
Return type:

T

Temporal profiles are SingleFrequencyProfile, GaussianPulseProfile, and CustomTimeSignalProfile.

Inverse design#

class fdtdx.TopologyOptimizerConfig(iterations, continuation_steps=None, learning_rate=0.1, final_learning_rate_fraction=0.1, beta_start=1.0, beta_end=50.0, lower_bound=0.0, upper_bound=1.0, maximize=True, early_stop_patience=None, early_stop_min_delta=0.0001, algorithm='adam', momentum=0.9, lbfgs_memory_size=10)[source]#

Device-independent bounded Adam continuation policy.

Parameters:
  • iterations (int)

  • continuation_steps (int | None)

  • learning_rate (float)

  • final_learning_rate_fraction (float)

  • beta_start (float)

  • beta_end (float)

  • lower_bound (float)

  • upper_bound (float)

  • maximize (bool)

  • early_stop_patience (int | None)

  • early_stop_min_delta (float)

  • algorithm (Literal['adam', 'sgd', 'lbfgs'])

  • momentum (float)

  • lbfgs_memory_size (int)

class fdtdx.TopologyOptimizationResult(final_parameters, best_parameters, best_objective, best_step, records)[source]#

Parameters and diagnostics returned by optimize_topology().

Parameters:
  • final_parameters (ndarray)

  • best_parameters (ndarray)

  • best_objective (float)

  • best_step (int)

  • records (tuple[TopologyStepRecord, ...])

fdtdx.optimize_topology(objective, initial_parameters, config, *, accept=None, callback=None)[source]#

Run a bounded Adam optimization with automatic projection continuation.

objective(parameters, beta, fraction) returns (value, auxiliary). The scalar fraction progresses inclusively from zero to one and lets a device objective schedule additional weights without owning an optimizer loop. accept may reject numerically nonphysical candidates (for example, passive-power violations) from best-design selection.

Parameters:
  • objective (Callable[[Array, Array, Array], tuple[Array, Any]])

  • initial_parameters (Array | ndarray)

  • config (TopologyOptimizerConfig)

  • accept (Callable[[Any], bool] | None)

  • callback (Callable[[TopologyStepRecord, ndarray, Any], None] | None)

Return type:

TopologyOptimizationResult

fdtdx.conic_filter(parameters, *, radius, spacing, padding='reflect')[source]#

Apply a conic minimum-feature filter with explicit boundary padding.

Parameters:
  • parameters (Array)

  • radius (float)

  • spacing (float)

  • padding (str)

Return type:

Array

fdtdx.tanh_projection(values, *, beta, eta=0.5)[source]#

Smoothly project filtered values toward a binary material system.

Parameters:
  • values (Array)

  • beta (float | Array)

  • eta (float)

Return type:

Array

fdtdx.erosion_dilation_penalty(parameters, *, radius, spacing, beta=10.0, padding='reflect')[source]#

Return the RMS morphological close/open discrepancy.

Parameters:
  • parameters (Array)

  • radius (float)

  • spacing (float)

  • beta (float)

  • padding (str)

Return type:

Array

fdtdx.d4_symmetrize(values)[source]#

Average a square material map over the eight D4 transformations.

This is the material symmetry used by four-port crossings: four rotations and their mirror images. Applying it after filtering and projection matches the topology transform used by Tidy3D’s S-matrix example while retaining one unconstrained parameter per design pixel.

Parameters:

values (Array)

Return type:

Array

fdtdx.binary_density(parameters, *, radius, spacing, threshold=0.5, padding='reflect')[source]#

Create the deterministic fully binary fabrication design.

Thresholding occurs after the same minimum-feature filter used during optimization. It is intentionally fixed at the projection threshold; objective-aware threshold sweeps would grant a hidden per-device optimization stage.

Parameters:
  • parameters (Array)

  • radius (float)

  • spacing (float)

  • threshold (float)

  • padding (str)

Return type:

Array

class fdtdx.LevelSetBoundary2D(reference_level_set, spacing=(1.0, 1.0), narrow_band_width=4.0, maximum_displacement=2.0, interface_width=0.25, supersample=4, threshold=0.5, diagonal_connectivity=False, exterior_edges=('min_x', 'max_x', 'min_y', 'max_y'))[source]#

Binary, topology-guarded boundary-normal design parameterization.

parameters are signed physical displacements on the vertex grid. Positive displacement grows material along its outward normal and negative displacement retreats it. A cosine narrow-band window makes the Maxwell derivative exactly zero in uniform bulk regions, so the gradient is a normal boundary sensitivity rather than a pixel-density sensitivity.

The basis cannot nucleate a remote component because displacement vanishes outside narrow_band_width. Boundary collision can still merge or erase existing components, so preserves_topology() and rebase() provide an explicit host-side acceptance guard.

Parameters:
  • reference_level_set (ndarray)

  • spacing (tuple[float, float])

  • narrow_band_width (float)

  • maximum_displacement (float)

  • interface_width (float)

  • supersample (int)

  • threshold (float)

  • diagonal_connectivity (bool)

  • exterior_edges (tuple[Literal['min_x', 'max_x', 'min_y', 'max_y'], ...])

classmethod from_density(density, *, spacing=(1.0, 1.0), threshold=0.5, narrow_band_width=None, maximum_displacement=None, interface_width=None, supersample=4, diagonal_connectivity=False, exterior_edges=('min_x', 'max_x', 'min_y', 'max_y'))[source]#

Threshold a grey result once and fit its boundary level set.

Parameters:
  • density (Array | ndarray)

  • spacing (tuple[float, float])

  • threshold (float)

  • narrow_band_width (float | None)

  • maximum_displacement (float | None)

  • interface_width (float | None)

  • supersample (int)

  • diagonal_connectivity (bool)

  • exterior_edges (tuple[Literal['min_x', 'max_x', 'min_y', 'max_y'], ...])

Return type:

LevelSetBoundary2D

initial_parameters(*, dtype=<class 'jax.numpy.float32'>)[source]#

Return the zero-displacement start for this reference boundary.

Parameters:

dtype (dtype)

Return type:

Array

boundary_window(*, dtype=<class 'jax.numpy.float32'>)[source]#

Cosine window equal to one on the interface and zero in the bulk.

Parameters:

dtype (dtype)

Return type:

Array

interface_normal(parameters)[source]#

Return the outward material normal on the vertex grid.

Parameters:

parameters (Array)

Return type:

Array

rebase(parameters, *, preserve_topology=True)[source]#

Accept a moved interface and return a fresh signed-distance stage.

Parameters:
  • parameters (Array | ndarray)

  • preserve_topology (bool)

Return type:

tuple[LevelSetBoundary2D, Array]

fdtdx.boundary_topology_signature(density, *, threshold=0.5, diagonal_connectivity=False, exterior_edges=('min_x', 'max_x', 'min_y', 'max_y'))[source]#

Return the material-component and enclosed-void counts of a 2-D mask.

Air connected to one of exterior_edges is exterior and is therefore not counted as a hole. Omit symmetry planes from that tuple: a half-hole touching a mirror plane then remains an enclosed hole after unfolding. This host-side diagnostic is intended for accepted candidate checks, not for differentiation inside a JIT-compiled objective.

Parameters:
  • density (Array | ndarray)

  • threshold (float)

  • diagonal_connectivity (bool)

  • exterior_edges (tuple[Literal['min_x', 'max_x', 'min_y', 'max_y'], ...])

Return type:

BoundaryTopology

fdtdx.topology_safe_boundary_step(basis, parameters, normal_velocity, *, step_size, backtracking_scales=(1.0, 0.5, 0.25, 0.125, 0.0625))[source]#

Take the largest proposed normal step that preserves interface topology.

normal_velocity is normally the gradient of a scalar Maxwell objective with respect to the basis parameters. The returned scale is zero when all candidates would merge, split, create, or erase a boundary component. An objective-aware optimizer should additionally accept only improving steps; this helper supplies the independent geometric guard for its line search.

This is deliberately a host-side operation because connected-component topology is discrete and should never be hidden inside a surrogate JAX gradient.

Parameters:
  • basis (LevelSetBoundary2D | SplineLevelSetBoundary2D)

  • parameters (Array | ndarray)

  • normal_velocity (Array | ndarray)

  • step_size (float)

  • backtracking_scales (tuple[float, ...])

Return type:

tuple[Array, float]

fdtdx.fixed_frequency_cavity_ldos(*, peak_resonant_ldos, quality_factor, pole_frequency, emitter_frequency, background_ldos=0.0)[source]#

Evaluate a fitted cavity pole at one immutable emitter frequency.

peak_resonant_ldos is the resonant contribution at the pole, excluding background_ldos. The returned value applies the single-pole Lorentzian detuning factor

1 / (1 + (2 Q (f_emitter - f_pole) / f_pole)**2).

Unlike optimizing peak Q/V while following a moving pole, this metric gives no benefit to a resonance that walks away from the emitter. Every operation remains differentiable with respect to the fitted pole, Q, mode volume, and ultimately the FDTD geometry.

Parameters:
  • peak_resonant_ldos (Array)

  • quality_factor (Array)

  • pole_frequency (Array)

  • emitter_frequency (Array)

  • background_ldos (float | Array)

Return type:

Array

fdtdx.initialize_planned_recorder(input_shape_dtypes, max_time_steps, *, backend='gpu', **plan_kwargs)[source]#

Plan a recorder and allocate its state in one call.

Parameters:
  • input_shape_dtypes (Mapping[str, ShapeDtypeStruct])

  • max_time_steps (int)

  • backend (Literal['gpu', 'tpu', 'cpu', 'METAL'])

Detectors#

API

Primary result

FieldDetector

selected field components over a region

EnergyDetector

electromagnetic energy history

PhasorDetector

complex fields at requested frequencies

PoyntingFluxDetector

integrated time-domain flux

PhasorPoyntingFluxDetector

frequency-domain flux

ModeOverlapDetector

complex amplitude in an eigenmode

ClosedSurfacePoyntingFluxDetector

net flux through a volume

class fdtdx.PhasorDetector(*a, **k)[source]#

Detector for measuring frequency components of electromagnetic fields using an efficient Phasor Implementation.

This detector computes complex phasor representations of the field components at specified frequencies, enabling frequency-domain analysis of the electromagnetic fields. The amplitude and phase of the original phase can be reconstructed using jnp.abs(phasor) and jnp.angle(phasor). The reconstruction itself can then be achieved using amplitude * jnp.cos(2 * jnp.pi * freq * t + phase).

Return type:

T

class fdtdx.PhasorPoyntingFluxDetector(*a, **k)[source]#

Time-averaged Poynting flux through a single plane in the frequency domain.

Frequency-domain analog of PoyntingFluxDetector. Instead of recording the instantaneous flux at every time step, it accumulates the complex field phasors (inheriting all of PhasorDetector’s DFT / subsampling / scaling machinery) and forms the time-averaged Poynting flux <S> = 1/2 Re(E(w) x H*(w)) in the post-processing method compute_poynting_flux(). This mirrors how ModeOverlapDetector computes its (also bilinear) overlap after the run.

Because the flux is a product of two independently accumulated DFTs, the surface integral cannot be folded into the per-step update the way the time-domain detector does – the phasors must be complete first. All six field components are therefore always recorded.

Return type:

T

class fdtdx.ModeOverlapDetector(*a, **k)[source]#

Detector for measuring the overlap of a waveguide mode with the simulation fields. This detector computes the overlap integral at every frequency in wave_characters, enabling broadband frequency-domain analysis of the electromagnetic fields.

The reference mode is obtained from the waveguide mode solver (compute_mode). For a user-supplied or analytic reference mode (e.g. a Gaussian beam) use CustomModeOverlapDetector or GaussianModeOverlapDetector instead; both share the same overlap machinery via BaseModeOverlapDetector.

The mode overlap is calculated by integrating the cross product of the mode fields with the simulation fields over a cross-sectional plane. This is useful for analyzing waveguide coupling efficiency, transmission coefficients, and modal decomposition of electromagnetic fields.

compute_overlap() returns a complex array of shape (num_freqs,), where num_freqs = len(wave_characters).

Return type:

T

Modes, ports, and metrics#

fdtdx.compute_mode(frequency, inv_permittivities, inv_permeabilities, resolution=None, direction='+', mode_index=0, filter_pol=None, dtype=<class 'jax.numpy.float32'>, bend_radius=None, bend_axis=None, symmetry=(0, 0), transverse_coords=None, fixed_propagation_axis=None)[source]#

Compute optical modes of a waveguide cross-section.

This function uses the Tidy3D mode solver to compute the optical modes of a given waveguide cross-section defined by its permittivity distribution.

By default modes are sorted by their effective index. The mode_index argument indexes this sorted list of modes and returns the desired mode. With filter_pol, it is also possible to only index a specific polarization.

Parameters:
  • frequency (float) – Operating frequency in Hz

  • inv_permittivities (jax.Array) – 3D array of inverse relative permittivity values

  • inv_permeabilities (jax.Array | float) – 3D array of inverse relative permittivity values or single float for uniform permeability distribution.

  • resolution (float | None) – Uniform-grid spacing in metres. Required when transverse_coords is not provided (uniform-grid path). Ignored when transverse_coords is given. Defaults to None.

  • direction (Literal["+", "-"]) – Propagation direction, either “+” or “-“.

  • mode_index (int, optional) – Index of the mode to compute. Defaults to 0.

  • filter_pol (Literal["te", "tm"] | None, optional)

  • dtype (jnp.dtype, optional) – Float dtype of the simulation. Controls whether mode fields are returned as complex64 (float32) or complex128 (float64). Defaults to jnp.float32.

  • bend_radius (float | None, optional) – Bend radius of the waveguide in meters. Must be set together with bend_axis. When set, the mode solver uses a conformal transformation to account for the bend. Defaults to None (straight waveguide).

  • bend_axis (int | None, optional) – Physical axis index (0/1/2) pointing from the waveguide toward the center of curvature. Must differ from the propagation axis. Required when bend_radius is set. Defaults to None.

  • symmetry (tuple[int, int], optional) – Symmetry-plane condition at the min edge of each transverse axis, in the order of the two non-propagation physical axes (increasing index). 0 imposes a PEC mirror (electric wall — the tidy3d default), 1 imposes a PMC mirror (magnetic wall). Use this when the waveguide sits on a symmetry plane of a reduced (half/quarter) domain so the mode solver reproduces the same boundary the FDTD uses there. For a +x-propagating TE mode on a y/z quarter domain with PEC at y=0 and PMC at the z Si-mid plane, pass (0, 1). Defaults to (0, 0) (PEC on both, i.e. no symmetry).

  • transverse_coords (Sequence[Array] | None) – Optional pair of physical edge-coordinate arrays, in metres, for the two axes transverse to propagation. Each array must have one more entry than the corresponding transverse cell count. When provided, the Tidy3D mode solver receives the non-uniform rectilinear grid directly. JAX arrays are accepted; the numpy conversion happens inside the tidy3d callback so the function remains compatible with jax.jit.

  • fixed_propagation_axis (int | None) – Optional physical axis normal to the mode plane. This disambiguates an extruded 2-D plane whose normal axis and invariant transverse axis are both one cell wide.

Returns:

Tuple of E, H field and the effective index as complex-valued jax arrays.

Return type:

Tuple[jax.Array, jax.Array, jax.Array]

fdtdx.calculate_sparam(objects, arrays, config, input_port_name, show_progress=True, input_normalization_detector_name=None, key=None)[source]#

Run the FDTD simulation and extract S-parameters from mode-overlap detectors.

Intended to be called with the outputs of setup_sparams_simulation(). Each ModeOverlapDetector in objects contributes one entry to the returned dictionary. Because a single simulation (with one active input port) measures the transmission to all output ports simultaneously, the dictionary keys are (detector_name, input_port_name) tuples so that results from multiple calls can be merged into a full S-matrix.

To simulate all input ports in one call (multiple simulations), use calculate_sparams().

Parameters:
  • objects (ObjectContainer) – ObjectContainer from setup_sparams_simulation().

  • arrays (ArrayContainer) – ArrayContainer from setup_sparams_simulation().

  • config (SimulationConfig) – SimulationConfig from setup_sparams_simulation().

  • input_port_name (str) – Name of the active input port. Should match the name field of the corresponding PortSpec, or the auto-generated name "Source_<i>" when no name was supplied.

  • show_progress (bool) – Whether to display the simulation progress bar.

  • input_normalization_detector_name (str | None) – Name (or substring) of the detector used to normalise the input power. Defaults to a detector whose name contains input_port_name.

  • key (Array | None) – JAX random key. Defaults to PRNGKey(0).

Returns:

A 2-tuple (sparams, detector_states) where sparams maps (detector_name, input_port_name) to a complex scattering-amplitude array indexed by frequency. For the single-frequency detectors created by setup_sparams_simulation(), each value has shape (1,). detector_states is the final DetectorState dict for every detector in the simulation.

Return type:

tuple[dict[tuple[str, str], Array], dict[str, dict[str, Array]]]

fdtdx.calculate_sparams(objects, arrays, config, input_port_names, show_progress=True, input_normalization_detector_name=None, key=None, return_detector_states=False)[source]#

Run FDTD simulations for multiple input ports and merge S-parameters.

Calls calculate_sparam() once per entry in input_port_names and merges all results into a single S-parameter dictionary.

Parameters:
  • objects (ObjectContainer) – ObjectContainer from setup_sparams_simulation().

  • arrays (ArrayContainer) – ArrayContainer from setup_sparams_simulation().

  • config (SimulationConfig) – SimulationConfig from setup_sparams_simulation().

  • input_port_names (Sequence[str]) – Names of the input ports to simulate.

  • show_progress (bool) – Whether to display the simulation progress bar.

  • input_normalization_detector_name (str | None) – Passed through to calculate_sparam().

  • key (Array | None) – JAX random key. Defaults to PRNGKey(0).

  • return_detector_states (bool) – When True, return the detector states from each simulation run as a list (one entry per input port). When False an empty list is returned.

Returns:

A 2-tuple (sparams, detector_states_list) where sparams is the merged dict[tuple[str, str], jax.Array] across all simulations and detector_states_list is either a list of per-simulation detector state dicts or an empty list.

Return type:

tuple[dict[tuple[str, str], Array], list[dict[str, dict[str, Array]]]]

fdtdx.compute_energy(E, H, inv_permittivity, inv_permeability, axis=0)[source]#

Computes the total electromagnetic energy density of the field.

Parameters:
  • E (jax.Array) – Electric field array with shape (3, nx, ny, nz)

  • H (jax.Array) – Magnetic field array with shape (3, nx, ny, nz)

  • inv_permittivity (jax.Array | float) – Inverse permittivity. Shape (3, nx, ny, nz) for anisotropic or scalar

  • inv_permeability (jax.Array | float) – Inverse permeability. Shape (3, nx, ny, nz) for anisotropic or scalar

  • axis (int, optional) – Axis index of the X,Y,Z component for the E and H field. Defaults to 0.

Returns:

Total energy density array with shape (nx, ny, nz)

Return type:

jax.Array

fdtdx.compute_poynting_flux(E, H, axis=0)[source]#

Calculates the Poynting vector (energy flux) from E and H fields.

Parameters:
  • E (jax.Array) – Electric field array with shape (3, nx, ny, nz)

  • H (jax.Array) – Magnetic field array with shape (3, nx, ny, nz)

  • axis (int, optional) – Axis for computing the poynting flux. Defaults to 0.

Returns:

Poynting vector array with shape (3, nx, ny, nz) representing energy flux in each direction

Return type:

jax.Array

Serialization and visualization#

Use export_json/import_from_json for the semantic scene, export_vti or export_vtr for VTK-compatible volume output, and plot_setup, plot_material, or plot_field_slice for local inspection. See output and diagnostics.

Stability contract

The upstream project is pre-1.0. These docs track the checked-out fork and use tested examples as the strongest compatibility contract. Pin a commit for production research and record it with results.