Flow Over Mounted Cube

The simulation of a wall-mounted cube is used for the validation of the combined features usage. The multiblock refined for a IBM body is used, the synthetic eddy method is applied at inlet to reproduce a category II velocity profile from EU standard. The turbulent flow around a surface-mounted cube is well estabilished in literature with results of experimental data available.

We seek to reproduce correct values of the average and standard deviation of the pressure in the cube surface.

[1]:
from nassu.cfg.model import ConfigScheme

filename = "./validation/wind_engineering/02_flow_over_wall_mounted_cube/02_flow_over_mounted_cube.nassu.yaml"

sim_cfgs = ConfigScheme.sim_cfgs_from_file_dct(filename)

The lateral boundaries and top of domain use free slip boundary conditions, for the outlet, a Neumann BC with fixed pressure is adopted.

Results

The results of the pressure coefficient are compared to the average of different laboratory results. An excellent agreement was achieved. The root mean squared pressure coefficent also presented great accordance with experimental data.

[2]:
import pathlib

import matplotlib.pyplot as plt
import numpy as np
import pandas as pd

import nassu.viz as common

common.use_style()


def get_experimental_profile_Cp(reynolds: float) -> dict[str, dict[str, pd.DataFrame]]:
    files_tau: dict[float, dict[str, dict[str, str]]] = {
        20000: {
            "frontal": {
                "Lim": "Re_20000_pressure_coefficient_frontal_lim2009.csv",
                "Holscher": "Re_20000_pressure_coefficient_frontal_holscher1998.csv",
            },
            "side": {
                "Lim": "Re_20000_pressure_coefficient_side_lim2009.csv",
            },
            "rms": {
                "Holscher": "Re_20000_pressure_coefficient_rms_top_lim2009.csv",
            },
            "skew": {
                "Holscher": "Re_20000_pressure_coefficient_skew_top_lim2009.csv",
            },
        }
    }
    files_get = files_tau[reynolds]
    vals_exp: dict[str, dict[str, pd.DataFrame]] = {}
    for type_file, dct in files_get.items():
        vals_exp[type_file] = {}
        for name, f in dct.items():
            filename = (
                pathlib.Path(
                    "validation/wind_engineering/02_flow_over_wall_mounted_cube/reference"
                )
                / f
            )
            # ([pos], [Cp])
            df = pd.read_csv(filename, delimiter=",")
            vals_exp[type_file][name] = df
    return vals_exp


exp = get_experimental_profile_Cp(20000)
holscher_frontal = exp["frontal"]["Holscher"]
holscher_top_rms = exp["rms"]["Holscher"]
holscher_top_skew = exp["skew"]["Holscher"]
lim_side = exp["side"]["Lim"]

Calculation of reference velocity:

[3]:
sim_cfgs.keys()
[3]:
dict_keys([('cubeFlowMultilevelLES', 0), ('cubeFlowMultiLevelLESnoCube', 0)])
[4]:
sim_cfg = sim_cfgs["cubeFlowMultiLevelLESnoCube", 0]
line_ref = sim_cfg.output.exports["velocity"].series.points["pitot"]
df_ref = line_ref.read_full_data("ux")

df_ref = df_ref[df_ref["time_step"] > 10000]

ux_avg = df_ref.mean()

u_ref = ux_avg["0"]
u_ref
[4]:
np.float32(0.05165463)
[5]:
from scipy.stats import skew
[6]:
sim_cfg = sim_cfgs["cubeFlowMultilevelLES", 0]
STATS_START = 10000

from nassu.viz import design_peak


