perturbation.eigenmodes
perturbation.eigenmodes(
prob,
x_bar,
freq_band=None,
*,
growth_band=None,
n_nodes=128,
n_probe=None,
eps=None,
eps_fb=1e-06,
u_floor=1e-08,
isentropic=False,
svd_tol=1e-10,
residual_tol=_RESIDUAL_TOL,
refine=True,
certify=True,
max_refine_rounds=_MAX_REFINE_ROUNDS,
rng=None,
contour=None,
)Free-oscillation eigenmodes of the perturbation network in a region of the complex plane.
Finds the complex frequencies omega at which A(omega) (the assembled perturbation operator under each terminal’s declared :class:PerturbationBC) is singular – the network’s self-sustained modes – by Beyn’s contour-integral method (:func:contour.beyn), polishing and validating each by its residual. The operator is identical to the one the forced/scattering driver uses, so the spectrum and the response are guaranteed consistent.
The search region is covered by overlapping sub-contours. On each, the argument principle counts the enclosed eigenvalues before Beyn runs, and that count fixes the rank of the moment matrix; a sub-contour enclosing none is skipped. The result is insensitive to how the band happens to be tiled, which a rank inferred from the moment’s singular values is not.
Use passive terminal BCs (hard_wall/open_end/anechoic/ reflection/impedance, or inherit); a terminal’s driven forcing has no meaning for a free oscillation (the eigenproblem ignores b). At least one length-bearing duct (or another omega-dependent term) must be present, else A has no frequency dependence and there is no spectrum.
Parameters
| Name | Type | Description | Default |
|---|---|---|---|
| prob | CompiledProblem or Solution | The compiled flow network (carries the terminal BCs in prob.node_bc). Pass a solved :class:nefes.Solution to have its problem and mean state supplied for you (then omit x_bar). |
required |
| x_bar | ndarray | Converged mean-flow state, shape (n_solve, E). Omit when prob is a Solution. |
required |
| freq_band | tuple of float | (f_lo, f_hi) real-frequency window to search, in Hz. Required unless an explicit contour is given. |
None |
| growth_band | tuple of float | (g_lo, g_hi) growth-rate window in 1/s (growth rate = -Im(omega); positive is unstable). Default: a roughly square region about the real axis (clamped to keep the duct phases from overflowing). Widen it to hunt strongly growing/decaying modes. The two bands set the semi-axes of an elliptical search region, not a rectangle: a mode near a corner of the implied box – high growth at the edge of the frequency window – lies outside the ellipse and is neither counted nor returned. Widen the band that it sits close to. The region is reported on :attr:EigenmodeResult.contour. |
None |
| n_nodes | int | Quadrature points on the contour (default 128). Trapezoidal quadrature converges exponentially, so more points buy accuracy cheaply; each costs one sparse factorization. | 128 |
| n_probe | int | Beyn probe-block width (upper bound on the modes resolved per call). Default: estimated from the ducts’ mode spacing in the band, grown automatically if it saturates. | None |
| eps | float | Operator-assembly regularizers forwarded to build_acoustic_blocks. |
None |
| eps_fb | float | Operator-assembly regularizers forwarded to build_acoustic_blocks. |
None |
| u_floor | float | Operator-assembly regularizers forwarded to build_acoustic_blocks. |
None |
| isentropic | bool | Force isentropic perturbations (rho' = p'/c^2): the convected entropy wave is pinned to zero on every edge, leaving the two acoustic waves (default False). This is the standard acoustic-stability assumption – it drops entropy/convective modes from the spectrum and removes the near-stagnant entropy-phase overflow entirely – and uses the same solver, contour, and certificate machinery (no reconfiguration). |
False |
| svd_tol | float | Relative singular-value cutoff for the Beyn rank (mode count). Default 1e-10. Consulted only on a sub-contour whose winding count could not be trusted; the rank normally comes from the argument principle. | 1e-10 |
| residual_tol | float | Residual cutoff to keep a mode, measured on the equilibrated operator (see :class:_ResidualScale). Default 1e-9: a converged mode lands orders of magnitude below it, an arbitrary point orders above. |
_RESIDUAL_TOL |
| refine | bool | Whether to Newton-polish each eigenpair before validating (default True). | True |
| certify | bool | Whether to cross-check completeness over the whole region with the argument principle (default True). The per-sub-contour counts that set the Beyn rank are always taken; this option adds one count over the region as a whole, whose result is reported on :attr:EigenmodeResult.expected and compared with the modes resolved on :attr:EigenmodeResult.certified. If fewer are resolved, the band is re-tiled finer and the probe widened, then re-searched, until the two agree or max_refine_rounds is exhausted (then a warning is raised). |
True |
| max_refine_rounds | int | Maximum adaptive re-tile/re-search rounds when the Beyn count falls short of the certificate (default 3). Each round multiplies the sub-contour count and probe width by a fixed factor. | _MAX_REFINE_ROUNDS |
| rng | numpy.random.Generator | Random source for the Beyn probe (default: a fixed seed, reproducible). | None |
| contour | Contour | A fully specified search contour, overriding freq_band/growth_band (for total control of the region; see :func:contour.ellipse_contour). |
None |
Returns
| Name | Type | Description |
|---|---|---|
| EigenmodeResult | The validated modes (frequencies in Hz, growth rates in 1/s, mode shapes). |
Raises
| Name | Type | Description |
|---|---|---|
| ValueError | If the band is degenerate. |
Notes
Convected scalar waves. With isentropic=False (the default) the convected entropy wave h is carried in A(omega) like the two acoustic waves, so entropy/convective modes appear in the spectrum – except on a near-stagnant duct, where its transit time diverges and its phase e^{-i*omega*tau_0} would overflow at complex omega; there it is decoupled (below _ENTROPY_DECOUPLE_MACH, exact for the acoustic band, see :func:build_operator). isentropic=True pins h = 0 on every edge, dropping the convected/entropy modes entirely and leaving the acoustic spectrum. A dense convected spectrum (long ducts, low Mach) is where the contour method struggles and :func:nyquist.open_loop_response is the robust tool instead.
omega-dependent table/impedance BCs are evaluated at the complex contour frequency; a tabulated reflection (interpolated on a real grid) is not analytically continuable and is unsupported for stability – use a constant or closed-form BC.
The completeness certificate (certify) counts algebraic multiplicity, so a genuine repeated root contributes more than one to :attr:EigenmodeResult.expected while the de-duplicated mode list holds it once; such (non-generic) exact degeneracies therefore read as uncertified. The count is likewise withheld (and warned about) when the counting contour does not resolve the determinant phase – a per-step phase jump near pi, whether from a mode grazing the region boundary or, at low mean-flow Mach, a convected/entropy spectrum too dense for the contour, which aliases the winding onto a spurious (often zero) count. The acoustic modes are then recovered with isentropic=True.
See also
contour.beyn : the contour-integral eigensolver this driver tiles and validates. contour.winding_count : the argument-principle completeness certificate. nyquist.open_loop_response : robust real-frequency stability count for the convected regime. eigenvalue_trajectory : track this spectrum as a setup parameter is varied.