179 lines
5.6 KiB
Markdown
179 lines
5.6 KiB
Markdown
# 2D Flat-Plate Boundary Layer — RANS k-ε with Neural Network damping functions
|
||
|
||
|
||
|
||
|
||
|
||
## Overview
|
||
The NN is trained on DNS channel flow data (Re_τ = 10 000) using `NN_SR.py`
|
||
and then loaded into the CFD solver via `calceps_NN_SR.py`.
|
||
|
||
---
|
||
|
||
## Directory structure
|
||
|
||
```
|
||
2d-example-boundary-layer/
|
||
├── pyCALC-RANS.py # main solver (do not edit)
|
||
├── global # global variable declarations (do not edit)
|
||
├── calc_earsm.py # empty EARSM placeholder (not used here)
|
||
│
|
||
└── boundary-layer-RANS-keps-NN/
|
||
├── run-python # bash script to assemble and run the solver
|
||
├── setup_case.py # case settings (turbulence model, BCs, solvers)
|
||
├── modify_case.py # hooks: modify_init, fix_eps, modify_eps, etc.
|
||
├── calceps_NN_SR.py # NN-augmented calceps (replaces calceps in solver)
|
||
├── generate-bound-layer-grid.py # grid generation script
|
||
├── plot_inlet_bound.py # post-processing and plotting
|
||
├── create-inlet-rans-profiles.py # saves inlet profiles for restarts
|
||
├── vel_2540_dns.prof # DNS reference data (Re_θ ≈ 2540)
|
||
├── x2d.dat, y2d.dat # grid files (generated by grid script)
|
||
├── z.dat # spanwise extent
|
||
└── nn/ # trained NN model files
|
||
├── model-f_2-f_mu-Re10000.pth
|
||
├── scaler-input0-f_2-f_mu-Re10000.bin
|
||
├── scaler-input1-f_2-f_mu-Re10000.bin
|
||
└── min-max-f_2-f_mu-Re10000.txt
|
||
```
|
||
|
||
---
|
||
|
||
## Changes from the original k-ω boundary layer case
|
||
|
||
### `setup_case.py`
|
||
|
||
| Parameter | Original (k-ω) | New (k-ε NN) |
|
||
|-----------|---------------|--------------|
|
||
| `kom` | `True` | `False` |
|
||
| `keps` | not set | `True` |
|
||
| `c_omega_1/2` | `5/9`, `3/40` | kept as dummies (required by solver init) |
|
||
| `prand_omega` | `2.0` | kept as dummy |
|
||
| `c_eps_1` | — | `1.5` |
|
||
| `c_eps_2` | — | `1.9` |
|
||
| `prand_eps` | — | `1.4` |
|
||
| `prand_k` | `2.0` | `1.4` |
|
||
| `urf_omega` | `0.5` | kept as dummy |
|
||
| `urf_eps` | — | `0.5` |
|
||
| `convergence_limit_om` | `-1e-6` | kept as dummy |
|
||
| `convergence_limit_eps` | — | `-1e-6` |
|
||
| `restart` | `True` | `False` (no eps restart file from k-ω run) |
|
||
| omega BCs | full block | replaced with eps BCs |
|
||
|
||
**Epsilon wall BC** (`eps_bc_south`) is set as Dirichlet but the value is
|
||
overridden every iteration by `fix_eps()` using ε = 2ν k/y².
|
||
|
||
### `modify_case.py`
|
||
|
||
- `modify_om` → replaced with `modify_eps` (same inlet injection logic)
|
||
- `fix_omega` → replaced with `fix_eps` (enforces ε = 2ν k/y² at south wall each iteration)
|
||
- `modify_init` → initialises `eps2d = Cμ k²/(100ν)` instead of `om2d`; **return order** is `u2d, v2d, k2d, om2d, eps2d, vis2d, dist`
|
||
|
||
### `calceps_NN_SR.py` (new file, injected by `run-python`)
|
||
|
||
Replaces `calceps` in `pyCALC-RANS.py`. Key differences from the standard solver:
|
||
|
||
- Loads `NuNet` model (tanh activations, dynamic layer list via `nn.ModuleList`)
|
||
- Predicts **both** f₂ and f_μ simultaneously (2-output network)
|
||
- Inputs: y⁺ (scaled with local u_τ from south wall) and y* (from ε)
|
||
- Outputs clipped to training min/max range
|
||
- Set `NN_bool = False` to fall back to standard analytic AKN expressions
|
||
|
||
### `run-python`
|
||
|
||
The original k-ω script used `cat` directly. The new script:
|
||
|
||
1. Renames `calceps` → `calceps_standard` in the solver (via `sed`)
|
||
2. Renames `fix_eps` → `fix_eps_standard` in the solver (via `sed`)
|
||
3. Injects `calceps_NN_SR.py` with the NN version before the solver
|
||
4. Uses `echo ""` between files to prevent concatenation syntax errors
|
||
|
||
```bash
|
||
#!/bin/bash
|
||
sed '/setup_case()/d' setup_case.py > temp_file
|
||
|
||
sed 's/def calceps/def calceps_standard/' ../pyCALC-RANS.py | \
|
||
sed 's/def fix_eps/def fix_eps_standard/' > temp_file1
|
||
|
||
{
|
||
cat ../global
|
||
echo ""
|
||
cat temp_file
|
||
echo ""
|
||
cat modify_case.py
|
||
echo ""
|
||
cat calceps_NN_SR.py
|
||
echo ""
|
||
cat temp_file1
|
||
} > exec-pyCALC-RANS.py
|
||
|
||
/chalmers/groups/lada_8/anaconda3/bin/python -u exec-pyCALC-RANS.py > out
|
||
```
|
||
|
||
---
|
||
|
||
## How to run
|
||
|
||
### Step 1 — Generate the grid (first time only)
|
||
|
||
```bash
|
||
cd boundary-layer-RANS-keps-NN/
|
||
python generate-bound-layer-grid.py
|
||
```
|
||
|
||
This produces `x2d.dat` and `y2d.dat`.
|
||
|
||
### Step 2 — Train the NN (first time only, or if re-training)
|
||
|
||
The NN files are already in `nn/`. If you need to retrain:
|
||
|
||
```bash
|
||
cd ../ # go to 2d-example-boundary-layer/
|
||
python NN_SR.py
|
||
```
|
||
|
||
This writes the model, scalers and min-max file into `nn/`.
|
||
|
||
### Step 3 — Link the nn/ folder into the case directory
|
||
|
||
```bash
|
||
cd boundary-layer-RANS-keps-NN/
|
||
ln -s ../nn nn # only needed if nn/ symlink does not already exist
|
||
```
|
||
|
||
### Step 4 — Run the CFD solver
|
||
|
||
```bash
|
||
chmod +x run-python # only needed once
|
||
./run-python
|
||
```
|
||
|
||
Output is written to `out`. Monitor convergence in a second terminal:
|
||
|
||
```bash
|
||
tail -f out | grep 'max res'
|
||
```
|
||
|
||
The run is converged when `max res` drops below `sormax = 5e-5` (set in `setup_case.py`).
|
||
|
||
### Step 5 — Plot results
|
||
|
||
```bash
|
||
python plot_inlet_bound.py
|
||
```
|
||
|
||
Produces the following figures:
|
||
|
||
| File | Contents |
|
||
|------|----------|
|
||
| `ustar-vs-x.png` | Friction velocity u_τ along the plate |
|
||
| `u_log_python.png` | U⁺ vs y⁺ (log), compared to DNS at Re_θ ≈ 2540 |
|
||
| `vis_python.png` | ν_t/ν vs y⁺ at three x stations |
|
||
| `vis_vs_y_python.png` | ν_t/ν vs y at three x stations |
|
||
| `eps_vs_y_python.png` | ε vs y at three x stations |
|
||
| `k_model_python.png` | k/u_τ² vs y⁺ at three x stations |
|
||
| `k_vs_y_python.png` | k/u_τ² vs y at three x stations |
|
||
| `cf_vs_re_mom.png` | Skin friction C_f vs Re_θ, compared to empirical correlation |
|
||
|
||
---
|
||
|