Result

The Result object returned by a Maxwell simulation, with field, material, monitor, port, plotting, and save/load access.

mw.Simulation.fdtd(...).run() and mw.Simulation.fdfd(...).run() return a Result (witwin.maxwell.Result, usually mw.Result). This page covers everything you reach from it: field and material tensors, frequency selection, monitor payloads, ports and circuits, typed post-processing helpers, plotting, and persistence. All tensors are torch.Tensor objects that stay on the scene device and keep any autograd graph, unless the text says otherwise.

result = mw.Simulation.fdtd(scene, frequencies=[0.9e9, 1.1e9], run_time=mw.TimeConfig(time_steps=400)).run()
ex_all = result.E.x                        # shape [F, ...] for several frequencies
ex = result.at(frequency=1.1e9).E.x        # one frequency
probe = result.monitor("probe")
result.save("run.pt")

Result#

class Result(*, method, scene, prepared_scene=None, frequency=None, frequencies=None, solver=None, fields=None, monitors=None, ports=None, circuits=None, network=None, embedded_networks=None, array_run_data=None, metadata=None, solver_stats=None, raw_output=None, breakdown=None)

Container for one simulation run. You normally get it from Simulation.run() or Result.load(...) and do not construct it yourself. All constructor arguments are keyword-only.

methodstrrequired

Run type, for example 'fdtd', 'fdfd', 'electrostatic', or 'capacitance'.

sceneScenerequired

The declarative scene of the run. See Scene.

prepared_sceneobject | Nonedefault None

Compiled scene. When None, it is built from scene on first use.

frequencyfloat | Nonedefault None

Single frequency in Hz. Used only when frequencies is None.

frequenciesSequence[float] | Nonedefault None

Frequencies in Hz. You must give frequency or a non-empty frequencies.

solverobject | Nonedefault None

Solver instance that produced the run. Needed by plot.field and some post-processing.

fieldsdict[str, torch.Tensor] | Nonedefault None

Full-domain field tensors keyed by upper-case component name ('EX', 'EY', 'EZ').

monitorsdict[str, Any] | Nonedefault None

Monitor payloads keyed by monitor name. A WireData value must be stored under its own monitor_name.

portsMapping[str, PortData] | Nonedefault None

Port records. Each key must equal the record's port_name.

circuitsMapping[str, CircuitData] | Nonedefault None

Circuit records. Each key must equal the record's circuit_name.

networkNetworkData | Nonedefault None

Network (S-parameter) data, or None.

embedded_networksMapping[str, EmbeddedNetworkData] | Nonedefault None

Embedded network records. Each key must equal the record's name.

array_run_dataobject | Nonedefault None

Retained array sweep data, used by array_basis.

metadatadict[str, Any] | Nonedefault None

Run metadata.

solver_statsdict[str, Any] | Nonedefault None

Solver statistics, merged into stats().

raw_outputAnydefault None

Raw solver output.

breakdownBreakdownResultData | Nonedefault None

Dielectric-breakdown output, exposed as breakdown_data.

Raises ValueError when no frequency is given or a mapping key does not match its record name; TypeError when a mapping value has the wrong type.

Plain attributes:

AttributeContent
methodrun type string
scenedeclarative scene
frequenciestuple of frequencies in Hz
frequencyfirst entry of frequencies
solversolver instance, or None (for example after load)
raw_outputraw solver output

Note

The standard FDTD and FDFD run paths store only the electric field components EX, EY, EZ as full-domain fields. Record magnetic fields with a monitor; see Monitors. A single-frequency FDTD run with full_field_dft=False stores the electric field at the last time step instead of a frequency-domain phasor; pass full_field_dft=True to Simulation.fdtd(...) for phasors. See Simulation.

Each component lives on its own Yee-staggered grid, so component shapes differ. With several frequencies, each field tensor has a leading frequency axis of length F.

Result.E#

Result.E -> ResultFieldAccessor

Property. Electric field accessor for all frequencies: result.E.x, result.E.y, result.E.z. Same as result.at().E.

Result.H#

Result.H -> ResultFieldAccessor