def get_cp_line(line_names: list[str]) -> pd.DataFrame:
    line_series = sim_cfg.output.exports["pressure"].series.lines
    pressure_series = sim_cfg.output.exports["pressure"].series.points["pressure_point"]
    df_pref = pressure_series.read_full_data("rho")
    df_pref = df_pref[df_pref["time_step"] > STATS_START]
    rho_ref = df_pref["0"].to_numpy().T

    df_ret = pd.DataFrame({})
    for i, line in enumerate(line_names):
        df_hs = line_series[line].read_full_data("rho")
        df_hs = df_hs[df_hs["time_step"] > STATS_START]
        df_rho = df_hs.drop(columns=["time_step"])
        df_rho["rho_ref"] = rho_ref
        df_cp = (df_rho.subtract(df_rho["rho_ref"], axis=0)) / (1.5 * (u_ref**2))
        df_cp = df_cp.drop(columns=["rho_ref"])
        cp_avg = df_cp.mean().to_numpy().T
        cp_rms = df_cp.std().to_numpy().T
        cp_skew = skew(df_cp).T
        # Cook-Mayne / Gumbel design peaks per point: the suction (min) and
        # pressure (max) extremes of each point's time series.
        cp_arr = df_cp.to_numpy()
        cp_peak_min = np.array(
            [
                design_peak(cp_arr[:, j], n_epochs=10, sign=-1)["peak"]
                for j in range(cp_arr.shape[1])
            ]
        )
        cp_peak_max = np.array(
            [
                design_peak(cp_arr[:, j], n_epochs=10, sign=1)["peak"]
                for j in range(cp_arr.shape[1])
            ]
        )
        df_cp = pd.DataFrame(
            {
                "cp_avg": cp_avg,
                "cp_rms": cp_rms,
                "cp_skew": cp_skew,
                "cp_peak_min": cp_peak_min,
                "cp_peak_max": cp_peak_max,
            }
        )
        df_cp["pos"] = np.linspace(i, i + 1, num=len(cp_avg), endpoint=True)
        df_ret = pd.concat([df_ret, df_cp])
    return df_ret


lines_cp_frontal = [f"long_line{i}" for i in range(1, 4)]
df_cp_frontal = get_cp_line(lines_cp_frontal)
lines_cp_side = [f"tr_line{i}" for i in range(1, 4)]
df_cp_side = get_cp_line(lines_cp_side)
[7]:
fig, ax = common.fig_triple()

ax[0].plot(
    holscher_frontal["x/h"],
    holscher_frontal["Cp"],
    **common.markers.exp(shape="o"),
    label="Holscher (1998)",
)
ax[0].plot(
    df_cp_frontal["pos"],
    df_cp_frontal["cp_avg"],
    **common.markers.sim_line(linestyle="-"),
    label="AeroSim",
)
ax[0].set_ylim(-1.5, 1.5)
ax[0].set_ylabel(r"$C_{p,\mathrm{avg}}$")
ax[0].set_xlabel(r"$x/L$")
ax[0].legend()

n_points = len(df_cp_frontal["pos"])
df_top = df_cp_frontal[(df_cp_frontal["pos"] >= 1.0) & (df_cp_frontal["pos"] <= 2.0)]
ax[1].plot(
    holscher_top_rms["x/h"],
    holscher_top_rms["Cp"],
    **common.markers.exp(shape="o"),
    label="Lim (2009)",
)
ax[1].plot(
    df_top["pos"], df_top["cp_rms"], **common.markers.sim_line(linestyle="-"), label="AeroSim"
)
ax[1].set_ylabel(r"$C_{p,\mathrm{rms}}$")
ax[1].set_xlabel(r"$x/L$")
ax[1].legend()
ax[1].set_ylim(0, 0.6)
ax[1].set_xlim(1, 2)

ax[2].plot(
    holscher_top_rms["x/h"],
    holscher_top_skew["Cp"],
    **common.markers.exp(shape="o"),
    label="Lim (2009)",
)
ax[2].plot(
    df_top["pos"], df_top["cp_skew"], **common.markers.sim_line(linestyle="-"), label="AeroSim"
)
ax[2].set_ylabel(r"$C_{p,\mathrm{skew}}$")
ax[2].set_xlabel(r"$x/L$")
ax[2].legend()
ax[2].set_ylim(-1.5, 1)
ax[2].set_xlim(1, 2)

plt.tight_layout()
plt.show(fig)
../../../_images/validation_wind_engineering_02_flow_over_wall_mounted_cube_02_flow_over_wall_mounted_cube_10_0.png

