magnelio.solver#

Solver components — the FIT time-domain engine and eigenmode results.

class magnelio.solver.EigenmodeResult(frequencies, modes, mesh, solver_info=<factory>)#

Result of a 3D cavity eigenmode analysis.

Parameters:
  • frequencies (np.ndarray) – Resonant frequencies [Hz], shape (n_modes,), ascending.

  • modes (list[FieldState]) – One FieldState per mode with E and H fields on the Yee grid. Field amplitudes are normalised so that e^T M_eps e = 1.

  • mesh (Mesh) – Reference mesh (grid, material library).

  • solver_info (dict) – Metadata: solver backend, number of iterations, residuals, etc.

plot(mode=0, component='E', *, normal=None, position=0.0, plot_type='vector', ax=None, scale_mm=True, cmap=None, geometry=None, flip=False, vmin=None, vmax=None, density=20, normalize_arrows=False, threshold=0.02)#

Plot a mode’s field pattern on a slice plane through the cavity.

The staggered Yee-grid components are interpolated onto cell centres and rendered on the plane selected by normal and position. Mode fields are normalised eigenvectors, so the amplitudes are in arbitrary units; the spatial pattern is the physical content.

Parameters:
  • mode (int) – Mode index (ascending in frequency).

  • component (str) – "E" or "H" for the vector plot / vector magnitude. "Ex", "Hy", … for a single component (scalar only).

  • normal ({"x", "y", "z"}) – Normal axis of the slice plane.

  • position (float) – Slice-plane position along normal [m]; snapped to the nearest cell-centre plane.

  • plot_type (str) – "vector", "color", or "contour".

  • ax (matplotlib.axes.Axes, optional)

  • scale_mm (bool) – Axis coordinates in mm instead of m.

  • cmap (str or None) – Colourmap (None = auto-select).

  • geometry (GeometryModel, optional) – Geometry for a cross-section overlay of the slice plane.

  • flip (bool) – Swap horizontal and vertical axes.

  • vmin (float, optional) – Colour limits (scalar) or arrow clipping (vector).

  • vmax (float, optional) – Colour limits (scalar) or arrow clipping (vector).

  • density (int) – Target arrows per axis (vector mode).

  • normalize_arrows (bool) – Unit-length arrows, colour = magnitude (vector mode).

  • threshold (float) – Suppress arrows below this fraction of peak (vector mode).

Returns:

  • fig (matplotlib.figure.Figure)

  • ax (matplotlib.axes.Axes)

property n_modes: int#

Number of physical modes found.

class magnelio.solver.FITTimeDomainSolver(mesh, boundary_conditions=<factory>, ports=<factory>, sources=<factory>, total_time_steps=1000, dt=1e-12, verbose=True, energy_stop_db=None, port_signal_stop_db=None, port_signal_min_steps=None, max_time_steps=None, energy_check_interval=None, recorder=None, diagnostics=<factory>, monitors=<factory>, sink=None, backend='auto', precision=None, sibc=None)#

FIT leapfrog solver.

Parameters:
  • mesh (Mesh) – The simulation mesh.

  • boundary_conditions (dict) – Dict mapping face names to BC objects.

  • ports (list) – List of objects implementing the magnelio.ports.base.Port protocol (PortOperatorLumped, PortOperatorModal). Excitation is configured on each operator via set_excitation before run().

  • sources (list) – List of source objects (e.g. plane-wave TF/SF).

  • total_time_steps (int | None) – Number of leapfrog steps, or None for an unbounded run that marches until the energy criterion (or a graceful stop) ends it — None requires energy_stop_db.

  • dt (float) – Time step [s].

  • verbose (bool) – Print progress during simulation.

  • energy_stop_db (float | None) – Stop when energy decays by this many dB below peak.

  • port_signal_stop_db (float | None) – Stop when the modal-port |V| envelope decays by this many dB below its run peak — see the field comment.

  • max_time_steps (int | None) – Runtime cap for unbounded runs (absolute step bound; warns and stops when no criterion fired) — see the field comment.

  • recorder (object | None) – Optional PortSignalRecorder — receives V/I from each port at every step.

  • backend (str) – "auto" (default) runs on the GPU via CuPy when CuPy and a CUDA device are available and falls back to the NumPy CPU backend with a one-time notice otherwise; "cupy" requires the GPU (raises with a clear message when unavailable); "numpy" forces the CPU backend.

  • port_signal_min_steps (int | None)

  • energy_check_interval (int | None)

  • diagnostics (list)

  • monitors (list)

  • sink (object | None)

  • precision (str | None)

  • sibc (object | None)

