Simulation

Simulation, TimeConfig, SpectralSampler, and Result API reference

Overview#

Simulation dispatches the FDTD or FDFD solver and returns a Result. The main entry point is Simulation.fdtd().

sim = mw.Simulation.fdtd(
    scene,
    frequencies=[1.0e9],
    run_time=mw.TimeConfig(time_steps=200),
)
result = sim.run()

Simulation#

Simulation.fdtd()#

Create and dispatch an FDTD simulation:

mw.Simulation.fdtd(
    scene,
    frequencies=[1.0e9],
    run_time=mw.TimeConfig.auto(steady_cycles=20),
    spectral_sampler=mw.SpectralSampler(window="hanning"),
    full_field_dft=False,
    absorber="cpml",
)
ParameterTypeDefaultDescription
sceneScene | SceneModulerequiredScene to simulate. Accepts SceneModule for differentiable workflows
frequencieslist[float]requiredTarget frequencies in Hz. Use frequency= for a single value
run_timeTimeConfig | NoneNoneTime stepping configuration. Defaults to TimeConfig.auto()
spectral_samplerSpectralSampler | NoneNoneDFT window and normalization settings
full_field_dftboolFalseEnable full 3D field DFT extraction
absorberstr"cpml"Absorber type. One of "cpml", "pml"
cpml_configdict | NoneNoneAdvanced CPML configuration

Simulation.fdfd()#

Create and dispatch an FDFD simulation:

mw.Simulation.fdfd(
    scene,
    frequency=1.0e9,
    solver=mw.GMRES(max_iter=5000, tol=1e-6),
)
ParameterTypeDefaultDescription
sceneScene | SceneModulerequiredScene to simulate
frequencyfloatrequiredSingle target frequency in Hz
solverGMRES | NoneNoneLinear solver configuration
enable_plotboolFalseEnable live plotting during solve
verboseboolFalseEnable verbose solver output

Note

Simulation.fdfd() is coming soon. It is defined in the API but not yet fully implemented.

sim.run()#

Run the simulation and return a Result:

result = sim.run()

For differentiable workflows — when scene is a SceneModule or contains trainable parameters — sim.run() automatically uses the adjoint backward path.

sim.prepare()#

Prepare the simulation without running it. Returns a PreparedSimulation that can be run later:

prepared = sim.prepare()
result = prepared.run()

TimeConfig#

Controls how many time steps the FDTD solver runs.

# Fixed number of steps
mw.TimeConfig(time_steps=500)
 
# Auto-estimate from domain size and frequency
mw.TimeConfig.auto(steady_cycles=20, transient_cycles=15)
ParameterDefaultDescription
time_stepsNoneFixed step count. If None, steps are estimated automatically
steady_cycles20Number of steady-state cycles for auto estimation
transient_cycles15Number of transient cycles for auto estimation

SpectralSampler#

Controls DFT windowing and source normalization for frequency-domain extraction.

mw.SpectralSampler(window="hanning", normalize_source=False)
ParameterDefaultDescription
window"hanning"DFT window. One of "none", "hanning", "ramp"
normalize_sourceFalseNormalize DFT output by source spectrum

GMRES#

Linear solver configuration for FDFD simulations.

mw.GMRES(max_iter=5000, tol=1e-6, restart=200)
ParameterDefaultDescription
max_iter5000Maximum iterations
tol1e-6Convergence tolerance
restart200GMRES restart interval

Result#

result = sim.run() returns a Result object with field data and monitor recordings.

Field Access#

# Electric field components
result.E   # dict with "EX", "EY", "EZ" as torch tensors
result.H   # dict with "HX", "HY", "HZ" as torch tensors (if available)

Monitor Access#

data = result.monitor("probe")["data"]

Plotting#

result.plot.field(axis="y", position=0.0, component="abs", field_log_scale=True)

Material Access#

eps, mu = result.materials  # compiled permittivity and permeability tensors

Saving#

result.save("output.pt")

Differentiable Workflows#

When the scene contains trainable parameters, sim.run() uses the adjoint backward path automatically. After the simulation, call loss.backward() to propagate gradients:

box_x = torch.tensor(0.10, device="cuda", requires_grad=True)
 
# ... build scene with box_x ...
 
result = sim.run()
probe = result.monitor("probe")["data"]
loss = torch.abs(probe) ** 2
loss.backward()
 
print("d(loss)/d(box_x) =", box_x.grad)

For module-style workflows, use SceneModule:

class MyDesign(mw.SceneModule):
    def to_scene(self):
        ...
 
model = MyDesign()
sim = mw.Simulation.fdtd(model, frequencies=[1.0e9], ...)
result = sim.run()

Next Steps#