Configuration recipes#
Automatic baseline#
The fork’s automatic setup mirrors the cell-count behavior used by the pinned Tidy3D scenes and fails early on an excessive voxel count.
import fdtdx
wavelength = 1.55e-6
size = (8e-6, 5e-6, 0.22e-6)
config = fdtdx.auto_config(
wavelength=wavelength,
domain_size=size,
time=300e-15,
ppw=20,
max_voxels=40_000_000,
)
boundaries = fdtdx.auto_boundary_config(pml_layers=10)
auto_grid chooses a target \(\Delta=\lambda/\text{ppw}\), rounds each axis up to an integer number of cells, and adjusts per-axis spacing to cover the exact domain. Supply dl= to override the wavelength rule.
Execution backend#
SimulationConfig.execution_mode defaults to "jax", the complete portable
solver. "auto" may select the optional typed CUDA backend when a validated
native library is installed and the scene uses only supported physics;
otherwise it falls back to JAX. "cuda" requires the native path and reports
unsupported sources, boundaries, monitors, or materials instead of changing
the scene silently. CPML and differentiated simulations currently stay on JAX.
Refractive index
ppw is based on the free-space wavelength passed to the function. To guarantee a chosen number of points inside index \(n_\max\), pass dl=wavelength/(ppw*n_max) or adjust the wavelength input intentionally.
Boundary overrides#
boundaries = fdtdx.auto_boundary_config(
pml_layers=12,
boundary_types={
"min_z": "periodic",
"max_z": "periodic",
"min_x": "pec",
},
)
Valid automatic boundary names are pml, periodic, pec, pmc, and bloch. For a nonzero Bloch vector, construct the corresponding boundary explicitly.
Symmetry reduction#
config = config.aset("symmetry", (0, -1, 0))
Entries are (x, y, z) with 0 for none, -1 for PEC/electric parity, and +1 for PMC/magnetic parity. A reduced axis must resolve to an even number of cells. Reconstruct full arrays with unfold_fields and detector state with unfold_detector_states.
Gradient configuration#
Checkpointed differentiation:
gradient = fdtdx.GradientConfig(method="checkpointed", num_checkpoints=8)
config = config.aset("gradient_config", gradient)
Reversible differentiation requires a Recorder and initialized recording state. num_checkpoints_reversible can place exact full-field anchors within the reverse reconstruction, improving robustness in lossy media at additional memory cost.
For a real, lossless dielectric design observed with phasor monitors, use the exact design-local adjoint and provide the reduced-grid spatial bounds of the only differentiable inverse-permittivity region:
design_region = design_object.grid_slice_tuple
gradient = fdtdx.GradientConfig(
method="adjoint",
design_region=design_region,
)
config = config.aset("gradient_config", gradient)
arrays = arrays.aset("recording_state", None)
The adjoint returns zero inverse-permittivity gradient outside design_region and fails closed when its linear, lossless assumptions are not met. Use checkpointed differentiation for general material physics, or reversible differentiation when a compact design region is unavailable. Unrolling several adjacent lax.scan steps was tested but is intentionally not exposed: it increased compile size and made the representative inverse-design workload slower.
Differentiable extruded thickness#
slab_fill_fractions accepts a traced scalar thickness and returns exact
fractional Yee-cell overlaps. This adds a global layer dimension to an
extruded 2-D inverse design without making every z voxel independent:
thickness = lower + (upper - lower) * jax.nn.sigmoid(thickness_logit)
z_fill = fdtdx.slab_fill_fractions(z_edges, thickness=thickness)
rho_xyz = fdtdx.extrude_density_2d(rho_xy, z_fill)
At a horizontal dielectric interface, use arithmetic permittivity mixing for the tangential Ex/Ey constitutive components and harmonic mixing for the normal Ez component. The overlap function defines a centered shape derivative when a face lies exactly on a cell edge, so a grid-aligned starting thickness does not receive a one-sided or vanishing gradient.
The live Fourier atom-hole campaign exposes two sigmoid-bounded dimensions:
the Si3N4 core and one SiO2 thickness shared by the symmetry-related top and
bottom claddings. Their default ranges can be changed with
FDTDX_FOURIER_HOLE_CORE_MIN_NM, FDTDX_FOURIER_HOLE_CORE_MAX_NM,
FDTDX_FOURIER_HOLE_CLADDING_MIN_NM, and
FDTDX_FOURIER_HOLE_CLADDING_MAX_NM. Set
FDTDX_FOURIER_HOLE_OPTIMIZE_THICKNESS=0 to retain fixed layers.
Memory estimate#
A field-only lower bound is six components × voxel count × bytes per value. Real runs also hold material arrays, PML state, dispersive poles, detectors, compiler buffers, and—during differentiation—recording/checkpoint data. Keep meaningful headroom below physical VRAM and measure peak allocation on the actual scene.