Skip to content

Commit

Permalink
Merge pull request #136 from GodotMisogi/develop
Browse files Browse the repository at this point in the history
Version 0.4.9: Fixed Freestream constructor and updated docstrings
  • Loading branch information
Arjit Seth authored Apr 9, 2023
2 parents ef98e15 + ed7538f commit b220e10
Show file tree
Hide file tree
Showing 6 changed files with 83 additions and 38 deletions.
2 changes: 1 addition & 1 deletion Project.toml
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
name = "AeroFuse"
uuid = "477c59f4-51f5-487f-bf1e-8db39645b227"
authors = ["GodotMisogi <[email protected]>"]
version = "0.4.8"
version = "0.4.9"

[deps]
Accessors = "7d9f7c33-5ae7-4f3b-8dc6-eff91059b697"
Expand Down
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -69,7 +69,7 @@ If you use AeroFuse in your research, please cite the following until any releva
author = {Arjit Seth, Rhea P. Liem},
title = {AeroFuse},
url = {https://github.com/GodotMisogi/AeroFuse},
version = {0.4.8},
version = {0.4.9},
date = {2023-04-10},
}
```
2 changes: 1 addition & 1 deletion docs/src/index.md
Original file line number Diff line number Diff line change
Expand Up @@ -61,7 +61,7 @@ If you use AeroFuse in your research, please cite the following until any releva
author = {Arjit Seth, Rhea P. Liem},
title = {AeroFuse},
url = {https://github.com/GodotMisogi/AeroFuse},
version = {0.4.8},
version = {0.4.9},
date = {2023-03-27},
}
```
Expand Down
109 changes: 77 additions & 32 deletions src/Geometry/AircraftGeometry/Foils/foil.jl
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,26 @@ function Foil(coords :: AbstractMatrix{<: Real}, name = "")
@views Foil(coords[:,1], coords[:,2], name)
end

"""
read_foil(
path :: String;
header = true;
name = ""
)
Generate a `Foil` from a file consisting of 2D coordinates with named arguments to skip the header (first line of the file) or assign a name.
By default, the header is assumed to exist and should contain the airfoil name, which is assigned to the name of the `Foil`.
"""
function read_foil(path :: String; name = "")
coords, foil_name = readdlm(path, header = true)
if name != ""
return Foil(Float16.(coords[:,1:2]), name)
else
return Foil(Float16.(coords[:,1:2]), strip(join(foil_name, " ")))
end
end

function Base.show(io :: IO, foil :: Foil)
print(io, foil.name, " ", typeof(foil), " with ", length(foil.x), " points.")
end
Expand Down Expand Up @@ -62,15 +82,33 @@ Scale the coordinates of a `Foil` to a scaling value.
"""
scale(foil :: Foil, scale) = Foil(scale .* coordinates(foil), foil.name)

"""
translate(foil :: Foil, vector)
Translate the coordinates of a `Foil` by a 2-dimensional vector ``\\mathbf v``.
"""
translate(foil :: Foil; vector) = Foil(foil.x .+ vector[1], foil.y .+ vector[2])

"""
rotate(foil :: Foil;
angle,
center = zeros(2)
)
Rotate the coordinates of a `Foil` about a 2-dimensional point (default is origin) by the angle ``θ`` (in degrees).
"""
@views function rotate(foil :: Foil; angle :: Real, center = zeros(2))
T = promote_type(eltype(angle), eltype(center))
trans = @views [ foil.x .- center[1] foil.y .- center[2] ] # Translate
rotate = trans * RotMatrix{2,T}(deg2rad(angle))' # Rotate
Foil(rotate[:,1] .+ center[1], rotate[:,2] .+ center[2], foil.name) # Inverse translate
end

"""
interpolate(foil :: Foil, xs)
Linearly interpolate the coordinates of a `Foil` to a given ``x ∈ [0,1]`` distribution.
"""
@views function interpolate(foil :: Foil, xs)
upper, lower = split_surface(foil)

Expand All @@ -80,17 +118,35 @@ end
Foil([ xs[end:-1:2]; xs ], [ y_u[end:-1:2]; y_l ], foil.name)
end

"""
reflect(foil :: Foil)
Reflect the ``y``-coordinates of a `Foil` about the ``y = 0`` line.
"""
reflect(foil :: Foil) = setproperties(foil, y = -foil.y, name = "Inverted " * foil.name)

"""
affine(
foil :: Foil,
angle, vector
)
Perform an affine transformation on the coordinates of a `Foil` by a 2-dimensional vector ``\\mathbf v`` and angle ``θ``.
"""
affine(foil :: Foil; angle, vector) = translate(rotate(foil; angle = angle); vector = vector)

"""
camber_thickness(foil :: Foil, num :: Integer)
Compute the camber-thickness distribution of a `Foil` with cosine spacing.
Compute the camber-thickness distribution of a `Foil` with cosine interpolation. Optionally specify the number of points for interpolation, default is 40.
"""
camber_thickness(foil :: Foil, num = 40) = coordinates_to_camber_thickness(foil, num + 1)

"""
leading_edge_index(foil :: Foil)
Get the index of the leading edge of a `Foil`. This will be the index of the point with the minimum ``x``-coordinate.
"""
leading_edge_index(foil :: Foil) = argmin(coordinates(foil)[:,1])

"""
Expand Down Expand Up @@ -126,6 +182,11 @@ function cosine_interpolation(foil :: Foil, n :: Integer = 40)
interpolate(foil, x_circ)
end