Property. Magnetic field accessor. Accessing a component raises KeyError when the result holds no H fields, which is the case for FDTD and FDFD runs.

Result.materials#

Result.materials -> ResultMaterialsAccessor

Property. Material accessor: result.materials.eps.scalar, result.materials.mu.x, and so on. Same as result.at().materials.

Result.at#

Result.at(*, frequency=None, freq_index=None, expand_symmetry=False, resolve_modal=True) -> ResultSelection

Returns a view of the result fixed to one frequency and options. Result.select is an alias.

frequencyfloat | Nonedefault None

Frequency in Hz to select. It must match a result frequency (relative tolerance 1e-9).

freq_indexint | Nonedefault None

Index into frequencies. Do not combine with frequency.

expand_symmetrybooldefault False

Mirror fields and materials across symmetry planes back to the full domain.

resolve_modalbooldefault True

Default for monitor(...) on the view: resolve mode, diffraction, and emission monitors to their higher-level dicts.

Raises ValueError when both frequency and freq_index are given. An unknown frequency raises KeyError, and an out-of-range index raises IndexError, when you read data from the view.

view = result.at(frequency=1.1e9)
ex = view.E.x
center = view.monitor("center")["data"]

Result.fields#

Result.fields -> dict[str, torch.Tensor]

Property. A copy of the field dict, keyed by upper-case component name.

Result.monitors#

Result.monitors -> dict[str, Any]

Property. A copy of the raw monitor dict as recorded, without frequency selection, cropping, or modal resolution.

Result.field#

Result.field(name='E', *, expand_symmetry=False, frequency=None, freq_index=None)

Returns field data by name.

namestrdefault 'E'

'E' or 'H' (case-insensitive) returns a dict of the available components, for example {'EX': ..., 'EY': ..., 'EZ': ...}. A component name such as 'Ex' returns that tensor.

expand_symmetrybooldefault False

Mirror across symmetry planes to the full domain.

frequencyfloat | Nonedefault None

Frequency in Hz to select.

freq_indexint | Nonedefault None

Frequency index to select.

Returns dict[str, torch.Tensor] for 'E'/'H', otherwise torch.Tensor.

Result.tensor#

Result.tensor(name, *, expand_symmetry=False, frequency=None, freq_index=None) -> torch.Tensor

Returns one field component tensor.

namestrrequired

Component name, for example 'Ex' (case-insensitive).

expand_symmetrybooldefault False

Mirror across symmetry planes to the full domain. Components normal or tangential to a PEC/PMC plane get the matching sign.

frequencyfloat | Nonedefault None

Frequency in Hz to select.

freq_indexint | Nonedefault None

Frequency index to select.

Without a selection, a multi-frequency result returns the full tensor with its leading frequency axis.

Raises KeyError when the component is not stored; KeyError or IndexError for an unknown frequency or index.

Result.material#

Result.material(name='eps_r', *, expand_symmetry=False) -> torch.Tensor

Returns a relative material tensor of the compiled scene.

namestrdefault 'eps_r'

Material quantity (case-insensitive), see the table below.

expand_symmetrybooldefault False

Mirror across symmetry planes to the full domain.

QuantityAccepted names
Relative permittivityeps, eps_r, permittivity
Permittivity componentseps_x, epsilon_x, permittivity_x (and y, z)
Relative permeabilitymu, mu_r, permeability
Permeability componentsmu_x, permeability_x (and y, z)

Raises KeyError for another name.

Result.monitor#

Result.monitor(name, *, frequency=None, freq_index=None, resolve_modal=True)

Returns the processed data of a named monitor. The return type depends on the monitor class; see the table in Monitors.

namestrrequired

Monitor name. For one face of a closed surface, use '<surface>::<label>'.

frequencyfloat | Nonedefault None

Select one monitor frequency in Hz. The returned dict then has frequencies of length 1 and data without the frequency axis.

freq_indexint | Nonedefault None

Select a monitor frequency by index into the monitor's own frequencies.

resolve_modalbooldefault True

