|
| 1 | +# The settings file |
| 2 | + |
| 3 | +A `vsm_settings.yaml` configures a whole run in one place: the flight condition, each |
| 4 | +wing and how it is discretised, and the numerical solver. [`VSMSettings`](@ref) reads |
| 5 | +it, and [`Wing`](@ref), [`Solver`](@ref) and [`set_va!`](@ref) are each built from the |
| 6 | +object it returns. |
| 7 | + |
| 8 | +```julia |
| 9 | +settings = VSMSettings("ram_air_kite/vsm_settings.yaml") # under data/ |
| 10 | +settings = VSMSettings("my/vsm_settings.yaml"; data_prefix=false) # as written |
| 11 | + |
| 12 | +wing = Wing(settings) |
| 13 | +body_aero = BodyAerodynamics([wing]) |
| 14 | +solver = Solver(body_aero, settings) |
| 15 | +set_va!(body_aero, settings) |
| 16 | +``` |
| 17 | + |
| 18 | +The file has three top-level blocks — `condition:`, `wings:` and `solver_settings:` — |
| 19 | +and each may be left out, in which case its defaults apply. `wings:` is a list, so a |
| 20 | +multi-wing configuration repeats the entry. |
| 21 | + |
| 22 | +## An annotated file |
| 23 | + |
| 24 | +Every key below is optional except a wing's `name`, `n_panels`, |
| 25 | +`spanwise_panel_distribution`, `spanwise_direction` and `remove_nan`, and — whenever |
| 26 | +`solver_settings:` is present — its `aerodynamic_model_type` and |
| 27 | +`type_initial_gamma_distribution`. An omitted key keeps its default: the `condition:` |
| 28 | +values shown are those defaults, and the docstrings linked below carry the rest. |
| 29 | + |
| 30 | +```yaml |
| 31 | +condition: |
| 32 | + wind_speed: 10.0 # free-stream velocity magnitude [m/s] |
| 33 | + alpha: 5.0 # angle of attack [°] |
| 34 | + beta: 0.0 # sideslip angle [°] |
| 35 | + yaw_rate: 0.0 # yaw rate [°/s] |
| 36 | + |
| 37 | +wings: |
| 38 | + - name: main_wing # label the wing carries into plots and output |
| 39 | + # sections and polars, resolved against the working directory |
| 40 | + geometry_file: data/ram_air_kite/geometry.yaml |
| 41 | + n_panels: 50 # panels over the span; two sections make a panel |
| 42 | + # LINEAR, COSINE, SPLIT_PROVIDED, UNCHANGED or BILLOWING |
| 43 | + spanwise_panel_distribution: LINEAR |
| 44 | + spanwise_direction: [0, 1, 0] # unit vector along the span, in the CAD frame |
| 45 | + remove_nan: true # interpolate over NaN entries in the polar tables |
| 46 | + use_prior_polar: false # reuse polars on disk instead of regenerating them |
| 47 | + billowing_percentage: 0.0 # trailing-edge billow, as % of arc length |
| 48 | + crease_frac: 0.75 # chordwise position of the deflection hinge [-] |
| 49 | + |
| 50 | + mesh: # how the sections were sliced from a CAD mesh |
| 51 | + obj_file: data/ram_air_kite/ram_air_kite.obj # the mesh sections come from |
| 52 | + n_sections: 45 # sections sliced from the mesh |
| 53 | + n_bins: 60 # leading-edge stations marched across the span |
| 54 | + # rows of the mesh-to-slicer rotation, whose x = chord, y = span, z = up |
| 55 | + rotation: [[0, 0, -1], [-1, 0, 0], [0, 1, 0]] |
| 56 | + wingtip_distance: 0.0 # arc length the outermost sections stop short [m] |
| 57 | + clearance: 0.006 # shrink-wrap offset outside the cloud [chord fraction] |
| 58 | + min_concave_radius: 0.02 # shrink-wrap rolling-ball radius [chord fraction] |
| 59 | + |
| 60 | + airfoil: # the 2D backend and the polars it tabulates |
| 61 | + solver: xfoil # section backend: neuralfoil or xfoil |
| 62 | + model_size: large # NeuralFoil network size |
| 63 | + n_crit: 9.0 # e^N transition criticality; lower transitions earlier |
| 64 | + xtr_upper: 0.05 # forced upper-surface transition [chord fraction] |
| 65 | + xtr_lower: 0.05 # forced lower-surface transition [chord fraction] |
| 66 | + alpha_range: [-180, 1, 180] # angle-of-attack sweep [°] as [first, step, last] |
| 67 | + delta_range: [-40, 10, 40] # flap-deflection sweep [°]; null for no flap sweep |
| 68 | + # angles off the reference angle a live polar is re-solved at [°] |
| 69 | + live_offsets: [-12, -9, -6, -3, 0, 3, 6, 9, 12] |
| 70 | + v_app: 25.0 # apparent wind the Reynolds number is taken at [m/s] |
| 71 | + chord_ref: 1.0 # reference (maximum panel) chord [m] |
| 72 | + table_format: arrow # per-node table format: csv or arrow |
| 73 | + |
| 74 | +solver_settings: |
| 75 | + aerodynamic_model_type: VSM # VSM or LLT |
| 76 | + type_initial_gamma_distribution: ELLIPTIC # ELLIPTIC or ZEROS |
| 77 | + solver_type: LOOP # LOOP or NONLIN |
| 78 | + density: 1.225 # air density [kg/m³] |
| 79 | + mu: 1.81e-5 # dynamic viscosity [N·s/m²] |
| 80 | + rtol: 1e-6 # relative tolerance on the circulation residual [-] |
| 81 | + relaxation_factor: 0.01 # under-relaxation of the circulation update [-] |
| 82 | +``` |
| 83 | +
|
| 84 | +[`SolverSettings`](@ref) lists the rest of `solver_settings:`; a key left out keeps its |
| 85 | +default. `n_panels` given there is ignored — the total is summed from the wings. |
| 86 | + |
| 87 | +## `mesh:` |
| 88 | + |
| 89 | +[`MeshSettings`](@ref) — which `.obj` mesh a wing's sections were cut from, and how. |
| 90 | +The block's `obj_file` is the mesh the sections are *generated from*, an input to the |
| 91 | +`geometry_file` the wing then flies; a wing's own top-level `obj_file` is a different |
| 92 | +route — straight from a mesh and a `.dat`, with no polar generation — and cannot be |
| 93 | +given alongside `geometry_file`. |
| 94 | + |
| 95 | +[`rotation_matrix`](@ref), [`slice_args`](@ref) and [`preview_args`](@ref) turn the |
| 96 | +block into the arguments |
| 97 | +[`obj_to_yaml`](@ref VortexStepMethod.ObjAdapter.obj_to_yaml) and |
| 98 | +[`plot_slices_3d`](@ref) take, and [`ShrinkWrap`](@ref) is built from `clearance` and |
| 99 | +`min_concave_radius`. A wing naming no `mesh:` block slices exactly as an |
| 100 | +unconfigured `obj_to_yaml` call does. [From CAD mesh to aerodynamic model](@ref) |
| 101 | +walks through what those arguments do. |
| 102 | + |
| 103 | +## `airfoil:` |
| 104 | + |
| 105 | +[`AirfoilSettings`](@ref) — the 2D section backend and the polars it tabulates. |
| 106 | +`solver:` chooses the viscous panel code (`xfoil`) or the neural surrogate |
| 107 | +(`neuralfoil`) for a whole dataset from the file, and [`airfoil_solver`](@ref) |
| 108 | +returns the [`XFoilSolver`](@ref) or [`NeuralFoilSolver`](@ref) it names. |
| 109 | + |
| 110 | +One block answers for both the tables a mesh is sliced into and the live polars a |
| 111 | +deformed section is re-solved on, so the two cannot be generated at different |
| 112 | +transition settings or off different networks. [`alpha_range`](@ref), |
| 113 | +[`delta_range`](@ref) and [`reynolds`](@ref) turn the sweeps and the |
| 114 | +`density * v_app * chord_ref / mu` reference into what the polar generator takes. |
0 commit comments