Scene
Scene, Domain, GridSpec, BoundarySpec, and MaterialRegion API reference
Overview#
Scene is the central object in WiTwin Maxwell. It holds the simulation domain, grid resolution, boundary conditions, structures, sources, monitors, and optional differentiable material regions.
import witwin.maxwell as mw
scene = mw.Scene(
domain=mw.Domain(bounds=((-0.5, 0.5), (-0.5, 0.5), (-0.5, 0.5))),
grid=mw.GridSpec.uniform(0.05),
boundary=mw.BoundarySpec.pml(num_layers=15, strength=1e6),
device="cuda",
)Scene#
Constructor#
| Parameter | Type | Default | Description |
|---|---|---|---|
domain | Domain | None | None | Simulation volume. Defaults to (-1, 1) on all axes |
grid | GridSpec | None | None | Grid resolution. Defaults to GridSpec.uniform(0.05) |
boundary | BoundarySpec | None | None | Boundary conditions. Defaults to BoundarySpec.none() |
structures | list | None | None | Initial list of Structure objects |
sources | list | None | None | Initial list of source objects |
monitors | list | None | None | Initial list of monitor objects |
material_regions | list | None | None | Initial list of MaterialRegion objects |
device | str | "cuda" | PyTorch device string |
subpixel_samples | int | 1 | Subpixel averaging samples for material compilation |
symmetry | tuple | None | None | Per-axis symmetry. Each entry is None, "PEC", or "PMC" |
verbose | bool | False | Enable verbose logging |
Methods#
scene.add_structure(structure) — Add a Structure to the scene.
scene.add_source(source) — Add a source to the scene.
scene.add_monitor(monitor) — Add a monitor to the scene.
scene.add_port(port) — Add a ModePort to the scene.
scene.add_material_region(material_region) — Add a MaterialRegion for differentiable material optimization.
scene.clone(**overrides) — Return a copy of the scene with selected fields replaced.
scene.to_tidy3d(**kwargs) — Export the scene to a tidy3d.Simulation object.
Properties#
| Property | Description |
|---|---|
scene.dx, scene.dy, scene.dz | Grid spacing along each axis |
scene.grid_spacing | Grid spacing as (dx, dy, dz) |
scene.domain_size | Maximum domain extent across all axes |
scene.boundary_type | Human-readable boundary type string |
scene.pml_thickness | PML layer count |
scene.pml_strength | PML strength |
scene.bloch_wavevector | Bloch wavevector (kx, ky, kz) |
scene.has_symmetry | True if any symmetry axis is set |
Domain#
Defines the 3D simulation volume as axis-aligned bounds.
mw.Domain(bounds=((-0.5, 0.5), (-0.5, 0.5), (-0.5, 0.5)))| Parameter | Type | Description |
|---|---|---|
bounds | ((xmin, xmax), (ymin, ymax), (zmin, zmax)) | Simulation volume bounds. Each axis must have end > start |
Domain.from_domain_range(domain_range) — Construct from a flat 6-tuple (xmin, xmax, ymin, ymax, zmin, zmax).
GridSpec#
Defines the spatial resolution of the Yee grid.
# Uniform grid
mw.GridSpec.uniform(0.05)
# Anisotropic grid
mw.GridSpec.anisotropic(dx=0.05, dy=0.05, dz=0.02)| Class method | Description |
|---|---|
GridSpec.uniform(dl) | Uniform spacing dl on all axes |
GridSpec.anisotropic(dx, dy, dz) | Independent spacing per axis |
| Property | Description |
|---|---|
grid.spacing | Grid spacing as (dx, dy, dz) |
grid.is_uniform | True if all spacings are equal |
BoundarySpec#
Defines boundary conditions on all six faces of the domain.
Presets#
mw.BoundarySpec.pml(num_layers=15, strength=1e6) # Perfectly matched layer
mw.BoundarySpec.none() # No boundary
mw.BoundarySpec.periodic() # Periodic on all axes
mw.BoundarySpec.bloch(wavevector=(kx, ky, kz)) # Bloch periodic
mw.BoundarySpec.pec() # Perfect electric conductor
mw.BoundarySpec.pmc() # Perfect magnetic conductorPer-face control#
mw.BoundarySpec.faces(
default="none",
num_layers=15,
strength=1e6,
x="pml", # Both x faces
y=("pml", "periodic"), # Low y = pml, high y = periodic
z_low="pec", # Low z face only
)| Parameter | Type | Description |
|---|---|---|
kind | str | Global boundary kind: "none", "pml", "periodic", "bloch", "pec", "pmc" |
num_layers | int | PML layer count. Required when using PML |
strength | float | PML absorption strength. Required when using PML |
bloch_wavevector | tuple[float, float, float] | Bloch wavevector. Required when using Bloch boundaries |
MaterialRegion#
A differentiable density-based material design region.
import torch
import witwin.maxwell as mw
density = torch.ones(32, 32, 32, device="cuda", requires_grad=True)
region = mw.MaterialRegion(
name="design",
geometry=mw.Box(position=(0.0, 0.0, 0.0), size=(0.5, 0.5, 0.5)),
density=density,
eps_bounds=(1.0, 12.0),
filter_radius=2.0,
projection_beta=10.0,
)
scene.add_material_region(region)| Parameter | Type | Default | Description |
|---|---|---|---|
name | str | required | Region name |
geometry | GeometryBase | required | Geometry defining the design region |
density | torch.Tensor | required | 3D density tensor of shape (Nx, Ny, Nz). Can have requires_grad=True |
bounds | tuple[float, float] | (0.0, 1.0) | Density value range |
eps_bounds | tuple[float, float] | (1.0, 1.0) | Permittivity interpolation range (eps_min, eps_max) |
mu_bounds | tuple[float, float] | (1.0, 1.0) | Permeability interpolation range |
filter_radius | float | None | None | Density filter radius. Must be > 0 when set |
projection_beta | float | None | None | Projection sharpness. Must be > 0 when set |
SceneModule#
Base class for wrapping a differentiable scene as a torch.nn.Module. Implement to_scene() to return a Scene:
class MyDesign(mw.SceneModule):
def __init__(self):
super().__init__()
self.density = torch.nn.Parameter(torch.ones(32, 32, 32))
def to_scene(self) -> mw.Scene:
scene = mw.Scene(...)
scene.add_material_region(
mw.MaterialRegion(
name="design",
geometry=mw.Box(...),
density=self.density,
eps_bounds=(1.0, 12.0),
)
)
return scenePass the SceneModule directly to Simulation.fdtd() — it calls to_scene() automatically before each forward pass.
Next Steps#
- Sources — source types and waveforms
- Monitors — monitor types
- Simulation — run the simulation