Postprocessing
Far-field transforms, RCS, directivity, antenna metrics, diffraction orders, mode overlap, S-parameters, Purcell factor, and mode tracking.
This page covers the functions and classes in witwin.maxwell.postprocess. They turn monitor data from a finished Result into derived quantities: far fields, radar cross section, directivity and gain, diffraction efficiencies, modal amplitudes, flux-based S-parameters, and Purcell factors.
Import them from the subpackage, or reach them through the top-level module:
import witwin.maxwell as mw
from witwin.maxwell.postprocess import NearFieldFarFieldTransformer, compute_directivity
mw.postprocess.compute_bistatic_rcs # same objectNone of these functions runs a solver. Most return plain dict objects whose values are torch.Tensor or Python floats; the keys are listed under each function.
Note
NearFieldFarFieldTransformer and StrattonChuPropagator default to device="cuda" and raise RuntimeError when CUDA is unavailable. Pass device="cpu" to run them on the CPU.
For SAR, power-loss, incident-power-density, and breakdown results, see Safety and stress.
Typical far-field workflow#
Record near fields
Add a plane monitor or a
ClosedSurfaceMonitoraround the radiator. See Monitors.Build equivalent currents
Call
equivalent_surface_currents_from_monitor(result, "box").Transform
Pass the currents to
NearFieldFarFieldTransformer(far zone) orStrattonChuPropagator(any distance).Reduce
Feed the far-field dictionary to
compute_directivityorcompute_bistatic_rcs.
import math
import torch
import witwin.maxwell as mw
from witwin.maxwell.postprocess import (
NearFieldFarFieldTransformer,
compute_directivity,
equivalent_surface_currents_from_monitor,
)
currents = equivalent_surface_currents_from_monitor(result, "nf_box")
transformer = NearFieldFarFieldTransformer(currents, solver=result.solver)
theta = torch.linspace(0.0, math.pi, 91)
phi = torch.linspace(0.0, 2.0 * math.pi, 181)
far = transformer.transform(theta[:, None], phi[None, :], radius=10.0)
metrics = compute_directivity(far)
print(float(metrics["D_max_db"]))NearFieldFarFieldTransformer#
class NearFieldFarFieldTransformer(
currents,
*,
solver=None,
c=None,
eps0=None,
mu0=None,
background_eps_r=None,
background_mu_r=None,
device=None,
)Radiates equivalent surface currents to the far zone with the far-field approximation of the radiation integral.
Equivalent electric and magnetic surface currents at one frequency. Build them with the equivalent_surface_currents_from_* functions on this page.
NoneSolver object (usually result.solver). The transformer reads c (or c0), eps0, and mu0 from it.
NoneSpeed of light in m/s. Used when solver is None or lacks the attribute.
NoneVacuum permittivity in F/m.
NoneVacuum permeability in H/m.
NoneRelative permittivity of the homogeneous exterior medium. None uses the value stored on currents.
NoneRelative permeability of the exterior medium. None uses the value stored on currents.
NoneCompute device. None means "cuda".
Raises ValueError when c, eps0, or mu0 cannot be resolved from solver or the explicit arguments. Raises RuntimeError when CUDA is requested but unavailable.
The instance exposes frequency (Hz), omega (rad/s), k (exterior wavenumber, rad/m), eta (exterior wave impedance, ohm), eta0 (vacuum impedance), c, eps0, mu0, background_eps_r, background_mu_r, device, and solver.
NearFieldFarFieldTransformer.transform#
NearFieldFarFieldTransformer.transform(theta, phi, *, radius=1.0, batch_size=1024) -> dictEvaluates the far field on spherical angles. theta and phi (radians) are broadcast together, so pass theta[:, None] and phi[None, :] to get a 2D grid.
Polar angle in radians, measured from +z.
Azimuth angle in radians, measured from +x.
1.0Observation distance in metres. Must be positive; broadcast to the angle grid.
1024Number of directions evaluated per batch. Must be positive.
Returns a dict with keys theta, phi, radius, directions (unit vectors, shape (..., 3)), frequency, E, H (shape (..., 3)), Ex, Ey, Ez, Hx, Hy, Hz, E_theta, E_phi, H_theta, H_phi, and power_density (radial time-averaged Poynting flux, W/m²).
NearFieldFarFieldTransformer.transform_directions#
NearFieldFarFieldTransformer.transform_directions(directions, *, radius=1.0, batch_size=1024) -> dictEvaluates the far field along explicit direction vectors.
Shape (3,) or (N, 3). Vectors are normalized; zero vectors raise ValueError.
1.0Observation distance in metres, broadcast to (N,).
1024Directions per batch.
Returns a dict with keys directions, radius, frequency, E, H, Ex, Ey, Ez, Hx, Hy, Hz, and power_density.
StrattonChuPropagator#
class StrattonChuPropagator(
currents,
*,
solver=None,
c=None,
eps0=None,
mu0=None,
background_eps_r=None,
background_mu_r=None,
device=None,
)Evaluates the full Stratton-Chu integral (near and far terms) from equivalent surface currents at arbitrary observation points. Use it when the observation plane is not in the far zone.
The arguments match NearFieldFarFieldTransformer. The same constant-resolution and CUDA rules apply.
from witwin.maxwell.postprocess import StrattonChuPropagator
propagator = StrattonChuPropagator(currents, c=299792458.0, eps0=8.8541878128e-12,
mu0=1.25663706212e-6, device="cpu")
plane = propagator.propagate_plane(position=0.25, batch_size=64)
intensity = plane["E_intensity"]StrattonChuPropagator.propagate_points#
StrattonChuPropagator.propagate_points(points, *, batch_size=256) -> dictComputes E and H at points of shape (3,) or (N, 3), in metres.
Returns a dict with keys points, E, H (shape (N, 3)), and Ex, Ey, Ez, Hx, Hy, Hz.
Raises ValueError when an observation point coincides with a source quadrature point.
StrattonChuPropagator.propagate_plane#
StrattonChuPropagator.propagate_plane(*, axis=None, position, u=None, v=None, batch_size=256) -> dictComputes fields on an axis-aligned observation plane.
NonePlane normal, "x", "y", or "z". You can omit it only when every source surface is planar with the same normal.
Plane coordinate along axis, in metres.
None1D coordinates along the first tangential axis. None reuses the source surface coordinates.
None1D coordinates along the second tangential axis.
256Observation points per batch.
Returns a dict with keys axis, position, frequency, u, v, the two tangential axis names (for example x and y), the normal axis name (holding position), E, H (shape (U, V, 3)), Ex to Hz, and E_intensity (sum of squared magnitudes of the E components).
StrattonChuPropagator.propagate#
StrattonChuPropagator.propagate(obs_u, obs_v, obs_position, *, axis=None, batch_size=256) -> dictShorthand for propagate_plane(axis=axis, position=obs_position, u=obs_u, v=obs_v, batch_size=batch_size).
equivalent_surface_currents_from_monitor#
equivalent_surface_currents_from_monitor(
result,
monitor_name,
*,
frequency=None,
freq_index=None,
tangential_bounds=None,
normal_direction=None,
window_size=None,
) -> PlanarEquivalentCurrents | EquivalentCurrentsSurfaceBuilds equivalent currents J = n x H and M = -n x E from a plane monitor or a closed-surface monitor stored on result.
Finished simulation result.
Name of a plane monitor (returns PlanarEquivalentCurrents) or ClosedSurfaceMonitor (returns EquivalentCurrentsSurface).
NoneFrequency to select, in Hz. If the selected payload still holds several frequencies, the first one is used.
NoneFrequency index to select instead of frequency.
NoneCrop each face to these coordinate ranges, keyed by axis name, in metres. Each range must keep at least two samples.
NoneOverride the outward normal sign, "+" or "-" (or a signed number). None uses the monitor setting.
NoneFractions of each tangential span to taper with gaussian_window_1d. None disables tapering.
Raises NotImplementedError for a closed surface whose exterior is not one homogeneous medium. For a closed surface, the exterior permittivity and permeability are read from the compiled materials and stored on the currents; plane monitors assume vacuum.
equivalent_surface_currents_from_monitors#
equivalent_surface_currents_from_monitors(
result,
monitor_names,
*,
frequency=None,
freq_index=None,
tangential_bounds=None,
monitor_tangential_bounds=None,
normal_directions=None,
window_size=None,
) -> EquivalentCurrentsSurfaceCombines several plane or closed-surface monitors into one EquivalentCurrentsSurface.
Monitor names. Must contain at least one name.
NonePer-monitor crop ranges, keyed by monitor name. Monitors not listed use tangential_bounds.
NonePer-monitor normal sign overrides, keyed by monitor name.
The other arguments behave as in equivalent_surface_currents_from_monitor.
equivalent_surface_currents_from_fields#
equivalent_surface_currents_from_fields(
*,
axis,
position,
frequency,
u,
v,
fields,
normal_direction="+",
window_size=None,
background_eps_r=1.0,
background_mu_r=1.0,
quadrature_rule="trapezoidal",
area_weights=None,
) -> PlanarEquivalentCurrentsBuilds planar equivalent currents from field arrays you supply.
Plane normal, "x", "y", or "z".
Plane coordinate in metres.
Frequency in Hz. Must be positive.
1D coordinates along the first tangential axis (for axis="z": x).
1D coordinates along the second tangential axis (for axis="z": y).
Complex field components of shape (U, V), keyed by name ("Ex", "Hy", ...; case-insensitive). The two tangential E and two tangential H components are required.
'+'Outward normal sign.
NoneTaper fractions, as in equivalent_surface_currents_from_monitor.
1.0Exterior relative permittivity stored on the currents.
1.0Exterior relative permeability stored on the currents.
'trapezoidal'"trapezoidal" or "cell_centered". Sets the area weights when area_weights is None.
NoneExplicit per-sample areas in m², shape (U, V), finite and positive.
Raises ValueError when a tangential component is missing or a shape does not match.
equivalent_surface_currents_from_surface_samples#
equivalent_surface_currents_from_surface_samples(
*,
frequency,
points,
normals,
areas,
E,
H,
background_eps_r=1.0,
background_mu_r=1.0,
) -> SurfaceEquivalentCurrentsBuilds currents on an arbitrary closed surface (for example a sphere) from sampled fields.
Frequency in Hz.
Quadrature points, shape (N, 3), in metres.
Outward normals, shape (N, 3). They are normalized; zero vectors raise ValueError.
Surface area per point, shape (N,), in m².
Complex electric field at the points, shape (N, 3).
Complex magnetic field at the points, shape (N, 3).
1.0Exterior relative permittivity.
1.0Exterior relative permeability.
PlanarEquivalentCurrents#
@dataclass(frozen=True)
class PlanarEquivalentCurrents(
axis,
position,
frequency,
u,
v,
J,
M,
background_eps_r=1.0,
background_mu_r=1.0,
normal_direction="+",
quadrature_rule="trapezoidal",
area_weights=None,
)Equivalent currents on one axis-aligned plane. J and M have shape (U, V, 3); (3, U, V) input is also accepted and moved to the last axis. Construction validates shapes, a positive frequency, positive lossless backgrounds, and quadrature_rule in "trapezoidal" or "cell_centered".
Properties: device, coord_dtype, tangential_axes (for example ("x", "y")), shape ((U, V)), and normal (unit normal tensor).
PlanarEquivalentCurrents.weights_2d#
PlanarEquivalentCurrents.weights_2d() -> torch.TensorReturns the (U, V) area weights in m²: area_weights if set, otherwise weights from quadrature_rule.
PlanarEquivalentCurrents.plane_points#
PlanarEquivalentCurrents.plane_points() -> torch.TensorReturns the sample positions, shape (U, V, 3).
PlanarEquivalentCurrents.quadrature#
PlanarEquivalentCurrents.quadrature() -> tuple[torch.Tensor, torch.Tensor, torch.Tensor]Returns flattened (points, J_weighted, M_weighted), each of shape (U*V, 3), with the area weights folded into the currents.
PlanarEquivalentCurrents.cropped#
PlanarEquivalentCurrents.cropped(tangential_bounds) -> PlanarEquivalentCurrentsReturns a copy limited to the given tangential ranges (dict keyed by axis name). None returns self.
PlanarEquivalentCurrents.windowed#
PlanarEquivalentCurrents.windowed(window_size) -> PlanarEquivalentCurrentsReturns a copy with J and M multiplied by a separable Gaussian edge taper. window_size is (frac_u, frac_v); None or zeros return self.
EquivalentCurrentsSurface#
@dataclass(frozen=True)
class EquivalentCurrentsSurface(surfaces)A group of PlanarEquivalentCurrents faces, for example the six faces of a Huygens box. All faces must share the frequency and exterior medium; otherwise the constructor raises ValueError. An empty list raises ValueError, and a non-planar entry raises TypeError.
Properties: surfaces (tuple), frequency, background_eps_r, background_mu_r, and device.
EquivalentCurrentsSurface.cropped#
EquivalentCurrentsSurface.cropped(tangential_bounds) -> EquivalentCurrentsSurfaceApplies PlanarEquivalentCurrents.cropped to every face.
EquivalentCurrentsSurface.windowed#
EquivalentCurrentsSurface.windowed(window_size) -> EquivalentCurrentsSurfaceApplies PlanarEquivalentCurrents.windowed to every face.
SurfaceEquivalentCurrents#
@dataclass(frozen=True)
class SurfaceEquivalentCurrents(
frequency,
points,
weights,
J,
M,
background_eps_r=1.0,
background_mu_r=1.0,
)Equivalent currents on a general surface sampled at explicit quadrature points. points, J, and M have shape (N, 3); weights (areas in m²) has shape (N,).
Properties: device, coord_dtype, and shape ((N,)).
SurfaceEquivalentCurrents.quadrature#
SurfaceEquivalentCurrents.quadrature() -> tuple[torch.Tensor, torch.Tensor, torch.Tensor]Returns (points, J_weighted, M_weighted) with the per-point areas folded into the currents.
build_plane_points#
build_plane_points(axis, position, u, v) -> torch.TensorReturns the 3D coordinates of a plane grid, shape (U, V, 3), in metres. axis is the plane normal; u and v are 1D coordinates along the remaining axes in x, y, z order.
gaussian_window_1d#
gaussian_window_1d(points, bound_min, bound_max, window_frac) -> torch.TensorReturns taper weights in [0, 1] for 1D points. Inside the central region the weight is 1. Within window_frac * (bound_max - bound_min) / 2 of either bound, it falls off as a Gaussian. window_frac of 0 or less returns all ones.
Raises ValueError when bound_max is not greater than bound_min.
compute_bistatic_rcs#
compute_bistatic_rcs(
far_field,
*,
incident_amplitude=None,
source=None,
scene=None,
result=None,
solver=None,
c=None,
eps=1e-30,
) -> dictComputes bistatic radar cross section sigma = 4 pi r² |E_s|² / |E_inc|² from a far-field dictionary.
The default incident amplitude is the plane wave's source_time.amplitude. That matches the recorded spectra only for a CW source, or for a pulsed source run with spectral_sampler=SpectralSampler(normalize_source=True). With a plain GaussianPulse run, the RCS is off by the pulse spectrum, often by orders of magnitude.
Output of NearFieldFarFieldTransformer.transform, or any dict with radius and either E_theta/E_phi or E. It must contain frequency, unless source has a source_time.
NoneIncident plane-wave field amplitude in V/m. None infers it with infer_incident_plane_wave_amplitude(source=..., scene=..., result=...).
NoneIncident source used for amplitude and frequency inference.
NoneScene searched for a single PlaneWave when source is None.
NoneResult whose scene is searched for a single PlaneWave.
NoneSupplies c (or c0) for the wavelength.
NoneSpeed of light in m/s, used when solver is None.
1e-30Floor applied before taking log10.
Returns a copy of far_field with added keys incident_amplitude, wavelength (m), rcs (m²), normalized_rcs (rcs / wavelength²), rcs_db (dB of normalized_rcs), and rcs_dbsm (dB relative to 1 m²).
Raises ValueError when c cannot be resolved, the frequency is unknown, or the incident amplitude is zero.
rcs = mw.postprocess.compute_bistatic_rcs(far, result=result, solver=result.solver)
print(rcs["rcs_dbsm"])transform_to_bistatic_rcs#
transform_to_bistatic_rcs(
transformer,
theta,
phi,
*,
radius=1.0,
incident_amplitude=None,
source=None,
scene=None,
result=None,
batch_size=1024,
) -> dictCalls transformer.transform(theta, phi, radius=radius, batch_size=batch_size) and passes the output to compute_bistatic_rcs, using the transformer's solver and c. Returns the same dict as compute_bistatic_rcs.
infer_incident_plane_wave_amplitude#
infer_incident_plane_wave_amplitude(*, source=None, scene=None, result=None) -> floatReturns the amplitude of the single PlaneWave source. It reads source_time.amplitude for CW, GaussianPulse, and RickerWavelet, or the "amplitude" key of a mapping. A source with no source_time returns 1.0.
Raises ValueError when no PlaneWave or more than one is found, TypeError when source is not a PlaneWave or the source_time type is unsupported.
compute_directivity#
compute_directivity(far_field, *, input_power=None) -> dictComputes directivity, optional gain, and half-power beam widths from a far field on a 2D (theta, phi) grid. The radiated power is the trapezoidal integral of U = r² * power_density over the sampled grid, so sample the full sphere for a correct total.
Dict with theta, phi (2D grid, radians; theta constant along axis 1, phi constant along axis 0), radius, power_density, and frequency. NearFieldFarFieldTransformer.transform output with theta[:, None] and phi[None, :] satisfies this.
NoneInput power in W. When given, gain and radiation efficiency are computed. Must be positive.
Returns a dict with keys:
| Key | Meaning |
|---|---|
theta, phi, frequency | Copied from the input |
P_rad | Integrated radiated power, W |
U | Radiation intensity, W/sr |
directivity, directivity_db | 4 pi U / P_rad, linear and dBi |
D_max, D_max_db | Peak directivity |
D_max_theta, D_max_phi | Angles of the peak, radians |
gain, gain_db, G_max, G_max_db | Gain, None without input_power |
radiation_efficiency | P_rad / input_power, None without input_power |
beam_width_e_plane, beam_width_h_plane | Half-power beam width in degrees in the phi = 0 and phi = 90° cuts, or None when it cannot be bracketed |
Raises ValueError when the grid is not 2D, power_density does not match it, or P_rad is not positive.
compute_antenna_data#
compute_antenna_data(
*,
frequencies,
theta,
phi,
driven_port,
e_theta=None,
e_phi=None,
radiation_intensity=None,
radius=1.0,
wave_impedance=FREE_SPACE_IMPEDANCE,
polarization=None,
phase_center=None,
frame=None,
surface_currents=None,
) -> AntennaDataBuilds port-referenced antenna metrics from full-sphere far-field data and one driven port. Returns an AntennaData.
Real 1D tensor of shape [F], Hz, strictly positive. Must equal driven_port.frequencies exactly (same values, dtype, and device).
Polar angles in radians: a 1D vector or a 2D grid. Must start at 0, end at pi, be strictly increasing, and have at least three samples.
Azimuth angles in radians: a 1D vector or a 2D grid. Must be strictly increasing, span exactly 2 pi, and have at least two samples.
Port result of the driven port, with one excitation (voltage shape [F]). Its incident and accepted powers must be finite and positive. See Ports.
NoneComplex peak-phasor far field, shape [F, T, P], V/m at radius. Pass together with e_phi.
NoneComplex peak-phasor far field, shape [F, T, P].
NoneNon-negative radiation intensity in W/sr, shape [F, T, P]. Pass this or the field pair, not both. With intensity only, polarization fields and axial ratio are None.
1.0Observation radius in metres; scalar, [F], or broadcastable to [F, T, P].
FREE_SPACE_IMPEDANCEReal positive wave impedance in ohm used to convert fields to intensity. The default is the vacuum impedance constant ETA_0.
NoneCo/cross-polarization basis. None uses Ludwig3().
NonePhase center, shape [3], metres. Stored as provenance here. None means the origin.
None3x3 right-handed orthonormal basis, columns are the local x, y, z axes. None means identity.
NoneEquivalent currents to store on the result for provenance.
Raises TypeError or ValueError on any shape, dtype, device, or positivity violation.
antenna_data_from_result#
antenna_data_from_result(
result,
*,
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,
) -> AntennaDataTransforms a closed Huygens monitor to the far field at every result frequency and calls compute_antenna_data. Result.antenna(...) takes the same keyword arguments.
Finished result with a closed-surface monitor and a port.
Name of the closed-surface monitor.
Name of the driven port, or its PortData.
NonePolar angles. None uses theta_points samples from 0 to pi.
NoneAzimuth angles. None uses phi_points samples from 0 to 2 pi.
181Number of default theta samples, at least 3.
361Number of default phi samples, at least 2.
NonePhase center in simulation coordinates, metres. Applied to the far-field phase.
NoneLocal coordinate frame; angles are expressed in this frame.
1024Directions per transform batch.
polarization and radius behave as in compute_antenna_data.
Raises NotImplementedError when the exterior medium is lossy. Raises ValueError when the port frequencies do not match result.frequencies.
antenna = mw.postprocess.antenna_data_from_result(
result, surface="huygens", driven_port="feed", theta_points=91, phi_points=181
)compute_diffraction_orders#
compute_diffraction_orders(
result,
monitor_name,
*,
incident_power=None,
background_index=1.0,
frequency=None,
freq_index=None,
) -> dictProjects a DiffractionMonitor plane onto the Floquet orders of the periodic unit cell and reports the power in each order. Periods come from the scene domain; the Bloch wavevector comes from the solver.
Result of a periodic simulation.
Name of a DiffractionMonitor. Other monitor types raise ValueError.
NonePower in W used as the efficiency denominator. None uses the total power in propagating orders.
1.0Refractive index of the medium at the monitor; sets the propagation cutoff.
NoneFrequency to select, Hz.
NoneFrequency index to select.
Returns a dict with keys monitor, kind ("diffraction"), frequency, axis, normal_direction, position, tangential_axes, periods, reciprocal_vectors, background_index, incident_power, total_power, propagating_power, num_propagating, and orders. Each entry of orders has m, n, kx, ky, kz (None if evanescent), propagating, power (W), efficiency, amplitude_E, amplitude_H, theta (radians, None if evanescent), and phi.
enumerate_diffraction_orders#
enumerate_diffraction_orders(
*,
periods,
k_bloch,
k0,
background_index=1.0,
max_order=None,
) -> tuple[list[dict], tuple[float, float]]Lists the grating orders (m, n) of a periodic cell without simulation data.
Unit-cell lengths along the two tangential axes, metres.
Transverse Bloch wavevector, rad/m.
Vacuum wavenumber, rad/m.
1.0Background refractive index. An order propagates when its transverse wavenumber is below k0 * background_index.
NoneLargest order index to list. None picks a bound that covers every propagating order.
Returns (orders, (Ga, Gb)). Each order dict has m, n, kx, ky, kz_squared, and propagating. Ga and Gb are the reciprocal vector lengths 2 pi / period.
compute_mode_overlap#
compute_mode_overlap(
result,
monitor_name,
*,
mode_source=None,
direction=None,
frequency=None,
freq_index=None,
) -> dictDecomposes the field on a plane monitor into forward and backward amplitudes of a waveguide eigenmode.
Warning
This function solves the reference mode the same way ModeSource does. Mode sources and mode monitors are experimental.
Finished result.
Plane monitor name. A monitor without an axis raises ValueError.
NoneReference mode. None uses the monitor's own mode spec, or the scene's only ModeSource (including mode ports). A string selects a ModeSource by name.
None"+" or "-". None uses the mode source direction.
NoneFrequency to select, Hz.
NoneFrequency index to select.
Returns a dict with keys monitor, frequency, axis, position, direction, mode_index, polarization_axis, effective_index, beta (rad/m), mode_power, total_power, amplitude_forward, amplitude_backward (complex), power_forward, power_backward, power_fraction_forward, power_fraction_backward (None when total power is near zero), coords, candidate_diagnostics, candidate_overlap_matrix, and selected_candidate_index.
overlap = mw.postprocess.compute_mode_overlap(result, "port", direction="+")
amplitude = complex(overlap["amplitude_forward"].cpu().item())compute_s_parameters#
compute_s_parameters(
result,
incident_monitor,
*,
transmitted_monitor=None,
reference_result=None,
incident_power=None,
) -> dictComputes S11 and S21 magnitudes from flux monitors. Reflected power is abs(incident_flux - P_incident).
Result with flux data on the named monitors (FluxMonitor or PlaneMonitor(compute_flux=True)).
Monitor on the source side.
NoneMonitor on the far side. When None, the S21 keys are None.
NoneEmpty-domain run whose flux on incident_monitor gives the incident power. Frequencies must match.
NoneIncident power in W per frequency, or "auto" to derive it analytically from the scene's single PlaneWave.
Pass exactly one of reference_result and incident_power; otherwise ValueError is raised.
Returns a dict with keys frequencies, S11, S11_mag, S11_db, S21, S21_mag, S21_db, P_incident, P_reflected, and P_transmitted. _db values are 20 log10 of the magnitude.
s = mw.postprocess.compute_s_parameters(
result, incident_monitor="port1", transmitted_monitor="port2", incident_power="auto"
)purcell_factor#
purcell_factor(structured, vacuum, name) -> dictReturns the ratio of power delivered by a dipole in a structured environment to the same dipole in vacuum, from two DipoleEmissionMonitor runs. Both runs must share grid, dipole waveform, and frequency sampling.
Result of the structured run, or its extracted monitor payload.
Result of the vacuum reference run, or its payload.
Name of the DipoleEmissionMonitor.
Returns a dict with kind ("dipole_emission"), purcell_factor (float for one frequency, otherwise a NumPy array), power_delivered, power_delivered_vacuum, and frequencies.
Raises ValueError when the monitor is not a DipoleEmissionMonitor or the frequency samplings differ.
purcell = mw.postprocess.purcell_factor(structured, reference, "emit")["purcell_factor"]compute_power_loss_data#
compute_power_loss_data(
compiled,
frequencies,
*,
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,
source_result_fingerprint=None,
autograd_provenance="live graph is preserved from supplied torch tensors; persisted data is detached",
) -> PowerLossDataLow-level reducer behind Result.power_loss. It needs a compiled monitor (CompiledPowerLossMonitor), so most users call Result.power_loss(name, ...) instead. The returned type and the channel rules are described under PowerLossData.
Compiled PowerLossMonitor from witwin.maxwell.compiler.power_loss.compile_power_loss_monitor.
Real 1D frequencies in Hz on the monitor device. Must equal the monitor frequencies when the monitor declares them.
NonePeak-phasor Ex, Ey, Ez. Required when the monitor requests the "conduction" channel and rejected otherwise.
The channel mappings take densities in W/m³ (volume), W/m² (surface, with face_areas), W/m (line, with line_lengths), or integrated power in W. Each requested channel must come from exactly one of them, and "conduction" is always computed from electric_fields.
track_modes#
track_modes(
beta,
overlaps=None,
*,
modal_basis=None,
beta_weight=0.05,
degeneracy_tolerance=1.0e-3,
min_overlap=0.5,
min_margin=0.05,
min_subspace_singular_value=0.5,
) -> ModeTrackingResultAssigns a stable order and phase to waveguide modes across a frequency sweep, using overlaps between adjacent frequencies.
Propagation constants, shape [F, M], real or complex, finite.
NoneComplex normalized overlaps, shape [F - 1, M, M], magnitude at most 1. overlaps[k, i, j] pairs candidate i at frequency k with candidate j at k + 1.
NoneComplex mode vectors, shape [F, M, ...]. Overlaps are computed from it when overlaps is None. Pass at least one of overlaps and modal_basis.
0.05Weight of the propagation-constant difference in the assignment score.
1.0e-3Tolerance that groups modes with nearly equal beta into a degenerate subspace.
0.5Minimum aligned overlap magnitude for an ordinary match.
0.05Minimum score margin over the next-best candidate.
0.5Minimum singular value for a degenerate subspace match.
Raises ModeTrackingError on a low-confidence match. Raises TypeError or ValueError on invalid shapes, dtypes, devices, or negative thresholds.
ModeTrackingResult#
@dataclass(frozen=True)
class ModeTrackingResult(
assignment,
beta,
orientation,
phase_factors,
overlap,
margin,
subspace_singular_values,
confidence,
degenerate,
aligned_basis=None,
)Output of track_modes. All fields are tensors on the device of beta.
| Field | Shape | Meaning |
|---|---|---|
assignment | [F, M] | Raw candidate index assigned to stable mode m (int64) |
beta | [F, M] | Propagation constants in tracked order |
orientation | [F, M, M] | Maps raw mode rows to the tracked basis |
phase_factors | [F, M] | Phase correction per tracked mode |
overlap | [F - 1, M] | Aligned overlap at each transition |
margin | [F - 1, M] | Score margin over the next candidate |
subspace_singular_values | [F - 1, M] | Singular values of matched blocks |
confidence | [F - 1, M] | Match confidence |
degenerate | [F - 1, M] | True where the mode belongs to a degenerate group |
aligned_basis | [F, M, ...] or None | modal_basis rotated into the tracked basis |
ModeTrackingError#
class ModeTrackingError(RuntimeError)Raised by track_modes when adjacent-frequency mode identity is not numerically reliable.