Resolve ModeMonitor, DiffractionMonitor, and DipoleEmissionMonitor payloads into modal, diffraction-order, and emission dicts. With False, you get the raw plane or point dict.

The lookup works in this order:

  1. Typed records

    A WireMonitor returns its WireData. A PowerLossMonitor returns power_loss(name). Both raise ValueError if you pass frequency or freq_index.

  2. Raw payload

    Everything else goes through raw_monitor(name, ...): closed surfaces are assembled from their faces, material monitors are evaluated from the compiled materials, and finite planes are cropped.

  3. Resolution

    With resolve_modal=True, diffraction, dipole-emission, and mode payloads are converted to their higher-level dicts. Closed-surface and other payloads are returned as they are.

Raises KeyError when the monitor has no recorded data, for example a ComponentStressMonitor (use component_stress). Use breakdown(name) for a BreakdownMonitor.

flux = result.monitor("transmission")["flux"]
modal = result.monitor("port_mode", frequency=3e14)
plane = result.monitor("port_mode", resolve_modal=False)

Result.raw_monitor#

Result.raw_monitor(name, *, frequency=None, freq_index=None)

Returns the underlying point or plane dict of a monitor, with frequency selection and finite-plane cropping applied but no modal, diffraction, or emission resolution. Closed surfaces and material monitors are built the same way as in monitor. A WireData record is returned as is.

namestrrequired

Monitor name.

frequencyfloat | Nonedefault None

Monitor frequency in Hz to select.

freq_indexint | Nonedefault None

Monitor frequency index to select.

Raises KeyError when no data is stored under name; ValueError when you select a frequency on WireData.

Result.port#

Result.port(name) -> PortData

Returns the record of a lumped or terminal port. Raises KeyError listing the available names. See Ports.

Result.ports#

Result.ports -> dict[str, PortData]

Property. A copy of all port records.

Result.circuit#

Result.circuit(name) -> CircuitData

Returns the record of a coupled circuit. Raises KeyError listing the available names. See Circuits.

Result.circuits#

Result.circuits -> dict[str, CircuitData]

Property. A copy of all circuit records.

Result.network#

Result.network -> NetworkData | None

Property. Network (S-parameter) data, or None. See Networks.

Result.embedded_network#

Result.embedded_network(name) -> EmbeddedNetworkData

Returns one embedded network record. Raises KeyError listing the available names.

Result.embedded_networks#

Result.embedded_networks -> dict[str, EmbeddedNetworkData]

Property. A copy of all embedded network records.

Result.antenna#

Result.antenna(*, surface, driven_port, polarization=None, theta=None, phi=None, theta_points=181, phi_points=361, radius=1.0, phase_center=None, frame=None, batch_size=1024) -> AntennaData

Computes far-field antenna data from a ClosedSurfaceMonitor and a driven port. surface is the closed-surface monitor name; driven_port is a port name or PortData. See Antennas and arrays for the parameters and AntennaData.

Result.array_basis#

Result.array_basis(*, monitor, polarization=None, theta=None, phi=None, theta_points=181, phi_points=361, radius=1.0, phase_center=None, frame=None, batch_size=1024) -> ArrayBasisData

Builds a reusable embedded-pattern basis from a port sweep run. See Antennas and arrays.

Result.power_loss#

Result.power_loss(name, *, electric_fields=None, volume_channels=None, integrated_channels=None, surface_channels=None, face_areas=None, line_channels=None, line_lengths=None, occupancy=None, material_ids=None, geometry_ids=None) -> PowerLossData

Computes the loss channels of a declared PowerLossMonitor. The conduction channel is computed from the stored Ex, Ey, Ez unless you pass electric_fields; the other arguments supply explicit channel data. See Safety.

Raises KeyError when name is not a PowerLossMonitor; NotImplementedError for a non-FDTD result; RuntimeError when conduction needs fields that the run did not store (run FDTD with full_field_dft=True).

Result.incident_power_density#

Result.incident_power_density(monitor, *, spatial_average=<unset>) -> IncidentPowerDensity

