Source code for buffalo_wings.airfoil.internal.factory

"""Public factory helpers for schema-driven airfoil construction."""

from __future__ import annotations

from typing import Literal

from .airfoil import Airfoil
from .airfoil_schema import (
    AirfoilDefinitionSpec,
    Naca4AirfoilParamsSpec,
    Naca4AirfoilSpec,
    Naca4ModifiedAirfoilParamsSpec,
    Naca4ModifiedAirfoilSpec,
    Naca5AirfoilParamsSpec,
    Naca5AirfoilSpec,
    Naca5ModifiedAirfoilParamsSpec,
    Naca5ModifiedAirfoilSpec,
)
from .naca4_airfoil import Naca4AirfoilClassic, Naca4AirfoilParams
from .naca4_modified_airfoil import (
    Naca4ModifiedAirfoilClassic,
    Naca4ModifiedAirfoilParams,
)
from .naca5_airfoil import Naca5AirfoilClassic, Naca5AirfoilParams
from .naca5_modified_airfoil import (
    Naca5ModifiedAirfoilClassic,
    Naca5ModifiedAirfoilParams,
)


[docs] class AirfoilFactory: """ Construct public airfoil runtime objects from user-facing specs. This factory centralizes the mapping from serialized airfoil schema objects to the concrete runtime classes used by the geometry library. """
[docs] @staticmethod def from_spec(spec: AirfoilDefinitionSpec) -> Airfoil: """ Build an airfoil object from a schema definition. Parameters ---------- spec : AirfoilDefinitionSpec Serialized airfoil definition to convert into a runtime object. Returns ------- Airfoil Runtime airfoil instance corresponding to ``spec``. Raises ------ ValueError If a NACA specification does not provide exactly one of ``designation`` or ``params``. NotImplementedError If the airfoil type is not yet supported by the factory. """ if isinstance(spec, Naca4AirfoilSpec): if spec.designation is not None and spec.params is None: return Naca4AirfoilClassic(spec) if spec.designation is None and spec.params is not None: return Naca4AirfoilParams(spec) raise ValueError( "NACA 4-digit specs must provide exactly one of designation " "or params." ) if isinstance(spec, Naca4ModifiedAirfoilSpec): if spec.designation is not None and spec.params is None: return Naca4ModifiedAirfoilClassic(spec) if spec.designation is None and spec.params is not None: return Naca4ModifiedAirfoilParams(spec) raise ValueError( "Modified NACA 4-digit specs must provide exactly one of " "designation or params." ) if isinstance(spec, Naca5AirfoilSpec): if spec.designation is not None and spec.params is None: return Naca5AirfoilClassic(spec) if spec.designation is None and spec.params is not None: return Naca5AirfoilParams(spec) raise ValueError( "NACA 5-digit specs must provide exactly one of designation " "or params." ) if isinstance(spec, Naca5ModifiedAirfoilSpec): if spec.designation is not None and spec.params is None: return Naca5ModifiedAirfoilClassic(spec) if spec.designation is None and spec.params is not None: return Naca5ModifiedAirfoilParams(spec) raise ValueError( "Modified NACA 5-digit specs must provide exactly one of " "designation or params." ) raise NotImplementedError( f"AirfoilFactory does not support {type(spec).__name__} yet." )
[docs] @staticmethod def naca4_from_designation( designation: str, ) -> Naca4AirfoilClassic: """ Build a classic NACA 4-digit airfoil from a designation. Parameters ---------- designation : str Four-digit NACA designation such as ``"2412"``. Returns ------- Naca4AirfoilClassic Runtime airfoil built from the classic designation. Raises ------ ValueError If ``designation`` is not a valid 4-digit NACA code. """ return Naca4AirfoilClassic.from_designation(designation)
[docs] @staticmethod def naca4_from_params( *, m: float, p: float, t: float, trailing_edge: Literal["standard", "sharp"] = "standard", leading_edge_radius: Literal["standard", "exact"] = "standard", ) -> Naca4AirfoilParams: """ Build a parametric NACA 4-digit airfoil from explicit params. Parameters ---------- m : float Maximum camber as a fraction of chord. p : float Chordwise location of maximum camber as a fraction of chord. t : float Maximum thickness as a fraction of chord. trailing_edge : {"standard", "sharp"}, default="standard" Trailing-edge closure model for the thickness distribution. leading_edge_radius : {"standard", "exact"}, default="standard" Leading-edge radius treatment for the thickness distribution. Returns ------- Naca4AirfoilParams Runtime airfoil built from the explicit parameters. Raises ------ ValueError If any parameter lies outside the supported NACA 4-digit range. """ params = Naca4AirfoilParamsSpec( m=m, p=p, t=t, trailing_edge=trailing_edge, leading_edge_radius=leading_edge_radius, ) return Naca4AirfoilParams(Naca4AirfoilSpec(params=params))
[docs] @staticmethod def naca4_modified_from_designation( designation: str, ) -> Naca4ModifiedAirfoilClassic: """ Build a classic modified NACA 4-digit airfoil from a designation. Parameters ---------- designation : str Modified NACA 4-digit designation such as ``"0003-64"``. Returns ------- Naca4ModifiedAirfoilClassic Runtime airfoil built from the modified-series designation. Raises ------ ValueError If ``designation`` is not a valid modified NACA 4-digit code. """ return Naca4ModifiedAirfoilClassic.from_designation(designation)
[docs] @staticmethod def naca4_modified_from_params( *, m: float, p: float, t: float, leading_edge_index: float, max_thickness_location: float, trailing_edge: Literal["standard", "sharp"] = "standard", ) -> Naca4ModifiedAirfoilParams: """ Build a parametric modified NACA 4-digit airfoil from params. Parameters ---------- m : float Maximum camber as a fraction of chord. p : float Chordwise location of maximum camber as a fraction of chord. t : float Maximum thickness as a fraction of chord. leading_edge_index : float Modified-series leading-edge shape index. max_thickness_location : float Chordwise location of maximum thickness as a fraction of chord. trailing_edge : {"standard", "sharp"}, default="standard" Trailing-edge closure model for the thickness distribution. Returns ------- Naca4ModifiedAirfoilParams Runtime airfoil built from the explicit parameters. Raises ------ ValueError If any parameter lies outside the supported modified-series range. """ params = Naca4ModifiedAirfoilParamsSpec( m=m, p=p, t=t, leading_edge_index=leading_edge_index, max_thickness_location=max_thickness_location, trailing_edge=trailing_edge, ) return Naca4ModifiedAirfoilParams( Naca4ModifiedAirfoilSpec(params=params) )
[docs] @staticmethod def naca5_from_designation( designation: str, ) -> Naca5AirfoilClassic: """ Build a classic NACA 5-digit airfoil from a designation. Parameters ---------- designation : str Five-digit NACA designation such as ``"23012"``. Returns ------- Naca5AirfoilClassic Runtime airfoil built from the classic designation. Raises ------ ValueError If ``designation`` is not a valid 5-digit NACA code. """ return Naca5AirfoilClassic.from_designation(designation)
[docs] @staticmethod def naca5_from_params( *, ideal_lift_coefficient: float, max_camber_location: float, reflexed: bool, t: float, trailing_edge: Literal["standard", "sharp"] = "standard", leading_edge_radius: Literal["standard", "exact"] = "standard", ) -> Naca5AirfoilParams: """ Build a parametric NACA 5-digit airfoil from explicit params. Parameters ---------- ideal_lift_coefficient : float Design lift coefficient associated with the camber line. max_camber_location : float Chordwise location of maximum camber as a fraction of chord. reflexed : bool Whether to build the reflexed camber-line family. t : float Maximum thickness as a fraction of chord. trailing_edge : {"standard", "sharp"}, default="standard" Trailing-edge closure model for the thickness distribution. leading_edge_radius : {"standard", "exact"}, default="standard" Leading-edge radius treatment for the thickness distribution. Returns ------- Naca5AirfoilParams Runtime airfoil built from the explicit parameters. Raises ------ ValueError If any parameter lies outside the supported NACA 5-digit range. """ params = Naca5AirfoilParamsSpec( ideal_lift_coefficient=ideal_lift_coefficient, max_camber_location=max_camber_location, reflexed=reflexed, t=t, trailing_edge=trailing_edge, leading_edge_radius=leading_edge_radius, ) return Naca5AirfoilParams(Naca5AirfoilSpec(params=params))
[docs] @staticmethod def naca5_modified_from_designation( designation: str, ) -> Naca5ModifiedAirfoilClassic: """ Build a classic modified NACA 5-digit airfoil from a designation. Parameters ---------- designation : str Modified NACA 5-digit designation string. Returns ------- Naca5ModifiedAirfoilClassic Runtime airfoil built from the modified-series designation. Raises ------ ValueError If ``designation`` is not a valid modified NACA 5-digit code. """ return Naca5ModifiedAirfoilClassic.from_designation(designation)
[docs] @staticmethod def naca5_modified_from_params( *, ideal_lift_coefficient: float, max_camber_location: float, reflexed: bool, t: float, leading_edge_index: float, max_thickness_location: float, trailing_edge: Literal["standard", "sharp"] = "standard", ) -> Naca5ModifiedAirfoilParams: """ Build a parametric modified NACA 5-digit airfoil from params. Parameters ---------- ideal_lift_coefficient : float Design lift coefficient associated with the camber line. max_camber_location : float Chordwise location of maximum camber as a fraction of chord. reflexed : bool Whether to build the reflexed camber-line family. t : float Maximum thickness as a fraction of chord. leading_edge_index : float Modified-series leading-edge shape index. max_thickness_location : float Chordwise location of maximum thickness as a fraction of chord. trailing_edge : {"standard", "sharp"}, default="standard" Trailing-edge closure model for the thickness distribution. Returns ------- Naca5ModifiedAirfoilParams Runtime airfoil built from the explicit parameters. Raises ------ ValueError If any parameter lies outside the supported modified-series range. """ params = Naca5ModifiedAirfoilParamsSpec( ideal_lift_coefficient=ideal_lift_coefficient, max_camber_location=max_camber_location, reflexed=reflexed, t=t, leading_edge_index=leading_edge_index, max_thickness_location=max_thickness_location, trailing_edge=trailing_edge, ) return Naca5ModifiedAirfoilParams( Naca5ModifiedAirfoilSpec(params=params) )
__all__ = ["AirfoilFactory"]