dragonfly_sim.core.shape_design
Shape design variables as modular layers on an lsdo_geo FFD block.
DG_windtunnel_model only sees an FFDShapeParameterization: it hands it
the wall nodes in set_up_sim (setup) and takes the resulting wall
displacement into the mesh warper (deform_mesh). Which design variables
exist, their bounds, and how they move the control points is decided entirely
by the layers given to the parameterization:
ControlPointMotions– raw control-point motions (cp_motions).SectionalVariables– theSectionalShapepresets (2D camber and thickness per chordwise station; 3D twist, chord, … per spanwise section).WingShape– a trapezoidal wing: quarter-chord (or any chord-line) sweep, aspect ratio, root chord, span and taper ratio, plus chordwise thickness and camber modes per spanwise station.
A driver then reads:
shape = FFDShapeParameterization(ffd_shape, degree, corner_list,
layers=[WingShape(planform={...}, sections={...})])
model = DG_windtunnel_model(mesh, boundary_dict, shape, ...)
model.set_up_sim()
shape_parameters = shape.declare_design_variables()
...
u_vec = model.evaluate(model.deform_mesh(), shape_parameters, alpha)
and constrains geometry through shape.outputs() (layer quantities such as
the wing’s planform area) and shape.geometry (WallGeometry: enclosed
measure, thickness at stations, planform stations).
The coefficient pipeline is C0 -> one lsdo_geo SectionalParameterization ->
additive layers. lsdo_geo freezes axes and stretch origins from the points’
values when the graph is built, so every layer’s sectional operations are
collected into a single evaluation on the constant baseline (and must share
one principal direction); additive motions (cp motions, sectional modes) are
linear and go on top.
A new layer subclasses ShapeLayer and overrides what it needs.
Classes
Raw control-point motions: one design variable |
|
An FFD block around the wall plus the design-variable layers that move it. |
|
|
|
Base of the design-variable layers of an FFDShapeParameterization. |
|
Planform and sectional design variables of a trapezoidal half wing. |
Functions
|
Bernstein polynomials of degree at xi: shape (len(xi), degree + 1). |
|
|
|
Parametric coordinate u in [0, 1] where the 1D B-spline with control |
|
Chordwise profiles of the WingShape section modes at chord fractions xi: |
Module Contents
- class dragonfly_sim.core.shape_design.ControlPointMotions(dv_spec, scaler_mode='bounds', name='cp_motions')
Bases:
ShapeLayerRaw control-point motions: one design variable
cp_motionsof shapeffd_shape + (n_opt,), with bounds fromdv_spec(see ffd_dv_utils).- additive(coefficients)
- declare(dvs)
Create this layer’s design variables in
dvs(a ShapeDVSet).
- describe()
Lines for
FFDShapeParameterization.print_design_variables.
- coord_idxs
- dv_spec
- name = 'cp_motions'
- scaler_mode = 'bounds'
- class dragonfly_sim.core.shape_design.FFDShapeParameterization(shape, degree=2, block_corner_list=None, layers=(), margin=0.0001, projection_newton_tol=1e-12, inner_bdry_rel_tol=1e-06, inner_bdry_overset_margin=0.0001)
An FFD block around the wall plus the design-variable layers that move it.
- Parameters:
- shapesequence of int
Control points per parametric direction.
- degreeint or sequence of int
- block_corner_listoptional
Two-surface block definition (
shape_parameterization. ffd_corners_from_corner_list); None wraps the wall’s bounding box. Also locates the wall when the model gets no explicitmesh_inner_bdry_function(inner_boundary_function).- layerssequence of ShapeLayer
Applied in order; their design variables are declared in this order.
- margin, projection_newton_tolsee
WallFFD. - inner_bdry_rel_tol, inner_bdry_overset_margincontainment test of
inner_boundary_function.
- __getitem__(name)
A declared design variable by name.
- _require_setup()
- coefficients()
Deformed FFD coefficients (built once, then cached).
- declare_design_variables()
Create every layer’s csdl design variables (with bounds), in layer order. Returns
parameter_vector(). Call inside the recorder, afterset_up_sim.
- inner_boundary_function()
Wall facet marker from the block corners, or None without them.
- outputs()
Constraint quantities of the layers:
{layer.name: {...}}for the layers that have any (e.g.outputs()['wing']['area']).
- parameter_vector()
All shape design variables as one flat vector (declaration order).
- print_design_variables(printer=print)
- setup(comm, wall_coords, wall_rows, wall_facets=None)
Build the FFD block around the wall and set up the layers. Collective.
- wall_coords(M_global, dim) replicated wall node coordinates, in the
rank-block order of the mesh’s wall node set; wall_rows : the rows this rank owns; wall_facets : replicated wall facets (rows of wall node ids), needed for
geometryand by layers that measure the baseline wall.
- wall_displacement()
Replicated
(M_global, dim)wall node displacement (cached).
- _coefficients = None
- _geometry = None
- _wall_displacement = None
- _wall_facets = None
- block_corner_list = None
- degree = 2
- property dim
- dvs = None
- ffd = None
- property geometry
WallGeometryof the baseline wall, built on first use.
- inner_bdry_overset_margin = 0.0001
- inner_bdry_rel_tol = 1e-06
- layers = []
- margin = 0.0001
- projection_newton_tol = 1e-12
- shape
- class dragonfly_sim.core.shape_design.SectionalVariables(principal_dim, variables, scaler_mode='bounds', name='sectional')
Bases:
ShapeLayerSectionalShapepresets as design variables.- variables{kind: spec}, kind one of
SectionalShape.add’s presets; spec is the bounds (anything
build_sectional_dvtakes) or a dict with keysboundsand optionallynum_values(fewer than the number of sections: a B-spline profile),pivotandprofile_degree. Each variable is a delta from the baseline.
- declare(dvs)
Create this layer’s design variables in
dvs(a ShapeDVSet).
- sectional(sectional)
Register sectional operations on
sectional(a SectionalShape).
- name = 'sectional'
- principal_dim
- scaler_mode = 'bounds'
- specs
- variables{kind: spec}, kind one of
- class dragonfly_sim.core.shape_design.ShapeLayer
Base of the design-variable layers of an FFDShapeParameterization.
A layer with sectional (lsdo_geo) operations sets
principal_dimand registers them insectional; that call happens inside an inline recording, so expressions of the design variables built there have values, which lsdo_geo needs.additiveadds motions that are linear in the variables on top of the sectional result.- additive(coefficients)
- declare(dvs)
Create this layer’s design variables in
dvs(a ShapeDVSet).
- describe()
Lines for
FFDShapeParameterization.print_design_variables.
- outputs()
- sectional(sectional)
Register sectional operations on
sectional(a SectionalShape).
- setup(parameterization)
Numpy precomputation once the FFD block exists (
parameterization.ffd,parameterization.geometry).
- name = 'layer'
- principal_dim = None
- class dragonfly_sim.core.shape_design.WingShape(planform=None, sections=None, sweep_chord_fraction=0.25, semi_span=None, derived=None, fit_tol=0.001, scaler_mode='bounds', name='wing')
Bases:
ShapeLayerPlanform and sectional design variables of a trapezoidal half wing.
The wall must be a straight-tapered half wing with its root on the y = 0 symmetry plane, x chordwise and z up, inside a lofted FFD block whose parametric axes are (chord, span, vertical) – the corner-list blocks of the wing drivers.
- planform{name: (lower, upper)} for any of
sweepsweep angle [rad] of the chord line atsweep_chord_fraction(0.25: quarter chord)
aspect_ratiofull-wing AR = b^2 / Sroot_chordspanfull-wing span b (twice the half wing’s semi-span)taper_ratiotip chord / root chord Absolute values: each variable starts at the baseline wing’s value and its bounds must bracket it. A name left out stays at its baseline, except thederivedone.- sections{name: spec} for
thicknessand/orcamber. spec is the bounds, or a dict {‘bounds’: …, ‘modes’: n} for n chordwise modes per FFD spanwise section (default 1). The variable then has n_sections x n entries, section-major (root first: all of the root’s modes, then the next section’s); bounds as for
build_sectional_dv– a scalar, a pair, or a pair of arrays of shape (n_sections,) (the same for every mode of a section), (n_sections, n) or (n_sections * n,). Pin an entry with (0., 0.). Deltas from the baseline, starting at zero, with xi the local chord fraction and B_m the Bernstein polynomials of degree n - 1:thicknessrelative change of the section’s thickness (t/c),sum_m tau_m B_m(xi) – 0.1 in every mode is 10% thicker
camberchange of camber over local chord, sum_m kappa_m4 xi (1 - xi) B_m(xi), so the leading and trailing edge stay put; kappa in every mode is a parabolic camber line of maximum kappa
With one mode these are a uniform thickness change and a parabolic camber line. The modes are least-squares fits on the block’s chordwise basis; they are exact when it is a Bezier (n_chord = degree + 1) of degree >= n - 1 for thickness and >= n + 1 for camber (
describereports the fit residual).- derivedwhich of
aspect_ratio,root_chordandspanfollows from the other two and the taper ratio, s = AR c_r (1 + taper) / 4. Default:
span, unless span is a variable – then whichever of aspect_ratio and root_chord is not (with only span a variable, name it).- sweep_chord_fractionchord line the sweep is measured on; sections scale
about it, and its root point stays fixed.
- semi_spanbaseline semi-span; default the wall’s largest y (which
includes any tip cap).
- fit_tolallowed deviation of the baseline leading/trailing edges from
straight lines, relative to the root chord.
The geometry: FFD section j, at baseline span fraction eta_j = y_j / s0, moves to y_j’ = eta_j s’, its chord c_j’ = c_r’ (1 - (1 - taper’) eta_j) scales it by r_j = c_j’/c_j0 about the reference chord line in x and about the chord plane in z (keeping t/c; the thickness modes act on top), and the reference line is placed at x_ref,root + y_j’ tan(sweep’). These are lsdo_geo sectional stretches and translations; thickness and camber are additive sectional modes. With the taper ratio fixed the map is affine, so the deformed wall is exactly the trapezoid the variables describe; a taper change is exact at the FFD sections and B-spline-blended between them.
- _derived_size(derived)
- _fit_baseline(geometry)
- _planform_variable(key)
- _section_bounds(bounds, n1, modes)
Broadcast per-section (n1,) or (n1, modes) bound arrays to the variable’s flat (n1 * modes,) layout; scalars pass through.
- _setup_sections(ffd)
- declare(dvs)
Create this layer’s design variables in
dvs(a ShapeDVSet).
- describe()
Lines for
FFDShapeParameterization.print_design_variables.
- outputs()
Planform quantities as csdl variables: sweep, aspect_ratio, root_chord, taper_ratio, tip_chord, semi_span, span, area (full wing) and section_chords (at the FFD sections).
- sectional(sectional)
Register sectional operations on
sectional(a SectionalShape).
- setup(parameterization)
Numpy precomputation once the FFD block exists (
parameterization.ffd,parameterization.geometry).
- PLANFORM_KEYS = ('sweep', 'aspect_ratio', 'root_chord', 'span', 'taper_ratio')
- SECTION_KEYS = ('thickness', 'camber')
- SIZE_KEYS = ('aspect_ratio', 'root_chord', 'span')
- derived = 'span'
- f
- fit_tol = 0.001
- name = 'wing'
- planform_spec
- principal_dim = 1
- scaler_mode = 'bounds'
- section_spec
- semi_span_arg = None
- dragonfly_sim.core.shape_design._bernstein(degree, xi)
Bernstein polynomials of degree at xi: shape (len(xi), degree + 1).
- dragonfly_sim.core.shape_design._bspline_basis(degree, n_coefficients, u)
- dragonfly_sim.core.shape_design._invert_monotone_bspline(degree, values, target)
Parametric coordinate u in [0, 1] where the 1D B-spline with control values
valuesequalstarget.
- dragonfly_sim.core.shape_design._section_mode_profiles(kind, num_modes, xi)
Chordwise profiles of the WingShape section modes at chord fractions xi: shape (len(xi), num_modes). Thickness: the Bernstein polynomials of degree num_modes - 1 (they sum to one: equal values scale the section uniformly). Camber: 4 xi (1 - xi) times those (zero at the leading and trailing edge; equal values give the parabolic camber line).