partmor / ezaero

ezaero - Easy aerodynamics in Python :airplane:

Home Page:https://ezaero.readthedocs.io

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

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:

x_A = (r - c_AC / 4) + i * dx_AC
x_B = (s - c_BD / 4) + i * dx_BD
x_C = x_A + dx_AC
x_D = x_B + dx_BD
x_pc = (q - c_pc / 4) + (i + 3 / 4) * dx_pc

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:

newplot (16)

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:

newplot (17)

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 section y (these are the r, 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 adding i steps from there.
    • and so on...

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 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! ❤️

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.