Wind tunnel case builder
This page produces the inputs that openfoam_case.py in
KeithBlackstock/windtunnel
writes into an OpenFOAM case: the duct domain, the background cell size, the snappyHexMesh
refinement levels and the model placement that comes from model_transformations.json.
Change a value here, copy the emitted code into the repository, run the generator.
What the repository runs today
- Geometry export.
export_stl()places the model with the saved 4×4 transform and writescase/constant/triSurface/model.stl. It warns if the mesh leaves the duct. - Dictionaries.
write_dicts()emitscontrolDict,blockMeshDict,snappyHexMeshDictandmeshQualityDictintocase/system/. - Meshing.
run_meshing()runsblockMesh -case casethensnappyHexMesh -case case -overwrite, producingcase/constant/polyMesh. - Dependencies that bite.
find_location_in_mesh()callsmesh.contains()andtrimesh.proximity.closest_point(). Both raiseModuleNotFoundErrorwithoutrtree, andclosest_point()also needsscipyfor its KD-tree. numpy and trimesh alone are not enough. - locationInMesh is picked automatically: the fluid candidate with the largest clearance to wall and model surface, ties going upstream.
| Python | 3.9+ with numpy, trimesh, rtree, scipy |
| Placement gizmo | pyvista, only for --reposition |
| Preview | plotly, only for preview_model_in_domain() |
| Meshing | blockMesh, snappyHexMesh on PATH |
| Distribution | OpenFOAM, or blueCFD-Core on Windows |
| Output | case/ beside the script |
Build a case
Values are millimetres. The generator rounds the domain to whole background cells, so pick a cell size that divides the duct exactly. Refinement level N gives a surface cell of background / 2N.
--reposition reopens the placement gizmo (PyVista) and rewrites
model_transformations.json; the first run opens it too, when no placement file exists yet.
STL_PATH or --stl PATH supplies the model; without either the script asks for it,
through a Tk dialog, or stdin when there is no terminal.
Shipped model.stl
The article in the repository as case/constant/triSurface/model.stl, drawn from its own
triangles. Every figure below is read from that file.
| Facets | 4,388 triangles |
| File size | 219,484 bytes |
| Bounds | x 32.79–67.38 · y 6.92–43.08 · z 21.89–26.95 mm |
| Placement | +40.7481 / +26.9389 / +20.2105 mm |
| Duct | 100 × 50 × 50 mm |
| Background | 5 mm → 20 × 10 × 10 = 2,000 hex |
| Refinement | level 2 to 3 → 1.25 to 0.625 mm surface cell |
What is in the tree
# meshing pipeline openfoam_case.py # exports STL, writes dicts, runs meshers fluid_volume_model.py # placement + STL loading model_transformations.json # saved 4x4 transform # case case/constant/triSurface/model.stl case/system/{controlDict,blockMeshDict,snappyHexMeshDict,meshQualityDict}
git clone https://github.com/KeithBlackstock/windtunnel.git cd windtunnel python -m pip install numpy trimesh rtree scipy python openfoam_case.py --stl /path/to/model.stl blockMesh -case case snappyHexMesh -case case -overwrite