Good accuracy of results were obtained against experimental data of the average and root mean squared pressure coefficient towards longitudinal direction. The results from Holscher, 1998 consist of an average of multiple wind tunnel experiments of a turbulent flow over a surface-mounted cube.

[8]:
fig, ax = common.fig_single()

ax.plot(lim_side["x/h"], lim_side["Cp"], **common.markers.exp(shape="o"), label="Lim (2009)")
ax.plot(
    df_cp_side["pos"],
    df_cp_side["cp_avg"],
    **common.markers.sim_line(linestyle="-"),
    label="AeroSim",
)

ax.set_ylabel(r"$C_{p,\mathrm{avg}}$")
ax.set_xlabel(r"$x/L$")
ax.set_ylim(-1.5, 1)

ax.legend()

plt.tight_layout()
plt.show(fig)
../../../_images/validation_wind_engineering_02_flow_over_wall_mounted_cube_02_flow_over_wall_mounted_cube_12_0.png

Good agreement was also observed along the transversal perimeter of the surface-mounted cube.

Peak pressure coefficients

The design peak (Cook-Mayne / Gumbel, via nassu.viz.design_peak) suction and pressure coefficients along the cube perimeter, computed from each point’s pressure time series. No committed wind-tunnel peak-\(C_p\) reference exists for this configuration (the literature peak/rms-\(C_p\) distributions are figure-only), so the simulated peaks are shown on their own, with the mean for context.

[9]:
fig, ax = common.fig_double()

for a, df_cp, name in [(ax[0], df_cp_frontal, "frontal / top"), (ax[1], df_cp_side, "side")]:
    a.plot(
        df_cp["pos"],
        df_cp["cp_peak_max"],
        **common.markers.sim_line(linestyle="-"),
        label="peak (max)",
    )
    a.plot(
        df_cp["pos"],
        df_cp["cp_peak_min"],
        **common.markers.sim_line(linestyle="--"),
        label="peak (min, suction)",
    )
    a.plot(df_cp["pos"], df_cp["cp_avg"], color=common.colors.exp, lw=1.0, alpha=0.6, label="mean")
    a.set_title(name)
    a.set_xlabel(r"$x/L$")
    a.set_ylabel(r"$C_p$ peak")
    a.legend(fontsize="small")

plt.tight_layout()
plt.show(fig)
../../../_images/validation_wind_engineering_02_flow_over_wall_mounted_cube_02_flow_over_wall_mounted_cube_15_0.png

Power Spectral Density

The power spectral density of the probe signals is computed to check the velocity fluctuations and to locate the wake-shedding peak. The frequency axis is expressed as a Strouhal number \(St = f L_u / u\) (with \(L_u\) the cube height), and the wake peak is compared against the reported shedding Strouhal numbers from the literature.

[10]:
import pandas as pd
[ ]:
from nassu.viz import read_series

sim_cfg = sim_cfgs["cubeFlowMultilevelLES", 0]

# The probe points live in the max-rate instantaneous series export named
# `spectrum` (the removed spectrum output kind, #1023). Each point is a
# single-point series; build one frame per (point, macr) with the macr as
# the column name so the PSD helper below reads it uniformly.
_spectrum_series = sim_cfg.output.exports["spectrum"].series


def read_df_point(point_name: str, macr: str) -> pd.DataFrame:
    probe = _spectrum_series.points[point_name]
    df = read_series(probe, macr, start_step=STATS_START)
    signal = df.drop(columns="time_step").iloc[:, 0]
    return pd.DataFrame({macr: signal, "time_step": df["time_step"]})


df_sa_pressure = read_df_point("point_pressure_top", "rho")
df_sa_velocity_top = read_df_point("point_velocity_top", "ux")
df_sa_velocity_wake = read_df_point("point_velocity_wake", "ux")
[ ]:
from nassu.viz import energy_spectrum

Lu = 2.8  # cube height H (lattice units): the convective length scale


