Discuss about sweep angle when defining a wing
jorgepiloto opened this issue · comments
While working in #3, I just noticed that panels are not being generated properly since a local chord shift is being introduced:
ezaero/src/ezaero/vlm/steady.py
Lines 224 to 228 in a7c1f31
This shift should be introduced only within vortex rings, not on wing panels. The bug has not been identified early since for drawing actual geometry of the wing, panel matrix was used. I implemented a geometry visualizer which does not require from a simulation to be used, only needs wing parameters:
Notice how panels are not placed in proper place, they are shifted in the local chord direction. I was finally able to fix this issue, see:
Now panels adapt perfectly to geometry and collocation points are 3/4 of the local chord
I've looked a bit into it, and I think there is not a bug.
Maybe the way the wing is built is a bit confusing. Let me try to break it down:
As is currently is (i.e. ignoring the -great- enhancement from #20) the wing is built using:
|-------------- y
| A ---- B
| | |
| C ---- D
|
x
- root and tip chords: the chord law (
get_chord_at_section
) is just a linear interpolation between these two values,c(y=0) = root_chord
,c(y= +-span/2) = tip_chord
. - the sweep angle is that of the quarter-chord line of the wing, not the leading edge. So what I do in
_build_panel()
is walk backwards from here:- get chord at section
y
,c(y)
- get the chordwise position (along
x
) of the quarter-chord line of the wing at sectiony
(these are ther
,s
,q
, coordinates corresponding to wing panel vertices and c-point). - get the panel's leading edge (segment
A-B
) by subtracting a quarter of a chord from the quarter-chord line, and then addingi
steps from there. - and so on...
- get chord at section
Then in _build_wing_vortex_panels()
I add the corresponding offset to each wing panel to obtain the vortex panel.
I think the confusing fact here is the definition of the sweep angle tied to the quarter-chord line. I think I chose that due to legacy reasons (I think it was preferred at UPM, where I studied).
If this is too unintuitive or not canon, I'm open to have a discussion and refactor this.
If you run the simple example in the examples
dir, you'll see that if you look at sim.wing_panels[0, 0]
and sim.wing_panels[-1, 0]
the delta_x
of the A
point from the former, and the C
point from the latter is exactly the tip_chord
.
@jorgepiloto let me know if this makes sense to you :)
PS: It is true I should've documented this a bit better, also the vectorization on 4-D arrays and absence of for-loops beyond the wing building method might make seem a bit obfuscated. On the latter, I might have got too excited using vectorized NumPy and einsums to squeeze performance; maybe Numba on more naive code would've made more sense for the sake of readability? who knows... at the time I committed to vectorization ;) (also open to discussion here)
Oh! Swept angle is the one for 1/4 chord line 💡
You are completely right, sweep angle is defined for the 25% of the chord. However, from a building point of view and once defining a wing part, I think it is more usual to have the "leading edge sweep angle". Therefore, this is not a bug but a misunderstanding, as you pointed out. Let me change the title of the issue.
What do you think we should use when defining a geometry? I can implement a function to convert between leading edge and 25% chord sweep angles, so user inputs the one for the LE but internally the one for 25% is used, so code is kept in the same way.
Regarding vectorization, your np.einsum
skills are outstanding! It took me a bit to understand those ndarray
matrices, but they are just a matrix of matrices holding each one the four panel boundaries coordinates. I will be using this approach from now on in other projects, code is so fast! Thanks! ❤️
What do you think we should use when defining a geometry? I can implement a function to convert between leading edge and 25% chord sweep angles, so user inputs the one for the LE but internally the one for 25% is used, so code is kept in the same way.
This sounds super reasonable @jorgepiloto, if it's not too much extra work go for it :)
Regarding vectorization, your
np.einsum
skills are outstanding! It took me a bit to understand thosendarray
matrices, but they are just a matrix of matrices holding each one the four panel boundaries coordinates. I will be using this approach from now on in other projects, code is so fast! Thanks! ❤️
haha! good ol' tensor Einstein summation! it's very handy to express these kind of linalg operations in a concise way. The good thing is that GPU-enabled frameworks like TensorFlow, JAX, etc. support this operation, so you have guaranteed compatibility if you are in the need of squeezing even more performance via GPU parallelization.