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[FieldArrays]) – One FieldArrays 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.
- field(mode=0)#
The mode’s field pattern as a
FieldState.The eigenvector is normalised to
e^T M_eps e = 1, i.e. to a peak stored electric energy of 0.5 J; the physical amplitude follows from that, the spatial pattern is the physical content. A Bloch mode with a phase advance other than 0 or 180 degrees is complex.- Parameters:
mode (int) – Mode index (ascending in frequency).
- 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 (
magnelio.fields.FieldState.plot()). Mode fields are normalised eigenvectors, so the amplitudes are in arbitrary units; the spatial pattern is the physical content. A complex mode (Bloch phase advance other than 0 or 180 degrees) is drawn as the real snapshot at the instant of maximum field energy on the slice — the global phase of an eigenvector is arbitrary, and this choice makes the picture independent of it.- 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)
- show(component='E', **kwargs)#
Interactive 3D view of the modes on a cutting plane.
The geometry viewer with a mode’s field laid on its cut and a slider over the modes (each labelled with its index and eigenfrequency), the position slider walking the layer through the cavity; a complex Bloch mode is shown at the instant of its maximum energy, with a phase slider to turn it. The result’s own mesh cuts the metal out of the sheet and names the symmetry planes the field is continued across, so the view shows the whole cavity. See
magnelio.plots.show_field()for the arguments —frame=picks the mode shown first, the plane (normal, position), geometry, the rendering mode and the rest.- Parameters:
component (str) –
"E","H", or one component such as"Ez".
- 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.Portprotocol (PortOperatorLumped,PortOperatorModal). Excitation is configured on each operator viaset_excitationbeforerun().sources (list) – List of source objects (e.g. plane-wave TF/SF).
total_time_steps (int | None) – Number of leapfrog steps, or
Nonefor an unbounded run that marches until the energy criterion (or a graceful stop) ends it —Nonerequiresenergy_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 beforerun(), which then continues the marching loop fromn_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
_abortedset. Wire aSIGINThandler to this for Ctrl-C, or call it from a monitor / GUI.- Return type:
None
- run()#
Execute the leapfrog time-stepping loop.
- Return type:
FieldArrays
- 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
ε_racross all active (non-PEC) edges, as returned bycompute_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
μ_racross all H-faces (conformal sub-cell faces haveμ_eff < 1because the geometricA_face_free / A_facereduction lowersM_μ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 = 0edges are removed, frozen H-faces enter through the exact1/M_mu = 0. This replaces thesqrt(eps_min * mu_min)worst-case product ofcourant_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_maxis measured with a matrix-free Lanczos iteration on the symmetrised operatorD^-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 measuredlambda_maxis 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