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.

Back to top