load_state_dict(state)#

Restore a checkpoint captured by state_dict().

The solver must be constructed identically (same mesh, dt, ports and boundary conditions) to the one that produced state — those fix the constant operators; this call only repopulates the evolving state. Call before run(), which then continues the marching loop from n_completed.

Parameters:

state (dict)

Return type:

None

request_stop()#

Ask the marching loop to stop gracefully at the next step.

Cooperative and thread-safe by construction (a single bool flag): the loop checks it at the top of each iteration, so the in-flight step completes and the break lands on a consistent leapfrog pair. The run then persists a resume checkpoint (if a sink is attached) and returns with _aborted set. Wire a SIGINT handler to this for Ctrl-C, or call it from a monitor / GUI.

Return type:

None

run()#

Execute the leapfrog time-stepping loop.

Return type:

FieldState

setup()#

Pre-compute operators and allocate field arrays.

Return type:

None

state_dict()#

Capture the full leapfrog state for a bit-exact resume.

Gathers everything the marching loop mutates — the E/H field, the completed-step count and pre-decay energy peak, and every stateful boundary (CPML ψ) and port (Mur previous-values, TF/SF source buffer, exact DTBC convolution history), keyed by face and port name. Constant operators (material matrices, absorbing- boundary kernels) are re-derived on the resuming solver, never stored.

Return type:

dict

magnelio.solver.courant_dt(grid, accuracy='normal', min_effective_eps=None, min_effective_mu=None)#

Compute the maximum stable time step for the given grid.

Parameters:
  • grid (GridLines) – The mesh grid.

  • accuracy (str) – One of 'draft' (0.90), 'normal' (0.95), 'high' (0.99).

  • min_effective_eps (float or None) – Minimum effective ε_r across all active (non-PEC) edges, as returned by compute_min_effective_eps(). When < 1, reduces dt to account for increased local wave speed at conformal boundary edges.

  • min_effective_mu (float or None) – Minimum effective μ_r across all H-faces (conformal sub-cell faces have μ_eff < 1 because the geometric A_face_free / A_face reduction lowers M_μ while the primal-face area in the geometric factor stays nominal). When < 1, reduces dt by √(μ_eff_min) symmetrically with the ε factor.

Returns:

Time step dt in seconds.

Return type:

float

Raises:

ValueError – If accuracy is not recognized.

magnelio.solver.spectral_dt(mesh, accuracy='normal', m_eps=None, m_mu=None)#

Sharp CFL limit from the spectral radius of the update operator.

The exact leapfrog stability limit is

dt_max = 2 / sqrt(lambda_max(M_eps^-1 C^T M_mu^-1 C))

restricted to the DOFs the solver actually updates: PEC-masked edges and frozen M_eps = 0 edges are removed, frozen H-faces enter through the exact 1/M_mu = 0. This replaces the sqrt(eps_min * mu_min) worst-case product of courant_dt(), which assumes the worst edge, the worst face and the smallest cell coincide — on conformal meshes they never do, and the product under-estimates the stable step by more than an order of magnitude (the measured limit sits at 67-75 % of the geometric Courant value where the heuristic reports 2-4 %).

lambda_max is measured with a matrix-free Lanczos iteration on the symmetrised operator D^-1/2 A D^-1/2. If Lanczos does not converge, the row-sum (Gershgorin) upper bound on the same operator is used instead — strictly safe, typically within ~20 % of the exact value. The measured lambda_max is cached on the mesh, so repeated calls (report + run) pay the eigensolve once.

Parameters:
  • mesh (Mesh) – Fully populated mesh.

  • accuracy (str) – Safety factor selector, same map as courant_dt().

  • m_eps (np.ndarray, optional) – Prebuilt mass matrices (build_M_eps / build_M_mu). Built from the mesh when omitted.

  • m_mu (np.ndarray, optional) – Prebuilt mass matrices (build_M_eps / build_M_mu). Built from the mesh when omitted.

Returns:

Time step dt in seconds.

Return type:

float