# akhileshmath/energy-stable-rom architecture

> Architecture diagram of the GitHub repository akhileshmath/energy-stable-rom, generated by GitDiagram from its file tree, README and a sample of source files (last updated 2026-06-24). It is an AI-made overview: check details against the source.

- Interactive diagram: https://gitdiagram.com/akhileshmath/energy-stable-rom
- Repository: https://github.com/akhileshmath/energy-stable-rom

## Overview

This repository is a research pipeline for incompressible-flow reduced-order modeling, centered on a single benchmark: the 2D flow past a cylinder at Reynolds 100. The architecture is stage-based: generate full-order snapshots, compress them with POD, assemble a Galerkin ROM, optionally augment it with a trained neural closure, then evaluate trajectories, energy behavior, and error bounds.

1. Full-order simulation layer  
The `fem_solver/` package is the high-fidelity PDE backend. It contains mesh generation, boundary-condition setup, Navier–Stokes formulation, time stepping, and snapshot collection. This is the only part that depends directly on the finite-element stack, with DOLFINx, Gmsh, MPI, and standard scientific Python libraries.

2. Snapshot production boundary  
The main output of the full-order layer is time-resolved velocity snapshot data saved under `data/snapshots/`. These snapshots are the interface between the PDE solver and the reduced-order pipeline; downstream components do not solve Navier–Stokes directly.

3. POD basis construction layer  
The `pod_rom/` package builds the reduced basis from snapshots. `pod_basis.py` computes the POD modes and singular values, while `galerkin_projection.py` projects the governing equations into reduced coordinates and assembles the reduced operators. The reduced model is driven by modal coefficients rather than the full velocity field.

4. Reduced-order dynamical core  
The ROM state is the vector of POD coefficients `a(t)`. The core reduced dynamics are a Galerkin system with linear viscous terms, nonlinear convective/modal-transfer terms, forcing, and an optional closure term. This is the central mathematical boundary in the repo: everything after POD works in reduced coordinates.

5. Neural closure subsystem  
The `neural_closure/` package adds a learned correction term to the ROM. `architecture.py` defines the closure network, and `trainer.py` handles training. The key architectural constraint is dissipativity in reduced coordinates, so the network is not just predictive; it is constrained to avoid spurious energy growth in the ROM.

6. Training and inference split for closure  
The closure model is trained offline from reduced-state data and then injected into a separate ROM rollout. That means the training path and simulation path are distinct: snapshots feed POD, POD feeds reduced trajectories, and reduced trajectories feed closure training. The trained model is then reused in enhanced ROM runs.

7. Analysis and stability layer  
The `analysis/` package contains `error_bounds.py`, which computes a posteriori indicators and long-time error estimates. This layer does not change the ROM itself; it post-processes reduced trajectories to evaluate stability, energy behavior, and trajectory deviation. It is conceptually downstream of both the standard ROM and the neural-augmented ROM.

8. Experiment orchestration  
The `scripts/` directory defines the end-to-end workflow in numbered stages:
- snapshot generation
- POD basis computation
- ROM assembly
- standard ROM run
- neural closure training
- enhanced ROM run
- error-bound computation
- figure generation

`run_full_pipeline.sh` is the top-level orchestrator. `scripts/config_utils.py` suggests the scripts are configuration-driven rather than hard-coded.

9. Configuration and reproducibility boundary  
`configs/default.yaml` and `configs/cylinder_vortex.yaml` provide experiment parameters, with the benchmark-specific config likely overriding the default settings for geometry, discretization, time horizon, and ROM dimensions. This configuration layer is what makes the pipeline reproducible across runs.

10. Persistent artifacts and data flow  
The repository stores intermediate and final artifacts in a structured way:
- `data/snapshots/` for snapshot arrays and ROM matrices
- `results/tables/` for computed summary metrics
- `paper/figures/` and `paper/tables/` for manuscript-ready outputs

The presence of `.npz` files in `data/snapshots/` indicates the pipeline already materializes reduced operators and POD coefficients for reuse.

11. Reporting and publication layer  
The `paper/` directory is a complete LaTeX manuscript that consumes outputs from the computational pipeline. Figures and tables generated by the scripts are embedded here, so the paper is effectively a downstream consumer of the numerical workflow rather than part of the solver stack.

12. Repository-level execution model  
This is not a service or interactive application; it is a batch scientific computing project. The architecture depends on offline numerical simulation, offline model reduction, offline neural training, and offline analysis/plot generation. The main runtime boundary is between MPI-enabled finite-element simulation and single-process or lighter-weight reduced-model training/evaluation.

