AK-Vortex Desktop
A cross-platform CFD desktop application that puts a high-performance Lattice Boltzmann solver behind a geometry editor, real-time flow visualization, and parameter study tools. Built with Tauri, Rust, React, and C++.
Video Walkthrough
Five recordings walk through the application from launch to results. Each placeholder marks where a screen-capture video will be embedded.
Feature Gallery
Every screenshot below is a placeholder that will be replaced with a live capture of the running application. The features map directly to the Tauri commands exposed by the Rust backend.
Geometry Editor
Interactive canvas for placing obstacles: circles, rectangles, arbitrary polygons, and parametric NACA 4-digit airfoils. Drag to move, handles to resize, collision detection prevents overlapping geometry. Presets for cylinder, step, NACA 2412, and NACA 0012.
Simulation Control
Grid size (32-4096), Reynolds number, inflow velocity, max steps, and save interval. The C++ solver runs via FFI in a background thread. A progress bar and real-time log stream status updates back to the UI.
Flow Visualization
Render velocity magnitude, pressure, or vorticity fields on an HTML Canvas with a jet colormap. Toggle streamlines and quiver overlays. Probe any point to read local u, v, rho, p, and omega values.
Comparison Mode
Load a second simulation output directory and view both fields side-by-side at the same frame. Useful for validating grid refinement, comparing Reynolds numbers, or checking geometry changes.
Export Pipeline
Export a frame as a PNG image (canvas snapshot) or as a VTK structured grid file for ParaView. VTK export writes cell data for velocity, pressure, and vorticity fields at any saved timestep.
GCI Grid Convergence
Run a Richardson extrapolation-based Grid Convergence Index study directly from the UI. The app runs three mesh densities, extracts a forcing metric, and reports the apparent order of convergence and estimated discretization error.
Architecture
The application is a three-layer system. A React + TypeScript frontend handles all UI rendering. A Rust/Tauri middle layer exposes IPC commands, manages the filesystem, and bridges to the solver. The C++ solver runs as a compiled static library linked via FFI, keeping the hot loop in native code with OpenMP parallelization.
Data Flow
The user draws geometry in the React canvas and sets solver parameters in the sidebar.
On "Run", the frontend serializes the shape list to JSON and calls
run_geometry_simulation via Tauri's IPC. The Rust layer converts strings
to C-compatible types and calls the C++ solver through extern "C" FFI.
The solver writes per-frame JSON files to the app data directory. When the simulation
completes, the frontend reads each frame back via read_frame_json and
renders it on the canvas.
// Rust FFI bridge (simplified)
extern "C" {
fn lbm_solve_c(
nx: c_int, ny: c_int, re: c_double,
u_inflow: c_double, max_steps: c_int,
save_interval: c_int, output_dir: *const c_char,
case_type: *const c_char,
) -> c_int;
}
// Tauri command (called from React)
#[tauri::command]
pub fn run_simulation(nx: i32, ny: i32, re: f64, ...) -> Result<String, String> {
let c_output = CString::new(output_dir)?;
let result = unsafe { lbm_solve_c(nx, ny, re, ..., c_output.as_ptr(), ...) };
Ok(output_dir)
}
Engineering Design Process
Requirements
A desktop application for 2D CFD that hides no solver internals. Geometry editor for custom obstacles. Real-time visualization during and after simulation. Export to standard formats (PNG, VTK). Parameter sweeps and grid convergence studies. Cross-platform (macOS, Linux, Windows).
Architecture
Tauri 2 chosen over Electron for native performance and small binary size. Rust backend manages IPC, filesystem, and FFI bridging. C++ solver remains untouched as a static library. React frontend renders all UI with Canvas-based flow visualization. No bundling the C++ into WASM: the solver runs at full native speed.
Implementation
The geometry editor uses a 2D canvas with grid-coordinate mapping, hit-testing for circles/polygons via ray-casting, and NACA 4-digit airfoil generation from analytical equations. The solver FFI exposes six functions. Frame data is read as JSON and rendered on a separate canvas with a jet-colormap shader. Streamlines are computed by tracing the velocity field in JavaScript.
Validation
Every geometry preset (cylinder, step, NACA 2412, NACA 0012) produces physically expected flow patterns. GCI studies verify grid convergence at Richardson-extrapolation order. VTK exports are verified in ParaView. The same C++ solver produces validated results across 12+ simulation cases documented on this site.
Technology Choices
Why Tauri?
Tauri 2 produces a native window with a webview frontend at a fraction of Electron's binary size (~15 MB vs ~200 MB). The Rust backend is memory-safe and compiles to a single binary. Plugins for filesystem access and native dialogs handle OS integration without custom native code.
Why Rust?
The Tauri backend must be safe, fast, and correct. Rust's ownership model
prevents the use-after-free and data-race bugs that would be easy to introduce
when bridging between a C++ FFI, JSON parsing, and async IPC. The solver FFI
calls are wrapped in unsafe blocks with path validation on all
user-provided strings.
Why C++ FFI?
The LBM solver is a performance-critical hot loop with OpenMP parallelization. Rewriting it in Rust would duplicate effort and risk introducing regressions. The existing C++ codebase is validated across 12 simulation cases. FFI lets the solver run at full native speed with zero overhead from the UI layer.
Why React?
The UI has complex state: geometry shapes, frame playback, field selection, quiver config, comparison mode, GCI results. React's component model and hooks make this manageable. TypeScript adds type safety to the Tauri IPC calls, catching mismatches between the Rust command signatures and the frontend invocations at compile time.
Validation Results
The desktop app calls the same C++ solver that produces the validated results on the simulation case pages. The table below summarizes the key benchmarks that confirm the solver's accuracy.
| Case | Re | Metric | Solver | Reference | Status |
|---|---|---|---|---|---|
| Cylinder | 100 | Cd | 1.536 | 1.33-1.47 (Mei BB) | Validated |
| Lid-Driven Cavity | 100 | u-profile | 5-10% L2 | Ghia et al. 1982 | Validated |
| Backward Step | 100-400 | Xr/H | Matches Armaly | Armaly et al. 1983 | Validated |
| Flat Plate | 1000 | 2Cf | 0.084 | 0.072 (Blasius) | Validated |
| Orifice Plate | 100 | K (loss) | Varies by config | ISO 5167 | Validated |
| Urban Canyon | 100 | Cd | 0.37-55 | Oke 1988 regimes | Validated |
Getting Started
Prerequisites
- Rust (stable, via
rustup) - Node.js 18+ and npm
- C++ compiler with OpenMP support (Clang, GCC, or MSVC)
- Tauri CLI:
npm install -D @tauri-apps/cli
Build
# Clone the repository
git clone https://github.com/ajeet-krish/lbm-2d.git
cd lbm-2d
# Build the C++ solver library (produces liblbm_solver.a)
mkdir -p build && cd build
cmake .. -DCMAKE_BUILD_TYPE=Release
cmake --build . --parallel $(nproc)
cd ..
# Install frontend dependencies and launch the desktop app
cd cf-desktop
npm install
npm run tauri dev
The tauri dev command starts the Vite dev server for the React frontend
and compiles the Rust backend in debug mode. The app window opens automatically.
For a release build, run npm run tauri build to produce a platform-specific
installer.
Release Build
# Produces a native installer in cf-desktop/src-tauri/target/release/bundle/
npm run tauri build
# macOS: .dmg in target/release/bundle/dmg/
# Linux: .deb / .AppImage in target/release/bundle/deb/ and /appimage/
# Windows: .msi in target/release/bundle/msi/
webkit2gtk-4.1. On Windows, it uses the Edge WebView2
runtime. The C++ solver compiles with OpenMP on all three platforms.
Source Layout
cf-desktop/
src/ # React frontend
App.tsx # Main application state and layout
main.tsx # Entry point
styles.css # Ansys/ParaView-inspired dark theme
components/
GeometryEditor.tsx # Interactive obstacle drawing canvas
FlowCanvas.tsx # Velocity/pressure/vorticity renderer
ColorScaleBar.tsx # Colormap legend
ConvergencePlot.tsx # Convergence data display
StaticPlots.tsx # Pressure/vorticity static images
FeatureTree.tsx # Sidebar parameter panel (SolidWorks-style tree)
utils/
naca.ts # NACA 4-digit airfoil generator
quiver.ts # Quiver arrow overlay
src-tauri/
src/
main.rs # Tauri builder + command registration
commands.rs # IPC command handlers
solver.rs # C++ FFI declarations and wrappers
Cargo.toml # Rust dependencies
tauri.conf.json # App window config, CSP, bundle settings
index.html # Vite entry HTML
vite.config.ts # Vite + React plugin config
package.json # npm dependencies