Localhost web app: upload an IFC building model, place a single sound source in a 3D view, and see a live, color-coded sound-level heatmap across every room in the building — computed with a closed-form acoustic model, no GPU or neural network required.
IFC file ──IfcOpenShell──> per-element meshes + materials + room boundaries
│
├──> Three.js 3D view (place source 🔴, hide roof, isolate a level)
│
room boundary mesh ──point-in-mesh containment──> 3D sample grid (per room)
│
materials database ──absorption + surface density──┤
│ ▼
Beranek diffuse-field spreading (in-room) ──> per-point relative Level (dB)
+ mass-law transmission loss (cross-room) ──> colored live in the browser
- Windows 10/11 (works on Linux too), Python 3.10–3.11
- No GPU required to run the app. A CUDA GPU is only needed if you also want to run the separate offline validation pipeline described below.
- git on PATH
cd acoustic-sim
uv venv --python 3.11 .venv :: or: py -3.11 -m venv .venv
.venv\Scripts\activate
uv pip install --python .venv\Scripts\python.exe -r requirements.txtsetup.py additionally clones MESH2IR and downloads its pretrained weights —
that's only needed for the offline validation pipeline (see below), not for
running the live app. Skip it if you just want the heatmap tool.
Double-click start.bat — it starts the server with the local .venv
and opens http://127.0.0.1:8000 in your browser as soon as it responds.
Or manually:
.venv\Scripts\python.exe backend\main.pyOpen http://127.0.0.1:8000. One uvicorn process serves both the API and the frontend (no build step; Three.js loads from CDN).
- Upload — drag an
.ifcfile onto the page. Every tangible element (walls, slabs, roofs, doors, windows, stairs, railings, beams, columns, members, coverings, furniture, …) is meshed in world coordinates (meters) and rendered semi-transparent, colored by type. - Place the source — click a room's 🔴 button in the room list to drop the source at that room's center, or use Place Source + click a floor in the 3D view. Fine-tune with the X/Y/Z number inputs.
- View controls — Hide Roof to see inside from above; Level cycles All → Level 1 → Level 2 → … to isolate one storey on multi-storey models; Plan View for a top-down orientation; Fit View to frame the whole model; the Snap toggle controls whether placement clicks land on floors or exact clicked surfaces.
- Compute heatmap — press the button. The backend samples a 3D grid of points across every room (spacing adjustable via the slider, default 0.6 m), computes a relative sound level at each point, and renders them as a soft volumetric point cloud colored on the source room's own min/max range. Cross-room (through-wall) levels are computed too, but the rendered heatmap is currently bounded to the source's own room.
| Endpoint | Method | Purpose |
|---|---|---|
/health |
GET | GPU/CUDA status (informational — not required for /field) |
/upload |
POST (multipart) | parse IFC → scene graph JSON (elements, rooms, bounding box) |
/materials |
GET | acoustic material database (37 entries, 6 octave bands) |
/update-material |
POST | {element_id, material_name} override |
/field |
POST | {source_position, spacing} → sampled points with per-point relative Level (dB), room, distance, cross-room flag |
No simulation or neural network is used for the live heatmap — every value traces to a named closed-form formula:
- In-room spreading (Beranek/Hopkins-Stryker diffuse-field formula):
Lp(r) = SWL + 10·log10(1/(4πr²) + 4/R)dB, whereR = S·α/(1−α)is the room's own Sabine room constant, computed from that room's actual boundary surfaces and materials (not the whole building's). - Cross-room transmission (single-leaf mass law):
TL(f) = 20·log10(f) + 20·log10(m″) − 47dB at 1000 Hz,m″= the surface density of the actual material assigned to the nearest separating wall, then re-spread into the receiving room with the same formula. - Sampling: up to 3,000 points per building, generated per room proportional to its volume, filtered against each room's real watertight boundary mesh (not just its bounding box) so a pitched-roof room's sample cloud follows the real slope.
- Units: a relative, uncalibrated Level in dB — not a real sound-pressure level, not T60/EDT/C50.
Full assumptions and what this model does not account for (flanking
paths, single frequency band, uncalibrated source, etc.) are in
limitations_acoustics.MD.
| File | What it is | Elements | Rooms | Faces | Parse |
|---|---|---|---|---|---|
AC20-FZK-Haus.ifc |
2-storey house w/ spiral stair (KIT) | 82 | 7 | 21.6k | ~4 s |
AC20-Institute-Var-2.ifc |
44 m institute building, 253 furniture items (KIT) | 701 | 82 | 42.7k | ~9 s |
AC-20-Smiley-West-10-Bldg.ifc |
75 m apartment block, 30 stairs (KIT) | 831 | 140 | 181k | ~20 s |
Sources: KIT IFC Examples, made available by the Institute for Automation and Applied Informatics (IAI), Karlsruhe Institute of Technology (KIT), for unrestricted use with attribution in publications (more variants + a bridge there). Other public collections worth browsing: buildingSMART community sample files on GitHub, and the ThatOpen/IFC.js test file repos. Any IFC2x3/IFC4 file with geometry works — Revit/ArchiCAD exports included.
An earlier, separate pipeline — MESH2IR neural room-impulse-response
generation, a what-if material advisor, and a local LLM chat agent that
orchestrated both — is still present in the codebase
(backend/mesh2ir_runner.py, backend/advisor.py, backend/agent.py) and
is used for offline validation and research, but it is not wired into the
live app's endpoints. The live app answers "what does the sound level look
like across this whole building," which made the single-point
simulate/advise/chat workflow redundant for that question; those files
remain for the validation results below and are no longer imported by
backend/main.py.
validation/run_validation.py compares MESH2IR (with a physics-based
post-correction) against pyroomacoustics on the same source/listener pairs
across three buildings (FZK-Haus, Institute, Smiley-West; n = 147 complete
observations after two real bugs — whole-building-scoped correction and
mesh-simplification blur on large buildings — were found and fixed via
cross-building testing). Headline result: analytic mid-band Eyring is the
strongest T60 estimator in this experiment (0.173 s MAE across all
observations), outperforming both the uncalibrated and FZK-calibrated neural
pipelines; all methods reach 1.000 material-ranking agreement, so that
agreement is not evidence unique to the neural component. MESH2IR's
demonstrated role is audible, position-conditioned RIR generation — the
validation does not establish accurate C50 or EDT. Full numbers, the
Listen2Scene backbone comparison, and the reference-engine sensitivity sweep
are in validation/results/.
validation/agent_eval.py runs 9 scripted scenarios against the local LLM
chat agent (tool discipline, apply-only-when-asked policy, number grounding
against tool outputs, isolation honesty, robustness to bad input), with
repeated runs for pass-rate statistics. qwen3:8b: 39/5/1 PASS/PARTIAL/FAIL
over 45 runs; llama3.1: 23/1/3 over 27 runs. Results:
validation/results/agent_eval_qwen3_x5.json, agent_eval_llama31_x3.json.
See limitations_acoustics.MD for the full,
explicit breakdown. Summary: single dominant separating surface per room
pair (no flanking paths), diffuse sound field assumed per room, single
1000 Hz reference band despite a 6-band materials table, uncalibrated
source reference level, and a near-field distance clamp. None of these
choices were reviewed by an acoustician or BIM specialist.
acoustic-sim/
├── backend/
│ ├── main.py FastAPI app + static frontend mount (live endpoints)
│ ├── field.py 3D sound-field sampling for the live heatmap
│ ├── transmission.py closed-form Beranek + mass-law acoustic model
│ ├── room_geometry.py per-room boundary mesh + point-in-mesh containment
│ ├── ifc_parser.py IfcOpenShell → per-element meshes + materials
│ ├── materials_db.py 37 acoustic materials, NRC, fuzzy IFC matching
│ ├── mesh2ir_runner.py MESH2IR clone/weights/inference (validation only)
│ ├── advisor.py what-if material optimizer (validation only)
│ ├── agent.py local LLM chat agent (validation only)
│ └── audio_samples/ synthesized on first run (validation only)
├── frontend/index.html Three.js single-page UI (live heatmap app)
├── test_models/ verified public IFC samples (see above)
├── validation/ offline MESH2IR/pyroomacoustics validation + agent eval
├── requirements.txt
├── setup.py clone + weights + deps + CUDA check (validation only)
└── MESH2IR/ cloned upstream repo (created by setup, gitignored)