Overall, the repo is organized as a one-way scientific pipeline: finite-element snapshots → POD compression → reduced Galerkin operators → optional dissipative neural closure → ROM evaluation and error analysis → figures/tables for the manuscript.

Main entry points: [`scripts`](https://github.com/akhileshmath/energy-stable-rom/tree/main/scripts) (Pipeline scripts), [`pod_rom/galerkin_projection.py`](https://github.com/akhileshmath/energy-stable-rom/blob/main/pod_rom/galerkin_projection.py) (Galerkin ROM), [`scripts/config_utils.py`](https://github.com/akhileshmath/energy-stable-rom/blob/main/scripts/config_utils.py) (Config utils), [`neural_closure/architecture.py`](https://github.com/akhileshmath/energy-stable-rom/blob/main/neural_closure/architecture.py) (Closure net)

## Diagram (Mermaid)

```mermaid
flowchart TD

subgraph group_pipeline["Pipeline"]
  node_scripts_pipeline["Pipeline scripts<br/>orchestration"]
  node_run_full_pipeline["Full pipeline<br/>orchestrator"]
  node_config_utils["Config utils<br/>config helper<br/>[config_utils.py]"]
end

subgraph group_fom["Full order"]
  node_mesh_generation["Mesh gen<br/>mesh prep<br/>[mesh_generation.py]"]
  node_boundary_conditions["Boundary conds<br/>PDE setup"]
  node_navier_stokes["Navier-Stokes<br/>PDE model<br/>[navier_stokes.py]"]
  node_time_stepping["Time stepping<br/>solver loop<br/>[time_stepping.py]"]
  node_snapshot_collector["Snapshot collector<br/>data capture"]
end

subgraph group_reduction["ROM core"]
  node_pod_basis["POD basis<br/>model reduction<br/>[pod_basis.py]"]
  node_galerkin_projection["Galerkin ROM<br/>reduced operators"]
  node_architecture["Closure net<br/>neural closure<br/>[architecture.py]"]
  node_trainer["Closure trainer<br/>training<br/>[trainer.py]"]
end

subgraph group_reporting["Reporting"]
  node_default_config["Default config<br/>experiment config<br/>[default.yaml]"]
  node_cylinder_config["Cylinder config<br/>benchmark config"]
  node_snapshots_data[("Snapshots<br/>artifact")]
  node_rom_matrices[("ROM matrices<br/>artifact")]
  node_coeff_data[("Coeff data<br/>artifact")]
  node_error_bounds["Error bounds<br/>analysis<br/>[error_bounds.py]"]
  node_paper_outputs["Paper outputs<br/>publication artifacts"]
end

node_run_full_pipeline -->|"drives"| node_scripts_pipeline
node_scripts_pipeline -->|"loads"| node_config_utils
node_config_utils -->|"reads"| node_default_config
node_config_utils -->|"overrides"| node_cylinder_config
node_scripts_pipeline -->|"stage 1"| node_mesh_generation
node_mesh_generation -->|"feeds"| node_boundary_conditions
node_boundary_conditions -->|"defines"| node_navier_stokes
node_navier_stokes -->|"solved by"| node_time_stepping
node_time_stepping -->|"emits"| node_snapshot_collector
node_snapshot_collector -->|"stores"| node_snapshots_data
node_snapshots_data -->|"input"| node_pod_basis
node_pod_basis -->|"basis for"| node_galerkin_projection
node_galerkin_projection -->|"writes"| node_rom_matrices
node_rom_matrices -->|"provides"| node_coeff_data
node_coeff_data -->|"trains"| node_trainer
node_trainer -->|"fits"| node_architecture
node_architecture -->|"augments"| node_galerkin_projection
node_galerkin_projection -->|"analyzed by"| node_error_bounds
node_architecture -->|"compared in"| node_error_bounds
node_error_bounds -->|"publishes"| node_paper_outputs
node_scripts_pipeline -->|"stage 8"| node_paper_outputs

click node_scripts_pipeline "https://github.com/akhileshmath/energy-stable-rom/tree/main/scripts"
click node_run_full_pipeline "https://github.com/akhileshmath/energy-stable-rom/blob/main/scripts/run_full_pipeline.sh"
click node_config_utils "https://github.com/akhileshmath/energy-stable-rom/blob/main/scripts/config_utils.py"
click node_default_config "https://github.com/akhileshmath/energy-stable-rom/blob/main/configs/default.yaml"
click node_cylinder_config "https://github.com/akhileshmath/energy-stable-rom/blob/main/configs/cylinder_vortex.yaml"
click node_mesh_generation "https://github.com/akhileshmath/energy-stable-rom/blob/main/fem_solver/mesh_generation.py"
click node_boundary_conditions "https://github.com/akhileshmath/energy-stable-rom/blob/main/fem_solver/boundary_conditions.py"
click node_navier_stokes "https://github.com/akhileshmath/energy-stable-rom/blob/main/fem_solver/navier_stokes.py"
click node_time_stepping "https://github.com/akhileshmath/energy-stable-rom/blob/main/fem_solver/time_stepping.py"
click node_snapshot_collector "https://github.com/akhileshmath/energy-stable-rom/blob/main/fem_solver/snapshot_collector.py"
click node_snapshots_data "https://github.com/akhileshmath/energy-stable-rom/tree/main/data/snapshots"
click node_pod_basis "https://github.com/akhileshmath/energy-stable-rom/blob/main/pod_rom/pod_basis.py"
click node_galerkin_projection "https://github.com/akhileshmath/energy-stable-rom/blob/main/pod_rom/galerkin_projection.py"
click node_rom_matrices "https://github.com/akhileshmath/energy-stable-rom/blob/main/data/snapshots/cylinder_vortex_rom_matrices.npz"
click node_coeff_data "https://github.com/akhileshmath/energy-stable-rom/blob/main/data/snapshots/cylinder_vortex_pod_coeffs.npz"
click node_architecture "https://github.com/akhileshmath/energy-stable-rom/blob/main/neural_closure/architecture.py"
click node_trainer "https://github.com/akhileshmath/energy-stable-rom/blob/main/neural_closure/trainer.py"
click node_error_bounds "https://github.com/akhileshmath/energy-stable-rom/blob/main/analysis/error_bounds.py"
click node_paper_outputs "https://github.com/akhileshmath/energy-stable-rom/tree/main/paper"

classDef toneNeutral fill:#f8fafc,stroke:#334155,stroke-width:1.5px,color:#0f172a
classDef toneBlue fill:#dbeafe,stroke:#2563eb,stroke-width:1.5px,color:#172554
classDef toneAmber fill:#fef3c7,stroke:#d97706,stroke-width:1.5px,color:#78350f
classDef toneMint fill:#dcfce7,stroke:#16a34a,stroke-width:1.5px,color:#14532d
classDef toneRose fill:#ffe4e6,stroke:#e11d48,stroke-width:1.5px,color:#881337
classDef toneIndigo fill:#e0e7ff,stroke:#4f46e5,stroke-width:1.5px,color:#312e81
classDef toneTeal fill:#ccfbf1,stroke:#0f766e,stroke-width:1.5px,color:#134e4a
class node_scripts_pipeline,node_run_full_pipeline,node_config_utils toneBlue
class node_mesh_generation,node_boundary_conditions,node_navier_stokes,node_time_stepping,node_snapshot_collector toneAmber
class node_pod_basis,node_galerkin_projection,node_architecture,node_trainer toneMint
class node_default_config,node_cylinder_config,node_snapshots_data,node_rom_matrices,node_coeff_data,node_error_bounds,node_paper_outputs toneRose
```

## Components

### Pipeline

End-to-end scientific workflow from simulation to analysis and publication outputs.

- [Pipeline scripts](https://github.com/akhileshmath/energy-stable-rom/tree/main/scripts): orchestration · Numbered stages that run the repository end-to-end. · `scripts`
- [Full pipeline](https://github.com/akhileshmath/energy-stable-rom/blob/main/scripts/run_full_pipeline.sh): orchestrator · Top-level shell entrypoint for the complete workflow. · `scripts/run_full_pipeline.sh`
- [Config utils](https://github.com/akhileshmath/energy-stable-rom/blob/main/scripts/config_utils.py): config helper · Shared configuration loading and stage setup for scripts. · `scripts/config_utils.py`

### Full order

Finite-element simulation backend and snapshot production.

- [Mesh gen](https://github.com/akhileshmath/energy-stable-rom/blob/main/fem_solver/mesh_generation.py): mesh prep · Builds the computational domain and mesh. · `fem_solver/mesh_generation.py`
- [Boundary conds](https://github.com/akhileshmath/energy-stable-rom/blob/main/fem_solver/boundary_conditions.py): PDE setup · Defines inflow, wall, and outlet conditions. · `fem_solver/boundary_conditions.py`
- [Navier-Stokes](https://github.com/akhileshmath/energy-stable-rom/blob/main/fem_solver/navier_stokes.py): PDE model · High-fidelity incompressible flow formulation. · `fem_solver/navier_stokes.py`
- [Time stepping](https://github.com/akhileshmath/energy-stable-rom/blob/main/fem_solver/time_stepping.py): solver loop · Advances the finite-element state in time. · `fem_solver/time_stepping.py`
- [Snapshot collector](https://github.com/akhileshmath/energy-stable-rom/blob/main/fem_solver/snapshot_collector.py): data capture · Stores time-resolved full-order fields for downstream reduction. · `fem_solver/snapshot_collector.py`

### ROM core

POD reduction, Galerkin assembly, and learned closure.

- [POD basis](https://github.com/akhileshmath/energy-stable-rom/blob/main/pod_rom/pod_basis.py): model reduction · Computes modes and singular values from snapshots. · `pod_rom/pod_basis.py`
- [Galerkin ROM](https://github.com/akhileshmath/energy-stable-rom/blob/main/pod_rom/galerkin_projection.py): reduced operators · Projects governing equations into reduced coordinates. · `pod_rom/galerkin_projection.py`
- [Closure net](https://github.com/akhileshmath/energy-stable-rom/blob/main/neural_closure/architecture.py): neural closure · Dissipative correction network in reduced coordinates. · `neural_closure/architecture.py`
- [Closure trainer](https://github.com/akhileshmath/energy-stable-rom/blob/main/neural_closure/trainer.py): training · Offline training for the learned ROM correction. · `neural_closure/trainer.py`

### Reporting

Batch orchestration, configuration, analysis, and manuscript outputs.

- [Default config](https://github.com/akhileshmath/energy-stable-rom/blob/main/configs/default.yaml): experiment config · Repository-wide default experiment parameters. · `configs/default.yaml`
- [Cylinder config](https://github.com/akhileshmath/energy-stable-rom/blob/main/configs/cylinder_vortex.yaml): benchmark config · Benchmark-specific settings for cylinder-flow runs. · `configs/cylinder_vortex.yaml`
- [Snapshots](https://github.com/akhileshmath/energy-stable-rom/tree/main/data/snapshots): artifact · Persistent snapshot and reduced-operator data used by the ROM pipeline. · `data/snapshots`
- [ROM matrices](https://github.com/akhileshmath/energy-stable-rom/blob/main/data/snapshots/cylinder_vortex_rom_matrices.npz): artifact · Stored reduced operators and POD coefficients for reuse. · `data/snapshots/cylinder_vortex_rom_matrices.npz`
- [Coeff data](https://github.com/akhileshmath/energy-stable-rom/blob/main/data/snapshots/cylinder_vortex_pod_coeffs.npz): artifact · Reduced-state coefficient snapshots used for ROM runs and closure training. · `data/snapshots/cylinder_vortex_pod_coeffs.npz`
- [Error bounds](https://github.com/akhileshmath/energy-stable-rom/blob/main/analysis/error_bounds.py): analysis · A posteriori indicators and long-time error estimates. · `analysis/error_bounds.py`
- [Paper outputs](https://github.com/akhileshmath/energy-stable-rom/tree/main/paper): publication artifacts · Figures, tables, and manuscript files that consume computed results. · `paper`

## Connections

- Full pipeline → Pipeline scripts: drives · The shell script executes the staged workflow.
- Pipeline scripts → Config utils: loads · Stages use shared configuration handling.
- Config utils → Default config: reads · Default parameters define the base experiment setup.
- Config utils → Cylinder config: overrides · Benchmark config specializes the default case.
- Pipeline scripts → Mesh gen: stage 1 · Initial full-order preprocessing creates the mesh.
- Mesh gen → Boundary conds: feeds · Geometry and domain setup support PDE boundary specification.
- Boundary conds → Navier-Stokes: defines · Boundary conditions are applied in the flow model.
- Navier-Stokes → Time stepping: solved by · The PDE is advanced through time integration.
- Time stepping → Snapshot collector: emits · Solver states are sampled during the trajectory.
- Snapshot collector → Snapshots: stores · Full-order snapshots are written as persistent artifacts.
- Snapshots → POD basis: input · Snapshot arrays are the basis construction input.
- POD basis → Galerkin ROM: basis for · The computed modes parameterize the reduced equations.
- Galerkin ROM → ROM matrices: writes · Reduced operators and coefficients are materialized for reuse.
- ROM matrices → Coeff data: provides · Reduced-state trajectories feed later stages and training.
- Coeff data → Closure trainer: trains · Reduced trajectories supervise the closure model.
- Closure trainer → Closure net: fits · Training instantiates the dissipative closure network.
- Closure net → Galerkin ROM: augments · The learned correction is injected into the reduced dynamics.
- Galerkin ROM → Error bounds: analyzed by · Reduced trajectories are post-processed for stability and error.
- Closure net → Error bounds: compared in · Enhanced ROM runs are evaluated against standard ROM behavior.
- Error bounds → Paper outputs: publishes · Computed metrics populate figures, tables, and manuscript sections.
- Pipeline scripts → Paper outputs: stage 8 · Final figure and table generation populates the paper.
