Airfoil Geometry Schema
This document defines the user-facing schema for airfoil geometry definitions.
Field definitions and validation rules are normative.
Examples are illustrative.
Machine-usable GUI and editor constraints are authoritative in the dataclass field metadata exposed through buffalo_wings.airfoil.schema_field_metadata.
Buffalo Wings now provides that accessor on top of the shared buffalo_core.schema metadata contract while keeping the Wings dataclasses as the source of truth.
Within the schema implementation, those constraints are now attached directly with buffalo_core.schema.SchemaField and explicit SchemaChoice entries where human-readable labels matter, rather than through a Wings-local metadata builder shim.
Enum-like choice metadata is exposed as structured {"value": ..., "label": ...} entries so editors can render human-readable option text without losing the serialized schema value.
1. Top-Level Structure
Required Keys
schema_version(int): schema version; current version is1airfoils(object): named airfoil definitions.curves(object): named open section-curve definitions.
Example Skeleton
schema_version: 1
airfoils: {}
curves: {}
2. Common Conventions
Unless otherwise noted, airfoil geometry is defined in a local nondimensional section frame:
chordwise coordinate:
xthickness/camber coordinate:
yleading edge at
x = 0trailing edge at
x = 1angular quantities are specified in degrees unless otherwise noted
Positive y corresponds to the upper surface side of the airfoil.
Unless otherwise specified, airfoil definitions are normalized to unit chord.
Unless otherwise specified by a particular airfoil type, all coordinates are interpreted in this normalized local frame.
3. airfoils
airfoils is a mapping from unique airfoil names to airfoil definitions.
In the Python schema API, this top-level document is represented by buffalo_wings.airfoil.AirfoilDocumentSpec.
Example:
airfoils:
root: {type: naca4, designation: "2412"}
tip: {type: file, path: "airfoils/tip.dat", format: auto}
Keys must be unique and are case-sensitive.
3.1 curves
curves is a mapping from unique curve names to open section-curve definitions.
These curves are intentionally distinct from full closed-body airfoil definitions.
They are meant for workflows that need mean lines, walls, or other section-local open geometry.
In the Python schema API, this still lives inside buffalo_wings.airfoil.AirfoilDocumentSpec.
Example:
airfoils:
root: {type: naca6, designation: "65(1)-213"}
curves:
root_camber:
type: airfoil_camber
airfoil: root
approximation:
spacing: cosine
num_points: 81
wall:
type: spline_curve
representation: bezier
control_points:
- [0.0, 0.0]
- [0.3, 0.08]
- [1.0, 0.0]
fence:
type: polyline_curve
points:
- [0.0, 0.0]
- [0.3, 0.08]
- [1.0, 0.0]
Keys must be unique and are case-sensitive.
3.1.1 airfoil_camber
This curve family derives a camber line from a named source airfoil. It exists so users can reuse an existing airfoil definition directly for mean-line or thin-airfoil workflows without restating family-specific camber parameters.
Fields
type:"airfoil_camber"airfoil: name of one entry in the top-levelairfoilsmapapproximation: optional fallback controls used only when the referenced airfoil family does not provide exact native camber
If approximation is present, it contains:
spacing:"uniform"or"cosine"; default"cosine"num_points: integer sample count for fallback approximation; default81
Notes
This schema captures authoring intent as “camber derived from this airfoil,” not “independent open curve that happens to match it today.”
Airfoil families with exact native camber may ignore the approximation controls.
Airfoil families without exact native camber may use these controls to build a deterministic approximate camber curve.
Future curve families may represent directly authored camber lines or non-airfoil walls without changing the role of
airfoil_camber.
3.1.2 spline_curve
This curve family stores directly authored open geometry. The initial schema slice uses Bezier control points so users can define walls or guide curves without going through a closed-body airfoil spec first.
Fields
type:"spline_curve"representation:"bezier"control_points: ordered list of at least two(x, y)control points
Notes
Control points are interpreted from
u = 0tou = 1.The schema family is intentionally backend-neutral in name even though the current runtime stores Bezier control points directly.
Future spline backends may extend the supported
representationvalues without changing the role ofspline_curveas a directly authored open curve family.
3.1.3 polyline_curve
This curve family stores explicit vertices for directly authored open geometry. It is the lightest-weight authoring path for simple walls, fences, or guide curves that do not need spline control behavior.
Fields
type:"polyline_curve"points: ordered list of at least two(x, y)vertices
Notes
Vertices are interpreted from curve start to curve end.
The runtime resolves this family to a piecewise-linear open curve parameterized by normalized cumulative arc length.
Consecutive duplicate vertices are invalid because they create zero-length segments.
4. Airfoil Definition Types
Airfoils may be defined using analytic parameterizations or point-based representations.
Analytic representations define the airfoil geometry through a parameterized model. Point-based representations define the airfoil geometry through discrete coordinates on the surface.
This schema supports standard NACA designations, externally stored coordinate files, inline coordinate definitions, and parameterized coefficient-based representations.
As of 2026-03-31, AirfoilFactory.from_spec(...) constructs runtime airfoils for naca4, naca4_modified, naca5, naca5_modified, ellipse, cst, and spline.
Other families documented in this schema are planned schema targets, but they are not yet constructable through the current runtime factory and are tracked as roadmap work rather than migration-completion work.
4.0 Construction Status
The current migration-complete construction surface is:
naca4naca4_modifiednaca5naca5_modifiedellipsesplinecst
The following schema families are planned but not yet constructable through AirfoilFactory.from_spec(...):
filepointsparsecnaca4btnaca4rnaca4fnaca16flat_platebiconvexbiconvex_parabolapolygoncircular_arcjoukowskinaca6naca6a
The following families are still only partially defined in this document and still need their defining designation grammar, explicit parameter form, or validation rules to be completed:
naca4btnaca4rnaca4f
All other airfoil families currently included in this document have explicit fields, validation rules, and examples.
4.1 NACA Airfoils
These airfoils are all based on the canonical NACA airfoil specifications.
4.1.1 NACA 4-digit
NACA 4-digit airfoils may be specified in either of two ways.
Designation
airfoils:
naca2412:
type: naca4
designation: "2412"
Explicit Parameters
airfoils:
naca2412_explicit:
type: naca4
params:
m: 0.02
p: 0.4
max_thickness: 0.12
trailing_edge: sharp
leading_edge_radius: exact
Fields
type:"naca4"Exactly one of:
designation: 4-digit NACA designation stringparams: explicit parameter definition
If params is present, it contains:
m: maximum camber as a fraction of chordp: location of maximum camber as a fraction of chordmax_thickness: maximum thickness as a fraction of chordtrailing_edge:"standard"or"sharp"; default"standard"leading_edge_radius:"standard"or"exact"; default"standard"
Designation Syntax
The designation must use the form
####.The first digit represents 100 times the maximum camber.
The second digit represents 10 times the location of maximum camber.
The last two digits combine to represent 100 times the maximum thickness.
For example, a
2312means:maximum thickness
0.12cmaximum camber is
0.02clocation of maximum camber is at
0.30c
Validation Rules
Exactly one of
designationandparamsmust be present.If
designationis present:must match
^[0-9]{4}$
If
paramsis present:0 <= m < 0.10 <= p <= 0.90 <= max_thickness <= 0.4if
m == 0, requirep == 0if
m > 0, requirep > 0trailing_edgemust be one ofstandard|sharpleading_edge_radiusmust be one ofstandard|exact
Examples
Accepted examples:
designation: "2412"designation: "0012"params: {m: 0.02, p: 0.4, max_thickness: 0.12}params: {m: 0.0, p: 0.0, max_thickness: 0.12}
Unsupported examples:
designation: "24-12"designation: "2412-46"params: {m: 0.02, p: 0.0, max_thickness: 0.12}params: {m: 0.0, p: 0.4, max_thickness: 0.12}
Notes
max_thickness = 0is permitted to support idealized zero-thickness analyses.Airfoil definitions are normalized to unit chord.
When
designationis used, the airfoil is interpreted as the classical NACA 4-digit designation.When
paramsis used, the airfoil remains within the NACA 4-digit family but allows higher-precision specification of the defining parameters and explicit control over trailing-edge closure and leading-edge radius treatment.In the runtime API,
AirfoilFactory.from_spec(...)maps designation-based NACA 4-digit specs tobuffalo_wings.airfoil.Naca4AirfoilClassic.In the runtime API,
AirfoilFactory.from_spec(...)maps explicit-parameter NACA 4-digit specs tobuffalo_wings.airfoil.Naca4AirfoilParams.
4.1.2 NACA Modified 4-digit
Modified NACA 4-digit airfoils may be specified in either of two ways.
Designation
airfoils:
naca2412_46:
type: naca4_modified
designation: "2412-46"
Explicit Parameters
airfoils:
naca2412_46_explicit:
type: naca4_modified
params:
m: 0.02
p: 0.4
max_thickness: 0.12
leading_edge_index: 4.0
max_thickness_location: 0.6
trailing_edge: sharp
Fields
type:"naca4_modified"Exactly one of:
designation: modified NACA 4-digit designation stringparams: explicit parameter definition
If params is present, it contains:
m: maximum camber as a fraction of chordp: location of maximum camber as a fraction of chordmax_thickness: maximum thickness as a fraction of chordleading_edge_index: modified-thickness leading-edge radius indexmax_thickness_location: location of maximum thickness as a fraction of chordtrailing_edge:"standard"or"sharp"; default"standard"
Designation Syntax
The designation must use the form
####-##.The first four digits are the standard NACA 4-digit designation.
The first digit after the dash is the leading-edge radius index.
The second digit after the dash is 10 times the chordwise location of maximum thickness.
For example,
2412-46means:NACA 4-digit camber line
2412leading-edge radius index
4maximum thickness at
0.6c
Validation Rules
Exactly one of
designationandparamsmust be present.If
designationis present:must match
^[0-9]{4}-[1-9][1-9]$
If
paramsis present:0 <= m < 0.10 <= p <= 0.90 <= max_thickness <= 0.41 <= leading_edge_index < 100.1 <= max_thickness_location < 1.0if
m == 0, requirep == 0if
m > 0, requirep > 0trailing_edgemust be one ofstandard|sharp
Examples
Accepted examples:
designation: "2412-46"designation: "0012-34"params: {m: 0.02, p: 0.4, max_thickness: 0.12, leading_edge_index: 4.0, max_thickness_location: 0.6}params: {m: 0.0, p: 0.0, max_thickness: 0.10, leading_edge_index: 3.0, max_thickness_location: 0.4}
Unsupported examples:
designation: "2412"designation: "2412-06"designation: "2412-4A"params: {m: 0.02, p: 0.4, max_thickness: 0.12, leading_edge_index: 0.0, max_thickness_location: 0.6}
Notes
The modified NACA 4-digit family reuses the standard NACA 4-digit camber definition.
The modified designation selects the modified thickness law through the dash suffix.
In the runtime API,
AirfoilFactory.from_spec(...)maps designation-based modified NACA 4-digit specs tobuffalo_wings.airfoil.Naca4ModifiedAirfoilClassic.In the runtime API,
AirfoilFactory.from_spec(...)maps explicit-parameter modified NACA 4-digit specs tobuffalo_wings.airfoil.Naca4ModifiedAirfoilParams.
4.1.3 NACA 4-digit B/T
This family is reserved for a future NACA 4-digit B/T specification.
The supported designation syntax, explicit parameter form, and validation rules are not yet defined in this document.
This family is planned, but it is not yet constructable through AirfoilFactory.from_spec(...).
4.1.4 NACA 4-digit R
This family is reserved for a future NACA 4-digit R specification.
The supported designation syntax, explicit parameter form, and validation rules are not yet defined in this document.
This family is planned, but it is not yet constructable through AirfoilFactory.from_spec(...).
4.1.5 NACA 4-digit F
This family is reserved for a future NACA 4-digit F specification.
The supported designation syntax, explicit parameter form, and validation rules are not yet defined in this document.
This family is planned, but it is not yet constructable through AirfoilFactory.from_spec(...).
4.1.6 NACA 5-digit
NACA 5-digit airfoils may be specified in either of two ways.
Designation
airfoils:
naca23015:
type: naca5
designation: "23015"
Explicit Parameters
airfoils:
naca23015_explicit:
type: naca5
params:
ideal_lift_coefficient: 0.3
max_camber_location: 0.15
reflexed: false
max_thickness: 0.15
trailing_edge: sharp
leading_edge_radius: exact
Fields
type:"naca5"Exactly one of:
designation: 5-digit NACA designation stringparams: explicit parameter definition
If params is present, it contains:
ideal_lift_coefficient: ideal lift coefficientmax_camber_location: location of maximum camber as a fraction of chordreflexed: whether the camber line has a reflexed trailing edgemax_thickness: maximum thickness as a fraction of chordtrailing_edge:"standard"or"sharp"; default"standard"leading_edge_radius:"standard"or"exact"; default"standard"
Designation Syntax
The designation must use the form
#####.The first digit represents 10 times two thirds of the ideal lift coefficient.
The second digit represents 10 times twice the location of maximum camber.
The third digit selects the camber-line family:
0: standard camber1: reflexed camber
The last two digits combine to represent 100 times the maximum thickness.
For example,
23015means:ideal lift coefficient
0.3maximum camber location
0.15cstandard non-reflexed camber
maximum thickness
0.15c
Validation Rules
Exactly one of
designationandparamsmust be present.If
designationis present:must match
^[0-9]{5}$the third digit must be
0or1
If
paramsis present:0.15 <= ideal_lift_coefficient < 0.60.05 <= max_camber_location < 0.30 <= max_thickness <= 0.4trailing_edgemust be one ofstandard|sharpleading_edge_radiusmust be one ofstandard|exact
Examples
Accepted examples:
designation: "23015"designation: "21012"designation: "23112"params: {ideal_lift_coefficient: 0.3, max_camber_location: 0.15, reflexed: false, max_thickness: 0.15}params: {ideal_lift_coefficient: 0.3, max_camber_location: 0.15, reflexed: true, max_thickness: 0.15}
Unsupported examples:
designation: "23015-46"designation: "23215"designation: "23-015"params: {ideal_lift_coefficient: 0.3, max_camber_location: 0.15, max_thickness: 0.15}
Notes
designationrepresents the traditional encoded NACA 5-digit form.paramsis more general thandesignation.The
paramsform may describe airfoils that do not correspond to a historical published NACA 5-digit designation.The
designationdigits are encoded indices, not the physical values stored inparams.For the first digit,
digit = 10 * (2 / 3) * ideal_lift_coefficient. Equivalently,ideal_lift_coefficient = 0.15 * first_digit.For the second digit,
digit = 10 * 2 * max_camber_location. Equivalently,max_camber_location = 0.05 * second_digit.For example,
23015maps to:ideal_lift_coefficient = 0.3max_camber_location = 0.15reflexed = falsemax_thickness = 0.15
The reflex behavior selects which camber implementation is used.
The explicit-parameter thickness path exposes the same trailing-edge and leading-edge-radius controls as the NACA 4-digit params schema.
In the runtime API,
AirfoilFactory.from_spec(...)maps designation-based NACA 5-digit specs tobuffalo_wings.airfoil.Naca5AirfoilClassic.In the runtime API,
AirfoilFactory.from_spec(...)maps explicit-parameter NACA 5-digit specs tobuffalo_wings.airfoil.Naca5AirfoilParams.
4.1.7 NACA Modified 5-digit
Modified NACA 5-digit airfoils may be specified in either of two ways.
Designation
airfoils:
naca23015_46:
type: naca5_modified
designation: "23015-46"
Explicit Parameters
airfoils:
naca23015_46_explicit:
type: naca5_modified
params:
ideal_lift_coefficient: 0.3
max_camber_location: 0.15
reflexed: false
max_thickness: 0.15
leading_edge_index: 4.0
max_thickness_location: 0.6
trailing_edge: sharp
Fields
type:"naca5_modified"Exactly one of:
designation: modified NACA 5-digit designation stringparams: explicit parameter definition
If params is present, it contains:
ideal_lift_coefficient: ideal lift coefficientmax_camber_location: location of maximum camber as a fraction of chordreflexed: whether the camber line has a reflexed trailing edgemax_thickness: maximum thickness as a fraction of chordleading_edge_index: modified-thickness leading-edge radius indexmax_thickness_location: location of maximum thickness as a fraction of chordtrailing_edge:"standard"or"sharp"; default"standard"
Designation Syntax
The designation must use the form
#####-##.The first five digits are the standard NACA 5-digit designation.
The first digit after the dash is the modified-thickness leading-edge radius index.
The second digit after the dash is 10 times the chordwise location of maximum thickness.
For example,
23015-46means:ideal lift coefficient
0.3maximum camber location
0.15cstandard non-reflexed 5-digit camber
maximum thickness
0.15cleading-edge radius index
4maximum thickness at
0.6c
Validation Rules
Exactly one of
designationandparamsmust be present.If
designationis present:must match
^[0-9]{5}-[1-9][1-9]$the third digit of the 5-digit designation must be
0or1
If
paramsis present:0.15 <= ideal_lift_coefficient < 0.60.05 <= max_camber_location < 0.30 <= max_thickness <= 0.41 <= leading_edge_index < 100.1 <= max_thickness_location < 1.0trailing_edgemust be one ofstandard|sharp
Examples
Accepted examples:
designation: "23015-46"designation: "23115-46"params: {ideal_lift_coefficient: 0.3, max_camber_location: 0.15, reflexed: false, max_thickness: 0.15, leading_edge_index: 4.0, max_thickness_location: 0.6}params: {ideal_lift_coefficient: 0.3, max_camber_location: 0.15, reflexed: true, max_thickness: 0.15, leading_edge_index: 4.0, max_thickness_location: 0.6}
Unsupported examples:
designation: "23015"designation: "23215-46"designation: "23015-06"params: {ideal_lift_coefficient: 0.3, max_camber_location: 0.15, reflexed: false, max_thickness: 0.15, leading_edge_index: 0.0, max_thickness_location: 0.6}
Notes
The modified NACA 5-digit family reuses the NACA 5-digit camber definition.
The camber implementation is selected by reflex behavior:
designation third digit
0orparams.reflexed = false: standard 5-digit camberdesignation third digit
1orparams.reflexed = true: reflexed 5-digit camber
The designation digits are encoded indices, not the physical values stored in
params.For the first digit of the 5-digit designation:
digit = 10 * (2 / 3) * ideal_lift_coefficient. Equivalently,ideal_lift_coefficient = 0.15 * first_digit.For the second digit of the 5-digit designation:
digit = 10 * 2 * max_camber_location. Equivalently,max_camber_location = 0.05 * second_digit.designationrepresents the traditional encoded modified NACA 5-digit form.paramsis more general thandesignation.The
paramsform may describe airfoils that do not correspond to a historical published modified NACA 5-digit designation.In the runtime API,
AirfoilFactory.from_spec(...)maps designation-based modified NACA 5-digit specs tobuffalo_wings.airfoil.Naca5ModifiedAirfoilClassic.In the runtime API,
AirfoilFactory.from_spec(...)maps explicit-parameter modified NACA 5-digit specs tobuffalo_wings.airfoil.Naca5ModifiedAirfoilParams.
4.1.8 NACA 16-Series
NACA 16-series airfoils may be specified in either of two ways.
Designation
airfoils:
naca16_312:
type: naca16
designation: "16-312"
Explicit Parameters
airfoils:
naca16_312_explicit:
type: naca16
params:
ideal_lift_coefficient: 0.3
max_thickness: 0.12
Fields
type:"naca16"Exactly one of:
designation: NACA 16-series designation stringparams: explicit parameter definition
If params is present, it contains:
ideal_lift_coefficient: ideal lift coefficientmax_thickness: maximum thickness as a fraction of chord
Designation Syntax
The designation must use the form
16-###.The first two digits are fixed as
16.The first digit after the dash represents 10 times the ideal lift coefficient.
The last two digits combine to represent 100 times the maximum thickness.
For example,
16-312means:ideal lift coefficient
0.3maximum thickness
0.12c
Validation Rules
Exactly one of
designationandparamsmust be present.If
designationis present:must match
^16-[0-9][0-9]{2}$the encoded ideal lift coefficient digit must be nonnegative
the encoded thickness digits must represent a positive thickness
If
paramsis present:0 <= ideal_lift_coefficient <= 0.90 < max_thickness <= 0.4
Examples
Accepted examples:
designation: "16-312"designation: "16-212"params: {ideal_lift_coefficient: 0.3, max_thickness: 0.12}params: {ideal_lift_coefficient: 0.2, max_thickness: 0.15}
Unsupported examples:
designation: "16312"designation: "16-31"designation: "16A-312"params: {ideal_lift_coefficient: 0.3, max_thickness: 0.0}
Notes
NACA 16-series airfoils are planned schema targets, but they are not yet constructable through
AirfoilFactory.from_spec(...).designationrepresents the traditional encoded NACA 16-series form.paramsis more general thandesignation.The
paramsform may describe airfoils that do not correspond to a historical published NACA 16-series designation.The designation digits are encoded indices, not the physical values stored in
params.For the first digit after the dash,
digit = 10 * ideal_lift_coefficient. Equivalently,ideal_lift_coefficient = 0.1 * digit.For the last two digits,
digits = 100 * max_thickness. Equivalently,max_thickness = 0.01 * digits.
4.1.9 NACA 6-Series
NACA 6-series airfoils may be specified in either of two ways.
Designation
airfoils:
naca65_213:
type: naca6
designation: "65(1)-213"
Explicit Parameters
airfoils:
naca65_explicit:
type: naca6
params:
thickness:
series: "65"
max_thickness: 0.12
camber:
components:
- ideal_lift_coefficient: 0.3
mean_line_shape_parameter: 0.8
Fields
type:"naca6"Exactly one of:
designation: NACA 6-series designation stringparams: explicit parameter definition
If params is present, it contains:
thickness.series: thickness-family designation such as"63","64","65","66", or"67"thickness.max_thickness: maximum thickness as a fraction of chordcamber.components: one or more additive 6-series mean-line components
Each camber.components entry contains:
ideal_lift_coefficient: ideal lift coefficient for that mean-line componentmean_line_shape_parameter: historical 6-series mean-line shape parameter often labeleda; optional only whencamber.componentscontains exactly one component, in which case it defaults to1.0
Designation Syntax
The designation syntax is not yet fully finalized in this schema.
The schema is expected to support common published 6-series forms such as
65-210,65(1)-212, and65(3)-218.In that common form:
the leading
65identifies the family designationan optional low-drag-range digit may appear as a historical subscript or as an ASCII parenthetical form such as
(1)the first of the trailing three digits encodes the nominal ideal lift coefficient in tenths
the last two of the trailing three digits encode the maximum thickness in hundredths of chord
For example,
65(1)-213denotes a 65-series section with low-drag-range digit1, nominal ideal lift coefficient0.2, and nominal maximum thickness0.13.When historical notation omits the low-drag-range subscript, ASCII designations may omit the parenthetical form as well, as in
65-210.Historical
a=...suffixes are not part of the supporteddesignationsurface and should be represented withparams.Additional compact or normalized designation variants may be added once the supported parsing surface is finalized.
Validation Rules
Exactly one of
designationandparamsmust be present.If
designationis present:must match one of the supported 6-series designation forms once that parsing surface is finalized
if a low-drag-range digit is present in the designation, it must be a positive integer digit
the encoded nominal ideal lift coefficient digit must be nonnegative
the encoded thickness digits must represent a positive thickness
If
paramsis present:thickness.seriesmust be one of63|64|65|66|670 <= thickness.max_thickness <= 0.4camber.componentsmust contain at least one componentif
camber.componentscontains exactly one component, that component’sideal_lift_coefficientmust satisfy0 <= value <= 0.5if
camber.componentscontains exactly one component andmean_line_shape_parameteris omitted, it defaults to1.0if
camber.componentscontains more than one component, each component’sideal_lift_coefficientmust satisfy-0.5 <= value <= 0.5if
camber.componentscontains more than one component, each component must explicitly providemean_line_shape_parametereach provided
camber.components[*].mean_line_shape_parametermust satisfy0 <= value <= 1
Examples
Accepted examples:
designation: "65-210"designation: "65(1)-212"designation: "65(3)-218"params: {thickness: {series: "65", max_thickness: 0.12}, camber: {components: [{ideal_lift_coefficient: 0.3}]}}params: {thickness: {series: "65", max_thickness: 0.18}, camber: {components: [{ideal_lift_coefficient: 0.3, mean_line_shape_parameter: 0.8}, {ideal_lift_coefficient: -0.1, mean_line_shape_parameter: 1.0}]}}
Unsupported examples:
designation: "65(1)213"designation: "65-210 a=0.8"designation: "65(1.5)-212"params: {thickness: {series: "65", max_thickness: 0.12}, camber: {components: [{ideal_lift_coefficient: 0.3}, {ideal_lift_coefficient: -0.1, mean_line_shape_parameter: 1.0}]}}params: {thickness: {series: "65", max_thickness: 0.12}, camber: {components: [{ideal_lift_coefficient: -0.1}]}}
Notes
NACA 6-series airfoils are planned schema targets, but they are not yet constructable through
AirfoilFactory.from_spec(...).The explicit
paramsform is more general thandesignation.The grouped
thicknessandcamberstructure reflects the historical separation between thickness-family inputs and additive camber-line inputs in the bundled 6-series references.The bundled NASA and PDAS lineage supports summing multiple 6-series mean-line components.
In additive definitions, component
ideal_lift_coefficientvalues may be positive or negative so that the resulting camber line is the algebraic sum of the component mean lines.For single-component definitions, the supported schema surface expects a nonnegative
ideal_lift_coefficient.When a 6-series
designationomits an explicit mean-line statement, the supported schema surface assumes the historical uniform-load mean line, corresponding tomean_line_shape_parameter = 1.0.For single-component
paramsdefinitions,mean_line_shape_parametermay likewise be omitted and defaults to1.0.Additive
paramsdefinitions require explicitmean_line_shape_parametervalues for each component.The low-drag-range digit that appears in historical 6-series designations is treated here as designation metadata tied to the named thickness form rather than as an independent explicit schema parameter.
The
designationform is intended to cover common published single-designation strings such as65-210and65(1)-212, including ASCII parenthetical notation used in place of historical subscript notation.The
paramsform is intended for explicit or non-canonical definitions, including additive camber definitions with more than one mean-line component and when more precision is needed on specifying the camber parameters.Historical scaled-thickness designation variants are currently out of scope for the supported
designationsurface and should be represented withparamsif needed.
4.1.10 NACA 6A-Series
NACA 6A-series airfoils may be specified in either of two ways.
Designation
airfoils:
naca65a_212:
type: naca6a
designation: "65A-212"
Explicit Parameters
airfoils:
naca65a_explicit:
type: naca6a
params:
thickness:
series: "65A"
max_thickness: 0.12
camber:
components:
- ideal_lift_coefficient: 0.3
Fields
type:"naca6a"Exactly one of:
designation: NACA 6A-series designation stringparams: explicit parameter definition
If params is present, it contains:
thickness.series: thickness-family designation such as"63A","64A", or"65A"thickness.max_thickness: maximum thickness as a fraction of chordcamber.components: one or more additive 6A-series mean-line components
Each camber.components entry contains:
ideal_lift_coefficient: ideal lift coefficient for that mean-line component
Designation Syntax
The designation syntax is not yet fully finalized in this schema.
The schema is expected to support common published 6A-series forms such as
64A-212once the supported parsing surface is finalized.The bundled references clearly identify 6A-series family tokens such as
63A,64A, and65A.The schema is expected to interpret the trailing three digits analogously to the 6-series form:
the first trailing digit encodes the nominal ideal lift coefficient in tenths
the last two trailing digits encode the maximum thickness in hundredths of chord
Historical
a=...suffixes are not part of the supporteddesignationsurface and should be represented withparamsif such an extension is ever needed.Additional designation guidance should be finalized together with the supported parsing rules.
Validation Rules
Exactly one of
designationandparamsmust be present.If
designationis present:must match one of the supported 6A-series designation forms once that parsing surface is finalized
the encoded nominal ideal lift coefficient digit must be nonnegative
the encoded thickness digits must represent a positive thickness
If
paramsis present:thickness.seriesmust be one of63A|64A|65A0 <= thickness.max_thickness <= 0.4camber.componentsmust contain at least one componentif
camber.componentscontains exactly one component, that component’sideal_lift_coefficientmust satisfy0 <= value <= 0.5if
camber.componentscontains more than one component, each component’sideal_lift_coefficientmust satisfy-0.5 <= value <= 0.5
Examples
Accepted examples:
designation: "64A-212"designation: "65A-218"params: {thickness: {series: "65A", max_thickness: 0.12}, camber: {components: [{ideal_lift_coefficient: 0.3}]}}params: {thickness: {series: "64A", max_thickness: 0.15}, camber: {components: [{ideal_lift_coefficient: 0.3}, {ideal_lift_coefficient: -0.1}]}}
Unsupported examples:
designation: "64A212"designation: "64A-212 a=0.8"params: {thickness: {series: "65A", max_thickness: 0.12}, camber: {components: [{ideal_lift_coefficient: 0.3, mean_line_shape_parameter: 0.8}]}}params: {thickness: {series: "65A", max_thickness: 0.12}, camber: {components: [{ideal_lift_coefficient: -0.1}]}}
Notes
NACA 6A-series airfoils are planned schema targets, but they are not yet constructable through
AirfoilFactory.from_spec(...).The explicit
paramsform is more general thandesignation.The grouped
thicknessandcamberstructure reflects the historical separation between thickness-family inputs and additive camber-line inputs in the bundled 6A-series references.The bundled NASA and PDAS lineage supports summing multiple 6A-series mean-line components.
In additive definitions, component
ideal_lift_coefficientvalues may be positive or negative so that the resulting camber line is the algebraic sum of the component mean lines.For single-component definitions, the supported schema surface expects a nonnegative
ideal_lift_coefficient.For 6A-series airfoils, the bundled NASA and PDAS lineage fixes the historical
aparameter to0.80rather than treating it as a user-specified field.Accordingly,
mean_line_shape_parameteris intentionally omitted from thenaca6aexplicit parameter form.The
designationform is intended to cover common published single-designation strings and implies the historical modified 6A mean line rather than a user-specifiedavalue.The
paramsform is intended for explicit or non-canonical definitions, including additive camber definitions with more than one mean-line component and when more precision is needed on specifying the mean-line component.Historical scaled-thickness designation variants are currently out of scope for the supported
designationsurface and should be represented withparamsif needed.
4.2 Coordinate Files
Coordinate-defined airfoils may be specified using the following file formats.
4.2.1 Selig Format
Selig format stores the airfoil as a single ordered surface curve.
The first non-ignored line is the airfoil name or title.
Subsequent non-ignored lines contain coordinate pairs.
Blank lines are ignored.
Lines whose first non-whitespace character is # are ignored.
The supported coordinate-row syntax is a numeric x y pair separated by whitespace or a comma.
The ordered points are expected to run from the trailing edge along one surface to the leading edge and then back to the trailing edge along the other surface.
The schema treats this as a single surface-curve topology rather than separate upper and lower blocks.
4.2.2 Lednicer Format
Lednicer format stores the airfoil as separate upper and lower surface blocks.
The first non-ignored line is the airfoil name or title.
The next non-ignored numeric line gives the declared upper-surface and lower-surface point counts.
Subsequent non-ignored lines contain coordinate pairs for the upper block followed by the lower block.
Blank lines are ignored.
Lines whose first non-whitespace character is # are ignored.
The supported coordinate-row syntax is a numeric x y pair separated by whitespace or a comma.
The upper and lower surface blocks are both expected to run from the leading edge to the trailing edge.
4.2.3 Native Structured Point Formats
In addition to Selig and Lednicer files, type: file may reference native structured point files.
The supported native structured point file formats are surface_curve and upper_lower.
These formats mirror the corresponding type: points schema forms and are stored as YAML or JSON files rather than inline YAML mappings.
A native structured point file contains only the point-format payload itself rather than a top-level airfoils mapping.
Coordinate-file airfoils may be specified as:
airfoils:
myfoil:
type: file
path: "airfoils/myfoil.yaml"
format: auto
4.2.4 Fields
type:"file"path: path to the coordinate fileformat:"auto","selig","lednicer","surface_curve", or"upper_lower"; default"auto"
4.2.5 Format Detection
If
format: "selig", the file is parsed using the Selig rules.If
format: "lednicer", the file is parsed using the Lednicer rules.If
format: "surface_curve"orformat: "upper_lower", the file is parsed as a native structured point file using the correspondingtype: pointsschema shape.If
format: "auto", the parser should detect the format from the file structure.File extensions may be used as hints during
autodetection, but they do not override an explicitly declaredformat.If a YAML or JSON file clearly declares
format: surface_curveorformat: upper_lower,autodetection should treat it as a native structured point file.Otherwise, if a valid Lednicer two-count line is present immediately after the title, ignoring blank lines and comment lines,
autodetection should treat the file aslednicer.Otherwise,
autodetection should treat the file asselig.
4.2.6 Validation Rules
pathis required.formatmust be one ofauto|selig|lednicer|surface_curve|upper_lower.If
format: "selig":the file must contain at least one non-ignored title line
the file must contain at least 3 coordinate rows after the title
each coordinate row must be a numeric pair
[x, y]
If
format: "lednicer":the file must contain at least one non-ignored title line
the file must contain exactly one declared point-count line before the coordinate blocks
the point-count line must contain exactly two positive integers: upper count and lower count
the file must contain exactly the declared number of upper and lower coordinate rows after ignored blank and comment lines are removed
each coordinate row must be a numeric pair
[x, y]
If
format: "surface_curve"orformat: "upper_lower":the file contents must satisfy the corresponding
type: pointsschema formYAML and JSON serializations are supported
the file contains only the point-format payload rather than a top-level
airfoilsmapping
For all supported file formats:
for
seligandlednicer, blank lines are ignoredfor
seligandlednicer, lines whose first non-whitespace character is#are ignoredfor native structured YAML or JSON files, comments and whitespace follow the rules of the host serialization format
finite trailing-edge thickness is allowed
the imported coordinates must define a valid nonzero chord extent so they can be normalized to unit chord
4.2.7 Examples
Accepted examples:
type: file, path: "airfoils/clarky.dat"type: file, path: "airfoils/clarky.dat", format: autotype: file, path: "airfoils/uiuc/mh60.dat", format: seligtype: file, path: "airfoils/uiuc/mh60_lednicer.dat", format: lednicertype: file, path: "airfoils/root.yaml", format: upper_lowertype: file, path: "airfoils/tip.json", format: surface_curve
Unsupported examples:
type: filetype: file, path: "airfoils/clarky.dat", format: csvtype: file, path: "airfoils/clarky.dat", format: lednicerwith no valid point-count linetype: file, path: "airfoils/clarky.dat", format: seligwith fewer than 3 coordinate rowstype: file, path: "airfoils/root.yaml", format: upper_lowerwith file contents that do not satisfy theupper_lowerpoint schema
4.2.8 Notes
Coordinate files define the airfoil through discrete surface points rather than an analytic parameterization.
Imported coordinates are interpreted in the local airfoil frame unless otherwise specified by the file format.
Imported airfoils are normalized internally to unit chord.
The first non-ignored line is treated as file metadata rather than as a coordinate row.
That in-file title or header line is not part of the geometry definition.
The schema-level airfoil identity comes from the
airfoilsmapping key and the imported source path rather than from a title embedded inside the external file.Ignoring the in-file title for geometry and identity avoids hidden schema changes when a file header is edited without changing the coordinates.
type: filesupports Selig and Lednicer import files as well as native structured point files that mirror thetype: pointsschema.By convention, Selig and Lednicer examples use
.datpaths, while native structured point-file examples use.yamlor.jsonpaths.format: autois intended for convenience when reading common UIUC-style coordinate files, while explicitformatmay be used when detection would otherwise be ambiguous.If preservation of original imported scale, translation, or orientation is needed in the future, that information should be treated as import provenance rather than as part of the canonical airfoil geometry definition.
Coordinate-file airfoils are planned, but they are not yet constructable through
AirfoilFactory.from_spec(...).
4.3 Point Coordinates
Coordinate-defined airfoils may be specified directly in the YAML file.
4.3.1 Surface curve format
airfoils:
flat_plate:
type: points
format: surface_curve
leading_edge: 3
points:
- [1.0, 0.0]
- [0.7, -0.02]
- [0.3, -0.03]
- [0.0, 0.0]
- [0.3, 0.03]
- [0.7, 0.02]
- [1.0, 0.0]
This format specifies a single ordered list of points that traces the airfoil surface starting and ending at the trailing edge.
4.3.2 Upper/Lower surface format
airfoils:
example_foil:
type: points
format: upper_lower
upper:
- [0.0, 0.0]
- [0.3, 0.06]
- [0.7, 0.03]
- [1.0, 0.0]
lower:
- [0.0, 0.0]
- [0.3, -0.02]
- [0.7, -0.01]
- [1.0, 0.0]
This format specifies the upper and lower surfaces separately.
4.3.3 Fields
type:"points"format:"surface_curve"or"upper_lower"
If format: "surface_curve":
leading_edge: 0-based index of the point that represents the leading edgepoints: ordered list of[x, y]coordinate pairs
If format: "upper_lower":
upper: ordered list of[x, y]coordinate pairslower: ordered list of[x, y]coordinate pairs
4.3.4 Supported Format Values
"surface_curve": points proceed around the airfoil surface starting and ending at the trailing edge"upper_lower": points are given as separate upper and lower surfaces, each starting from the leading edge and going to the trailing edge
4.3.5 Validation Rules
If
format: "surface_curve":pointsrequiredmust contain at least 3 points
each point must be a numeric pair
[x, y]
leading_edgeis required and must be a valid index into thepointslistupperandlowernot allowed
If
format: "upper_lower":upperandlowerrequiredeach must contain at least 2 points
each point must be a numeric pair
[x, y]the first point of both lists (the leading edge) must be coincident
the last point of each list defines the trailing-edge point for that surface
these may be coincident for a sharp trailing edge
pointsandleading_edgenot allowed
The input geometry must define a valid nonzero chord extent so it can be normalized to unit chord internally
4.3.6 Notes
Point-based airfoils define the geometry directly through discrete coordinates on the surface.
Point-defined airfoils are normalized to unit chord.
In
surface_curveformat, the trailing-edge point must be represented for both surfaces, even if the two points are coincident.In
upper_lowerformat, the upper and lower surfaces are specified independently and must share the same leading-edge point.The
leading_edgeindex is required insurface_curveformat to identify the surface split and avoid ambiguity in point sets with multiple candidate leading-edge points or nonuniform sampling.If preservation of original point-set scale, translation, or orientation is needed in the future, that information should be treated as provenance rather than as part of the canonical normalized airfoil geometry definition.
Point-defined airfoils are planned, but they are not yet constructable through
AirfoilFactory.from_spec(...).
4.4 Spline Airfoils
Spline-backed airfoils provide the natural persisted representation for non-analytic airfoils whose authoritative geometry is stored as editable control-point curves rather than as source points or analytic parameters.
The first implemented spline schema subtype is a Bezier-backed airfoil.
airfoils:
edited_tip:
type: spline
representation: bezier
upper:
control_points:
- [0.0, 0.0]
- [0.2, 0.06]
- [0.7, 0.03]
- [1.0, 0.002]
lower:
control_points:
- [0.0, 0.0]
- [0.2, -0.03]
- [0.7, -0.02]
- [1.0, -0.002]
4.4.1 Fields
type:"spline"representation: spline representation subtypeupper: upper-surface spline definitionlower: lower-surface spline definitionprovenance: optional source and construction metadata
For the initial implemented Bezier subtype:
representation:"bezier"upper.control_points: ordered list of planar[x, y]control pointslower.control_points: ordered list of planar[x, y]control points
The Bezier degree is derived from the number of control points and is therefore not stored explicitly in the first implemented Bezier-backed schema form.
4.4.2 Validation Rules
For the initial implemented Bezier subtype:
representationmust be"bezier"upper.control_pointsandlower.control_pointsmust each contain at least 2 pointseach control point must be a numeric pair
[x, y]the first upper and lower control points must coincide at the leading edge
the last upper and lower control points define the upper and lower trailing-edge endpoints
The first implemented spline schema does not require higher-order leading-edge continuity such as G1 or G2.
The first implemented spline schema also does not require coincident upper and lower trailing-edge endpoints, which allows both sharp and blunt trailing edges.
4.4.3 Notes
In this repository, “spline” means geometric parametric spline curves such as Bezier, B-spline, and eventually NURBS, not interpolation splines such as PCHIP.
The current implementation supports only the Bezier subtype.
For the Bezier subtype, both upper and lower surfaces use their own natural parameterization from leading edge to trailing edge.
The schema should remain backend-neutral even if the first runtime implementation uses Splipy internally for broader spline families later.
type: splineis the natural persisted representation for edited or fitted non-analytic airfoils once their authoritative geometry is no longer just the original source points or analytic definition.The current implementation constructs
type: splinethroughAirfoilFactory.from_spec(...)forrepresentation: bezier.Canonical
type: cstairfoils may be exported exactly into this persisted Bezier-backed spline form throughbuffalo_wings.airfoil.cst_airfoil_to_spline_spec(...).That exact export path is intended for cases where CST remains the source definition but spline geometry becomes the authoritative stored representation for downstream editing or interchange.
4.5 CST Coefficients
CST airfoils are defined directly through separate upper-surface and lower-surface Class-Shape Transformation coefficient sets.
airfoils:
cst_foil:
type: cst
trailing_edge_thickness: 0.0025
upper: {a: [0.2, 0.1, 0.0]}
lower: {a: [-0.1, -0.05, 0.0]}
4.5.1 Fields
type:"cst"trailing_edge_thickness: trailing-edge thickness as a fraction of chord; default0.0upper: upper-surface CST definition; default{n1: 0.5, n2: 1.0, a: []}lower: lower-surface CST definition; default{n1: 0.5, n2: 1.0, a: []}
Each surface definition contains:
n1: leading-edge class-function exponent; optional, default0.5n2: trailing-edge class-function exponent; optional, default1.0a: ordered list of shape-function coefficients; default[]
4.5.2 Validation Rules
upper.n1must be numericupper.n2must be numericlower.n1must be numericlower.n2must be numerictrailing_edge_thicknessmust be numerictrailing_edge_thickness >= 0upper.n1 >= 0upper.n2 >= 0lower.n1 >= 0lower.n2 >= 0upper.amust be a list of numeric coefficientslower.amust be a list of numeric coefficients
4.5.3 Examples
Accepted examples:
type: csttype: cst, trailing_edge_thickness: 0.0025, upper: {a: [0.2, 0.1, 0.0]}, lower: {a: [-0.1, -0.05, 0.0]}type: cst, upper: {n1: 0.5, n2: 1.0, a: [0.1, 0.0]}, lower: {n1: 0.5, n2: 1.0, a: [-0.1, 0.0]}
Unsupported examples:
type: cst, trailing_edge_thickness: -0.001, upper: {a: [0.2]}, lower: {a: [-0.2]}type: cst, upper: {n1: -0.5, n2: 1.0, a: [0.2]}, lower: {n1: 0.5, n2: 1.0, a: [-0.2]}type: cst, upper: {n1: 0.5, n2: 1.0, a: "0.2,0.1"}, lower: {n1: 0.5, n2: 1.0, a: [-0.1]}type: cst, upper: {n1: 0.5}, lower: {a: [-0.1]}
4.5.4 Notes
CST defines the airfoil geometry through separate coefficient sets for the upper and lower surfaces.
The class function exponents and coefficient arrays determine the surface shape in the normalized local airfoil frame.
Omitting
n1andn2selects the standard airfoil CST class function withn1 = 0.5andn2 = 1.0.Nondefault
n1orn2values are allowed, but they describe more general CST class-function shapes rather than the typical rounded-leading-edge, cusped-trailing-edge airfoil form.trailing_edge_thicknessexplicitly controls the trailing-edge gap in the airfoil definition.Airfoil definitions are normalized to unit chord.
The coefficient ordering in
ais the schema order and should be preserved exactly as given.AirfoilFactory.from_spec(...)constructs runtimeCstAirfoilobjects for canonicaln1 = 0.5,n2 = 1.0CST specs and runtimeCstGeometryobjects for more general CST exponent choices.Canonical
CstAirfoiland generalCstGeometrycan represent the same canonical CST shape, but they do not share the same curve parameterization.CstAirfoiluses the airfoil-specific curve parameterizationx = u^2, which keeps canonical curve-parameter derivatives finite at the leading edge.CstGeometrykeeps the general full-airfoil curve parameterizationx = |u|, so leading-edge curve-parameter derivatives may remain singular for exponent choices such asn1 = 0.5.Curve-parameter derivatives, breakpoint-side values, and coordinates sampled at the same
ucan therefore differ betweenCstAirfoilandCstGeometryeven when they describe the same geometric shape under the mappingtau = sign(u) * u^2.
4.6 PARSEC Coefficients
This uses a 12-parameter PARSEC specification with independently specified upper and lower leading-edge radii.
airfoils:
parsec_foil:
type: parsec
leading_edge_radius:
upper: 0.005
lower: 0.005
trailing_edge:
thickness: 0.0025
location: -0.006
direction_angle: 7.0
wedge_angle: 10.0
upper_surface_max:
location: [0.41, 0.11]
curvature: -0.9
lower_surface_min:
location: [0.20, -0.023]
curvature: 0.05
4.6.1 Fields
type:"parsec"leading_edge_radius.upper: upper-surface leading-edge radiusleading_edge_radius.lower: lower-surface leading-edge radiustrailing_edge.thickness: trailing-edge thicknesstrailing_edge.location: vertical coordinate of the midpoint between the upper and lower trailing-edge endpointstrailing_edge.direction_angle: angle of the bisector of the upper and lower trailing-edge surface directionstrailing_edge.wedge_angle: included angle between the upper and lower surface directions at the trailing edgeupper_surface_max.location:[x, y]location of the upper-surface maximumupper_surface_max.curvature: curvature of the upper surface at the upper-surface maximumlower_surface_min.location:[x, y]location of the lower-surface minimumlower_surface_min.curvature: curvature of the lower surface at the lower-surface minimum
4.6.2 Validation Rules
leading_edge_radiusmust contain bothupperandlowerleading_edge_radius.upper > 0leading_edge_radius.lower > 0trailing_edge.thickness >= 0upper_surface_max.locationmust be a numeric 2-tuple[x, y]lower_surface_min.locationmust be a numeric 2-tuple[x, y]0 < upper_surface_max.location[0] < 10 < lower_surface_min.location[0] < 1upper_surface_max.location[1] > 0lower_surface_min.location[1] < 0
4.6.3 Examples
Accepted examples:
type: parsec, leading_edge_radius: {upper: 0.005, lower: 0.005}, trailing_edge: {thickness: 0.0025, location: -0.006, direction_angle: 7.0, wedge_angle: 10.0}, upper_surface_max: {location: [0.41, 0.11], curvature: -0.9}, lower_surface_min: {location: [0.20, -0.023], curvature: 0.05}type: parsec, leading_edge_radius: {upper: 0.004, lower: 0.004}, trailing_edge: {thickness: 0.0, location: 0.0, direction_angle: 0.0, wedge_angle: 8.0}, upper_surface_max: {location: [0.4, 0.08], curvature: -0.8}, lower_surface_min: {location: [0.25, -0.02], curvature: 0.04}
Unsupported examples:
type: parsec, leading_edge_radius: {upper: -0.005, lower: 0.005}, trailing_edge: {thickness: 0.0025, location: -0.006, direction_angle: 7.0, wedge_angle: 10.0}, upper_surface_max: {location: [0.41, 0.11], curvature: -0.9}, lower_surface_min: {location: [0.20, -0.023], curvature: 0.05}type: parsec, leading_edge_radius: {upper: 0.005, lower: 0.005}, trailing_edge: {thickness: 0.0025, location: -0.006, direction_angle: 7.0, wedge_angle: 10.0}, upper_surface_max: {location: [1.2, 0.11], curvature: -0.9}, lower_surface_min: {location: [0.20, -0.023], curvature: 0.05}type: parsec, leading_edge_radius: {upper: 0.005}, trailing_edge: {thickness: 0.0025, location: -0.006, direction_angle: 7.0, wedge_angle: 10.0}, upper_surface_max: {location: [0.41, 0.11], curvature: -0.9}, lower_surface_min: {location: [0.20, -0.023], curvature: 0.05}
4.6.4 Notes
All length quantities are nondimensionalized by the chord.
Angular quantities are specified in degrees.
Airfoil definitions are normalized to unit chord.
This representation defines the airfoil through geometric constraints rather than directly through surface points.
Upper and lower leading-edge radii are specified independently.
PARSEC airfoils are planned, but they are not yet constructable through
AirfoilFactory.from_spec(...).
4.7 Simple Analytic Airfoils
These airfoils are defined by simple geometric shapes rather than by a historical designation system.
4.7.1 Flat Plate
Flat-plate airfoils are specified directly by type.
Example
airfoils:
plate:
type: flat_plate
Fields
type:"flat_plate"
Validation Rules
No additional fields are required.
Examples
Accepted examples:
type: flat_plate
Unsupported examples:
type: flat_plate, params: {}
Notes
This represents an idealized zero-thickness flat plate in the normalized local frame.
Flat-plate airfoils are planned, but they are not yet constructable through
AirfoilFactory.from_spec(...).
4.7.2 Biconvex
Biconvex airfoils are specified through the maximum thickness only.
Example
airfoils:
biconvex_12:
type: biconvex
params:
max_thickness: 0.12
Fields
type:"biconvex"params.max_thickness: maximum thickness as a fraction of chord
Validation Rules
paramsmust be present.0 <= params.max_thickness <= 1.0
Examples
Accepted examples:
params: {max_thickness: 0.12}params: {max_thickness: 0.04}
Unsupported examples:
type: biconvexparams: {}params: {max_thickness: -0.1}
Notes
In this schema,
biconvexmeans the circular-arc form defined by two intersecting circular arcs.Parabolic-arc variants also appear in the literature and in benchmark configurations, but they are treated as a distinct approximation rather than as the canonical meaning of
biconvexhere.Use
biconvex_parabolawhen the intended shape is the parabolic variant.Biconvex airfoils are planned, but they are not yet constructable through
AirfoilFactory.from_spec(...).
4.7.3 Biconvex Parabola
Parabolic biconvex airfoils are specified through the maximum thickness only.
Example
airfoils:
biconvex_parabola_12:
type: biconvex_parabola
params:
max_thickness: 0.12
Fields
type:"biconvex_parabola"params.max_thickness: maximum thickness as a fraction of chord
Validation Rules
paramsmust be present.0 <= params.max_thickness <= 1.0
Examples
Accepted examples:
params: {max_thickness: 0.12}params: {max_thickness: 0.04}
Unsupported examples:
type: biconvex_parabolaparams: {}params: {max_thickness: -0.1}
Notes
This type represents the parabolic-arc variant sometimes used in analytical approximations and benchmark problems.
Use
biconvexwhen the intended shape is the circular-arc form.Parabolic biconvex airfoils are planned, but they are not yet constructable through
AirfoilFactory.from_spec(...).
4.7.4 Polygon
Polygonal airfoils are specified by ordered vertices connected by straight segments.
Example
airfoils:
diamond:
type: polygon
params:
vertices:
- [1.0, 0.0]
- [0.5, 0.05]
- [0.0, 0.0]
- [0.5, -0.05]
Fields
type:"polygon"params.vertices: ordered polygon vertices in the normalized local frame
Validation Rules
paramsmust be present.params.verticesmust contain at least 3 points.Each vertex must be a numeric 2-tuple
[x, y].
Examples
Accepted examples:
params: {vertices: [[1.0, 0.0], [0.5, 0.05], [0.0, 0.0], [0.5, -0.05]]}params: {vertices: [[1.0, 0.01], [0.0, 0.06], [0.0, -0.04], [1.0, -0.01]]}
Unsupported examples:
type: polygonparams: {vertices: []}params: {vertices: [[1.0, 0.0], [0.0, 0.0]]}
Notes
The airfoil boundary is closed by connecting the last vertex back to the first.
Open trailing edges are allowed by specifying distinct upper and lower trailing-edge-adjacent vertices.
Polygonal airfoils are planned, but they are not yet constructable through
AirfoilFactory.from_spec(...).
4.7.5 Ellipse
Elliptical airfoils are specified through the maximum thickness only.
Example
airfoils:
ellipse_12:
type: ellipse
params:
max_thickness: 0.12
Fields
type:"ellipse"params.max_thickness: maximum thickness as a fraction of chord
Validation Rules
paramsmust be present.0 < params.max_thickness <= 1.0
Examples
Accepted examples:
params: {max_thickness: 0.12}params: {max_thickness: 1.0}
Unsupported examples:
type: ellipseparams: {max_thickness: 0.0}params: {max_thickness: 1.2}
Notes
max_thickness = 1.0corresponds to the circle case in the normalized local frame.Elliptical airfoils are planned, but they are not yet constructable through
AirfoilFactory.from_spec(...).
4.7.6 Circular Arc
Circular-arc airfoils are specified through the maximum thickness only.
Example
airfoils:
arc_08:
type: circular_arc
params:
max_thickness: 0.08
Fields
type:"circular_arc"params.max_thickness: maximum thickness as a fraction of chord
Validation Rules
paramsmust be present.0 <= params.max_thickness <= 1.0
Examples
Accepted examples:
params: {max_thickness: 0.08}params: {max_thickness: 0.0}
Unsupported examples:
type: circular_arcparams: {max_thickness: -0.05}
Notes
Circular-arc airfoils are planned, but they are not yet constructable through
AirfoilFactory.from_spec(...).
4.7.7 Joukowski
Joukowski airfoils are specified by the classical transformation parameters nu and epsilon.
Example
airfoils:
joukowski_example:
type: joukowski
params:
nu: 0.1
epsilon: 0.05
Fields
type:"joukowski"params.nu: camber-related Joukowski shape parameterparams.epsilon: thickness-related Joukowski shape parameter
Validation Rules
paramsmust be present.params.numust be numeric.params.epsilonmust be numeric.
Examples
Accepted examples:
params: {nu: 0.1, epsilon: 0.05}params: {nu: 0.0, epsilon: 0.03}
Unsupported examples:
type: joukowskiparams: {nu: 0.1}params: {epsilon: 0.05}
Notes
nuandepsilonare shape-control parameters and do not directly equal the resulting geometric camber or thickness.Joukowski airfoils are planned, but they are not yet constructable through
AirfoilFactory.from_spec(...).
5. Normalization
Normalization defines how coordinate-based airfoil definitions are transformed into the canonical local airfoil frame used by this schema.
This section applies to imported coordinate files and inline point-coordinate airfoils. Analytic airfoil definitions, such as NACA, CST, and PARSEC, are already defined in the normalized local frame unless otherwise specified.
5.1 Canonical Normalized Frame
A normalized airfoil is represented in the local airfoil frame with the following properties:
leading-edge reference at
[0.0, 0.0]trailing-edge reference at
[1.0, 0.0]chord line aligned with the positive
xaxispositive
ydirected toward the upper surface side of the airfoilchord length equal to
1
5.2 Reference Definitions
Normalization is based on a leading-edge reference and a trailing-edge reference.
The leading-edge reference is the geometric leading-edge point used to define the start of the chord line.
The trailing-edge reference is the point used to define the end of the chord line.
For airfoils with distinct upper and lower trailing-edge endpoints, the trailing-edge reference is the midpoint of those two endpoints.
This definition avoids ambiguity for blunt trailing edges, where the upper and lower trailing-edge points may not coincide.
5.3 Reference Extraction by Representation
5.3.1 Coordinate Files
For file-based coordinate definitions, the leading-edge and trailing-edge references are determined from the parsed file format and the file topology.
For
lednicerfiles, the leading-edge reference is the shared leading-edge endpoint of the parsed upper and lower surfaces.For
lednicerfiles, the trailing-edge reference is the midpoint of the upper and lower trailing-edge endpoints.For
seligfiles, the trailing-edge reference is determined from the first and last surface points.For
seligfiles, the leading-edge reference is determined from the parsed surface-curve topology as the leading-edge point implied by the turn between the two surfaces.
5.3.2 Point Coordinates
For type: "points" airfoils:
If
format: "surface_curve":the first and last points define the two trailing-edge endpoints
the trailing-edge reference is the midpoint of those two endpoints
the
leading_edgeindex identifies the leading-edge reference point
If
format: "upper_lower":the first point of both
upperandlowerdefines the shared leading-edge referencethe last points of
upperandlowerdefine the upper and lower trailing-edge endpointsthe trailing-edge reference is the midpoint of the two trailing-edge endpoints
5.4 Normalization Transform
For imported coordinate files and inline point-coordinate airfoils, the following transform is applied:
Translate the airfoil so that the leading-edge reference is at the origin.
Rotate the airfoil so that the line from the leading-edge reference to the trailing-edge reference lies on the positive
xaxis.Scale the airfoil so that the distance from the leading-edge reference to the trailing-edge reference is
1.
After normalization, the leading-edge reference is at [0.0, 0.0] and the trailing-edge reference is at [1.0, 0.0].
5.5 Orientation
If the input geometry is oriented such that the upper surface lies at negative y after normalization, the implementation must either:
reject the geometry as invalid, or
apply a reflection about the
xaxis if such behavior is explicitly supported by the implementation
Recommended behavior: reject the geometry unless automatic reflection is explicitly documented.
5.6 Validation Rules
normalization requires a valid leading-edge reference
normalization requires a valid trailing-edge reference
the distance between the leading-edge reference and trailing-edge reference must be greater than zero
for airfoils with separate upper and lower trailing-edge endpoints, both endpoints must be valid before the trailing-edge midpoint is computed
if normalization is disabled for a coordinate-based airfoil, the geometry is preserved as provided, but it must still define a valid nonzero chord extent
5.7 Notes
Normalization must not define the leading edge purely as the point with minimum
x, because valid airfoil definitions may contain points withx < 0relative to the normalized leading-edge reference.Normalization must not define the trailing edge purely as the point with maximum
x, because blunt trailing edges may have distinct upper and lower endpoints.For blunt trailing edges, the trailing-edge midpoint is the canonical chord endpoint used for normalization.
This normalization procedure is intended to make coordinate-defined airfoils consistent with analytic airfoil definitions in this schema.