def psd_strouhal(df, macr):
    """Variance-normalized premultiplied spectrum vs Strouhal St = f Lu / u.

    The probe is a max-rate series sampled every finest-level iteration, with
    the time step recorded in level-0 units, so the sampling interval is read
    directly from the ``time_step`` column rather than hard-coded.
    """
    series = df[macr].to_numpy(dtype=np.float64)
    dt = float(np.median(np.diff(df["time_step"].to_numpy())))
    f, S = energy_spectrum(series, dt)  # f in 1 / level-0 step
    st = f * Lu / u_ref
    return st, f * S / series.var()


st_1, psd_1 = psd_strouhal(df_sa_pressure, "rho")
st_2, psd_2 = psd_strouhal(df_sa_velocity_top, "ux")
st_3, psd_3 = psd_strouhal(df_sa_velocity_wake, "ux")
[13]:
# Reference wake-shedding Strouhal numbers (St = f H / U) from the literature.
# The full spectra are figure-only; only the reported peak St values are tabulated.
df_cube_st = pd.read_csv(
    "validation/wind_engineering/02_flow_over_wall_mounted_cube/reference/cube_shedding_strouhal.csv",
    comment="#",
)
df_cube_st
[13]:
bl_condition delta_over_H Re_H St mode status source
0 thin 0.2 10000.0 0.113 antisymmetric_shedding reported_value JFM, On the flow dynamics around a surface-mou...
1 thick 0.8 10000.0 0.086 antisymmetric_shedding reported_value JFM, On the flow dynamics around a surface-mou...
2 both NaN 10000.0 0.010 low_freq_symmetric_pumping reported_value JFM, On the flow dynamics around a surface-mou...
3 laminar NaN NaN 0.110 antisymmetric_shedding reported_value Int. J. Heat Fluid Flow, sciencedirect S014272...
4 turbulent NaN NaN 0.090 antisymmetric_shedding reported_value Int. J. Heat Fluid Flow, sciencedirect S014272...
[14]:
fig, ax = common.fig_triple()

panels = [
    ("Pressure top", st_1, psd_1),
    ("Velocity top", st_2, psd_2),
    ("Velocity wake", st_3, psd_3),
]
for a, (title, st, psd) in zip(ax, panels):
    a.plot(st, psd, color=common.colors.sim, alpha=0.8, label="AeroSim")
    a.set_title(title)
    a.set_xlabel(r"$f\,L_{u}/u$")
    a.set_xscale("log")
    a.set_yscale("log")
ax[0].set_ylabel(r"$f\,S_{uu}/ \sigma_{u}^{2}$")

# Overlay the literature wake-shedding Strouhal values and the simulated peak
# on the wake panel. The category-II inlet here is closest to the thin-BL value.
for j, st_val in enumerate(df_cube_st["St"]):
    ax[2].axvline(
        st_val,
        color=common.colors.refline,
        ls="--",
        alpha=0.5,
        label="lit. St" if j == 0 else None,
    )
st_peak_wake = float(st_3[np.argmax(psd_3)])
ax[2].axvline(
    st_peak_wake, color=common.colors.sim, ls=":", alpha=0.9, label=f"St peak = {st_peak_wake:.2f}"
)

for a in ax:
    a.legend(fontsize="small")

plt.tight_layout()
plt.show(fig)
../../../_images/validation_wind_engineering_02_flow_over_wall_mounted_cube_02_flow_over_wall_mounted_cube_22_0.png

Flow field

Instantaneous velocity magnitude on the cube planes (plane_series): the vertical symmetry plane (stagnation, separation and wake) and the horizontal plane at half cube height (horseshoe vortex), framed from the cube geometry.

[15]:
from nassu import viz

viz.enable_offscreen()

cfg = sim_cfgs["cubeFlowMultilevelLES", 0]
body, geom = viz.read_body(cfg, "cube")

