Project overview¶
| Attribute | Value |
|---|---|
| System | LinStabPy |
| Project type | CLI and scientific library |
| Domain | Compressible flow linear stability and resolvent analysis |
| Audience | Master students and researchers fluent in math, linear algebra, and HPC, plus CFD engineers and scientific developers |
Conventions
The discrete perturbation state is \(q' = [\rho', u', v', w', T']^T\) at each grid point. Assembly builds the sparse matrix \(L_0\) with \(\partial_t q' = L_0 q'\) in the interior, then applies sponge, dissipation, and boundary conditions in that fixed order.
Temporal eigenvalues are \(\omega = \mathrm{eig}(i L_0)\) with time factor \(\exp(-i\omega t)\). Growth in time is \(\mathrm{Im}(\omega) > 0\). Targets you pass in YAML live in \(\omega\) space. This matches stability/_eigenvalues.py, which is the source of truth.
The resolvent at \((\beta, \omega)\) with real discount \(\gamma\) is \(H = C F (L_0 - (\gamma + i\omega) I)^{-1} F B\). Gains are weighted singular values. The default energy is the diagonal Chu norm described in Architecture.
SBP orders are exactly \(2\), \(4\), \(6\), \(8\) (even only, with validated boundary closures). The default shifted solve is KSPPREONLY with PCLU through MUMPS, driven by SLEPc EPS with Krylov-Schur and shift-invert. Every solver term here is defined in the solver glossary.
Project introduction¶
Project name and description¶
LinStabPy is a Python toolkit for linear stability and resolvent analysis of compressible flows. It started as a Python port of LinStab2D style MATLAB workflows and now runs distributed on HPC through MPI, PETSc, and SLEPc.
A run starts from two inputs you supply. One is the base flow, a steady compressible Navier-Stokes solution stored as arrays on a structured grid. The code linearizes about it and never computes it. The other is a short YAML case file with physics, numerics, and solver policy. From there the pipeline builds the linearized Navier-Stokes (LNSE) matrix \(L_0\) with summation-by-parts (SBP) finite differences, enforces boundary conditions, and solves one or more of:
- Temporal eigenproblem, \(\omega = \mathrm{eig}(iL_0)\) near a target
- Spatial eigenproblem, generalized \(Ax = \lambda Rx\) for streamwise wavenumber
- Adjoint eigenproblem, \(W^{-1} L_0^H W\) for receptivity and sensitivity
- Resolvent problem, leading gains and forcing and response modes of \(H\)
Large sparse algebra runs through PETSc and SLEPc. The spine is factorize once, solve many. One sparse direct factorization of the shifted operator serves all Krylov iterations and all \(H\) and \(H^H\) applies at that shift. The default backend is MUMPS. An optional cuDSS path exists for GPU factors.
What you get¶
| Capability | What it gives you |
|---|---|
| Large LNSE eigen and resolvent studies on HPC without MATLAB | Same analysis semantics as LinStab2D, on clusters, with a reproducible Python stack |
| Mean flow files turned into modes, gains, and sensitivity fields | A direct bridge from RANS, LES, or DNS averages to transition and control insight |
| Temporal, spatial, and adjoint spectra with structural sensitivity | Growth rates, frequencies, wavenumbers, and wavemaker maps |
| Resolvent gain maps over frequency \(\omega\) and spanwise wavenumber \(\beta\) | Quantified nonnormal amplification, even where all modes are stable |
| YAML driven runs with schema checks and provenance | Config hash, git SHA, backend, and cost recorded with every result |
In short, LinStabPy turns CFD mean flow dumps into stability spectra, resolvent gains, and sensitivity results for transition and flow control work.
How it is built¶
- Language and delivery. Python CLI plus importable library. Plain
import linstabpystays light and does not initialize PETSc or MPI. The driver initializes them when a solve stage starts. - Discretization. Structured grids. SBP differences at even orders \(2\) to \(8\). Cartesian and cylindrical (axisymmetric) coefficient paths. Optional Mattsson style filters and artificial dissipation.
- State and operators. LNSE for \(q' = [\rho', u', v', w', T']\). Sparse \(L_0\) with sponge and Dirichlet and Neumann recipes applied last.
- Solvers. SLEPc
EPSfor eigenproblems. Resolvent through a weighted normalMatShellwith repeated shifted solves. - Parallelism. MPI distribution of matrices, vectors, and case orchestration through
petsc4pyandslepc4py. Complex scalars are required for production paths. - Linear algebra core. PETSc
KSPandPC. Sparse direct LU through MUMPS by default. Optional GPU sparse direct through cuDSS as a PETSc preconditioner shell. - Local numerics and IO. NumPy and SciPy for arrays and CSC and CSR assembly before PETSc conversion. Base flow from
npydirectories ornpzarchives. Cases from YAML. - Architecture style. Staged pipeline with a dedicated solver router for cost aware \(\beta\) and frequency campaigns with anchors, factor reuse, and residual gates.
Who uses it¶
Roles¶
flowchart LR
subgraph users [Users]
FDR["Fluid dynamics researchers"]
ENG["CFD and aerospace engineers"]
DEV["Scientific software developers"]
end
SYS["LinStabPy"]
FDR -->|"spectra, adjoints, sensitivity, maps"| SYS
ENG -->|"base flow ingest, BC recipes, sweeps"| SYS
DEV -->|"library API, typed config, provenance"| SYS
| Role | Description |
|---|---|
| People studying hydrodynamic stability, transition, and receptivity in compressible flow. | |
| People who already hold a mean flow and need its linear modes and amplifier behavior. | |
| Scientific software developers | People who embed LNSE stages in larger pipelines and need a clean API and contracts. |
If you are a master student, start in the researcher row. You need the base flow idea, the \(\omega\) convention above, and one example. MPI and Krylov details can wait until your first map campaign feels slow.
Usage scenarios¶
| Scenario | Who | What happens |
|---|---|---|
| Temporal eigenvalue analysis | Researchers, engineers | Load mean flow and mesh, assemble \(L_0\) with boundary conditions, factorize the shifted system, run SLEPc near the target, emit \(\omega\), modes, residuals, and provenance. |
| Resolvent gain analysis | Researchers, engineers | Build \(H\) from \(L_0\) at target \(\omega\), solve the weighted normal eigenproblem, return gains with forcing and response pairs. |
| Gain map over \(\beta\) and \(\omega\) | Researchers on HPC | One \(L_0\) per spanwise wavenumber \(\beta\), frequency bands marked, anchors factorized, nearby \(\omega\) points reuse factors as preconditioners under a residual gate. |
| Spatial eigenproblem | Researchers, engineers | Assemble spatial block pair \((A, R)\), run generalized SLEPc for streamwise wavenumber and spatial growth. |
| Base flow ingest and operator prep | Engineers, developers | npy or npz dumps pass through sponge, shock cleanup, and viscosity setup, then mesh and SBP, then BC ready \(L_0\). |
| Library embedding | Developers | Import analysis functions without PETSc init on import, use typed config, SciPy and PETSc bridges, metrics and provenance. |
What each role needs¶
Researchers need:
- Temporal and spatial spectra with a clear \(\omega\) convention
- Adjoint modes and structural sensitivity (wavemaker) fields
- Gain maps over \(\omega\) and \(\beta\) with residuals attached
- YAML cases that rerun bit reproducibly on MPI clusters
Engineers need:
- Ingest of
npyandnpzbase flows without reformatting by hand - Dirichlet and Neumann recipes expressed as data, not code edits
- Direct sparse solves with MUMPS, with GPU factors available
- Sweeps that reuse factors instead of refactoring at every point
Developers need:
- Importable API that stays free of PETSc init on import
- Typed config with schema validation
- SciPy and PETSc conversion helpers in one place
- Provenance and metrics with stable key names
System boundaries¶
Scope¶
In scope starts from loaded mean flow and mesh geometry and ends at results, metrics, and payloads.
Inside that envelope, LinStabPy:
- Assembles \(L_0\) and spatial pairs on structured SBP grids
- Enforces boundary condition recipes
- Factorizes shifted systems once per shift
- Runs eigen and resolvent workflows, including parametric maps
- Orchestrates cases through CLI and driver code with validation, IO, and provenance
It does not generate nonlinear base flows or ship visualization products.
flowchart TB
subgraph outside [Outside the boundary]
CFD["Nonlinear CFD solvers"]
GUI["Plotting and GUIs"]
UNS["Unstructured or full 3D frameworks"]
MULTI["General non-LNSE multiphysics"]
CLOUD["Cloud auth and tenancy"]
end
subgraph inside [LinStabPy]
BF["Base flow load and preprocess"]
MS["Structured mesh, SBP, filters"]
OP["LNSE coefficients and assembly"]
BC["BC recipes"]
ST["Temporal, spatial, adjoint eigensolvers"]
RS["Resolvent gains and maps"]
FA["Sparse factorization"]
RT["Solver routing"]
DR["CLI, config, IO, provenance"]
end
CFD -.->|"mean flow files only"| BF
BF --> MS --> OP --> BC
OP --> ST
OP --> RS
FA --> ST
FA --> RS
RT --> RS
DR --> BF
DR --> ST
DR --> RS
DR --> RT
Included components¶
| Component | Role |
|---|---|
| Base flow load and preprocess | Ingest mean fields and make them safe to linearize |
| Structured mesh with SBP and filters | Discrete derivatives, norms, quadrature, stabilization |
| LNSE coefficients and assembly | Build sparse \(L_0\) and spatial pairs |
| Boundary condition recipes | Enforce Dirichlet and Neumann rows and publish free degrees of freedom |
| Temporal, spatial, and adjoint eigensolvers | Core stability product |
| Resolvent operator, gains, and maps | Amplifier and receptivity product |
| Sparse factorization layer | Factorize once, solve many |
| Solver routing with anchors and sweeps | Cost aware parametric campaigns |
| CLI and driver with config, IO, and provenance | Reproducible HPC entry and exit |
Internal modules. Case Orchestration, Configuration Management, Baseflow Management, Mesh Discretization, LNSE Operator Assembly (including boundary conditions), Stability Analysis, Resolvent Analysis, Solver Routing and Sweep Optimization, Linear Algebra Infrastructure, Shared Scientific Utilities.
Excluded components¶
| Excluded | Why |
|---|---|
| Nonlinear CFD solvers | Upstream data providers only, coupled through files |
| GUIs and interactive visualization | Results are files for external tools |
| Unstructured or fully 3D volume frameworks | Scope is structured grids |
| General non-LNSE multiphysics | Single purpose toolkit |
| Cloud deployment, auth, and tenancy | HPC CLI and library, not a hosted service |
External pieces¶
List¶
| External piece | Type | What it does here |
|---|---|---|
| PETSc | Library | Distributed Mat and Vec, KSP and PC, parallel runtime |
| SLEPc | Library | EPS eigensolvers for temporal, spatial, adjoint, and resolvent normal problems |
| MUMPS | Backend via PETSc | Default sparse direct LU for shifted systems |
| MPI | Runtime | Process parallelism for matrices, vectors, and orchestration |
| cuDSS | Optional backend | Optional GPU sparse direct path, wrapped as a PETSc shell |
| NumPy and SciPy | Libraries | Arrays, CSC and CSR assembly, local kernels before PETSc conversion |
| Base flow file stores | File input | Mean fields as npy directories or npz archives |
| YAML case config | File input | Case, mesh, eigen, resolvent, and solver policy |
How they connect¶
flowchart LR
subgraph inputs [File inputs]
YAML["YAML case config"]
CFDData["Base flow files"]
end
subgraph linstab [LinStabPy]
Core["LNSE stability and resolvent"]
end
subgraph libs [Libraries and runtimes]
NP["NumPy and SciPy"]
MPI["MPI"]
PETSc["PETSc"]
SLEPc["SLEPc"]
MUMPS["MUMPS"]
cuDSS["cuDSS, optional"]
end
YAML -->|"merge and validate"| Core
CFDData -->|"mean flow and mesh"| Core
Core -->|"local arrays, CSC and CSR"| NP
Core -->|"distributed runtime"| MPI
Core -->|"Mats, Vecs, KSP, PC"| PETSc
PETSc --> MUMPS
PETSc -.-> cuDSS
Core -->|"EPS problems"| SLEPc
SLEPc --> PETSc
File inputs.
- YAML case config. Merged with environment overrides and defaults, then schema checked for eigen, resolvent, mesh, MPI, and router policy before any heavy stage runs.
- Base flow file stores. Nondimensional primitives and mesh plus optional sponge fields. No live coupling to a CFD process.
Libraries and runtimes.
- NumPy and SciPy. Host side fields and sparse assembly before distributed conversion.
- MPI with PETSc. Distributed execution fabric, matrices and vectors, direct and preconditioned solves.
- MUMPS through PETSc. Primary sparse direct backend.
- cuDSS, optional. GPU direct factor where selected by resource policy.
- SLEPc. Eigenvalue and gain eigenproblems on PETSc objects.
Which dependencies matter most¶
| Dependency | Criticality | Notes |
|---|---|---|
| PETSc with MPI | Required for distributed paths | Core parallel algebra and orchestration runtime |
| SLEPc | Required for eigen and resolvent outputs | Built on PETSc structures |
| MUMPS | Default direct path | Reached as a PETSc backend, not a separate app |
| NumPy and SciPy | Required | Local numerics and IO bridge |
| cuDSS | Optional | Probed for capability, chosen under RAM and cost policy |
| Base flow files | Required as data source | One way file dependency |
| YAML configs | Required for CLI campaigns | Policy source of truth after merge and validation |
LinStabPy consumes CFD artifacts and HPC libraries. Edges are library linkage and file IO, not service APIs.
System context¶
Context diagram¶
graph TB
Researcher["Fluid dynamics researcher"]
Engineer["CFD and aerospace engineer"]
Developer["Scientific software developer"]
LinStabPy["LinStabPy: compressible LNSE stability and resolvent on HPC"]
YAMLConfig["YAML case config"]
CFDStore["Base flow file stores"]
NumPySciPy["NumPy and SciPy"]
MPIRuntime["MPI"]
PETScLib["PETSc"]
SLEPcLib["SLEPc"]
MUMPSLib["MUMPS"]
CuDSSLib["cuDSS, optional"]
Researcher -->|"YAML cases, MPI jobs, spectra, gains"| LinStabPy
Engineer -->|"base flows, BC policy, sweeps"| LinStabPy
Developer -->|"API, typed config, metrics"| LinStabPy
YAMLConfig -->|"case and solver policy"| LinStabPy
CFDStore -->|"mean flow and mesh"| LinStabPy
LinStabPy -->|"arrays, CSC and CSR"| NumPySciPy
LinStabPy -->|"process parallelism"| MPIRuntime
LinStabPy -->|"distributed Mats, Vecs, KSP, PC"| PETScLib
LinStabPy -->|"eigen and gain problems"| SLEPcLib
PETScLib -->|"sparse direct LU"| MUMPSLib
PETScLib -.->|"optional GPU factor"| CuDSSLib
SLEPcLib -->|"uses PETSc objects"| PETScLib
Main flows¶
Flow A. Temporal eigenvalue analysis¶
- Launch CLI or call the stability API.
- Initialize PETSc and MPI. Merge and validate YAML, env, and defaults.
- Load and preprocess mean flow. Build structured mesh with SBP.
- Compute LNSE coefficients. Assemble sparse \(L_0\). Apply BC recipes.
- Factorize the shifted operator at the \(\omega\) target.
- Run SLEPc near the target. Validate modes by residuals and boundary leakage.
- Emit eigenvalues, vectors, metrics, and provenance.
Flow B. Resolvent gain analysis¶
- Resolve frequency, weights, \(B\) and \(C\) maps, and backend policy.
- Reuse the same base flow, mesh, and \(L_0\) foundation as Flow A.
- Factorize \((L_0 - (\gamma + i\omega) I)\). Apply \(H\) and \(H^H\) through that factor.
- Run SLEPc on the weighted normal shell. Extract gains with \(\sigma = \sqrt{\mathrm{Re}(\lambda)}\).
- Package gains, modes, residuals, and solver metrics.
Flow C. Gain map over \(\beta\) and \(\omega\)¶
- Validate map, router, and resource policy.
- Assemble one \(L_0\) per spanwise wavenumber \(\beta\).
- Mark frequency bands. Walk lines with anchor factorizations, preconditioner reuse, residual gated refactor, and optional stable sweeps.
- Probe MUMPS, LU, and cuDSS backends under RAM and cost policy.
- Record leading gains with cost samples and certification metadata.
Flow D. Spatial stability¶
- Resolve
solver.spatialpolicy, with fallback tosolver.eigen. - Assemble spatial block pair from prepared coefficients and mesh.
- Configure direct shift-invert backend. Run generalized SLEPc solve for streamwise wavenumber and growth.
Decisions visible at this level¶
| Decision | What it means | Consequence |
|---|---|---|
| Port MATLAB workflows to Python HPC | Keep LinStab2D analysis semantics, add MPI orchestration | Familiar quantities, no MATLAB runtime |
| File based CFD boundary | Mean flow enters only as npy and npz |
Clean split from nonlinear solvers |
| PETSc and SLEPc as algebra stack | No custom distributed eigensolver | Strong fit with cluster numerical ecosystems |
| Factorize once, solve many | Direct factors serve shift-invert and resolvent applies | MUMPS and optional cuDSS appear explicitly |
| YAML with schema as contract | Validate before heavy compute | Config files are first class inputs |
| No GUI and no cloud tenancy | CLI with library and file payloads | Plotting and multi tenant ops stay outside |
| Structured SBP only | Exclude unstructured and full 3D frameworks | Narrow, deep scope |
| Lazy library import | Public API without PETSc init on import | Embeddable without forcing MPI at import time |
Technical architecture¶
Stack¶
| Layer | Choice |
|---|---|
| Language and packaging | Python, CLI entry plus importable package |
| Configuration | YAML cases, env overrides, defaults, typed models, schema checks |
| Local arrays and sparse | NumPy, SciPy CSC and CSR |
| Discretization | Structured mesh, SBP orders \(2\), \(4\), \(6\), \(8\), filters, pole treatments |
| Parallel runtime | MPI |
| Distributed algebra | PETSc Mat and Vec, KSP, PC |
| Eigen and gain algebra | SLEPc EPS |
| Sparse direct backends | MUMPS by default through PETSc, optional cuDSS |
| Data in | npy directories, npz archives, YAML |
| Data out | Result payloads with eigenvalues and vectors, gains, modes, metrics, provenance |
Patterns¶
| Pattern | Where it shows up |
|---|---|
| Staged pipeline | Config, base flow, mesh, operators and BCs, factorize, solve, payload |
| File and library boundary | Domain science inside, CFD files and PETSc and SLEPc and MPI outside |
| Factorize once, solve many | Shared layer under shift-invert eigen and resolvent applies |
| Strategy and backend registry | MUMPS, LU, and cuDSS selection under cost and RAM policy |
| Router optimized sweep | Anchors, recycling, residual gates, stable sweeps for \(\beta\) and \(\omega\) maps |
| Declarative BC recipes | Dirichlet and Neumann rules sequenced onto operators with free degree sets |
| Lazy facade API | Public surface defers heavy runtime init |
Key design choices¶
- Single policy source. Merged, validated YAML with env and defaults drives mesh, eigen, resolvent, MPI, and router behavior.
- Single operator family. Stability, adjoint, sensitivity, and resolvent consume BC enforced assembled operators, not ad hoc matrices per product.
- HPC first. MPI distributed vectors and matrices with case orchestration are first class. MATLAB parity is a workflow goal, not the scaling ceiling.
- Cost aware maps. Large \(\beta\) and \(\omega\) studies use the router. Factorization cost is explicit in metrics and certification, not hidden in a double loop.
- Strict boundary. Nonlinear CFD, visualization, unstructured 3D, general multiphysics, and cloud tenancy stay out of scope.
- Dual use. CLI and driver for full cases, importable library for embedding. Both share the same pipeline without forcing PETSc on import.
What connects most strongly inside¶
At context level the software is one bubble. The strongest internal relations, which explain why PETSc and SLEPc and MUMPS matter, are:
- Case Orchestration calls Configuration, Baseflow, Stability, Resolvent, Routing, Operators, and Linear Algebra
- Operator Assembly composes Mesh and consumes Baseflow data
- Stability and Resolvent consume Operators for \(L_0\) and Linear Algebra for factorized shifted solves
- Routing calls Resolvent and Linear Algebra for map walks and anchor reuse
Package detail lives in Architecture and the Module guide.
Summary¶
LinStabPy is an HPC Python CLI and library for compressible LNSE stability and resolvent analysis on structured SBP grids. It starts from base flow files and YAML cases and delivers spectra, modes, gains, sensitivity, metrics, and provenance. It excludes CFD generation, GUIs, and cloud service layers.
People are researchers, engineers, and developers. System is LinStabPy. External pieces are YAML and base flow file stores, NumPy and SciPy, MPI, PETSc, SLEPc, MUMPS, and optional cuDSS.
This overview sets the boundary for the rest of the docs.