Skip to content

Commit 48d83c8

Browse files
committed
Exact middle twist
1 parent acbbb8f commit 48d83c8

2 files changed

Lines changed: 41 additions & 17 deletions

File tree

src/wing_geometry.jl

Lines changed: 33 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -552,22 +552,45 @@ function _apply_refined_section_thetas!(wing::Wing{P, T}, section_thetas) where
552552
local_y = zeros(MVector{3, T})
553553
chord = zeros(MVector{3, T})
554554
normal = zeros(MVector{3, T})
555+
n_sec = wing.n_panels + 1
555556

556-
for i in 1:(wing.n_panels + 1)
557+
for i in 1:n_sec
557558
theta = section_thetas[i]
558559
section = wing.non_deformed_sections[i]
559-
560-
if i < wing.n_panels + 1
561-
section2 = wing.non_deformed_sections[i + 1]
562-
local_y .= normalize(section.LE_point - section2.LE_point)
563-
else
564-
section_prev = wing.non_deformed_sections[i - 1]
565-
local_y .= normalize(section_prev.LE_point - section.LE_point)
560+
le = section.LE_point
561+
562+
# Spanwise axis: average of unit vectors to the left and right neighbour LE
563+
# points so curvature does not bias the twist axis. Boundaries fall back to
564+
# whichever side exists.
565+
local_y .= zero(T)
566+
if i > 1
567+
le_prev = wing.non_deformed_sections[i - 1].LE_point
568+
dx = le_prev[1] - le[1]
569+
dy = le_prev[2] - le[2]
570+
dz = le_prev[3] - le[3]
571+
inv_n = 1 / sqrt(dx * dx + dy * dy + dz * dz)
572+
local_y[1] += dx * inv_n
573+
local_y[2] += dy * inv_n
574+
local_y[3] += dz * inv_n
575+
end
576+
if i < n_sec
577+
le_next = wing.non_deformed_sections[i + 1].LE_point
578+
dx = le[1] - le_next[1]
579+
dy = le[2] - le_next[2]
580+
dz = le[3] - le_next[3]
581+
inv_n = 1 / sqrt(dx * dx + dy * dy + dz * dz)
582+
local_y[1] += dx * inv_n
583+
local_y[2] += dy * inv_n
584+
local_y[3] += dz * inv_n
566585
end
586+
inv_n = 1 / sqrt(local_y[1]^2 + local_y[2]^2 + local_y[3]^2)
587+
local_y[1] *= inv_n
588+
local_y[2] *= inv_n
589+
local_y[3] *= inv_n
567590

568-
chord .= section.TE_point .- section.LE_point
591+
chord .= section.TE_point .- le
569592
normal .= chord × local_y
570-
@. wing.refined_sections[i].TE_point = section.LE_point +
593+
@. wing.refined_sections[i].TE_point = le +
571594
cos(theta) * chord - sin(theta) * normal
572595
end
573596
return nothing

test/ram_geometry/test_kite_geometry.jl

Lines changed: 8 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -190,22 +190,23 @@ using Serialization
190190
wing = ObjWing(test_obj_path, test_dat_path; remove_nan=true)
191191
body_aero = BodyAerodynamics([wing])
192192

193-
# Store original TE point for comparison
194-
i = length(body_aero.panels) ÷ 2
193+
# Sample the apex panel: with even n_panels, refined section (n_panels/2 + 1)
194+
# sits exactly at γ=0, so panels[n_panels/2 + 1].TE_point_1 is the apex TE
195+
# where the LE tangent is purely along y and twist preserves y exactly.
196+
@test iseven(wing.n_panels)
197+
i = wing.n_panels ÷ 2 + 1
195198
original_te_point = copy(body_aero.panels[i].TE_point_1)
196199

197-
# Apply deformation with non-zero angles
198-
theta_dist = fill(deg2rad(30.0), wing.n_panels) # 30 degrees twist for all panels
199-
delta_dist = fill(deg2rad(5.0), wing.n_panels) # 5 degrees TE deflection for all panels
200+
theta_dist = fill(deg2rad(30.0), wing.n_panels)
201+
delta_dist = fill(deg2rad(5.0), wing.n_panels)
200202

201203
VortexStepMethod.deform!(wing, theta_dist, delta_dist)
202204
VortexStepMethod.reinit!(body_aero)
203205

204-
# Check if TE point changed after deformation
205206
deformed_te_point = copy(body_aero.panels[i].TE_point_1)
206207
@test !isapprox(original_te_point, deformed_te_point, atol=1e-2)
207208
@test deformed_te_point[3] < original_te_point[3] # right hand rule
208-
@test deformed_te_point[2] original_te_point[2] atol=1e-2 # right hand rule
209+
@test deformed_te_point[2] original_te_point[2] atol=1e-5 # right hand rule
209210
@test deformed_te_point[1] < original_te_point[1] # right hand rule
210211
@test body_aero.panels[i].delta deg2rad(5.0)
211212

0 commit comments

Comments
 (0)