diff --git a/CHANGELOG.md b/CHANGELOG.md index 9b303475..1c360a56 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -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 diff --git a/docs/src/private_functions.md b/docs/src/private_functions.md index d8b0c836..7b179fc6 100644 --- a/docs/src/private_functions.md +++ b/docs/src/private_functions.md @@ -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! diff --git a/src/wing_geometry.jl b/src/wing_geometry.jl index c849c001..1a1cec65 100644 --- a/src/wing_geometry.jl +++ b/src/wing_geometry.jl @@ -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) @@ -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 @@ -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 diff --git a/test/wing_geometry/test_wing_geometry.jl b/test/wing_geometry/test_wing_geometry.jl index c78a5dba..3160ac05 100644 --- a/test/wing_geometry/test_wing_geometry.jl +++ b/test/wing_geometry/test_wing_geometry.jl @@ -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