Requirements#
Behavioral requirements derived from the test suite. Each row is asserted by
at least one pytest. Source CSVs live in docs/dev/reqs/.
Geometry parsing (avl_fileread)#
id |
requirement |
rationale |
test |
|---|---|---|---|
req-geom-1 |
Parse any .avl file into AvlGeometry without error |
avl_fileread is the sole entry point; if it errors the entire pipeline is blocked |
|
req-geom-2 |
Populate header fields: name, Mach, symmetry flags, Sref/Cref/Bref, CG, CDoref |
Reference quantities are required for normalizing aero coefficients and setting up run cases |
|
req-geom-3 |
Parse all SURFACE sections and return them keyed by name |
Surface names are used as labels in plots and output tables |
|
req-geom-4 |
Parse per-section geometry (xle, yle, chord) for each surface |
Section coordinates are required for geometry visualization |
|
req-geom-5 |
Parse CONTROL entries on each section |
Control names are carried through to the command generator and aero tables |
|
req-geom-6 |
Parse BODY section when present |
Body data must not halt parsing of real aircraft files that include a fuselage |
|
req-geom-7 |
Expose ordered control names via AvlGeometry.ctrl_names |
Ordered names map directly to AVL’s d1..dN slots in the command script |
|
req-geom-8 |
Return empty ctrl_names for geometry with no control surfaces |
Wing-only models must not produce phantom control entries or errors |
|
req-geom-9 |
ctrl_names returns the same sequence on repeated calls |
Sweep code calls ctrl_names multiple times; non-determinism would corrupt Di index assignment |
Stability output parsing (st_fileread)#
id |
requirement |
rationale |
test |
|---|---|---|---|
req-stab-1 |
Parse a single .st file and return exactly one StResult |
One output file per run case; parsing must not split or merge |
|
req-stab-2 |
StResult.filename matches the source file basename |
Filename is used as a row key in the results DataFrame |
|
req-stab-3 |
StResult.controls maps d0N indices to surface names as written in the .st header |
Control map is needed to translate d0N keys back to named surfaces in aero_filewrite |
|
req-stab-4 |
Extract flight-condition scalars: Alpha, Beta, Mach |
Alpha and beta become the table breakpoints in aero_filewrite |
|
req-stab-5 |
Extract total force coefficients: CLtot, CDtot, CDvis, CYtot, etc. |
These are the primary outputs users build lookup tables from |
|
req-stab-6 |
Extract stability derivatives: CLa, Cma, Cnb, Cmq, etc. |
Required for flight dynamics modeling and stability margin calculations |
|
req-stab-7 |
Extract control derivatives: CLdN, CmdN, etc. |
Required for control law design and control authority analysis |
|
req-stab-8 |
Extract neutral-point location as Xnp |
Common stability metric frequently requested independently of the full coefficient set |
|
req-stab-9 |
Store spiral stability ratio under key Clb_Cnr_div_Clr_Cnb and not Cnb |
The compound key prevents the ratio from silently overwriting the real Cnb derivative |
|
req-stab-10 |
Parse all .st files in a directory and return one result per file |
Enables batch processing after a full sweep without requiring individual file paths |
|
req-stab-11 |
results_to_dataframe returns a pd.DataFrame with one row per StResult |
Provides a pandas interface for downstream analysis and CSV export |
|
req-stab-12 |
DataFrame columns include filename and every key present in .data |
All parsed fields must be accessible by name for filtering and analysis |
|
req-stab-13 |
DataFrame cell values match the parsed .data values exactly |
Ensures no silent truncation or type coercion during pivot |
|
req-stab-14 |
results_to_dataframe returns exactly one row per StResult |
Row count must equal result count; extra or missing rows would corrupt downstream analysis |
Command generation (avl_rungen)#
id |
requirement |
rationale |
test |
|---|---|---|---|
req-cmd-1 |
make_reset_run output contains a ‘—’ separator line |
AVL requires the exact run-case format; missing fields produce silent zero-value substitutions |
|
req-cmd-2 |
Case name encodes the geometry name |
Name appears in AVL output and helps correlate .st files to source geometry |
|
req-cmd-3 |
Alpha and beta are mapped to their respective AVL variables |
Unmapped variables default to zero in AVL silently ignoring sweep inputs |
|
req-cmd-4 |
All named controls are assigned to their respective variables |
Unmapped controls default to zero in AVL silently ignoring requested deflections |
|
req-cmd-5 |
CDoref is written into the run case |
Ensures viscous drag is included consistently across all cases |
|
req-cmd-6 |
CG coordinates (Xref, Yref, Zref) are written into the run case |
Moment coefficients and neutral point depend on the reference CG position |
|
req-cmd-7 |
Unit strings are written when Lunit/Munit/Tunit are provided |
Physical units affect dimensional output quantities |
|
req-cmd-8 |
Geometry with no controls produces a valid run block without control lines |
Wing-only runs must not emit malformed control assignments |
|
req-cmd-9 |
Stdin command script begins with LOAD <avl_file> to load geometry |
AVL is driven entirely via stdin; LOAD must precede PLOP and OPER to initialize geometry before sweep commands |
|
req-cmd-18 |
Stdin command script loads the run-case file via CASE <run_file> before OPER commands |
CASE initializes run-case variables from reset.run; without it AVL uses uninitialized defaults |
|
req-cmd-10 |
Graphics are disabled via PLOP followed by G |
Suppresses interactive plot windows that would block AVL in headless or CI environments |
|
req-cmd-11 |
Script opens the OPER menu |
All run execution and output saving commands are issued inside OPER |
|
req-cmd-12 |
Script ends with Quit |
Without Quit the AVL subprocess hangs waiting for further input |
|
req-cmd-13 |
Each run case sets alpha and beta via A A and B B direct assignments |
Direct assignment bypasses AVL trim logic and uses the specified flight condition exactly |
|
req-cmd-14 |
Each run case saves a .st file to out_dir |
Output files are the only persistent artifact of each AVL run |
|
req-cmd-15 |
Each run case executes (i), saves (st), and resets (x then CINI) before the next |
CINI clears accumulated forces; omitting it causes subsequent results to inherit prior state |
|
req-cmd-16 |
Control sweep emits Di Di |
Incorrect Di index or deflection value silently runs a different flight condition |
|
req-cmd-17 |
Multiple alphas produce one run block each |
Batches the full alpha sweep in a single AVL invocation |
|
req-cmd-19 |
Alpha and beta values appear verbatim in the A A and B B assignment commands |
Formatting errors or rounding in the command string would silently run a different flight condition |
|
req-cmd-20 |
Reset run block initialises alpha to 0.0 |
The reset case must start from zero so subsequent A A commands apply from a known baseline |
Binary management (avl_bin)#
id |
requirement |
rationale |
test |
|---|---|---|---|
req-bin-1 |
find_avl checks ~/bin/avl first |
Allows a local user build to take priority over a system install |
|
req-bin-2 |
find_avl raises FileNotFoundError with message AVL binary not found when absent from both locations |
Clear error message guides the user to install the binary rather than a cryptic traceback |
|
req-bin-3 |
find_avl falls back to shutil.which (PATH) when ~/bin/avl is absent |
Supports system-wide installs and CI environments without a ~/bin directory |
|
req-bin-4 |
verify returns the resolved Path for a working AVL binary |
Provides a quick pre-flight check before starting a potentially long sweep |
|
req-bin-5 |
verify raises RuntimeError containing exited with code for a non-functional binary |
Prevents silent failures from a corrupt or wrong-platform binary masquerading as a valid install |
|
req-bin-6 |
run passes the command script as input= to the subprocess with no positional CLI args |
AVL is driven entirely via stdin; geometry and run-case are loaded via LOAD/CASE commands inside the script |
|
req-bin-7 |
CLI verify subcommand returns exit code 0 on success and 1 on failure |
Enables health-check scripting and CI pipeline gates |
|
req-bin-8 |
CLI verify subcommand returns exit code 1 on FileNotFoundError |
Distinguishes binary absent from binary broken so diagnostic scripts can act accordingly |
|
req-bin-9 |
CLI with no arguments triggers SystemExit (help text) |
First-time users get usage information rather than an unhandled exception |
CLI commands and config (avl_cli / avl_config)#
id |
requirement |
rationale |
test |
|---|---|---|---|
req-cli-1 |
A complete .yml project file round-trips through load_config without error |
Confirms the parser accepts all valid fields without silent data loss |
|
req-cli-2 |
load_config raises SystemExit when the [sweep] section is absent |
Missing sweep section makes the file unusable; fail-fast with a clear error is better than a downstream AttributeError |
|
req-cli-3 |
load_config raises SystemExit when the [input] section is absent |
Missing input section means no geometry file can be located |
|
req-cli-4 |
load_config raises SystemExit when alpha is an empty list |
An empty alpha sweep would produce no .st files silently |
|
req-cli-5 |
load_config raises SystemExit when beta is an empty list |
An empty beta sweep would produce no .st files silently |
|
req-cli-6 |
load_config raises SystemExit for an unrecognised output format |
Unknown format cannot be written; failing fast avoids a silent no-op after a full sweep |
|
req-cli-7 |
load_config raises SystemExit when a ctrl_sweeps entry is an empty list |
An empty deflection list silently omits that surface from the sweep |
|
req-cli-8 |
load_config raises SystemExit for non-numeric alpha values |
Non-numeric values cannot be passed to AVL; early error avoids a downstream traceback |
|
req-cli-9 |
load_config raises SystemExit for syntactically invalid YAML |
Malformed YAML is always a user error; fail-fast with a clear message |
|
req-cli-10 |
ProjectConfig defaults output.format to csv and ctrl_sweeps to empty dict when omitted |
Sensible defaults reduce boilerplate in simple project files |
|
req-cli-11 |
SweepSpec emits a UserWarning when a ctrl_sweeps entry omits 0.0 |
0.0 is required for neutral aero tables; silently omitting it corrupts stab tables |
|
req-cli-12 |
SweepSpec inserts 0.0 into ctrl_sweeps entries that omit it |
Auto-insertion ensures stab tables are always populated without requiring the user to know why |
|
req-cli-13 |
input.geometry is resolved relative to the .yml file’s directory |
Geometry and .yml travel together; relative paths survive moving the project directory |
|
req-cli-14 |
CLI sweep writes output to _runs/ |
Keeps generated outputs out of the geometry directory without requiring an explicit out_dir argument |
|
req-cli-15 |
CLI sweep passes alpha / beta / ctrl_sweeps / out_dir / out_format correctly to avl_sweep.run |
Ensures config fields are not silently dropped or transformed between YAML parse and AVL invocation |
|
req-cli-16 |
CLI sweep exits with error when a ctrl_sweeps key is not a valid surface name in the .avl |
Typos in the .yml would silently sweep with no deflections applied |
|
req-cli-17 |
CLI plot geometry calls avl_fileplot with the parsed geometry |
Confirms the command wires geometry parsing to the plotting function without silent skips |
|
req-cli-18 |
CLI plot geometry writes |
Predictable output path keeps the plot alongside the geometry file it depicts |
|
req-cli-19 |
CLI plot totals auto-selects the latest timestamped subdirectory when given a parent directory |
Avoids requiring users to type full timestamps for the most common case of plotting the most recent run |
|
req-cli-20 |
CLI plot totals accepts a specific run directory directly |
Enables reproducible re-plotting of any historical run |
|
req-cli-21 |
CLI plot totals exits with error when no sweep results exist in the given directory |
Prevents a silent empty plot when the sweep has not been run or the path is wrong |
|
req-cli-22 |
CLI plot totals exits with error when the given directory does not exist |
Catches path typos before attempting to read results |
|
req-cli-23 |
CLI plot totals resolves run directories named |
Run directories include the geometry name as a prefix; the auto-latest logic must match this pattern |
|
req-cli-24 |
CLI plot totals accepts a directory containing a .raw/ subdirectory directly without searching for a parent |
Supports direct paths to known run directories bypassing the auto-latest search |
|
req-cli-25 |
CLI plot totals writes stab.html and ctrl_ |
Predictable filenames enable scripted post-processing and the index.html link list |
|
req-cli-37 |
CLI plot totals –beta-ref forwards the sideslip angle to aero_fileplot |
Users must be able to choose which beta slice is shown in control-surface plots without modifying code |
|
req-cli-38 |
CLI plot stab-deriv auto-selects the latest timestamped subdirectory when given a parent directory |
Consistent directory-discovery behaviour across all plot subcommands |
|
req-cli-39 |
CLI plot stab-deriv writes stabderiv_{alpha beta p q r}.html to the run directory |
Predictable filenames let users identify which perturbation variable each file covers without opening it |
|
req-cli-40 |
CLI plot ctrl-deriv auto-selects the latest timestamped subdirectory when given a parent directory |
Consistent directory-discovery behaviour across all plot subcommands |
|
req-cli-41 |
CLI plot ctrl-deriv writes ctrlderiv_{surface}.html per control surface to the run directory |
One file per surface keeps plots focused; filenames identify the surface without opening the HTML |
|
req-cli-42 |
CLI plot all invokes totals stab-deriv and ctrl-deriv in a single command writing all HTML files |
Avoids three separate commands for the common case of generating the full plot set |
|
req-cli-43 |
CLI plot all –beta-ref forwards the sideslip angle to plot_totals |
Consistent –beta-ref behaviour between plot totals and plot all |
|
req-cli-26 |
_write_index_html creates an index.html listing all .html files in the directory |
Provides a single entry point for reviewing all plots from a run in a browser |
|
req-cli-27 |
All shipped example .yml files parse without error |
Ensures examples remain valid as the config schema evolves |
|
req-cli-28 |
ctrl_sweeps keys in example .yml files all match surface names in the corresponding .avl |
Prevents shipping broken examples that would error at runtime |
|
req-cli-29 |
End-to-end: CLI verify returns exit code 0 with the real AVL binary installed |
Confirms the full binary-discovery and health-check path works against the actual installed binary |
|
req-cli-30 |
End-to-end: CLI sweep produces results.csv and provenance.json in a timestamped run directory with the correct case count |
Full pipeline smoke test from .yml config through AVL execution to structured output files |
|
req-cli-31 |
End-to-end: CLI plot geometry writes |
Confirms the geometry plot command runs without error against a real geometry file |
|
req-cli-32 |
End-to-end: CLI plot aero writes stab.html and ctrl_CLtot.html after a real sweep |
Confirms the aero plot command correctly finds the latest run and produces all output HTML files |
|
req-cli-33 |
End-to-end: Python API chain (avl_fileread → avl_fileplot → avl_sweep → aero_filewrite → aero_fileplot) produces 9 results with CLtot in every case |
Smoke test confirming every public API function works in sequence against the real AVL binary |
|
req-cli-34 |
CLI verify subcommand returns exit code 0 when the binary is healthy |
Enables scripted health checks and CI pipeline gates to confirm the install is working |
|
req-cli-35 |
CLI verify subcommand returns exit code 1 when the binary is missing |
Distinguishes binary absent from binary broken for diagnostic scripts |
|
req-cli-36 |
CLI verify subcommand returns exit code 1 when the binary fails its health check |
Distinguishes binary broken from binary absent for diagnostic scripts |
Sweep orchestration (avl_sweep)#
id |
requirement |
rationale |
test |
|---|---|---|---|
req-sweep-1 |
run invokes avl_runner.run exactly once per call |
All cases are batched into one AVL invocation; multiple calls would spawn redundant processes |
|
req-sweep-2 |
run passes the .avl file’s parent directory as cwd |
The LOAD command uses a bare filename; cwd=avl_dir ensures it resolves and that relative paths inside the .avl (airfoil data) also resolve |
|
req-sweep-3 |
run creates a timestamped subdirectory {avl_stem}_{timestamp} inside out_dir |
Fresh directory per run ensures previous results are never overwritten |
|
req-sweep-4 |
Timestamped output subdirectory is named {avl_stem}_{timestamp} |
Name encodes the geometry and time so multiple runs on the same geometry are distinguishable |
|
req-sweep-5 |
run raises RuntimeError with the exit code when AVL exits non-zero |
AVL can produce partial output before failing; raising prevents the caller from silently using corrupt results |
|
req-sweep-6 |
stdin LOAD command uses the bare geometry filename (not a full path) |
cwd=avl_dir means bare filename resolves correctly and stays under AVL’s ~80-char Fortran string limit |
|
req-sweep-7 |
Generated command script contains A A |
Alpha values must reach AVL unchanged; silent truncation or formatting errors would run the wrong flight condition |
|
req-sweep-8 |
out_dir is required; omitting it raises TypeError with message out_dir is required |
An explicit out_dir forces the caller to choose where results land; no implicit write to cwd |
|
req-sweep-9 |
out_format=csv writes results.csv to out_dir |
Common interchange format for spreadsheets and downstream tools |
|
req-sweep-10 |
out_format=json writes results.json to out_dir |
Common interchange format for web tools and other language consumers |
|
req-sweep-11 |
out_format=df returns results in memory without writing any file |
Avoids unnecessary disk I/O in programmatic usage |
|
req-sweep-12 |
out_format= |
Fails fast with a clear error rather than silently writing nothing |
|
req-sweep-13 |
Single-point integration run returns at least one StResult with Alpha and CLtot fields |
Smoke test confirming the full AVL binary pipeline produces parseable stability output |
|
req-sweep-14 |
A 180-case bd sweep (5 alpha × 3 beta × 12 ctrl points at 5° steps) completes within 250 ms/case |
Baseline throughput measured at 107 ms/case on a 2025 MacBook; 250 ms/case gives 2× headroom for CI and prevents silent performance regressions |
|
req-sweep-15 |
run writes sweep.inp to the .in/ subdirectory containing LOAD and CASE commands |
Provides a human-readable on-disk record of exactly what was piped to AVL to produce the .st files in that directory |
|
req-sweep-16 |
run emits a UserWarning when a ctrl_sweeps entry omits 0.0 |
0.0 deflection is required for neutral aero tables; a warning alerts users without halting the sweep |
|
req-sweep-17 |
run inserts 0.0 into ctrl_sweeps deflection lists that omit it |
Auto-insertion ensures stab tables are always populated regardless of what the caller provided |
Geometry plotting (avl_fileplot)#
id |
requirement |
rationale |
test |
|---|---|---|---|
req-plot-1 |
avl_fileplot returns a plotly Figure |
Caller can embed the figure in notebooks or save to HTML via fig.write_html() |
|
req-plot-2 |
Figure has exactly one 3-D scene |
Single interactive scene enables rotate/zoom; the four-view matplotlib layout is replaced by the interactive plotly viewer |
|
req-plot-3 |
All figure traces are Scatter3d or Cone instances |
Non-3D traces would flatten geometry in the interactive viewer and misrepresent dihedral |
|
req-plot-5 |
Figure layout.title.text contains the geometry header.name |
Distinguishes saved plots when multiple geometries are compared |
|
req-plot-6 |
At least one Scatter3d line trace is present |
Missing line traces indicate that surface parsing failed or coordinates were not transferred to the figure |
|
req-plot-7 |
CG position is rendered as a Scatter3d marker trace |
CG visualization is critical for stability interpretation |
|
req-plot-8 |
Geometry without a body section plots without error |
Wing-only and body-less models are common and must not raise |
|
req-plot-9 |
With mirrored surfaces at least 4 Scatter3d line traces are present |
Mirrored surfaces must produce traces on both sides of the symmetry plane |
|
req-plot-10 |
Geometry with a body section plots without error |
Files with fuselage bodies must not raise during plotting |
Aero database construction (aero_filewrite)#
id |
requirement |
rationale |
test |
|---|---|---|---|
req-write-1 |
aero_filewrite returns an AeroDatabase instance |
Defines the structured output contract for the entire pipeline |
|
req-write-2 |
aero_filewrite raises ValueError (message contains empty) for an empty result list |
An empty list is always a caller error; silent NaN-filled tables are harder to diagnose |
|
req-write-3 |
AeroDatabase.date is a non-empty string |
Provenance field lets users identify when a table was generated |
|
req-write-4 |
Reference quantities (Sref, Cref, Bref, Xref, Yref, Zref) are read from the first result |
Carries reference geometry from the .st file through to the aero database without a separate geometry argument |
|
req-write-5 |
A StabTable is created for every name in COEF_NAMES |
All standard 6-DOF coefficients must be queryable even if some were absent from some runs |
|
req-write-6 |
A CtrlTable is created for every (coef, surface) pair keyed as |
Each control surface independently affects every coefficient; the compound key prevents collisions |
|
req-write-7 |
Alpha breakpoints are sorted in ascending order |
Monotonic axes are required by scipy RegularGridInterpolator and MATLAB lookup-table blocks |
|
req-write-8 |
Beta breakpoints are sorted in ascending order |
Monotonic axes are required by scipy RegularGridInterpolator and MATLAB lookup-table blocks |
|
req-write-9 |
StabTable.data shape is (n_alpha x n_beta) |
Correct shape is required for 2-D table indexing and interpolation |
|
req-write-10 |
Neutral-control results (all deflections ≈ 0) populate StabTable at the correct (alpha, beta) cell |
Off-neutral data must not enter the neutral aero map; populating only on zero-deflection runs enforces this |
|
req-write-11 |
Off-neutral results do not overwrite StabTable cells |
Ensures the neutral map is uncontaminated even when neutral and deflected runs share the same breakpoint |
|
req-write-12 |
CtrlTable.data shape is (n_alpha x n_beta x n_defl) |
Correct shape is required for 3-D lookup table blocks and RegularGridInterpolator |
|
req-write-13 |
CtrlTable defl breakpoints are sorted in ascending order |
Monotonic defl axis is required for 3-D interpolation routines |
|
req-write-14 |
CtrlTable cell values match source StResult.data values |
Ensures no silent truncation or reordering during pivot from list to 3-D array |
|
req-write-15 |
CtrlTable.surface is <d_idx>_<ctrl_name> and CtrlTable.ctrl_name is the surface name |
Metadata fields are used for axis labels and export struct field names |
|
req-write-16 |
Geometry with no control surfaces produces an empty ctrl dict |
ctrl must not contain phantom entries for non-existent surfaces |
|
req-write-17 |
Geometry with no control surfaces still fills StabTable |
Stability-only models are valid and must produce a complete neutral aero map |
|
req-write-18 |
A coefficient absent from a result’s .data produces NaN at that table cell |
NaN distinguishes a genuinely missing value from a coefficient that happens to be zero |
|
req-write-19 |
StabTable.data shape is (n_alpha × 1) and values are correct with multiple alpha breakpoints |
Multi-alpha tables must not collapse rows or reorder values during pivot from list to 2-D array |
|
req-write-20 |
AeroDatabase.stab_deriv contains all 30 stability-derivative keys (CLa through Cnr) as StabTable objects |
All linearised stability derivatives must be accessible for analysis and plotting — missing keys would silently skip derivatives |
|
req-write-21 |
stab_deriv table values match the fixture data at the correct (alpha beta) index |
Validates that the extraction loop maps AVL derivative keys to the right array cell without off-by-one or key collision |
|
req-write-22 |
stab_deriv tables are NaN for off-neutral runs |
Stability derivatives are computed at neutral control; mixing in deflected values would corrupt the linearisation |
|
req-write-23 |
AeroDatabase.ctrl_deriv contains one StabTable per (coef surface) pair with keys in {coef}{d_idx}{ctrl_name} format |
Control derivatives must be keyed consistently so plots and downstream code can look them up without guessing the format |
|
req-write-24 |
ctrl_deriv table values match the fixture CLd01 and Cld02 values at the correct array cell |
Validates that CTRL_DERIV_COEFS × d_idx indexing maps to the correct AVL key without transposition or coef confusion |
|
req-write-25 |
ctrl_deriv tables are NaN for off-neutral runs |
Control derivatives are linearised at the neutral condition; deflected runs must not corrupt the derivative baseline |
Aero database plotting (aero_fileplot)#
id |
requirement |
rationale |
test |
|---|---|---|---|
req-aeroplot-1 |
plot_totals returns a dict mapping string keys to Plotly Figure objects |
Caller iterates items() to get both the name and figure without a separate name list |
|
req-aeroplot-2 |
Every item in the returned list is a Figure |
Mixed types would break callers that iterate and call fig.savefig |
|
req-aeroplot-3 |
The first figure is the stability figure with 6 subplots (one per coefficient) |
Consistent ordering enables programmatic access by index |
|
req-aeroplot-4 |
Stability figure axes titles include coefficient names (CLtot, CDtot, etc.) |
Labels identify which subplot carries which coefficient without documentation |
|
req-aeroplot-5 |
If no control surfaces are present exactly one figure is returned |
Single-figure output for geometry-only models must not produce empty control figures |
|
req-aeroplot-6 |
With one surface and all COEF_NAMES, seven figures are returned (1 stability + 6 control) |
One figure per coefficient for each surface; count must be deterministic |
|
req-aeroplot-7 |
Each control figure has one subplot per surface |
Combines all surfaces for a given coefficient on one figure for side-by-side comparison |
|
req-aeroplot-8 |
Each control figure suptitle contains a coefficient name |
Identifies the figure when saved to disk or displayed in a multi-figure viewer |
|
req-aeroplot-9 |
When beta_ref is not an exact breakpoint the nearest available beta is used |
Exact beta values are rarely available; nearest-neighbor avoids a crash or silent empty plot |
|
req-aeroplot-10 |
aero_stabderivplot returns exactly 5 Plotly figures (one per perturbation variable α β p′ q′ r′) |
Five perturbation variables are always present in AVL output; returning fewer would silently drop derivative groups |
|
req-aeroplot-11 |
Each stability-derivative figure title contains the partial-derivative notation for its perturbation variable |
Title must identify the variable so saved HTML files are self-describing without opening them |
|
req-aeroplot-12 |
plot_stab_derivs returns an empty dict when stab_deriv is empty |
Graceful empty-data handling prevents crashes when plotting a database built without derivatives |
|
req-aeroplot-13 |
aero_ctrlderivplot returns one figure per control surface |
One figure per surface keeps the plots focused; mixing surfaces on one figure obscures which surface drives each coefficient |
|
req-aeroplot-14 |
Each control-derivative figure title contains the surface name |
Title must identify the surface so saved HTML files are self-describing without opening them |
|
req-aeroplot-15 |
plot_ctrl_derivs returns an empty dict when ctrl_deriv is empty |
Graceful empty-data handling prevents crashes when plotting a geometry with no control surfaces |