panels = [
    viz.Panel(
        "vertical symmetry",
        viz.PlaneSource.from_cfg(cfg, series="plane_series", plane="vertical_symmetry"),
        viz.frame_body(geom, "y", downstream=1.0, half_extent=2.0),
    ),
    viz.Panel(
        "horizontal, half cube height",
        viz.PlaneSource.from_cfg(cfg, series="plane_series", plane="horizontal_half_h"),
        viz.frame_body(geom, "z", downstream=1.0, half_extent=2.0),
    ),
]
steps = [panels[0].source.steps[-1]]
plotter = viz.render_grid(
    panels,
    steps=steps,
    scalar="u_mag",
    cmap="viridis",
    clim=(0.0, 0.09),
    bar_title="|u|",
    bodies=[body],
)
plotter.show()
---------------------------------------------------------------------------
KeyError                                  Traceback (most recent call last)
Cell In[15], line 11
      7
      8 panels = [
      9     viz.Panel(
     10         "vertical symmetry",
---> 11         viz.PlaneSource.from_cfg(cfg, series="plane_series", plane="vertical_symmetry"),
     12         viz.frame_body(geom, "y", downstream=1.0, half_extent=2.0),
     13     ),
     14     viz.Panel(

File ~/Documents/Codigos/AeroSim/nassu/nassu/viz/fields.py:190, in PlaneSource.from_cfg(cls, cfg, series, plane, project_root)
    187 @classmethod
    188 def from_cfg(cls, cfg, series: str, plane: str, project_root=None) -> "PlaneSource":
    189     """Open the plane ``plane`` of historic series ``series``."""
--> 190     export = cfg.output.series[series].planes[plane]
    191     xdmf = _resolve(export.xdmf_filename, project_root)
    192     return cls._from_xdmf(cfg, xdmf, f"plane series {series}.{plane}")

KeyError: 'vertical_symmetry'

Version

[ ]:
sim_info = sim_cfg.output.read_info()

nassu_commit = sim_info["commit"]
nassu_version = sim_info["version"]
print("Version:", nassu_version)
print("Commit hash:", nassu_commit)
Version: 1.6.51
Commit hash: 8df9b1583e06d6d8c62a3b7a522ae42bdc82d42a

Configuration

[ ]:
from IPython.display import Code

Code(filename=filename)
variables:
  simul:
    dev_time: 10000
    stats_time: 30000
    scale: !math 1/16
    plane_height: 5.01
    sigma_sem: 20
    body_pos: 150
  domain:
    length: 600
    width: 160
    height: 96
  var:
    cube_length: 2.8
    body_lvl: 5
    # Inlet reference (top-of-profile) lattice velocity, from the SEM profile
    # CSV (Uh = 0.06). Used as the velocity scale for the Mach-derived NonEqTBL
    # pressure-gradient multiplier below.
    u_ref: 0.06
    # Lattice Mach number Ma_LBM = U_LBM / cs, cs = 1/sqrt(3). Driving the
    # NonEqTBL pressure-gradient multiplier from this value rescales the raw
    # `dp/ds` magnitude back to the incompressible-equivalent expectation of the
    # TBL ODE - see `theory/wall_model/neq_pres_filter`.
    Ma_LBM: !math ${var.u_ref} * (3 ** 0.5)
  aux:
    offset: !math 2*(1/(2**${var.body_lvl}))
    ref_delta: 0.02

simulations:
  - name: cubeFlowMultilevelLES
    save_path: ./validation/wind_engineering/02_flow_over_wall_mounted_cube/results/

    n_steps: !math "${simul.dev_time}+${simul.stats_time}"

    report:
      frequency: 1000

    data:
      divergence: { frequency: 1 }
      monitors:
        fields:
          macrs_stats:
            macrs: [rho, u]
            stats: [min, max, mean]
            interval: { start_step: 0, frequency: 10 }
      instantaneous:
        full_domain: { interval: { frequency: 0 }, macrs: [rho, u] }
      export_IBM_nodes:
        ibm_exp:
          body_name: cube
          frequency: 5000
      probes:
        historic_series:
          pressure:
            macrs: ["rho"]
            interval: { frequency: 1, lvl: 0 }
            points:
              pressure_point:
                pos:
                  !math [
                    "${simul.body_pos}",
                    "0.5*${domain.width}",
                    "0.5*${domain.height}-32",
                  ]
            lines:
              long_line1:
                dist: 0.0625
                start_pos:
                  !math [
                    "${simul.body_pos} - 0.5*${var.cube_length} - ${aux.offset}",
                    "0.5*${domain.width}",
                    "${simul.plane_height}",
                  ]
                end_pos:
                  !math [
                    "${simul.body_pos} - 0.5*${var.cube_length} - ${aux.offset}",
                    "0.5*${domain.width}",
                    "${simul.plane_height} + ${var.cube_length}",
                  ]
              long_line2:
                dist: 0.0625
                start_pos:
                  !math [
                    "${simul.body_pos} - 0.5*${var.cube_length}",
                    "0.5*${domain.width}",
                    "${simul.plane_height} + ${var.cube_length} + ${aux.offset}",
                  ]
                end_pos:
                  !math [
                    "${simul.body_pos} + 0.5*${var.cube_length}",
                    "0.5*${domain.width}",
                    "${simul.plane_height} + ${var.cube_length} + ${aux.offset}",
                  ]
              long_line3:
                dist: 0.0625
                start_pos:
                  !math [
                    "${simul.body_pos} + 0.5*${var.cube_length} + ${aux.offset}",
                    "0.5*${domain.width}",
                    "${simul.plane_height} + ${var.cube_length}",
                  ]
                end_pos:
                  !math [
                    "${simul.body_pos} + 0.5*${var.cube_length} + ${aux.offset}",
                    "0.5*${domain.width}",
                    "${simul.plane_height}",
                  ]
              tr_line1:
                dist: 0.0625
                start_pos:
                  !math [
                    "${simul.body_pos}",
                    "0.5*${domain.width} - 0.5*${var.cube_length} - ${aux.offset}",
                    "${simul.plane_height}",
                  ]
                end_pos:
                  !math [
                    "${simul.body_pos}",
                    "0.5*${domain.width} - 0.5*${var.cube_length} - ${aux.offset}",
                    "${simul.plane_height} + ${var.cube_length}",
                  ]
              tr_line2:
                dist: 0.0625
                start_pos:
                  !math [
                    "${simul.body_pos}",
                    "0.5*${domain.width} - 0.5*${var.cube_length}",
                    "${simul.plane_height} + ${var.cube_length} + ${aux.offset}",
                  ]
                end_pos:
                  !math [
                    "${simul.body_pos}",
                    "0.5*${domain.width} + 0.5*${var.cube_length}",
                    "${simul.plane_height} + ${var.cube_length} + ${aux.offset}",
                  ]
              tr_line3:
                dist: 0.0625
                start_pos:
                  !math [
                    "${simul.body_pos}",
                    "0.5*${domain.width} + 0.5*${var.cube_length} + ${aux.offset}",
                    "${simul.plane_height} + ${var.cube_length}",
                  ]
                end_pos:
                  !math [
                    "${simul.body_pos}",
                    "0.5*${domain.width} + 0.5*${var.cube_length} + ${aux.offset}",
                    "${simul.plane_height}",
                  ]
        spectrum_analysis:
          macrs: ["rho", "u"]
          points:
            point_pressure_top:
              pos:
                !math [
                  "${simul.body_pos}",
                  "0.5*${domain.width}",
                  "${simul.plane_height} + ${var.cube_length} + ${aux.offset}",
                ]
            point_velocity_top:
              pos:
                !math [
                  "${simul.body_pos}",
                  "0.5*${domain.width}",
                  "${simul.plane_height} + 1.14*${var.cube_length}",
                ]
            point_velocity_wake:
              pos:
                !math [
                  "${simul.body_pos} + 1.5*${var.cube_length}",
                  "0.5*${domain.width} + 0.5*${var.cube_length}",
                  "${simul.plane_height} + ${var.cube_length}",
                ]

    domain:
      domain_size:
        x: !math "${domain.length}"
        y: !math "${domain.width}"
        z: !math "${domain.height}"
      block_size: 8
      bodies:
        cube:
          IBM:
            cfg_use: body_wm
            order: 2
          geometry_path: fixture/lnas/basic/cube_no_floor.lnas
          small_triangles: "add"
          transformation:
            scale:
              !math [
                "0.1*${var.cube_length}",
                "0.1*${var.cube_length}",
                "0.1*${var.cube_length}",
              ]
            translation:
              !math [
                "${simul.body_pos} - 0.5*${var.cube_length}",
                "0.5*${domain.width} - 0.5*${var.cube_length}",
                "${simul.plane_height}",
              ]
        full_plane:
          IBM:
            cfg_use: terrain_wm
          geometry_path: fixture/stl/wind_tunnel/full_plane.stl
          small_triangles: "add"
          transformation:
            translation: !math [0, 0, "${simul.plane_height}"]
        obstacles_category_II:
          IBM:
            order: 1
          geometry_path: fixture/stl/wind_tunnel/category_II/plates_Nx160Ny70_6x2_spacing16x32_offset19y.stl
          volumes_limits:
            body_transformed:
              - start: !math [4, 20, 0]
                end:
                  !math [
                    "${simul.body_pos} - 0.75*${var.cube_length}",
                    "${domain.width} - 20",
                    "${domain.height}",
                  ]
          small_triangles: "add"
          transformation:
            scale:
              !math [
                "64.0*${simul.scale}",
                "64.0*${simul.scale}",
                "32.0*${simul.scale}",
              ]
            translation: !math [0, 0, "${simul.plane_height}"]
      refinement:
        static:
          lvl1:
            volumes_refine:
              - start: [0.0, 55.0, 0.0]
                end: [272.0, 105.0, 32.0]
                lvl: 1
                is_abs: true
          lvl2:
            volumes_refine:
              - start: [0.0, 67.5, 0.0]
                end: [208.0, 92.5, 20.0]
                lvl: 2
                is_abs: true
          lvl3:
            volumes_refine:
              - start: [0.0, 73.75, 2.0]
                end: [176.0, 86.25, 14.0]
                lvl: 3
                is_abs: true
          lvl4:
            volumes_refine:
              - start: [140.0, 76.875, 4.0]
                end: [160.0, 83.125, 11.0]
                lvl: 4
                is_abs: true
          body_refinement:
            bodies:
              - body_name: cube
                lvl: 5
                normal_offsets: !range [-0.25, 0.751, 0.125]
                transformation:
                  translation: !math [0, 0, "-${aux.ref_delta}"]
              - body_name: cube
                lvl: 5
                normal_offsets: !range [-0.25, 0.751, 0.25]
    models:
      precision:
        default: single

      LBM:
        tau: 0.50002
        vel_set: D3Q27
        coll_oper: RRBGK
      initialization:
        sem_field: true
      engine:
        name: CUDA

      BC:
        periodic_dims: [false, false, false]
        BC_map:
          - pos: E
            BC: RegularizedNeumannOutlet
            rho: 1.0
            wall_normal: E
            order: 2

          - pos: F
            BC: Neumann
            wall_normal: F
            order: 1

          - pos: B
            BC: RegularizedHWBB
            wall_normal: B
            order: 1

          - pos: N
            BC: Neumann
            wall_normal: N
            order: 0

          - pos: S
            BC: Neumann
            wall_normal: S
            order: 0
        SEM:
          eddies:
            lengthscale:
              {
                x: !sub "${simul.sigma_sem}",
                y: !sub "${simul.sigma_sem}",
                z: !sub "${simul.sigma_sem}",
              }
            eddies_vol_density: 300
            domain_limits_yz:
              start: !math ["${simul.sigma_sem}", "-${simul.sigma_sem}"]
              end:
                !math [
                  "${domain.width}-${simul.sigma_sem}",
                  "${domain.height}-${simul.sigma_sem}",
                ]
          profile:
            csv_profile_data: "fixture/SEM/category_vprofile/profile_log_cat2_H150_Uh0.06.csv"
            z_offset: !math "${simul.plane_height}"
            length_mul: !math "${simul.scale}"

      LES:
        model: Smagorinsky
        sgs_cte: 0.17

      IBM:
        forces_accomodate_time: 0
        dirac_delta: "3_points"
        body_cfgs:
          default:
            n_iterations: 3
            forces_factor: 1.0
          terrain_wm:
            n_iterations: 3
            forces_factor: 0.5
            kinetic_energy_correction: false
            wall_model:
              name: EqLog
              dist_ref: 3.125
              dist_shell: 0.125
              start_step: 5000
              params:
                z0: !math "0.05*${simul.scale}"
                TDMA_max_error: 1e-04
                TDMA_max_iters: 10
                TDMA_max_div: 51
          body_wm:
            n_iterations: 3
            forces_factor: 0.25
            wall_model:
              name: NonEqTBL
              dist_ref: 3.125
              dist_shell: 0.125
              start_step: 10000
              params:
                z0: !math "0.05*${simul.scale}"
                TDMA_max_error: 1e-04
                TDMA_max_iters: 10
                TDMA_min_div: 51
                TDMA_max_div: 51
                NeqWM_u_friction_floor: 1.0e-4
                # Magnitude-rescaling of dp/ds from the LBM weakly-compressible
                # signal to the incompressible-equivalent expectation of the
                # TBL ODE - see the theory page for the derivation.
                NeqWM_pres_grad_mult: !math ${var.Ma_LBM}

  - name: cubeFlowMultiLevelLESnoCube
    parent: cubeFlowMultilevelLES
    run_simul: true

    n_steps: !math "${simul.dev_time}+${simul.stats_time}"

    data:
      divergence: { frequency: 1 }
      export_IBM_nodes: !not-inherit {}
      probes: !not-inherit
        historic_series:
          velocity:
            macrs: ["u"]
            interval: { frequency: 1, lvl: 0 }
            points:
              pitot:
                pos:
                  !math [
                    "${simul.body_pos}",
                    "0.5*${domain.width}",
                    "${simul.plane_height} + ${var.cube_length}",
                  ]
            lines:
              velocity_profile:
                dist: 0.0625
                start_pos:
                  !math [
                    "${simul.body_pos}",
                    "0.5*${domain.width}",
                    "${simul.plane_height}",
                  ]
                end_pos:
                  !math [
                    "${simul.body_pos}",
                    "0.5*${domain.width}",
                    "${simul.plane_height} + ${var.cube_length}",
                  ]

    domain:
      bodies: !not-inherit
        full_plane:
          IBM:
            cfg_use: terrain_wm
          geometry_path: fixture/stl/wind_tunnel/full_plane.stl
          small_triangles: "add"
          transformation:
            translation: !math [0, 0, "${simul.plane_height}"]
        obstacles_category_II:
          IBM:
            order: 1
          geometry_path: fixture/stl/wind_tunnel/category_II/plates_Nx160Ny70_6x2_spacing16x32_offset19y.stl
          volumes_limits:
            body_transformed:
              - start: !math [4, 20, 0]
                end:
                  !math [
                    "${simul.body_pos} - 0.75*${var.cube_length}",
                    "${domain.width} - 20",
                    "${domain.height}",
                  ]
          small_triangles: "add"
          transformation:
            scale:
              !math [
                "64.0*${simul.scale}",
                "64.0*${simul.scale}",
                "32.0*${simul.scale}",
              ]
            translation: !math [0, 0, "${simul.plane_height}"]
      refinement: !not-inherit
        static:
          lvl1:
            volumes_refine:
              - start: [0.0, 55.0, 0.0]
                end: [272.0, 105.0, 32.0]
                lvl: 1
                is_abs: true
          lvl2:
            volumes_refine:
              - start: [0.0, 67.5, 0.0]
                end: [208.0, 92.5, 20.0]
                lvl: 2
                is_abs: true
          lvl3:
            volumes_refine:
              - start: [0.0, 73.75, 2.0]
                end: [176.0, 86.25, 12.0]
                lvl: 3
                is_abs: true
          lvl4:
            volumes_refine:
              - start: [140.0, 76.875, 4.0]
                end: [160.0, 83.125, 8.0]
                lvl: 4
                is_abs: true