Reduces an IncidentPowerDensityMonitor to incident power density in W/m^2 and plane flux in W. Leave spatial_average unset to use the monitor's window area, pass None to disable averaging, or pass an area in m^2 to override it. Raises KeyError when monitor is not an IncidentPowerDensityMonitor. See Safety.

Result.sar#

Result.sar(monitor, *, averaging=None, normalization=None, electric_fields=None, volume_channels=None) -> SARResult

Reduces a PowerLossMonitor and the tissue mass model to SAR. It never runs a solver. averaging is a SARAveraging; normalization defaults to PowerNormalization.none() (unit source amplitude). Raises KeyError for a monitor that is not a PowerLossMonitor and NotImplementedError for a non-FDTD result. See Safety.

Result.breakdown#

Result.breakdown(name) -> BreakdownStressData

Returns the dielectric-stress record of a BreakdownMonitor: peak field, exceedance durations, qualifying locations, and per-cell maps kept on the device. Raises KeyError listing the available names. See Safety.

Result.breakdown_names#

Result.breakdown_names() -> tuple[str, ...]

Names of the BreakdownMonitor records in the result.

Result.breakdown_data#

Result.breakdown_data -> BreakdownResultData | None

Property. Output of dielectric-breakdown materials, or None when the scene has none. This is separate from breakdown(name), which reads a BreakdownMonitor.

Result.breakdown_events#

Result.breakdown_events -> tuple

Property. Breakdown events ordered by (step, cell_index), or an empty tuple when breakdown is inactive.

Result.component_stress#

Result.component_stress(name) -> ComponentStressData

Reduces the voltage and current series bound by a ComponentStressMonitor to power P = V I, cumulative energy, and an exceedance summary against its ComponentRating. Raises KeyError when the binding or a series is missing, and ValueError when the two series have different sample counts or time axes. See Safety.

Result.component_stress_names#

Result.component_stress_names() -> tuple[str, ...]

Names of the ComponentStressMonitor bindings on the scene.

Result.esd_waveform#

Result.esd_waveform(name) -> ESDPortRecord

