Skip to content

Commit 760ddf9

Browse files
authored
Add linearization feature and nonlinear solve (#140)
* Add smooth deform function * Reduce allocs * Add linearize function and docs * Working linearize example * Add nonlin solver which added allocations * Move bench2 test to bench * Fix allocations * Add nonlinear solver * Add nonlin test * Remove a lot of unnecessary function signature types * Use a lot more mvec * Nonlin solve for jacobian * Move cache inside struct * Fix example * Fix docstring * Fix docstring * Add types back to struct * Non-allocating smooth deform * Improve jacobian calculation * Less allocs * Add result tests * Rename wa to body_aero * Fix unchanged benchmark * Add docs to linearize * Fix create interp bug * Add linearization tests * Fix test for windows * Fix tests for windows * Remove unused P * Add back types * Remove function arg type * Back to old types
1 parent 543a1f6 commit 760ddf9

23 files changed

+974
-490
lines changed

Project.toml

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,8 @@ version = "1.1.2"
77
Colors = "5ae59095-9a9b-59fe-a467-6f913c188581"
88
DefaultApplication = "3f0dd361-4fe0-5fc6-8523-80b14ec94d85"
99
DelimitedFiles = "8bb1440f-4735-579b-a4ab-409b98df4dab"
10+
DifferentiationInterface = "a0c0ee7d-e4b9-4e03-894e-1c5f64a51d63"
11+
FiniteDiff = "6a86dc24-6348-571c-b903-95158fe2bd41"
1012
Interpolations = "a98d9a8b-a2ab-59e6-89dd-64a1c18fca59"
1113
LaTeXStrings = "b964fa9f-0449-5b57-a5c2-d3ea65f4040f"
1214
LinearAlgebra = "37e2e46d-f89d-539d-b4ee-838fcccc9c8e"
@@ -17,6 +19,7 @@ Parameters = "d96e819e-fc66-5662-9728-84c9c7592b0a"
1719
Pkg = "44cfe95a-1eb2-52ea-b672-e2afdf69b78f"
1820
PreallocationTools = "d236fae5-4411-538c-8e31-a6e3d9e00b46"
1921
PrecompileTools = "aea7be01-6a6a-4083-8856-8a6e6704d82a"
22+
SciMLBase = "0bca4576-84f4-4d90-8ffe-ffa030f20462"
2023
Serialization = "9e88b42a-f829-5b0c-bbe9-9e923198166b"
2124
SharedArrays = "1a1011a3-84de-559e-8e89-a11a2f7dc383"
2225
StaticArrays = "90137ffa-7385-5640-81b9-e52037218182"
@@ -39,8 +42,10 @@ ControlPlots = "0.2.5"
3942
DataFrames = "1.7"
4043
DefaultApplication = "1"
4144
DelimitedFiles = "1"
45+
DifferentiationInterface = "0.6.48"
4246
Distributed = "1.10"
4347
Documenter = "1.8"
48+
FiniteDiff = "2.27.0"
4449
Interpolations = "0.15"
4550
LaTeXStrings = "1"
4651
LinearAlgebra = "1"
@@ -51,6 +56,7 @@ Parameters = "0.12"
5156
Pkg = "1"
5257
PreallocationTools = "0.4.25"
5358
PrecompileTools = "1.2.1"
59+
SciMLBase = "2.79.0"
5460
Serialization = "1"
5561
SharedArrays = "1"
5662
StaticArrays = "1"

README.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -117,7 +117,7 @@ add_section!(wing,
117117
INVISCID)
118118

119119
# Step 3: Initialize aerodynamics
120-
wa = BodyAerodynamics([wing])
120+
body_aero = BodyAerodynamics([wing])
121121

122122
# Set inflow conditions
123123
vel_app = [cos(alpha), 0.0, sin(alpha)] .* v_a

docs/src/examples.md

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -54,19 +54,19 @@ add_section!(wing,
5454

5555
#### Step 4: Initialize aerodynamics
5656
```
57-
wa = BodyAerodynamics([wing])
57+
body_aero = BodyAerodynamics([wing])
5858
```
5959
We need to pass here an array of wing objects, because a body can have multiple wings.
6060

6161
###### Set inflow conditions
6262
```julia
6363
vel_app = [cos(alpha), 0.0, sin(alpha)] .* v_a
64-
set_va!(wa, vel_app, [0, 0, 0.1])
64+
set_va!(body_aero, vel_app, [0, 0, 0.1])
6565
```
6666
#### Step 5: Plot the geometry
6767
```julia
6868
plot_geometry(
69-
wa,
69+
body_aero,
7070
"Rectangular_wing_geometry";
7171
data_type=".pdf",
7272
save_path=".",
@@ -86,8 +86,8 @@ vsm_solver = Solver(aerodynamic_model_type=VSM)
8686

8787
#### Step 7: Solve using both methods
8888
```
89-
results_llt = solve(llt_solver, wa)
90-
results_vsm = solve(vsm_solver, wa)
89+
results_llt = solve(llt_solver, body_aero)
90+
results_vsm = solve(vsm_solver, body_aero)
9191
```
9292

9393
##### Print results comparison
@@ -103,7 +103,7 @@ println("Projected area = $(round(results_vsm["projected_area"], digits=4)) m²"
103103

104104
#### Step 8: Plot spanwise distributions
105105
```julia
106-
y_coordinates = [panel.aero_center[2] for panel in wa.panels]
106+
y_coordinates = [panel.aero_center[2] for panel in body_aero.panels]
107107

108108
plot_distribution(
109109
[y_coordinates, y_coordinates],
@@ -121,7 +121,7 @@ You should see a plot like this:
121121
angle_range = range(0, 20, 20)
122122
plot_polars(
123123
[llt_solver, vsm_solver],
124-
[wa, wa],
124+
[body_aero, body_aero],
125125
["LLT", "VSM"];
126126
angle_range,
127127
angle_type="angle_of_attack",

docs/src/index.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -115,7 +115,7 @@ add_section!(wing,
115115
INVISCID)
116116

117117
# Step 3: Initialize aerodynamics
118-
wa = BodyAerodynamics([wing])
118+
body_aero = BodyAerodynamics([wing])
119119

120120
# Set inflow conditions
121121
vel_app = [cos(alpha), 0.0, sin(alpha)] .* v_a

docs/src/types.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,7 @@ A body is constructed of one or more abstract wings. An abstract wing can be a W
2828
A Wing/ RamAirWing has one or more sections.
2929
```@docs
3030
Section
31-
Section(LE_point::Vector{Float64}, TE_point::Vector{Float64}, aero_model=nothing, aero_data=nothing)
31+
Section(LE_point::PosVector, TE_point::PosVector, aero_model)
3232
Wing
3333
Wing(n_panels::Int; spanwise_distribution::PanelDistribution=LINEAR,
3434
spanwise_direction::PosVector=MVec3([0.0, 1.0, 0.0]))

examples/bench.jl

Lines changed: 14 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -32,29 +32,28 @@ add_section!(wing,
3232
INVISCID)
3333

3434
# Step 3: Initialize aerodynamics
35-
wa = BodyAerodynamics([wing])
35+
body_aero = BodyAerodynamics([wing])
3636

3737
# Set inflow conditions
3838
vel_app = [cos(alpha), 0.0, sin(alpha)] .* v_a
39-
set_va!(wa, vel_app)
39+
set_va!(body_aero, vel_app)
4040

4141
# Step 4: Initialize solvers for both LLT and VSM methods
42-
P = length(wa.panels)
43-
llt_solver = Solver{P}(aerodynamic_model_type=LLT)
44-
vsm_solver = Solver{P}(aerodynamic_model_type=VSM)
42+
llt_solver = Solver(body_aero; aerodynamic_model_type=LLT)
43+
vsm_solver = Solver(body_aero; aerodynamic_model_type=VSM)
4544

4645
# Step 5: Solve using both methods
47-
results_vsm = solve(vsm_solver, wa)
48-
sol = solve!(vsm_solver, wa)
49-
results_vsm_base = solve_base!(vsm_solver, wa)
46+
results_vsm = solve(vsm_solver, body_aero)
47+
sol = solve!(vsm_solver, body_aero)
48+
results_vsm_base = solve_base!(vsm_solver, body_aero)
5049
println("Rectangular wing, solve_base!:")
51-
@time results_vsm_base = solve_base!(vsm_solver, wa)
50+
@time results_vsm_base = solve_base!(vsm_solver, body_aero)
5251
# time Python: 32.0 ms Ryzen 7950x
5352
# time Julia: 0.42 ms Ryzen 7950x
5453
println("Rectangular wing, solve!:")
55-
@time sol = solve!(vsm_solver, wa)
54+
@time sol = solve!(vsm_solver, body_aero)
5655
println("Rectangular wing, solve:")
57-
@time solve(vsm_solver, wa)
56+
@time solve(vsm_solver, body_aero)
5857

5958
# Create wing geometry
6059
wing = RamAirWing("data/ram_air_kite_body.obj", "data/ram_air_kite_foil.dat")
@@ -64,7 +63,8 @@ body_aero = BodyAerodynamics([wing])
6463
vsm_solver = Solver(
6564
body_aero;
6665
aerodynamic_model_type=VSM,
67-
is_with_artificial_damping=false
66+
is_with_artificial_damping=false,
67+
solver_type=NONLIN,
6868
)
6969

7070
# Setting velocity conditions
@@ -82,8 +82,8 @@ set_va!(body_aero, vel_app)
8282

8383
# Solving and plotting distributions
8484
results = solve(vsm_solver, body_aero)
85-
results_base = solve_base!(vsm_solver, body_aero)
85+
solve_base!(vsm_solver, body_aero)
8686
println("RAM-air kite:")
87-
@time results_base = solve_base!(vsm_solver, body_aero)
87+
@time solve_base!(vsm_solver, body_aero)
8888

8989
nothing

examples/ram_air_kite.jl

Lines changed: 32 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -2,9 +2,10 @@ using ControlPlots
22
using VortexStepMethod
33
using LinearAlgebra
44

5-
PLOT = false
5+
PLOT = true
66
USE_TEX = false
7-
DEFORM = true
7+
DEFORM = false
8+
LINEARIZE = false
89

910
# Create wing geometry
1011
wing = RamAirWing("data/ram_air_kite_body.obj", "data/ram_air_kite_foil.dat")
@@ -14,23 +15,18 @@ println("First init")
1415

1516
if DEFORM
1617
# Linear interpolation of alpha from 10° at one tip to 0° at the other
17-
n_panels = wing.n_panels
18-
theta_start = deg2rad(10)
19-
theta_end = deg2rad(0)
20-
delta_start = deg2rad(10)
21-
delta_end = deg2rad(0)
22-
theta_dist = [theta_start - i * (theta_start - theta_end)/(n_panels-1) for i in 0:(n_panels-1)]
23-
delta_dist = [delta_start - i * (delta_start - delta_end)/(n_panels-1) for i in 0:(n_panels-1)]
2418
println("Deform")
25-
@time VortexStepMethod.deform!(wing, theta_dist, delta_dist)
19+
@time VortexStepMethod.smooth_deform!(wing, deg2rad.([10,20,10,0]), deg2rad.([-10,0,-10,0]))
2620
println("Deform init")
2721
@time VortexStepMethod.init!(body_aero; init_aero=false)
2822
end
2923

3024
# Create solvers
31-
vsm_solver = Solver(body_aero;
25+
solver = Solver(body_aero;
3226
aerodynamic_model_type=VSM,
33-
is_with_artificial_damping=false
27+
is_with_artificial_damping=false,
28+
rtol=1e-5,
29+
solver_type=NONLIN
3430
)
3531

3632
# Setting velocity conditions
@@ -46,6 +42,26 @@ vel_app = [
4642
] * v_a
4743
set_va!(body_aero, vel_app)
4844

45+
if LINEARIZE
46+
println("Linearize")
47+
jac, res = VortexStepMethod.linearize(
48+
solver,
49+
body_aero,
50+
[zeros(4); vel_app; zeros(3)];
51+
theta_idxs=1:4,
52+
va_idxs=5:7,
53+
omega_idxs=8:10,
54+
moment_frac=0.1)
55+
@time jac, res = VortexStepMethod.linearize(
56+
solver,
57+
body_aero,
58+
[zeros(4); vel_app; zeros(3)];
59+
theta_idxs=1:4,
60+
va_idxs=5:7,
61+
omega_idxs=8:10,
62+
moment_frac=0.1)
63+
end
64+
4965
# Plotting polar data
5066
PLOT && plot_polar_data(body_aero)
5167

@@ -63,8 +79,9 @@ PLOT && plot_geometry(
6379
)
6480

6581
# Solving and plotting distributions
66-
results = solve(vsm_solver, body_aero; log=true)
67-
@time results = solve(vsm_solver, body_aero; log=true)
82+
println("Solve")
83+
results = VortexStepMethod.solve(solver, body_aero; log=true)
84+
@time results = solve(solver, body_aero; log=true)
6885

6986
body_y_coordinates = [panel.aero_center[2] for panel in body_aero.panels]
7087

@@ -80,7 +97,7 @@ PLOT && plot_distribution(
8097
)
8198

8299
PLOT && plot_polars(
83-
[vsm_solver],
100+
[solver],
84101
[body_aero],
85102
[
86103
"VSM from Ram Air Kite OBJ and DAT file",

examples/rectangular_wing.jl

Lines changed: 11 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -28,22 +28,21 @@ add_section!(wing,
2828
INVISCID)
2929

3030
# Step 3: Initialize aerodynamics
31-
wa = BodyAerodynamics([wing])
31+
body_aero = BodyAerodynamics([wing])
3232

3333
# Set inflow conditions
3434
vel_app = [cos(alpha), 0.0, sin(alpha)] .* v_a
35-
set_va!(wa, vel_app, [0, 0, 0.1])
35+
set_va!(body_aero, vel_app, [0, 0, 0.1])
3636

3737
# Step 4: Initialize solvers for both LLT and VSM methods
38-
P = length(wa.panels)
39-
llt_solver = Solver{P}(aerodynamic_model_type=LLT)
40-
vsm_solver = Solver{P}(aerodynamic_model_type=VSM)
38+
llt_solver = Solver(body_aero; aerodynamic_model_type=LLT)
39+
vsm_solver = Solver(body_aero; aerodynamic_model_type=VSM)
4140

4241
# Step 5: Solve using both methods
43-
results_llt = solve(llt_solver, wa)
44-
@time results_llt = solve(llt_solver, wa)
45-
results_vsm = solve(vsm_solver, wa)
46-
@time results_vsm = solve(vsm_solver, wa)
42+
results_llt = solve(llt_solver, body_aero)
43+
@time results_llt = solve(llt_solver, body_aero)
44+
results_vsm = solve(vsm_solver, body_aero)
45+
@time results_vsm = solve(vsm_solver, body_aero)
4746

4847
# Print results comparison
4948
println("\nLifting Line Theory Results:")
@@ -56,7 +55,7 @@ println("Projected area = $(round(results_vsm["projected_area"], digits=4)) m²"
5655

5756
# Step 6: Plot geometry
5857
PLOT && plot_geometry(
59-
wa,
58+
body_aero,
6059
"Rectangular_wing_geometry";
6160
data_type=".pdf",
6261
save_path=".",
@@ -66,7 +65,7 @@ PLOT && plot_geometry(
6665
)
6766

6867
# Step 7: Plot spanwise distributions
69-
y_coordinates = [panel.aero_center[2] for panel in wa.panels]
68+
y_coordinates = [panel.aero_center[2] for panel in body_aero.panels]
7069

7170
PLOT && plot_distribution(
7271
[y_coordinates, y_coordinates],
@@ -80,7 +79,7 @@ PLOT && plot_distribution(
8079
angle_range = range(0, 20, 20)
8180
PLOT && plot_polars(
8281
[llt_solver, vsm_solver],
83-
[wa, wa],
82+
[body_aero, body_aero],
8483
["LLT", "VSM"];
8584
angle_range,
8685
angle_type="angle_of_attack",

examples/stall_model.jl

Lines changed: 10 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -42,15 +42,14 @@ CAD_wing = Wing(n_panels; spanwise_distribution)
4242
for rib in rib_list
4343
add_section!(CAD_wing, rib[1], rib[2], rib[3], rib[4])
4444
end
45-
body_aero_CAD_19ribs = BodyAerodynamics([CAD_wing])
45+
body_aero = BodyAerodynamics([CAD_wing])
4646

4747
# Create solvers
48-
P = length(body_aero_CAD_19ribs.panels)
49-
vsm_solver = Solver{P}(
48+
vsm_solver = Solver(body_aero;
5049
aerodynamic_model_type=VSM,
5150
is_with_artificial_damping=false
5251
)
53-
VSM_with_stall_correction = Solver{P}(
52+
VSM_with_stall_correction = Solver(body_aero;
5453
aerodynamic_model_type=VSM,
5554
is_with_artificial_damping=true
5655
)
@@ -66,11 +65,11 @@ vel_app = [
6665
sin(side_slip),
6766
sin(aoa_rad)
6867
] * v_a
69-
set_va!(body_aero_CAD_19ribs, vel_app)
68+
set_va!(body_aero, vel_app)
7069

7170
# Plotting geometry
7271
PLOT && plot_geometry(
73-
body_aero_CAD_19ribs,
72+
body_aero,
7473
"";
7574
data_type=".svg",
7675
save_path="",
@@ -82,11 +81,11 @@ PLOT && plot_geometry(
8281
)
8382

8483
# Solving and plotting distributions
85-
results = solve(vsm_solver, body_aero_CAD_19ribs)
86-
@time results_with_stall = solve(VSM_with_stall_correction, body_aero_CAD_19ribs)
87-
@time results_with_stall = solve(VSM_with_stall_correction, body_aero_CAD_19ribs)
84+
results = solve(vsm_solver, body_aero)
85+
@time results_with_stall = solve(VSM_with_stall_correction, body_aero)
86+
@time results_with_stall = solve(VSM_with_stall_correction, body_aero)
8887

89-
CAD_y_coordinates = [panel.aero_center[2] for panel in body_aero_CAD_19ribs.panels]
88+
CAD_y_coordinates = [panel.aero_center[2] for panel in body_aero.panels]
9089

9190
PLOT && plot_distribution(
9291
[CAD_y_coordinates, CAD_y_coordinates],
@@ -112,7 +111,7 @@ path_cfd_lebesque = joinpath(
112111

113112
PLOT && plot_polars(
114113
[vsm_solver, VSM_with_stall_correction],
115-
[body_aero_CAD_19ribs, body_aero_CAD_19ribs],
114+
[body_aero, body_aero],
116115
[
117116
"VSM CAD 19ribs",
118117
"VSM CAD 19ribs , with stall correction",

0 commit comments

Comments
 (0)