"""
camber_line(foil :: Foil, n :: Integer = 40)
Get the camber line of a `Foil`. Optionally specify the number of points for linear interpolation, default is 40.
"""
function camber_line(foil :: Foil, n = 60)
upper, lower = split_surface(foil)
xs = LinRange(minimum(foil.x), maximum(foil.x), n + 1)
Expand All @@ -135,6 +196,11 @@ function camber_line(foil :: Foil, n = 60)
[ xs (y_u + y_l) / 2 ]
end

"""
thickness_line(foil :: Foil, n :: Integer = 40)
Get the thickness line of a `Foil`. Optionally specify the number of points for linear interpolation, default is 40.
"""
function thickness_line(foil :: Foil, n = 60)
upper, lower = split_surface(foil)
xs = LinRange(minimum(foil.x), maximum(foil.x), n + 1)
Expand All @@ -144,7 +210,6 @@ function thickness_line(foil :: Foil, n = 60)
[ xs (y_u - y_l) ]
end


"""
make_panels(foil :: Foil)
make_panels(foil :: Foil, n :: Integer)
Expand All @@ -155,6 +220,11 @@ make_panels(foil :: Foil) = @views Panel2D.(foil.x[2:end], foil.y[2:end], foil.x

make_panels(foil :: Foil, n :: Integer) = make_panels(cosine_interpolation(foil, n ÷ 2))

"""
camber(foil :: Foil, x_by_c)
Obtain the camber value of a `Foil` at a specified ``(x/c)``.
"""
function camber(foil :: Foil, x_by_c)
upper, lower = split_surface(foil)
y_u = @views linear_interpolation(upper[:,1], upper[:,2])(x_by_c * chord_length(foil))
Expand All @@ -173,30 +243,25 @@ function control_surface(foil :: Foil, δ, xc_hinge)
end

"""
control_surface(foil :: Foil, δ, xc_hinge)
control_surface(foil :: Foil; angle, hinge)
Modify a `Foil` to mimic a control surface by specifying a deflection angle (in degrees, clockwise-positive convention) and a normalized hinge ``x``-coordinate ``∈ [0,1]`` in terms of the chord length.
Modify a `Foil` to mimic a control surface by specifying a deflection angle ``δ``` (in degrees, clockwise-positive convention) and a normalized hinge ``x``-coordinate ``∈ [0,1]`` in terms of the chord length. A constructor with named arguments `angle, hinge` is provided for convenience.
"""
control_surface(foil :: Foil; angle, hinge) = control_surface(foil, angle, hinge)


"""
maximum_thickness_to_chord(wing :: Wing, num :: Integer)
maximum_thickness_to_chord(wing :: Foil, num :: Integer)
Compute the maximum thickness-to-chord ratio ``(t/c)ₘₐₓ`` and its location ``(x/c)`` of a `Foil`. Returned as the pair ``(x/c, (t/c)ₘₐₓ)``.
A `num` must be specified to interpolate the `Foil` coordinates, which affects the accuracy of ``(t/c)ₘₐₓ`` accordingly.
A `num` must be specified to interpolate the `Foil` coordinates, which affects the accuracy of ``(t/c)ₘₐₓ`` accordingly, default is 40.
"""
maximum_thickness_to_chord(foil :: Foil, n = 40) = maximum_thickness_to_chord(coordinates_to_camber_thickness(foil, n))

## Camber-thickness representation
#==========================================================================================#

"""
coordinates_to_camber_thickness(coords, n = 40)
Convert 2-dimensional coordinates to its camber-thickness representation after cosine interpolation with ``2n`` points.
"""
function coordinates_to_camber_thickness(foil :: Foil, n = 40)
# Cosine interpolation and splitting
upper, lower = split_surface(cosine_interpolation(foil, n))
Expand All @@ -207,11 +272,7 @@ function coordinates_to_camber_thickness(foil :: Foil, n = 40)
@views [ upper[:,1] camber thickness ]
end

"""
camber_thickness_to_coordinates(xs, camber, thickness)
Convert the camber-thickness representation to 2-dimensional coordinates given the ``x``-locations and their corresponding camber and thickness values.
"""
# Convert the camber-thickness representation to 2-dimensional coordinates given the ``x``-locations and their corresponding camber and thickness values.
camber_thickness_to_coordinates(xs, camber, thickness) =
@views [ [xs camber + thickness / 2][end:-1:2,:];
xs camber - thickness / 2 ]
Expand All @@ -229,20 +290,4 @@ function maximum_thickness_to_chord(coords)
max_thick_arg = argmax(thiccs)
chord = @views maximum(coords[:,1])
@views xs[max_thick_arg] / chord, thiccs[max_thick_arg] / chord
end

"""
read_foil(path :: String; header = true; name = "")
Generate a `Foil` from a file consisting of 2D coordinates with named arguments to skip the header (first line of the file) or assign a name.
By default, the header is assumed to exist and should contain the airfoil name, which is assigned to the name of the `Foil`.
"""
function read_foil(path :: String; name = "")
coords, foil_name = readdlm(path, header = true)
if name != ""
return Foil(Float16.(coords[:,1:2]), name)
else
return Foil(Float16.(coords[:,1:2]), strip(join(foil_name, " ")))
end
end
2 changes: 1 addition & 1 deletion src/Tools/Laplace.jl
Original file line number Diff line number Diff line change
Expand Up @@ -284,6 +284,6 @@ freestream_to_cartesian(r, θ, φ) = r * SVector(cos(θ) * cos(φ), -sin(φ), si
Convert Cartesian coordinates to freestream (spherical polar) flow coordinates.
"""
cartesian_to_freestream(U) = SVector(norm(U), -atand(U[3], U[1]), -atand(U[2], (U[1]^2 + U[3]^2)))
cartesian_to_freestream(U) = SVector(norm(U), atand(-U[3], -U[1]), atand(U[2], (U[1]^2 + U[3]^2)))

end
4 changes: 2 additions & 2 deletions test/runtests.jl
Original file line number Diff line number Diff line change
Expand Up @@ -198,11 +198,11 @@ end
V_test = [ cosd(θ) * cosd(φ), -sind(φ), sind(θ) * cosd(φ) ]
V_run = velocity(fs)

φ_test, θ_test = cartesian_to_freestream(V_run)
φ_test, θ_test = AeroFuse.cartesian_to_freestream(-V_run)

@test V_run V_test atol = 1e-6
@test φ_test φ atol = 1e-6
@test θ_test -θ atol = 1e-6
@test θ_test θ atol = 1e-6
end

@testset "Aerodynamics - Reference Values" begin
Expand Down

2 comments on commit b220e10

@GodotMisogi
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@JuliaRegistrator
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Registration pull request created: JuliaRegistries/General/81295

After the above pull request is merged, it is recommended that a tag is created on this repository for the registered package version.

This will be done automatically if the Julia TagBot GitHub Action is installed, or can be done manually through the github interface, or via:

git tag -a v0.4.9 -m "<description of version>" b220e10c47d7c08624ef5599b5b840728b0ef11e
git push origin v0.4.9

Please sign in to comment.