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",
)| Parameter | Type | Default | Description |
|---|---|---|---|
scene | Scene | SceneModule | required | Scene to simulate. Accepts SceneModule for differentiable workflows |
frequencies | list[float] | required | Target frequencies in Hz. Use frequency= for a single value |
run_time | TimeConfig | None | None | Time stepping configuration. Defaults to TimeConfig.auto() |
spectral_sampler | SpectralSampler | None | None | DFT window and normalization settings |
full_field_dft | bool | False | Enable full 3D field DFT extraction |
absorber | str | "cpml" | Absorber type. One of "cpml", "pml" |
cpml_config | dict | None | None | Advanced 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),
)| Parameter | Type | Default | Description |
|---|---|---|---|
scene | Scene | SceneModule | required | Scene to simulate |
frequency | float | required | Single target frequency in Hz |
solver | GMRES | None | None | Linear solver configuration |
enable_plot | bool | False | Enable live plotting during solve |
verbose | bool | False | Enable 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)| Parameter | Default | Description |
|---|---|---|
time_steps | None | Fixed step count. If None, steps are estimated automatically |
steady_cycles | 20 | Number of steady-state cycles for auto estimation |
transient_cycles | 15 | Number of transient cycles for auto estimation |
SpectralSampler#
Controls DFT windowing and source normalization for frequency-domain extraction.
mw.SpectralSampler(window="hanning", normalize_source=False)| Parameter | Default | Description |
|---|---|---|
window | "hanning" | DFT window. One of "none", "hanning", "ramp" |
normalize_source | False | Normalize DFT output by source spectrum |
GMRES#
Linear solver configuration for FDFD simulations.
mw.GMRES(max_iter=5000, tol=1e-6, restart=200)| Parameter | Default | Description |
|---|---|---|
max_iter | 5000 | Maximum iterations |
tol | 1e-6 | Convergence tolerance |
restart | 200 | GMRES 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 tensorsSaving#
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()