Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,10 @@

### Fixed

- A refined panel exactly between two unrefined sections maps to the one farther from
the middle of the span, so a mirror-symmetric wing maps mirror panels to mirror
sections; the first section in order used to win, which puts both midway panels of a
three-section wing on the same side.
- The docs define the body frame as KiteUtils' `KA` frame: x from LE to TE, y towards
the right tip, z = x × y up. The separate `KB` definition, whose `Z = Y × X` pointed
down, is gone; the solver's frame is unchanged. CL, CD and CS are documented as
Expand Down
2 changes: 2 additions & 0 deletions docs/src/private_functions.md
Original file line number Diff line number Diff line change
Expand Up @@ -99,6 +99,8 @@ unrefined_section_range
panel_range
deform!
compute_refined_panel_mapping!
section_centre_dist2
section_span_position
compute_refined_section_interpolation!
copy_sections
copy_sections_to_refined!
Expand Down
50 changes: 42 additions & 8 deletions src/wing_geometry.jl
Original file line number Diff line number Diff line change
Expand Up @@ -1013,13 +1013,40 @@ function refine!(wing::AbstractWing{T}; recompute_mapping=true, sort_sections=tr
end


"""
section_centre_dist2(section, x, y, z)

Squared distance from the centre of `section` (the midpoint of its LE and TE) to
`(x, y, z)`.
"""
function section_centre_dist2(section, x, y, z)
d1 = (section.LE_point[1] + section.TE_point[1]) * 0.5 - x
d2 = (section.LE_point[2] + section.TE_point[2]) * 0.5 - y
d3 = (section.LE_point[3] + section.TE_point[3]) * 0.5 - z
return d1 * d1 + d2 * d2 + d3 * d3
end

"""
section_span_position(wing, section)

Position of the centre of `section` along `wing.spanwise_direction`.
"""
function section_span_position(wing, section)
direction = wing.spanwise_direction
return (direction[1] * (section.LE_point[1] + section.TE_point[1]) +
direction[2] * (section.LE_point[2] + section.TE_point[2]) +
direction[3] * (section.LE_point[3] + section.TE_point[3])) * 0.5
end

"""
compute_refined_panel_mapping!(wing::AbstractWing)

Compute the mapping from refined panels to unrefined sections by finding
the closest unrefined section for each refined panel (based on section center distance).
Maps each refined panel index to its corresponding unrefined section index
(1 to n_unrefined_sections).
(1 to n_unrefined_sections). Sections within `1e-9` of the closest distance, relative,
tie, and a tie goes to the one farther along `spanwise_direction` from the middle of
the span, so a mirror-symmetric wing maps mirror panels to mirror sections.
Works after refinement is complete.
"""
function compute_refined_panel_mapping!(wing::AbstractWing)
Expand All @@ -1039,6 +1066,12 @@ function compute_refined_panel_mapping!(wing::AbstractWing)
return nothing
end

span_min, span_max = Inf, -Inf
for u in wing.unrefined_sections
span = section_span_position(wing, u)
span_min, span_max = min(span_min, span), max(span_max, span)
end
span_middle = 0.5 * (span_min + span_max)
# For each refined panel, find closest unrefined section
# using scalar arithmetic to avoid MVec3 allocations
for pi in 1:n_panels
Expand All @@ -1052,16 +1085,17 @@ function compute_refined_panel_mapping!(wing::AbstractWing)
r2.LE_point[3] + r2.TE_point[3]) * 0.25

min_dist = Inf
for u in wing.unrefined_sections
min_dist = min(min_dist, section_centre_dist2(u, rc1, rc2, rc3))
end
closest = Int16(1)
outboard = -Inf
for ui in 1:n_unref
u = wing.unrefined_sections[ui]
uc1 = (u.LE_point[1] + u.TE_point[1]) * 0.5
uc2 = (u.LE_point[2] + u.TE_point[2]) * 0.5
uc3 = (u.LE_point[3] + u.TE_point[3]) * 0.5
d1 = rc1 - uc1; d2 = rc2 - uc2; d3 = rc3 - uc3
dist = d1 * d1 + d2 * d2 + d3 * d3
if dist < min_dist
min_dist = dist
section_centre_dist2(u, rc1, rc2, rc3) <= min_dist * (1 + 1e-9) || continue
offset = abs(section_span_position(wing, u) - span_middle)
if offset > outboard
outboard = offset
closest = Int16(ui)
end
end
Expand Down
10 changes: 10 additions & 0 deletions test/wing_geometry/test_wing_geometry.jl
Original file line number Diff line number Diff line change
Expand Up @@ -624,6 +624,16 @@ end
end
end


@testset "a panel midway between two sections maps outboard" begin
wing = Wing(10; spanwise_distribution=LINEAR)
add_section!(wing, [0.0, 1.0, 0.0], [1.0, 1.0, 0.0], INVISCID)
add_section!(wing, [0.0, 0.0, 0.0], [1.0, 0.0, 0.0], INVISCID)
add_section!(wing, [0.0, -1.0, 0.0], [1.0, -1.0, 0.0], INVISCID)
refine!(wing)
# panels 3 and 8 are centred at y = ±0.5, midway between two sections
@test wing.refined_panel_mapping == Int16[1, 1, 1, 2, 2, 2, 2, 3, 3, 3]
end
end

@testset "UNCHANGED preserves sections exactly" begin
Expand Down
Loading