"""Generate AVL run-case and command files for alpha/beta/deflection sweeps."""
from __future__ import annotations
from pathlib import Path
[docs]
def make_run_reset(
avl_name: str,
ctrl_names: list[str],
*,
Mach: float = 0.0,
CDoref: float = 0.0,
Xref: float = 0.0,
Yref: float = 0.0,
Zref: float = 0.0,
Lunit: str = "Lunit",
Munit: str = "Munit",
Tunit: str = "Tunit",
) -> str:
"""Return the content of a reset run-case file (all states zeroed).
The reset run case is loaded into AVL before each sweep point to ensure
a clean starting state. ctrl_names is the ordered list of control surface
names (e.g. ["flap", "aileron", "elevator", "rudder"]).
Example
-------
>>> from avl_aero_tables.avl_rungen import make_run_reset
>>> text = make_run_reset(
... "bd",
... ["flap", "aileron", "elevator", "rudder"],
... CDoref=0.017,
... Xref=3.4,
... Zref=0.5,
... )
>>> "Run case 1: Reset bd" in text
True
>>> " CDo = 0.01700" in text
True
"""
lines: list[str] = [
"",
" ---------------------------------------------",
f" Run case 1: Reset {avl_name}",
"",
]
for name in ["alpha", "beta", "pb/2V", "qc/2V", "rb/2V"]:
lines.append(f" {name:<12} -> {name:<11} = {0:.5f}")
for ctrl in ctrl_names:
lines.append(f" {ctrl:<12} -> {ctrl:<11} = {0:.5f}")
lines.append(" ")
scalar_rows: list[tuple[str, float, str]] = [
("alpha", 0.0, "deg"),
("beta", 0.0, "deg"),
("pb/2V", 0.0, ""),
("qc/2V", 0.0, ""),
("rb/2V", 0.0, ""),
("CL", 0.0, ""),
("CDo", CDoref, ""),
("bank", 0.0, "deg"),
("elevation", 0.0, "deg"),
("heading", 0.0, "deg"),
("Mach", Mach, ""),
("velocity", 0.0, f"{Lunit}/{Tunit}"),
("density", 1.0, f"{Munit}/{Tunit}^3"),
("grav.acc.", 1.0, f"{Lunit}/{Tunit}^2"),
("turn_rad.", 0.0, Lunit),
("load_fac.", 1.0, ""),
("X_cg", Xref, Lunit),
("Y_cg", Yref, Lunit),
("Z_cg", Zref, Lunit),
("mass", 1.0, Munit),
("Ixx", 1.0, f"{Munit}-{Lunit}^2"),
("Iyy", 1.0, f"{Munit}-{Lunit}^2"),
("Izz", 1.0, f"{Munit}-{Lunit}^2"),
("Ixy", 0.0, f"{Munit}-{Lunit}^2"),
("Iyz", 0.0, f"{Munit}-{Lunit}^2"),
("Izx", 0.0, f"{Munit}-{Lunit}^2"),
("visc CL_a", 0.0, ""),
("visc CL_u", 0.0, ""),
("visc CM_a", 0.0, ""),
("visc CM_u", 0.0, ""),
]
for param, val, unit in scalar_rows:
lines.append(f" {param:<10}= {val:.5f} {unit}")
return "\n".join(lines) + "\n"
[docs]
def make_run_command(
avl_name: str,
alpha: list[float],
beta: list[float],
ctrl_names: list[str],
ctrl_sweeps: dict[str, list[float]],
out_dir: Path,
) -> str:
"""Return the AVL interactive command script for a sweep.
Parameters
----------
avl_name:
Geometry file stem without extension (e.g. "bd").
alpha:
List of angle-of-attack values in degrees.
beta:
List of sideslip angle values in degrees.
ctrl_names:
Ordered list of control-surface names matching AVL's D1, D2, … indices.
ctrl_sweeps:
Mapping from control-surface name to its deflection sweep values.
Only surfaces present in this dict are swept; others stay at zero.
An empty dict produces one run per (alpha, beta) point.
out_dir:
Directory where .st output files will be written. May be an absolute
or relative path — keep it short; AVL has an ~80-char filename limit.
Example
-------
>>> from pathlib import Path
>>> from avl_aero_tables.avl_rungen import make_run_command
>>> cmd = make_run_command(
... "bd",
... alpha=[0.0, 5.0],
... beta=[0.0],
... ctrl_names=["flap", "aileron", "elevator", "rudder"],
... ctrl_sweeps={},
... out_dir=Path("/tmp/avl_out"),
... )
>>> cmd.splitlines()[0]
'LOAD bd'
>>> cmd.count("A A") # one alpha line per case
2
"""
out_dir = Path(out_dir)
lines: list[str] = [f"LOAD {avl_name}", "PLOP", "G", "", "OPER"]
ctrl_points: list[tuple[int, float]] = [
(ctrl_names.index(name) + 1, defl)
for name, defl_vals in ctrl_sweeps.items()
if name in ctrl_names
for defl in defl_vals
]
case_num = 0
for a in alpha:
for b in beta:
if ctrl_points:
for surf_idx, defl in ctrl_points:
case_num += 1
st_path = out_dir / f"case_{case_num:04d}.st"
lines.extend(
[
f"A A {a:f}",
f"B B {b:f}",
f"D{surf_idx} D{surf_idx} {defl:g}",
"i",
"x",
"st",
str(st_path),
"",
"CINI",
"OPER",
]
)
else:
case_num += 1
st_path = out_dir / f"case_{case_num:04d}.st"
lines.extend(
[
f"A A {a:f}",
f"B B {b:f}",
"i",
"x",
"st",
str(st_path),
"",
"CINI",
"OPER",
]
)
lines.extend(["", "Quit", ""])
return "\n".join(lines)