Returns the injection record of an ESDCurrentSource: target waveform diagnostics, the waveform resampled onto the run time grid, provenance, and measured (the port's PortData when the run recorded one, otherwise None). Raises KeyError listing the available sources. See Safety.

Result.esd_waveform_names#

Result.esd_waveform_names() -> tuple[str, ...]

Names of the ESDCurrentSource sources on the scene.

Result.esd_generator#

Result.esd_generator(name) -> dict[str, Any]

Returns the provenance dict of a circuit-driven ESD generator network (built by ESDVoltageSource.build_circuit). The port voltage and current time series live on result.circuit(name). Raises KeyError listing the available names.

Result.esd_generator_names#

Result.esd_generator_names() -> tuple[str, ...]

Names of the ESD generator circuits on the scene.

Result.electrostatic#

Result.electrostatic -> ElectrostaticResultData

Property. Output of a Simulation.electrostatic(...) run. Raises AttributeError for other runs. See Electrostatics.

Result.electrostatic_prebias#

Result.electrostatic_prebias -> dict | None

Property. Provenance of the electrostatic pre-bias initial condition of an FDTD run, or None.

Result.capacitance#

Result.capacitance -> CapacitanceData

Property. Output of a Simulation.capacitance(...) run. Raises AttributeError for other runs.

Result.prepared_scene#

Result.prepared_scene

Property. The compiled scene. It is built from scene on first access when the result has none (for example after load without prepared_scene).

Result.solver_stats#

Result.solver_stats -> dict[str, Any]

Property. A copy of the raw solver statistics.

Result.stats#

Result.stats() -> dict[str, Any]

Returns solver_stats plus method, frequency, frequencies, num_frequencies, num_fields, num_monitors, num_ports, num_circuits, has_network, and num_embedded_networks. FDTD runs include keys such as time_steps, steps_run, dt, elapsed_s, ms_per_step, steps_per_second, dft_window, full_field_dft, and shutoff_triggered. FDFD runs include solver, converged, solver_info, and final_residual.

stats = result.stats()
print(stats["time_steps"], stats["ms_per_step"])

Result.plot#

Result.plot -> ResultPlotter

Property. Plotting helper; see ResultPlotter. A new helper is created on each access.

Result.save#

Result.save(path) -> None

Saves a detached CPU snapshot with torch.save. It stores method, frequencies, fields, monitors, ports, circuits, network, embedded networks, metadata, and solver statistics. It does not store the scene, prepared scene, solver, raw output, autograd graphs, retained array sweep columns, or breakdown_data. Parent directories are created.

pathstr | Pathrequired

Output file path.

Tip

To reuse array embedded patterns later, call result.array_basis(...) and save the returned ArrayBasisData before you save the result.

Result.load#

Result.load(path, *, scene, prepared_scene=None, map_location='cpu') -> Result

Classmethod. Loads a snapshot written by save. You supply the scene, because it is not saved.

pathstr | Pathrequired

Snapshot file path.

sceneScenerequired

Keyword-only. The declarative scene of the saved run.

prepared_sceneobject | Nonedefault None

Keyword-only. Compiled scene, if you have one.

map_locationAnydefault 'cpu'

Keyword-only. Passed to torch.load.

Raises ValueError when the file is not a schema-version-2 result snapshot or misses required keys.

Warning

Result files use pickle-backed torch.load(weights_only=False). Load them only from trusted sources.

result.save("run.pt")
restored = mw.Result.load("run.pt", scene=scene)
data = restored.monitor("state")

Result.save_sharded#

Result.save_sharded(directory)

Writes the result metadata and each field shard to a new directory without assembling global field tensors. It needs a solver that provides export_field_shards() (a multi-GPU run). See Batch and multi-GPU.

Raises FileExistsError when directory exists; RuntimeError when the solver cannot export shards.

Result.load_sharded#

Result.load_sharded(directory, *, scene, prepared_scene=None, gather_fields=False, map_location='cpu') -> Result

Classmethod. Loads a directory written by save_sharded. Fields are gathered only when gather_fields=True. Raises TypeError when gather_fields is not a bool.

Result.is_sharded#

Result.is_sharded -> bool

Property. True for a result loaded with load_sharded. The related properties sharded_manifest and shard_paths (a tuple of Path) describe the loaded shards.

ResultSelection#

class ResultSelection(result, frequency=None, freq_index=None, expand_symmetry=False, resolve_modal=True)

Frozen view returned by Result.at(...). Every accessor passes the stored frequency and options to the Result methods. You get it from result.at(...); it is not exported at package level.

Raises ValueError when both frequency and freq_index are set.

ResultSelection.E#

ResultSelection.E -> ResultFieldAccessor

Property. Electric field accessor for the selected frequency.

ResultSelection.H#

ResultSelection.H -> ResultFieldAccessor

Property. Magnetic field accessor for the selected frequency.

ResultSelection.materials#

ResultSelection.materials -> ResultMaterialsAccessor

Property. Material accessor. Materials honour expand_symmetry and ignore the frequency.

ResultSelection.field#

ResultSelection.field(name='E')

Same as Result.field with the view's frequency and expand_symmetry.

ResultSelection.tensor#

ResultSelection.tensor(name) -> torch.Tensor

Same as Result.tensor with the view's frequency and expand_symmetry.

ResultSelection.material#

ResultSelection.material(name='eps_r') -> torch.Tensor

Same as Result.material with the view's expand_symmetry.

ResultSelection.monitor#

ResultSelection.monitor(name, *, resolve_modal=None)

Same as Result.monitor with the view's frequency. resolve_modal=None uses the view's setting.

ResultSelection.raw_monitor#

ResultSelection.raw_monitor(name)

Same as Result.raw_monitor with the view's frequency.

ResultSelection.at#

ResultSelection.at(*, frequency=<unset>, freq_index=<unset>, expand_symmetry=<unset>, resolve_modal=<unset>) -> ResultSelection

Returns a new view. Arguments you leave out keep the current view's values. ResultSelection.select is an alias.

full = result.at(freq_index=0, expand_symmetry=True)
ez = full.E.z

ResultFieldAccessor#

class ResultFieldAccessor(selection, family)

Field accessor returned by E and H. family is 'E' or 'H'.

ResultFieldAccessor.x#

ResultFieldAccessor.x -> torch.Tensor

Property. The x component (Ex or Hx) for the selection. The properties y and z return the other components. Each raises KeyError when the component is not stored.

ResultFieldAccessor.as_dict#

ResultFieldAccessor.as_dict() -> dict[str, torch.Tensor]

Returns the stored components as a dict keyed 'x', 'y', 'z'. Missing components are skipped.

ResultMaterialsAccessor#

class ResultMaterialsAccessor(selection)

Material accessor returned by materials.

ResultMaterialsAccessor.eps#

ResultMaterialsAccessor.eps -> ResultMaterialTensorAccessor

Property. Relative permittivity accessor. permittivity is an alias.

ResultMaterialsAccessor.mu#

ResultMaterialsAccessor.mu -> ResultMaterialTensorAccessor

Property. Relative permeability accessor. permeability is an alias.

ResultMaterialTensorAccessor#

class ResultMaterialTensorAccessor(selection, family)

Accessor for one material quantity; family is 'eps' or 'mu'.

ResultMaterialTensorAccessor.scalar#

ResultMaterialTensorAccessor.scalar -> torch.Tensor

Property. The scalar relative permittivity (eps_r) or permeability (mu_r). r is an alias.

ResultMaterialTensorAccessor.x#

ResultMaterialTensorAccessor.x -> torch.Tensor

Property. The x component tensor. The properties y and z return the other components.

ResultMaterialTensorAccessor.as_dict#

ResultMaterialTensorAccessor.as_dict() -> dict[str, torch.Tensor]

Returns a dict with keys 'scalar', 'x', 'y', 'z'.

eps = result.materials.eps.scalar
mu_z = result.materials.mu.z

ResultPlotter#

class ResultPlotter(result)

Matplotlib plotting helper returned by result.plot.

ResultPlotter.field#

ResultPlotter.field(axis='z', position=0.0, component='abs', **kwargs) -> None

Plots a field-magnitude cross-section next to the permittivity on the same slice, by calling the solver's plot_cross_section. The slice is taken at the grid index nearest position.

axisstrdefault 'z'

Slice normal: 'x', 'y', or 'z'.

positionfloatdefault 0.0

Slice coordinate in metres.

componentstrdefault 'abs'

'abs' plots the total magnitude of E, interpolated to cell centres; 'Ex', 'Ey', 'Ez' (case-insensitive) plot one component magnitude. Other values fall back to 'abs' for FDTD and raise ValueError for FDFD.

field_log_scalebooldefault False

Keyword argument passed to the solver. Plot in dB relative to the slice maximum.

figsizetupledefault (12, 5)

Keyword argument passed to the solver. Figure size in inches.

save_pathstr | Nonedefault None

Keyword argument passed to the solver. Save the figure to this path and close it, instead of calling plt.show().

verbosebool | Nonedefault True

Keyword argument passed to the solver. Print the saved path. The FDFD solver defaults to None, which uses the solver's own verbosity.

Returns None.

Raises RuntimeError when the result has no solver with plot_cross_section, for example after Result.load.

result.plot.field(axis="z", position=0.0, component="abs", save_path="field_z0.png")

ResultPlotter.material#

ResultPlotter.material(name='eps_r', axis='z', position=0.0, figsize=(8, 6), cmap='viridis')

Plots a slice of a material tensor from Result.material(name).

namestrdefault 'eps_r'

Material name, as accepted by Result.material.

axisstrdefault 'z'

Slice normal.

positionfloatdefault 0.0

Slice coordinate in metres; the nearest grid index is used.

figsizetuple[int, int]default (8, 6)

Figure size in inches.

cmapstrdefault 'viridis'

Matplotlib colormap name.

Returns (fig, ax), the Matplotlib figure and axes. The figure is not shown or saved; call fig.savefig(...) or plt.show() yourself.

fig, ax = result.plot.material("eps_r", axis="y", position=0.0)
fig.savefig("eps_y0.png")