A responsive, browser-based OpenFOAM workspace built with Trame, VTK, and Docker.
FOAMTrame brings case selection, tutorial import, OpenFOAM command execution, live logs, run history, plots, and VTK post-processing into one glass-styled web interface. OpenFOAM operations run through a configured Docker image, while VTK rendering and data processing remain server-side.
- Start here
- Features
- Application workflow
- Architecture
- Requirements
- Installation
- Running FOAMTrame
- Using the application
- App-state persistence
- Backup and restore
- Supported datasets
- Optional Flask API
- Project structure
- Caching and performance
- Development checks
- Documentation maintenance
- Extension roadmap
- Contributing
- Troubleshooting
- Security notes
- License
Choose the shortest route for what you want to do. Every command in this README is intended to be run from the repository root.
| I want to… | Start with | Then read |
|---|---|---|
| Use FOAMTrame on Windows | Windows installation | Running FOAMTrame |
| Use FOAMTrame on Linux | Linux installation | Using the application |
| Run an unattended installation | Automated silent-install examples | Runtime configuration |
| Develop or review a change | Project structure | Development checks |
| Diagnose a problem | Troubleshooting | Security notes |
| Extend the product | Extension roadmap | Contributing |
Quick start on Windows:
.\install.ps1
.\start.ps1Quick start on Linux:
./install.sh
./start.shThe default URL is http://localhost:8087. Docker may be unavailable while the UI starts, but tutorial import and OpenFOAM execution need a reachable Docker daemon and configured image.
- Verifies the Trame server, Docker daemon, and configured OpenFOAM image.
- Detects
WM_PROJECT_VERSIONfrom the configured Docker image and displays it in the always-visible Setup sidebar footer, with an explicitly labelled configured-version fallback when the container runtime cannot be inspected. - Shows a dynamic
Build YYYY-MM-DDvalue in that footer. Packaged and CI builds may setFOAMTRAME_BUILD_DATE; local source runs fall back to theapp.pymodification date. - Scans a configurable case-root directory and restores the last active case.
- Creates a blank OpenFOAM case with
0,constant, andsystemdirectories. - Discovers official tutorials inside the Docker image.
- Provides searchable tutorial browsing and imports a selected tutorial into the local workspace.
- Disables active-case selection with a clear empty state when no cases exist.
Implementation: tabs/setup_tab.py
- Opens on Case when an active case exists and renders every supported native
surface under
constant/geometrywhen present, otherwise underconstant/triSurface. The Active geometry dropdown switches between that default and individual imported triSurface files. Reload case geometry resets the selector to the default before reloading it. - Falls back to Custom when no case is selected; case-dependent Case and Library controls remain visible but disabled.
- Clears the case render before switching to a session-only custom VTK or surface dataset.
- Browses
$FOAM_TUTORIALS/resources/geometryinside the configured OpenFOAM image and safely imports a selected resource into the active case. - Displays dataset type, aggregate point count, and aggregate cell count.
- Uses server-side VTK rendering with camera reset and interactive controls.
- Persists the preferred geometry mode, library selection, and per-case active geometry choice in SQLite and the portable JSON backup. Geometry files and uploaded datasets remain on disk and are not embedded in the database or backup.
Implementation: tabs/geometry_tab.py and backend/geometry/library.py
- The Meshing navigation surface is currently reserved for future meshing tools.
- OpenFOAM meshing commands such as
blockMeshare available from Run/Log.
Placeholder: tabs/meshing_tab.py
- Detects logical and physical CPU counts.
- Configures process count and reports decomposition status.
- Scans the active case and configured Docker image to expose only validated application actions while keeping unavailable commands visible with their exact missing prerequisite.
- Prefers a case-provided
Allrun; otherwise offers a reviewable guided sequence containing only confidently detected preprocessing, meshing, and solver steps. - Keeps WORKFLOW, DETECTED COMMANDS, and CLEANUP visible in the wider Run/Log sidebar. The compact command grid remains directly actionable, while the detailed capability list and unavailable reasons open from Available actions.
- Derives the solver application and optional solver module from
system/controlDictinstead of assumingsimpleFoamorpimpleFoam. - Detects
surfaceFeatureExtract,blockMesh,snappyHexMesh,topoSet,setFields,decomposePar,reconstructPar, andfoamToVTKfrom their dictionaries, decomposition directories, result times, and Docker executables. - Requires confirmation before
Allcleanand provides a separate safe-clean preview limited to detected time results, processor directories,postProcessing,VTK, andlog.*files. The initial0directory andconstant/polyMeshare preserved. - Streams console output and supports stopping the active process.
- Archives FOAMTrame console output separately from case-owned solver logs. A
case-provided
Allrunremains responsible forlog.foamRun, so launching or observing a run never truncates an existing residual log. - On Allclean, stages the current FOAMTrame archive outside the bind-mounted case
and writes
<case>/logs/run_<id>.logonly after the cleanup container exits. This prevents Windows from blocking the case script when it removeslogs. - Recognizes OpenFOAM's “already run” output. If every
Allrunstage is skipped, records the run as Skipped, uses a warning status instead of success, and shows a dismissible warning notification with reviewed cleanup guidance. Partial skips retain Completed status but are identified in both the console and an informational notification. Cleanup choices are emphasized, while safely escaped console output uses distinct command, information, warning, error, and ordinary output colors. Existing results are never deleted automatically. - Accepts additional validated runs while a simulation is active, executes them one at a time in FIFO order, and allows waiting jobs to be cancelled or cleared. Each submission retains the case and runtime configuration selected when it was queued.
- Retains up to 100 indexed run-history records in the application database.
Implementation: tabs/run_log_tab.py, the dependency-free FIFO worker in backend/simulation_queue.py, and the shared, fixed-ID action service in backend/case/capabilities.py. UI controls and future chatbot tools should resolve actions through this service rather than submitting arbitrary shell strings.
- Detects running simulations automatically, streams live updates, and serves completed results from the synchronized cache without a manual refresh.
- Selects scalar fields and renders scalar, velocity-magnitude, velocity-component, and residual charts.
- Switches between glass, white, black, and grey plot backgrounds with contrast-aware palettes.
- Supports Helvetica Neue-style (bundled TeX Gyre Heros), bundled Roboto, Times New Roman-style (bundled Liberation Serif), and Arial typography plus no logo, the FOAMFlask logo, or a custom image.
- Maximizes any plot while keeping the remaining charts available in a responsive sidebar.
- Exports each chart as a publication-friendly PNG with a consistent white paper background, regardless of the selected on-screen theme.
- Persists plot appearance and logo preferences in the unified app state so they participate in JSON backup and restore.
Implementation: tabs/plots_tab.py
- Reads VTK XML and legacy datasets plus common surface formats.
- Slices along the X, Y, or Z axis.
- Clips using plane, sphere, or box controls.
- Colours data using point or cell scalar arrays.
- Applies translation, rotation, and scale transforms.
- Shows adjustable translucent source context.
- Creates streamlines from available vector arrays.
Implementation: tabs/visualizer_tab.py and backend/post/postprocessor.py
- Downloads case configuration, plot preferences, security preferences, and run history as one versioned JSON backup.
- Validates uploaded backups before enabling restore.
- Applies restored configuration and history transactionally to SQLite and the live Trame state.
- Provides disabled-by-default, opt-in network binding, CORS, response-header, request-size, WebSocket-size, and companion-API-key controls. The ordinary server listener remains loopback-only unless explicitly changed.
Implementation: tabs/settings_tab.py and app_state.py. Database schema and transactions are implemented in database.py.
- Reads this
README.mddirectly from the repository; there is no second copy to become stale. - Splits level-two headings into a persistent, keyboard-accessible section list in the drawer; all section names remain discoverable without a dropdown.
- Renders headings, lists, tables, links, quotes, and fenced code blocks locally, without a CDN or browser-side Markdown dependency.
- Converts the supported fenced Mermaid
flowchart LRsubset into accessible inline SVG and safely displays unsupported Mermaid syntax as escaped code. - Sanitizes README content before it reaches Vue and provides Reload README for reviewing edits without restarting FOAMTrame.
Implementation: tabs/documentation_tab.py
- Open Setup and wait for both health checks.
- Select an existing case, create a blank case, or import an OpenFOAM tutorial.
- Inspect available case geometry in Geometry.
- Run meshing, solver, conversion, or case scripts from Run/Log.
- Monitor solver data under Plots.
- Inspect VTK results under Post.
- Consult the in-app Documentation page for setup, operating, and development guidance sourced from this README.
- Download periodic state backups from the gear-shaped Settings tab.
flowchart LR
Browser["Browser UI<br>Vue 2 + Vuetify"]
Trame["Trame server<br>app.py :8087"]
Services["Application services<br>shared human/agent commands"]
State["foamtrame.db<br>SQLite + WAL"]
Backup["Portable JSON<br>backup / restore"]
Agent["Future chatbot<br>typed tool calls"]
Docker["Docker daemon<br>OpenFOAM image"]
Cases["Case workspace<br>tutorial_cases/"]
VTK["VTK pipeline<br>geometry + post-processing"]
Browser <-->|"wslink state and actions"| Trame
Trame --> Services
Agent -->|"validated actions"| Services
Services <-->|"transactions"| State
State <-->|"export / restore"| Backup
Trame <-->|"container execution"| Docker
Docker <-->|"mounted case data"| Cases
Trame <-->|"scan/import/run"| Cases
Trame <-->|"server-side rendering"| VTK
The primary entry point is app.py. It composes each tab under tabs/, connects backend managers under backend/, and starts Trame on port 8087.
FOAMTrame uses SQLite as its operational database. This is deliberate: the current application is local, single-process software, so an embedded database preserves simple installation and portable project state without requiring a database server, credentials, or another container. WAL mode, foreign keys, a busy timeout, and short-lived per-operation connections make background simulation-thread access predictable.
The database boundary lives in database.py, while app_state.py retains the stable application-facing API. If FOAMTrame later becomes a hosted multi-user service or runs independent workers, that boundary should move to PostgreSQL rather than exposing SQL throughout the UI and backend modules.
The planned chatbot should not automate browser clicks. Buttons and chatbot tools should invoke the same application-service commands. The automation_actions table is reserved for durable parameters, confirmation state, execution status, results, errors, and audit history; destructive or expensive commands can therefore require explicit confirmation before execution.
- Docker Desktop or another reachable Docker daemon
- A modern browser with WebSocket support
- Enough memory for the selected VTK dataset and OpenFOAM container workload
Direct dependencies are declared in pyproject.toml, and the complete cross-platform environment is reproducibly pinned in uv.lock:
- Trame 3 and Trame-Vuetify 3
- VTK 9.3+
- Docker SDK for Python 7.1+
- Flask 3 and Flask-Compress
- Requests and psutil
Clone or download the repository. The supported installers use uv sync to create
the project .venv from uv.lock, initialize SQLite, run machine-readable
diagnostics, and preserve any existing database or JSON migration data. A global
Python and uv installations are optional on Windows and Linux x86_64. The
platform installer first uses an existing CPython 3.12 interpreter when one is
available through PATH (or the Windows Python launcher). Otherwise, it verifies
and extracts bundled CPython 3.12.13. It then prefers a system uv, falling back
to the verified bundled uv 0.10.12. Both local runtimes live only in the ignored
.foamtrame-tools/ directory, require no administrator privileges, and do not
modify PATH, the Windows registry, or existing Python installations.
.\install.ps1Install development/test dependencies as well:
.\install.ps1 --devChoose a specific Trame port, or let the installer select a free one:
.\install.ps1 --port 5087
.\install.ps1 --auto-portRun a fully unattended installation with no console progress:
.\install.ps1 --silent
# Unattended and automatically select a free port:
.\install.ps1 --silent --auto-portbash ./install.sh
# Include test tooling:
bash ./install.sh --devbash ./install.sh --port 5087
bash ./install.sh --auto-port# Fully unattended; command output is recorded instead of printed:
bash ./install.sh --silent
bash ./install.sh --silent --auto-portBoth installers accept --help, --dev, --skip-docker-check, --port,
--auto-port, and --silent (also --quiet or -q). The shared implementation is
install.py, so Windows and Linux follow the same installation
logic.
When neither port option is supplied, the installer uses 8087. It verifies
and reserves the selected port before creating the virtual environment or
installing packages. If 8087 (or an explicitly requested port) is unavailable,
installation stops with instructions to use --port PORT or --auto-port.
The successful selection is stored locally in .foamtrame-port and used by the
start scripts.
Silent mode is non-interactive: subprocess stdin and uv progress output are
disabled, and detailed command output is appended to
logs/YYYYMMDD/install.log. A successful silent install exits with code 0
without console output. Failures return a nonzero code and print only the log
location. Silent mode does not weaken port validation: without a port option it
still requires 8087 to be free; use --port PORT or --auto-port when that is
unsuitable.
The repository includes official compressed CPython and uv runtimes, published
checksums, and licenses for Windows x86_64 and Linux x86_64 (GNU libc). Therefore
an offline computer does not need Python or uv preinstalled. Compatible system
installations are preferred when available, while verified project-local copies
are installed automatically otherwise. Windows requires its built-in tar
utility; the standalone Python build also follows the standard CPython requirement
for the Microsoft Visual C++ runtime. Linux requires GNU libc 2.17 or newer,
tar, and either sha256sum or shasum.
Bundling Python and uv does not bundle VTK or the other packages referenced by
uv.lock. A first-time installation on a completely offline computer must also be
provided with those platform-specific packages, an already synchronized .venv,
or a populated uv cache. Docker-based OpenFOAM operations additionally require
Docker and the configured image to already be installed locally. Once these assets
are present, start.ps1 and start.sh are independent of global Python and uv
installations. The launchers use the installed .venv directly on normal starts;
the verified Python and uv bootstrap path is retained as a fallback when that
environment is absent.
Invoke the Windows installer directly from deployment software without loading a user profile or opening an interactive shell:
# Windows PowerShell 5.1
powershell.exe -NoProfile -NonInteractive -ExecutionPolicy Bypass -File .\install.ps1 --silent --auto-port
# PowerShell 7+
pwsh -NoProfile -NonInteractive -File .\install.ps1 --silent --auto-portUse the documented default port (8087) and fail if it is occupied:
# Windows PowerShell
.\install.ps1 --silent
if ($LASTEXITCODE -ne 0) { exit $LASTEXITCODE }# Linux shell
./install.sh --silentUse a fixed deployment port:
.\install.ps1 --silent --port 5087
if ($LASTEXITCODE -ne 0) { exit $LASTEXITCODE }./install.sh --silent --port 5087Automatically reserve a free port and read the selected value after installation:
.\install.ps1 --silent --auto-port
if ($LASTEXITCODE -ne 0) { exit $LASTEXITCODE }
$FoamTramePort = (Get-Content -LiteralPath .\.foamtrame-port -Raw).Trim()
Write-Output "FOAMTrame installed on port $FoamTramePort"./install.sh --silent --auto-port
FOAMTRAME_PORT="$(<.foamtrame-port)"
printf 'FOAMTrame installed on port %s\n' "$FOAMTRAME_PORT"Surface the dated installer log when an unattended installation fails:
.\install.ps1 --silent --auto-port
$InstallExitCode = $LASTEXITCODE
if ($InstallExitCode -ne 0) {
$LogFile = Join-Path (Join-Path .\logs (Get-Date -Format yyyyMMdd)) install.log
if (Test-Path -LiteralPath $LogFile) { Get-Content -LiteralPath $LogFile -Tail 100 }
exit $InstallExitCode
}if ! ./install.sh --silent --auto-port; then
log_file="logs/$(date +%Y%m%d)/install.log"
[[ -f "$log_file" ]] && tail -n 100 "$log_file"
exit 1
fiExample GitHub Actions steps:
- name: Install FOAMTrame unattended
shell: bash
run: ./install.sh --silent --auto-port
- name: Publish selected port to later steps
shell: bash
run: echo "FOAMTRAME_PORT=$(cat .foamtrame-port)" >> "$GITHUB_ENV"Make sure Docker is running and pull the default image if it is not already available:
docker pull haldardhruv/ubuntu_noble_openfoam:v12The image, OpenFOAM version, and case-root directory can be changed later under Setup → Advanced Settings.
Use the platform launcher after installation:
.\start.ps1./start.shThe launchers execute the synchronized .venv directly, call run.py,
forward termination signals, and keep the working directory deterministic. The
verified Python and uv bootstrap path remains available when .venv is absent;
routine launches do not repeat dependency resolution. The installer prints the
selected URL; with no port option it is
http://localhost:8087.
Trame's standard server arguments remain supported:
./start.sh --port 8090 --host 127.0.0.1Run diagnostics or initialize/upgrade the database independently:
uv run --locked python manage.py doctor
uv run --locked python manage.py init-db| Environment variable | Default | Purpose |
|---|---|---|
FOAMTRAME_DATA_DIR |
Repository directory | Database and legacy migration data |
FOAMTRAME_DATABASE_PATH |
<data-dir>/foamtrame.db |
Explicit SQLite database path |
FOAMTRAME_LOG_DIR |
<data-dir>/logs |
Base directory for date-grouped application logs |
FOAMTRAME_LOG_LEVEL |
INFO |
DEBUG, INFO, WARNING, ERROR, or CRITICAL |
FOAMTRAME_FRAMEWORK_LOG_LEVEL |
WARNING |
Trame/wslink verbosity; set to INFO only for framework diagnostics |
FOAMTRAME_STARTUP_TIMING |
Disabled | Set to 1 to log timed import, controller, layout, and server-ready checkpoints |
FOAMTRAME_PORT |
Installer selection (8087 when skipped) |
Override the installed port when --port is omitted |
Operational logs are grouped by the local start date using YYYYMMDD folders.
Structured application logs rotate at 5 MB with three retained backups under
logs/YYYYMMDD/foamtrame.log. Every start-script session is also appended
verbatim to logs/YYYYMMDD/run.log, including child stdout, stderr, the invoked
command, timestamps, and exit code. Silent installer output uses
logs/YYYYMMDD/install.log. CLI --host and --port override runtime defaults. When --host is
omitted, the Trame host comes from Settings → Security (127.0.0.1 by default).
Measure first-HTTP-response startup time without changing real settings:
.\.venv\Scripts\python.exe benchmarks\benchmark_startup.py --runs 3Add --verbose to include the internal startup checkpoints for bottleneck
diagnosis. The benchmark uses a temporary database, log directory, and free
loopback port for every run.
Use --data with a server-local supported dataset:
./start.sh --data /path/to/model.vtu- Open Setup.
- Select Create Blank Case.
- Enter a case name.
- Select Create Case.
The case is created below the configured CASE_ROOT and becomes active.
- Wait for Docker integration ready.
- Select Import Tutorial.
- Search the tutorial list.
- Select a tutorial source.
- Select Import Tutorial.
Tutorial discovery and import use the configured Docker image. The tutorial is copied into the local case workspace rather than edited inside the image.
- Choose an active case under Setup.
- Open Run/Log.
- Set the desired process count if parallel execution is required.
- Select a workflow or detected command from the drawer. Use Available actions to review the complete capability list and unavailable reasons.
- Follow output in Console Log Output.
- If
Allrunis reported as Skipped, review Allclean or Safe Clean Generated Outputs before rerunning. Cleanup is always explicit and confirmed.
Run history records command, case, status, timestamps, and duration. The main status chip and run history distinguish completed, skipped, failed, and running states using matching success, warning, error, and progress treatments.
FOAMTrame stores operational application state in one embedded database:
foamtrame.db
The database and its WAL sidecar files are excluded by .gitignore because they may contain machine-specific paths and local run history. SQLite stores configuration and simulation runs in relational tables; case folders, OpenFOAM result files, and large logs remain in the case workspace and are referenced by path rather than copied into database blobs.
JSON is now an interchange format only. A portable backup schema example remains available at app_state.json.example:
{
"version": 3,
"case_config": {
"CASE_ROOT": "/path/to/tutorial_cases",
"DOCKER_IMAGE": "haldardhruv/ubuntu_noble_openfoam:v12",
"OPENFOAM_VERSION": "12",
"ACTIVE_CASE": "aerofoilNACA0012"
},
"geometry_preferences": {
"preferred_mode": "case",
"library_selection": "",
"case_geometry_selections": {}
},
"run_history": [],
"plot_preferences": {
"font": "roboto",
"background": "glass",
"logo_mode": "foamtrame",
"custom_logo_data": ""
},
"security_preferences": {
"security_enabled": false,
"bind_mode": "loopback",
"cors_mode": "same_origin",
"cors_origin": "",
"security_headers": true,
"api_key_enabled": false,
"api_key_hash": "",
"max_request_mb": 2,
"websocket_max_message_mb": 4,
"session_timeout_enabled": false,
"session_timeout_minutes": 30
}
}Database updates use transactions. On first launch, an existing app_state.json is imported into SQLite; older case_config.json and run_history.json files are also supported as migration sources. Legacy files are left untouched so migration is recoverable, but SQLite becomes the source of truth once initialized.
The initial schema contains:
| Table | Responsibility |
|---|---|
schema_metadata |
Schema version and initialization markers |
app_config |
Typed JSON values for case root, active case, Docker image, and OpenFOAM version |
simulation_runs |
Indexed command, case, status, timestamps, duration, and complete compatible run record |
app_preferences |
Plot typography, background, and logo preferences |
geometry_preferences |
Preferred Geometry subpage and library selection |
security_preferences |
Validated network, CORS, header, size-limit, session-timeout, and API-key policy |
cases |
Relational case catalogue ready for workspace synchronization |
automation_actions |
Future chatbot/automation command queue and audit trail |
- Open the gear-shaped Settings tab.
- Select Backup JSON.
- Store
foamtrame-app-state.jsonsomewhere safe.
- Open Settings.
- Choose a previously downloaded
.jsonbackup. - Wait for validation to succeed.
- Select Restore App State.
Restore replaces the persisted case configuration, plot, geometry, and security preferences, and run history. It does not copy case directories, imported case geometry, simulation results, uploaded VTK datasets, or Docker images. If a backup references a case root that does not exist on the new machine, update Advanced Settings after restoring. Security preferences containing an API-key hash are transferable, but the original plain-text key cannot be recovered from a backup.
| Extension | Dataset or surface type |
|---|---|
.vtk |
VTK legacy dataset |
.vtu |
XML unstructured grid |
.vtp |
XML polydata |
.vti |
XML image data |
.vtr |
XML rectilinear grid |
.vts |
XML structured grid |
.ply |
Polygon surface |
.stl |
Triangulated surface |
.obj |
Wavefront surface |
Parallel XML collections such as .pvtu are not accepted through the single-file browser uploader because their referenced piece files must travel together.
flask_server.py exposes a companion HTTP API on port 5000. It is not required for the main Trame UI.
Start it separately when API access is needed:
python flask_server.pyWhen API-key protection is enabled in Settings → Security, mutating requests
(POST, PUT, PATCH, and DELETE) must include the generated key as
X-FOAMTrame-API-Key. Read-only requests remain available, subject to the selected
CORS policy. The companion API remains loopback-bound by default.
| Method | Endpoint | Purpose |
|---|---|---|
GET |
/get_case_root |
Read the configured case root |
GET |
/get_active_case |
Read the active case |
POST |
/set_active_case |
Change the active case |
POST |
/set_case |
Update case selection data |
GET |
/get_docker_config |
Read Docker/OpenFOAM configuration |
POST |
/set_docker_config |
Update Docker/OpenFOAM configuration |
GET |
/api/cases/list |
List local cases |
POST |
/api/case/create |
Create a blank case |
GET |
/api/tutorials |
Discover available tutorials |
POST |
/load_tutorial |
Import a tutorial |
GET |
/api/case/resolve_vtk |
Resolve the newest supported case dataset |
GET |
/api/startup_status |
Read backend startup status |
.
├── app.py # Main Trame application and global visual system
├── app_state.py # State API, legacy migration, JSON backup/restore
├── database.py # SQLite schema, transactions, and repository boundary
├── runtime.py # Runtime paths, logging, and preflight diagnostics
├── manage.py # Doctor and database administration commands
├── install.py # Shared cross-platform installer implementation
├── install.ps1 / install.sh # Windows and Linux installer entry points
├── start.ps1 / start.sh # Direct .venv launchers with bootstrap fallback
├── app_state.json.example # Portable state schema example
├── flask_server.py # Optional companion HTTP API
├── run.py # Process wrapper and signal forwarding
├── python_bootstrap.ps1/.sh # System/bundled CPython selection and extraction
├── uv_bootstrap.py # Verified system/bundled uv selection and extraction
├── pyproject.toml # Project metadata and direct dependencies
├── uv.lock # Reproducible dependency lockfile
├── benchmarks/ # Startup and cache microbenchmarks
├── vendor/uv/ # Offline uv archives, checksums, and upstream licenses
├── vendor/python/ # Offline CPython archives, checksums, and licenses
├── tests/
│ ├── integration/ # Database, migration, rollback, concurrency
│ └── smoke/ # One complete server availability test
├── .github/workflows/ci.yml # Windows/Linux automated verification
├── backend/
│ ├── case/ # Case-management helpers
│ ├── geometry/ # Geometry managers and visualization
│ ├── mesh/ # Mesh readers and utilities
│ ├── meshing/ # OpenFOAM meshing helpers
│ ├── plots/ # Realtime/cached plotting backend
│ ├── post/ # VTK post-processing backend
│ └── visualization/ # Shared visualization abstractions
├── static/
│ └── icons/ # FOAMTrame, Docker, and Trame assets
└── tabs/
├── setup_tab.py
├── geometry_tab.py
├── meshing_tab.py
├── run_log_tab.py
├── plots_tab.py
├── visualizer_tab.py
├── documentation_tab.py
└── settings_tab.py
Follow the links below for the principal implementation surfaces:
- Main application
- State persistence
- Database repository and schema
- UI tabs
- Backend modules
- Static assets
FOAMTrame uses Cachebox 6.1 for
thread-safe, bounded in-memory memoization. LRU caches cover repeated
controlDict metadata reads, safe-clean directory scans, OpenFOAM field-header
lookups, directory scans, compiled variable patterns, plot logos, and generated
geometry/mesh views. Repeated Docker executable probes use a five-second TTL to
coalesce rapid rescans without masking runtime changes for long. File-backed
keys include modification time (and file size where relevant), so a changed
case or asset naturally produces a cache miss.
Large live-result caches remain specialized and append-aware: residual logs and
time series reuse stable parsed history while reading only newly appended data.
Server startup keeps Matplotlib and bundled-font registration off the readiness
critical path. The Plots tab begins with lightweight SVG placeholders and loads
the plotting stack on its first real render; background case-data discovery still
starts eagerly. Use benchmarks/benchmark_startup.py and
FOAMTRAME_STARTUP_TIMING=1 to distinguish interpreter, import, layout, and
server-ready costs.
Cache capacities are deliberately bounded. High-cardinality field and file lookups retain up to 4,096 entries, directory scans up to 1,024, and rendered assets use smaller workload-specific limits. Selecting a different case or requesting a plot refresh continues to clear the relevant case-scoped entries.
The reproducible microbenchmark compares the uncached implementation with a warmed normal cache hit while retaining the same filesystem signature checks:
uv run --locked python benchmarks/benchmark_cachebox.pyOn Windows with CPython 3.13.7, using the default 2,000 iterations and the median of seven rounds, the implementation measured:
| Operation | Uncached (µs/call) | Cached (µs/call) | Speedup |
|---|---|---|---|
controlDict solver metadata |
486.36 | 28.90 | 16.8× |
| Safe-clean scan (200 outputs) | 6,254.79 | 10.62 | 588.7× |
These are local microbenchmarks, not end-to-end UI latency guarantees. Results vary with filesystem, antivirus, hardware, case size, and cache warmth; use the included script to measure the target machine.
Install the development profile first:
./install.sh --dev
# Windows: .\install.ps1 --devCompile the main Python modules after making changes:
uv run --locked python -m py_compile \
app.py app_state.py database.py flask_server.py \
tabs/setup_tab.py tabs/run_log_tab.py tabs/settings_tab.pyLint and type-check the Python code with the locked Ruff and ty versions:
uv run --locked ruff check .
uv run --locked ruff format --check .
uv run --locked ty checkRuff enforces the core Pyflakes and critical pycodestyle lint rules plus its
deterministic formatter. Run uv run --locked ruff format . to apply formatting
before committing. ty targets every supported platform and checks application
code, tests, and benchmarks while excluding scratch diagnostics. A narrow ty
override covers cachebox decorator-generated methods, and optional PyVista and
native accelerator imports remain valid when those components are not installed.
CodeAudit is installed only on Python 3.11+, so its exact optional API module is
also allowed to remain unresolved during Python 3.10 type checking.
On Python 3.11 or newer, run the CodeAudit SAST gate as well. Reviewed false
positives use inline # nosec comments with a reason; new medium, high, or
critical findings fail the command and CI:
uv run --locked python scripts/codeaudit_gate.py .Validate database initialization and the persisted state schema:
uv run --locked python -c "import app_state; from database import database; state = app_state.load_app_state(); print(database.path, state['version'], state.keys())"Run the integration suite:
uv run --locked python -m unittest discover -s tests/integration -v
# or
uv run --locked pytest -m integrationRun the cache benchmark after changing cache keys, capacities, or invalidation:
uv run --locked python benchmarks/benchmark_cachebox.pyRun the single end-to-end server smoke test:
uv run --locked python -m unittest tests.smoke.test_server_starts -v
# or
uv run --locked pytest -m smokeThe smoke test starts the complete application on an ephemeral loopback port, waits for an HTTP 200 HTML response, and always terminates the child process. It skips only when Trame/VTK are absent from the selected interpreter. The CI workflow installs the full runtime and runs all tests on both Windows and Linux.
For UI changes, check at least one desktop and one constrained viewport. Confirm that navigation remains reachable, cards do not overflow, and controls retain visible focus states.
This README is both the repository landing page and the source for FOAMTrame's in-app Documentation page. Keep it useful to both audiences:
- Add major topics as level-two (
##) sections. Each one automatically becomes a selectable in-app section. - Use level-three headings for tasks within a topic and keep heading names unique so anchor links remain predictable.
- Put the outcome and common command first, followed by constraints, alternatives, and implementation detail.
- Prefer relative repository links and fenced code blocks with a language label.
Use fenced
mermaidwithflowchart LRfor architecture diagrams; the in-app renderer converts the supported node-and-edge subset into accessible inline SVG. - Update the table of contents, relevant feature description, project tree, and troubleshooting guidance when a change affects them.
- Keep machine-local paths, credentials, API keys, databases, logs, and case results out of examples.
The in-app renderer deliberately supports a stable Markdown subset: headings, paragraphs, emphasis, links, ordered and unordered lists, blockquotes, tables, fenced code, and left-to-right Mermaid flowcharts. Unsupported or malformed Mermaid syntax is displayed safely as code instead of being executed. Raw HTML is not trusted in the application view. Repository-hosted Markdown can still use presentation HTML for badges and the centered logo. Validated relative file and directory links open their GitHub blob/tree targets, while validated relative images use the repository's raw-content URL. Missing paths, traversal outside the repository, and directories used as images are rejected.
When a topic grows large enough to obscure the main workflow, add a concise
summary here and move deep reference material into docs/<topic>.md. Link the new
guide from Start here, the table of contents, and the relevant feature section.
This keeps the README comprehensive as an index while allowing future material to
grow without turning one page into an unstructured manual.
The current service boundaries are intended to support future additions without duplicating validation or coupling new surfaces directly to UI buttons.
| Addition | Preferred extension point | Required safeguards |
|---|---|---|
| Meshing workflows | backend/meshing/ plus tabs/meshing_tab.py |
Resolve fixed action IDs and verify case prerequisites |
| New case commands | backend/case/capabilities.py |
Keep unavailable actions visible with reasons; never accept arbitrary shell text |
| Plot types and parsers | backend/plots/realtime_plots.py and tabs/plots_tab.py |
Preserve incremental reads, non-overlap layout, and white PNG export |
| Dataset readers or filters | backend/post/ and the owning UI tab |
Keep processing server-side and document accepted extensions |
| Automation or chatbot tools | Shared application/service actions | Require typed parameters, confirmation where needed, and durable audit state |
| Persistence fields | database.py, app_state.py, and backup normalization |
Add a migration, preserve transactions, and update app_state.json.example |
| Optional security controls | security.py and tabs/settings_tab.py |
Remain disabled by default and validate restored values before use |
| Additional documentation | A new ## section or focused docs/*.md guide |
Update navigation links and keep the in-app subset readable |
These are extension options, not promises of schedule or scope. New work should follow the same local-first behavior: Docker-dependent features may degrade, but the application shell and documentation should continue to start.
Before changing code, read AGENTS.md, inspect the nearest tests, and preserve unrelated workspace changes. Keep each change focused and compatible with Python 3.10 or newer.
A contribution is ready for review when it includes:
- the user-visible implementation and proportionate automated tests;
- documentation for changed behavior, configuration, or supported formats;
- schema and portable-backup updates for persistence changes;
- focused verification results and, for UI changes, desktop plus constrained-width visual checks;
- no machine-local databases, logs, ports, virtual environments, case results, or credentials.
Use the commands under Development checks. A pull request or handoff should summarize behavior, compatibility or migration impact, and the exact commands that passed.
- Start Docker Desktop or the Docker daemon.
- Confirm
docker versionworks from the same terminal. - Check that the configured image exists with
docker image ls. - Pull the default image if required.
- Verify Setup → Advanced Settings matches the intended OpenFOAM version.
- Confirm Docker integration reports ready.
- Check that the configured image contains
/opt/openfoam<version>/etc/bashrc. - Re-open Import Tutorial to trigger a cached-state republish.
- Inspect server output for tutorial-discovery errors.
- Create or import a case under Setup.
- Confirm
CASE_ROOTexists and is writable. - Select Refresh List after adding a case outside the application.
The backup stores the case name and root path, not the case directory. Copy the case data to the restored CASE_ROOT, or update the root path and refresh.
- Confirm the extension appears in Supported datasets.
- For case auto-loading, verify the file is inside the active case directory.
- Use a server-local
--datapath for very large datasets.
Restart FOAMTrame so the current Run/Log implementation is loaded, then retry the
confirmed Allclean action. Allclean output is staged outside the case until the
container exits, preventing an open host-side logs/run_<id>.log from blocking
the case script on Windows. Do not manually broaden cleanup beyond the reviewed
case action.
Run the installer with another port or request automatic assignment:
./install.sh --port 8090
./install.sh --auto-portFor an already installed application, a one-time launch override remains available:
./start.sh --port 8090Run python manage.py doctor with the installed interpreter and inspect the JSON result. A missing Docker executable is a warning because the UI can start without it, but OpenFOAM tutorial and simulation operations require a reachable daemon.
FOAMTrame can execute Docker containers and OpenFOAM commands against local case directories. Run it only in a trusted environment, review imported state files, and keep the default loopback binding for local use. The Settings restore flow validates structure and file size, but a restored case-root path still controls where the application reads and writes case data.
Optional controls are under Settings → Security. The entire security feature set is disabled by default and no optional policy is enforced until Enable optional security controls is switched on and saved:
- Allow network access changes the Trame listener from
127.0.0.1to0.0.0.0. A CLI--hostvalue still takes precedence. - CORS defaults to same-origin, can allow one exact trusted HTTP(S) origin, or can allow any origin. The any-origin mode is intentionally marked unsafe.
- Security headers add content-type, referrer, framing, and permissions-policy protections to Trame and companion-API responses.
- API key protection applies to mutating companion-API calls. Keys are generated with cryptographic randomness and persisted only as PBKDF2-SHA256 hashes. Copy a new key before saving because it cannot be displayed again.
- Request and WebSocket limits cap companion-API request bodies and wslink messages between 1 and 64 MiB.
- Session timeout is disabled by default. When enabled, FOAMTrame stops after the configured 1–1440 minute grace period with no browser connected. It does not interrupt an active browser session.
Listener, CORS, WebSocket-limit, and session-timeout changes require an application restart. The companion API evaluates its CORS, header, request-size, and API-key policy on each request. CORS is a browser policy—not authentication—and TLS should still terminate at a trusted reverse proxy for any network deployment.
Do not expose the single-process application directly to an untrusted network. A hosted or multi-user deployment needs TLS at a reverse proxy, authentication, per-user authorization, resource quotas, and a Trame launcher/process-isolation strategy. Chatbot actions that create cases, execute containers, or alter files must use the confirmation and audit boundary described in Architecture.
FOAMTrame is licensed under the GNU General Public License v3.0. See the repository's LICENSE file for the complete terms.