From ba44984f6eaeb27c85c60cf847477d1409708f35 Mon Sep 17 00:00:00 2001 From: "Documenter.jl" Date: Thu, 15 Aug 2024 19:50:54 +0000 Subject: [PATCH] build based on 7715271 --- dev/.documenter-siteinfo.json | 2 +- dev/C4Blade/airfoil_types/CCBlade/index.html | 10 +- dev/C4Blade/airfoil_types/DFDC/index.html | 2 +- .../airfoil_types/actuator_disk/index.html | 2 +- dev/C4Blade/airfoil_types/cascade/index.html | 2 +- dev/C4Blade/api/index.html | 2 +- dev/C4Blade/corrections/index.html | 12 +- dev/C4Blade/intro/index.html | 2 +- .../manual_repaneling/index.html | 2 +- dev/DuctAPE/advanced_usage/option/index.html | 8 +- dev/DuctAPE/advanced_usage/outputs/index.html | 2 +- .../advanced_usage/precompilation/index.html | 8 +- dev/DuctAPE/api/api_index/index.html | 2 +- dev/DuctAPE/api/private_api/index.html | 2 +- .../api/private_postprocess/index.html | 26 +- dev/DuctAPE/api/private_prelims/index.html | 10 +- dev/DuctAPE/api/private_preprocess/index.html | 114 ++++---- dev/DuctAPE/api/private_process/index.html | 30 +- dev/DuctAPE/api/private_utilities/index.html | 4 +- dev/DuctAPE/api/public_api/index.html | 28 +- dev/DuctAPE/theory/index.html | 2 +- .../tutorial/{f30479a7.svg => 8298b59a.svg} | 66 ++--- .../tutorial/{db81a906.svg => c80dff45.svg} | 90 +++--- .../tutorial/{5f10b6fa.svg => dde32380.svg} | 262 +++++++++--------- dev/DuctAPE/tutorial/index.html | 20 +- dev/assets/ductapelogo.svg | 53 ++++ dev/assets/gen_logo.jl | 15 +- dev/assets/logo.png | Bin 94375 -> 99004 bytes dev/index.html | 2 +- dev/search_index.js | 2 +- 30 files changed, 422 insertions(+), 360 deletions(-) rename dev/DuctAPE/tutorial/{f30479a7.svg => 8298b59a.svg} (81%) rename dev/DuctAPE/tutorial/{db81a906.svg => c80dff45.svg} (77%) rename dev/DuctAPE/tutorial/{5f10b6fa.svg => dde32380.svg} (78%) create mode 100644 dev/assets/ductapelogo.svg diff --git a/dev/.documenter-siteinfo.json b/dev/.documenter-siteinfo.json index f993bf62..115caa3e 100644 --- a/dev/.documenter-siteinfo.json +++ b/dev/.documenter-siteinfo.json @@ -1 +1 @@ -{"documenter":{"julia_version":"1.10.4","generation_timestamp":"2024-07-23T18:17:08","documenter_version":"1.5.0"}} \ No newline at end of file +{"documenter":{"julia_version":"1.10.4","generation_timestamp":"2024-08-15T19:50:34","documenter_version":"1.5.0"}} \ No newline at end of file diff --git a/dev/C4Blade/airfoil_types/CCBlade/index.html b/dev/C4Blade/airfoil_types/CCBlade/index.html index e09f855a..4c948988 100644 --- a/dev/C4Blade/airfoil_types/CCBlade/index.html +++ b/dev/C4Blade/airfoil_types/CCBlade/index.html @@ -2,13 +2,13 @@ CCBlade Airfoil Types · DuctAPE.jl

CCBlade Airfoil Types

DuctAPE includes all the airfoil types and methods available in CCBlade. We repeat them here for convenience, but refer the user to the CCBlade documentation for more context if advanced usage is desired.

DuctAPE.C4Blade.AlphaAFType
AlphaAF(alpha, cl, cd, info, Re, Mach)
 AlphaAF(alpha, cl, cd, info, Re=0.0, Mach=0.0)
 AlphaAF(alpha, cl, cd, info="CCBlade generated airfoil", Re=0.0, Mach=0.0)
-AlphaAF(filename::String; radians=true)

Airfoil data that varies with angle of attack. Data is fit with an Akima spline.

Arguments:

  • alpha::Vector{Float64}: angles of attack
  • cl::Vector{Float64}: corresponding lift coefficients
  • cd::Vector{Float64}: corresponding drag coefficients
  • info::String: a description of this airfoil data (just informational)
  • Re::Float64: Reynolds number data was taken at (just informational)
  • Mach::Float64: Mach number data was taken at (just informational)

or

a file

Arguments:

  • filename::String: name/path of file to read in
  • radians::Bool: true if angle of attack in file is given in radians
source
DuctAPE.C4Blade.AlphaMachAFType
AlphaMachAF(alpha, Mach, cl, cd, info, Re)
+AlphaAF(filename::String; radians=true)

Airfoil data that varies with angle of attack. Data is fit with an Akima spline.

Arguments:

  • alpha::Vector{Float64}: angles of attack
  • cl::Vector{Float64}: corresponding lift coefficients
  • cd::Vector{Float64}: corresponding drag coefficients
  • info::String: a description of this airfoil data (just informational)
  • Re::Float64: Reynolds number data was taken at (just informational)
  • Mach::Float64: Mach number data was taken at (just informational)

or

a file

Arguments:

  • filename::String: name/path of file to read in
  • radians::Bool: true if angle of attack in file is given in radians
source
DuctAPE.C4Blade.AlphaMachAFType
AlphaMachAF(alpha, Mach, cl, cd, info, Re)
 AlphaMachAF(alpha, Mach, cl, cd, info)
 AlphaMachAF(alpha, Mach, cl, cd)
-AlphaMachAF(filenames::Vector{String}; radians=true)

Airfoil data that varies with angle of attack and Mach number. Data is fit with a recursive Akima spline.

Arguments:

  • alpha::Vector{Float64}: angles of attack
  • Mach::Vector{Float64}: Mach numbers
  • cl::Matrix{Float64}: lift coefficients where cl[i, j] corresponds to alpha[i], Mach[j]
  • cd::Matrix{Float64}: drag coefficients where cd[i, j] corresponds to alpha[i], Mach[j]
  • info::String: a description of this airfoil data (just informational)
  • Re::Float64: Reynolds number data was taken at (just informational)

or

filenames with one file per Mach number.

Arguments:

  • filenames::Vector{String}: name/path of files to read in, each at a different Mach number in ascending order
  • radians::Bool: true if angle of attack in file is given in radians
source
DuctAPE.C4Blade.AlphaReAFType
AlphaReAF(alpha, Re, cl, cd, info, Mach)
+AlphaMachAF(filenames::Vector{String}; radians=true)

Airfoil data that varies with angle of attack and Mach number. Data is fit with a recursive Akima spline.

Arguments:

  • alpha::Vector{Float64}: angles of attack
  • Mach::Vector{Float64}: Mach numbers
  • cl::Matrix{Float64}: lift coefficients where cl[i, j] corresponds to alpha[i], Mach[j]
  • cd::Matrix{Float64}: drag coefficients where cd[i, j] corresponds to alpha[i], Mach[j]
  • info::String: a description of this airfoil data (just informational)
  • Re::Float64: Reynolds number data was taken at (just informational)

or

filenames with one file per Mach number.

Arguments:

  • filenames::Vector{String}: name/path of files to read in, each at a different Mach number in ascending order
  • radians::Bool: true if angle of attack in file is given in radians
source
DuctAPE.C4Blade.AlphaReAFType
AlphaReAF(alpha, Re, cl, cd, info, Mach)
 AlphaReAF(alpha, Re, cl, cd, info)
 AlphaReAF(alpha, Re, cl, cd)
-read_AlphaReAF(filenames::Vector{String}; radians=true)

Airfoil data that varies with angle of attack and Reynolds number. Data is fit with a recursive Akima spline.

Arguments:

  • alpha::Vector{Float64}: angles of attack
  • Re::Vector{Float64}: Reynolds numbers
  • cl::Matrix{Float64}: lift coefficients where cl[i, j] corresponds to alpha[i], Re[j]
  • cd::Matrix{Float64}: drag coefficients where cd[i, j] corresponds to alpha[i], Re[j]
  • info::String: a description of this airfoil data (just informational)
  • Mach::Float64: Mach number data was taken at (just informational)

or

filenames with one file per Reynolds number.

Arguments:

  • filenames::Vector{String}: name/path of files to read in, each at a different Reynolds number in ascending order
  • radians::Bool: true if angle of attack in file is given in radians
source
DuctAPE.C4Blade.AlphaReMachAFType
AlphaReMachAF(alpha, Re, Mach, cl, cd, info)
+read_AlphaReAF(filenames::Vector{String}; radians=true)

Airfoil data that varies with angle of attack and Reynolds number. Data is fit with a recursive Akima spline.

Arguments:

  • alpha::Vector{Float64}: angles of attack
  • Re::Vector{Float64}: Reynolds numbers
  • cl::Matrix{Float64}: lift coefficients where cl[i, j] corresponds to alpha[i], Re[j]
  • cd::Matrix{Float64}: drag coefficients where cd[i, j] corresponds to alpha[i], Re[j]
  • info::String: a description of this airfoil data (just informational)
  • Mach::Float64: Mach number data was taken at (just informational)

or

filenames with one file per Reynolds number.

Arguments:

  • filenames::Vector{String}: name/path of files to read in, each at a different Reynolds number in ascending order
  • radians::Bool: true if angle of attack in file is given in radians
source
DuctAPE.C4Blade.AlphaReMachAFType
AlphaReMachAF(alpha, Re, Mach, cl, cd, info)
 AlphaReMachAF(alpha, Re, Mach, cl, cd)
-AlphaReMachAF(filenames::Matrix{String}; radians=true)

Airfoil data that varies with angle of attack, Reynolds number, and Mach number. Data is fit with a recursive Akima spline.

Arguments:

  • alpha::Vector{Float64}: angles of attack
  • Re::Vector{Float64}: Reynolds numbers
  • Mach::Vector{Float64}: Mach numbers
  • cl::Array{Float64}: lift coefficients where cl[i, j, k] corresponds to alpha[i], Re[j], Mach[k]
  • cd::Array{Float64}: drag coefficients where cd[i, j, k] corresponds to alpha[i], Re[j], Mach[k]
  • info::String: a description of this airfoil data (just informational)

or files with one per Re/Mach combination

Arguments:

  • filenames::Matrix{String}: name/path of files to read in. filenames[i, j] corresponds to Re[i] Mach[j] with Reynolds number and Mach number in ascending order.
  • radians::Bool: true if angle of attack in file is given in radians
source
DuctAPE.C4Blade.DuSeligEggersType
DuSeligEggers(a, b, d, m, alpha0)
-DuSeligEggers(a=1.0, b=1.0, d=1.0, m=2*pi, alpha0=0.0)  # uses defaults

DuSelig correction for lift an Eggers correction for drag.

Arguments:

  • a, b, d::Float64: parameters in Du-Selig paper. Normally just 1.0 for each.
  • m::Float64: lift curve slope. Defaults to 2 pi for zero argument version.
  • alpha0::Float64: zero-lift angle of attack. Defaults to 0 for zero argument version.
source
DuctAPE.C4Blade.SimpleAFType
SimpleAF(m, alpha0, clmax, clmin, cd0, cd2)

A simple parameterized lift and drag curve.

  • cl = m (alpha - alpha0) (capped by clmax/clmin)
  • cd = cd0 + cd2 * cl^2

Arguments:

  • m::Float64: lift curve slope
  • alpha0::Float64: zero-lift angle of attack
  • clmax::Float64: maximum lift coefficient
  • clmin::Float64: minimum lift coefficient
  • cd0::Float64: zero lift drag
  • cd2::Float64: quadratic drag term
source
DuctAPE.C4Blade.SkinFrictionType
SkinFriction(Re0, p)

Skin friction model for a flat plate. cd *= (Re0 / Re)^p

Arguments:

  • Re0::Float64: reference Reynolds number (i.e., no corrections at this number)
  • p::Float64: exponent in flat plate model. 0.5 for laminar (Blasius solution), ~0.2 for fully turbulent (Schlichting empirical fit)
source
DuctAPE.C4Blade.afevalMethod
afeval(af::AFType, alpha, Re, Mach)

Evaluate airfoil aerodynamic performance

Arguments:

  • af::AFType or Function: dispatch on AFType or if function call: cl, cd = af(alpha, Re, Mach)
  • alpha::Float64: angle of attack in radians
  • Re::Float64: Reynolds number
  • Mach::Float64: Mach number

Returns:

  • cl::Float64: lift coefficient
  • cd::Float64: drag coefficient
source
DuctAPE.C4Blade.mach_correctionMethod
mach_correction(::MachCorrection, cl, cd, Mach)

Mach number correction for lift/drag coefficient

Arguments:

  • mc::MachCorrection: used for dispatch
  • cl::Float64: lift coefficient before correction
  • cd::Float64: drag coefficient before correction
  • Mach::Float64: Mach number

Returns:

  • cl::Float64: lift coefficient after correction
  • cd::Float64: drag coefficient after correction
source
DuctAPE.C4Blade.parsefileMethod

A basic airfoil file format. nheader is the number of header lines, which will be skipped. For one Reynolds/Mach number. Additional data like cm is optional but will be ignored.

format:

informational header

Re

Mach

alpha1 cl1 cd1 ...

alpha2 cl2 cd2

alpha3 cl3 cd3

...

source
DuctAPE.C4Blade.re_correctionMethod
re_correction(re::ReCorrection, cl, cd, Re)

Reynolds number correction for lift/drag coefficient

Arguments:

  • re::ReCorrection: used for dispatch
  • cl::Float64: lift coefficient before correction
  • cd::Float64: drag coefficient before correction
  • Re::Float64: Reynolds number

Returns:

  • cl::Float64: lift coefficient after correction
  • cd::Float64: drag coefficient after correction
source
DuctAPE.C4Blade.re_correctionMethod
re_correction(sf::SkinFriction, cl, cd, Re)

Skin friction coefficient correction based on flat plat drag increases with Reynolds number.

source
DuctAPE.C4Blade.rotation_correctionFunction
rotation_correction(rc::RotationCorrection, cl, cd, cr, rR, tsr, alpha, phi=alpha, alpha_max_corr=30*pi/180)

Rotation correction (3D stall delay).

Arguments:

  • rc::RotationCorrection: used for dispatch
  • cl::Float64: lift coefficient before correction
  • cd::Float64: drag coefficient before correction
  • cr::Float64: local chord / local radius
  • rR::Float64: local radius / tip radius
  • tsr::Float64: local tip speed ratio (Omega r / Vinf)
  • alpha::Float64: local angle of attack
  • phi::Float64: local inflow angles (defaults to angle of attack is precomputing since it is only known for on-the-fly computations)
  • alpha_max_corr::Float64: angle of attack for maximum correction (tapers off to zero by 90 degrees)

Returns:

  • cl::Float64: lift coefficient after correction
  • cd::Float64: drag coefficient after correction
source
DuctAPE.C4Blade.tip_correctionMethod
tip_correction(::TipCorrection, r, Rhub, Rtip, phi, B)

Tip corrections for 3D flow.

Arguments:

  • tc::TipCorrection: used for dispatch
  • r::Float64: local radius
  • Rhub::Float64: hub radius
  • Rtip::Float64: tip radius
  • phi::Float64: inflow angle
  • B::Integer: number of blades

Returns:

  • F::Float64: tip loss factor to multiple against loads.
source
DuctAPE.C4Blade.viternaFunction
viterna(alpha, cl, cd, cr75, nalpha=50)

Viterna extrapolation. Follows Viterna paper and somewhat follows NREL version of AirfoilPrep, but with some modifications for better robustness and smoothness.

Arguments:

  • alpha::Vector{Float64}: angles of attack
  • cl::Vector{Float64}: correspnding lift coefficients
  • cd::Vector{Float64}: correspnding drag coefficients
  • cr75::Float64: chord/Rtip at 75% Rtip
  • nalpha::Int64: number of discrete points (angles of attack) to include in extrapolation

Returns:

  • alpha::Vector{Float64}: angle of attack from -pi to pi
  • cl::Vector{Float64}: correspnding extrapolated lift coefficients
  • cd::Vector{Float64}: correspnding extrapolated drag coefficients
source
DuctAPE.C4Blade.write_afMethod
write_af(filename(s), af::AFType; radians=true)

Write airfoil data to file

Arguments:

  • filename(s)::String or Vector{String} or Matrix{String}: name/path of file to write to
  • af::AFType: writing is dispatched based on type (AlphaAF, AlphaReAF, etc.)
  • radians::Bool: true if you want angle of attack to be written in radians
source
+AlphaReMachAF(filenames::Matrix{String}; radians=true)

Airfoil data that varies with angle of attack, Reynolds number, and Mach number. Data is fit with a recursive Akima spline.

Arguments:

or files with one per Re/Mach combination

Arguments:

source
DuctAPE.C4Blade.DuSeligEggersType
DuSeligEggers(a, b, d, m, alpha0)
+DuSeligEggers(a=1.0, b=1.0, d=1.0, m=2*pi, alpha0=0.0)  # uses defaults

DuSelig correction for lift an Eggers correction for drag.

Arguments:

  • a, b, d::Float64: parameters in Du-Selig paper. Normally just 1.0 for each.
  • m::Float64: lift curve slope. Defaults to 2 pi for zero argument version.
  • alpha0::Float64: zero-lift angle of attack. Defaults to 0 for zero argument version.
source
DuctAPE.C4Blade.PrandtlTipType
PrandtlTip()

Standard Prandtl tip loss correction.

source
DuctAPE.C4Blade.PrandtlTipHubType
PrandtlTipHub()

Standard Prandtl tip loss correction plus hub loss correction of same form.

source
DuctAPE.C4Blade.SimpleAFType
SimpleAF(m, alpha0, clmax, clmin, cd0, cd2)

A simple parameterized lift and drag curve.

  • cl = m (alpha - alpha0) (capped by clmax/clmin)
  • cd = cd0 + cd2 * cl^2

Arguments:

  • m::Float64: lift curve slope
  • alpha0::Float64: zero-lift angle of attack
  • clmax::Float64: maximum lift coefficient
  • clmin::Float64: minimum lift coefficient
  • cd0::Float64: zero lift drag
  • cd2::Float64: quadratic drag term
source
DuctAPE.C4Blade.SkinFrictionType
SkinFriction(Re0, p)

Skin friction model for a flat plate. cd *= (Re0 / Re)^p

Arguments:

  • Re0::Float64: reference Reynolds number (i.e., no corrections at this number)
  • p::Float64: exponent in flat plate model. 0.5 for laminar (Blasius solution), ~0.2 for fully turbulent (Schlichting empirical fit)
source
DuctAPE.C4Blade.afevalMethod
afeval(af::AFType, alpha, Re, Mach)

Evaluate airfoil aerodynamic performance

Arguments:

  • af::AFType or Function: dispatch on AFType or if function call: cl, cd = af(alpha, Re, Mach)
  • alpha::Float64: angle of attack in radians
  • Re::Float64: Reynolds number
  • Mach::Float64: Mach number

Returns:

  • cl::Float64: lift coefficient
  • cd::Float64: drag coefficient
source
DuctAPE.C4Blade.mach_correctionMethod
mach_correction(::MachCorrection, cl, cd, Mach)

Mach number correction for lift/drag coefficient

Arguments:

  • mc::MachCorrection: used for dispatch
  • cl::Float64: lift coefficient before correction
  • cd::Float64: drag coefficient before correction
  • Mach::Float64: Mach number

Returns:

  • cl::Float64: lift coefficient after correction
  • cd::Float64: drag coefficient after correction
source
DuctAPE.C4Blade.mach_correctionMethod
mach_correction(::PrandtlGlauert, cl, cd, Mach)

Prandtl/Glauert Mach number correction for lift coefficient

source
DuctAPE.C4Blade.parsefileMethod

A basic airfoil file format. nheader is the number of header lines, which will be skipped. For one Reynolds/Mach number. Additional data like cm is optional but will be ignored.

format:

informational header

Re

Mach

alpha1 cl1 cd1 ...

alpha2 cl2 cd2

alpha3 cl3 cd3

...

source
DuctAPE.C4Blade.re_correctionMethod
re_correction(re::ReCorrection, cl, cd, Re)

Reynolds number correction for lift/drag coefficient

Arguments:

  • re::ReCorrection: used for dispatch
  • cl::Float64: lift coefficient before correction
  • cd::Float64: drag coefficient before correction
  • Re::Float64: Reynolds number

Returns:

  • cl::Float64: lift coefficient after correction
  • cd::Float64: drag coefficient after correction
source
DuctAPE.C4Blade.re_correctionMethod
re_correction(sf::SkinFriction, cl, cd, Re)

Skin friction coefficient correction based on flat plat drag increases with Reynolds number.

source
DuctAPE.C4Blade.rotation_correctionFunction
rotation_correction(rc::RotationCorrection, cl, cd, cr, rR, tsr, alpha, phi=alpha, alpha_max_corr=30*pi/180)

Rotation correction (3D stall delay).

Arguments:

  • rc::RotationCorrection: used for dispatch
  • cl::Float64: lift coefficient before correction
  • cd::Float64: drag coefficient before correction
  • cr::Float64: local chord / local radius
  • rR::Float64: local radius / tip radius
  • tsr::Float64: local tip speed ratio (Omega r / Vinf)
  • alpha::Float64: local angle of attack
  • phi::Float64: local inflow angles (defaults to angle of attack is precomputing since it is only known for on-the-fly computations)
  • alpha_max_corr::Float64: angle of attack for maximum correction (tapers off to zero by 90 degrees)

Returns:

  • cl::Float64: lift coefficient after correction
  • cd::Float64: drag coefficient after correction
source
DuctAPE.C4Blade.tip_correctionMethod
tip_correction(::TipCorrection, r, Rhub, Rtip, phi, B)

Tip corrections for 3D flow.

Arguments:

  • tc::TipCorrection: used for dispatch
  • r::Float64: local radius
  • Rhub::Float64: hub radius
  • Rtip::Float64: tip radius
  • phi::Float64: inflow angle
  • B::Integer: number of blades

Returns:

  • F::Float64: tip loss factor to multiple against loads.
source
DuctAPE.C4Blade.viternaFunction
viterna(alpha, cl, cd, cr75, nalpha=50)

Viterna extrapolation. Follows Viterna paper and somewhat follows NREL version of AirfoilPrep, but with some modifications for better robustness and smoothness.

Arguments:

  • alpha::Vector{Float64}: angles of attack
  • cl::Vector{Float64}: correspnding lift coefficients
  • cd::Vector{Float64}: correspnding drag coefficients
  • cr75::Float64: chord/Rtip at 75% Rtip
  • nalpha::Int64: number of discrete points (angles of attack) to include in extrapolation

Returns:

  • alpha::Vector{Float64}: angle of attack from -pi to pi
  • cl::Vector{Float64}: correspnding extrapolated lift coefficients
  • cd::Vector{Float64}: correspnding extrapolated drag coefficients
source
DuctAPE.C4Blade.write_afMethod
write_af(filename(s), af::AFType; radians=true)

Write airfoil data to file

Arguments:

  • filename(s)::String or Vector{String} or Matrix{String}: name/path of file to write to
  • af::AFType: writing is dispatched based on type (AlphaAF, AlphaReAF, etc.)
  • radians::Bool: true if you want angle of attack to be written in radians
source
diff --git a/dev/C4Blade/airfoil_types/DFDC/index.html b/dev/C4Blade/airfoil_types/DFDC/index.html index f742817d..57a23b5d 100644 --- a/dev/C4Blade/airfoil_types/DFDC/index.html +++ b/dev/C4Blade/airfoil_types/DFDC/index.html @@ -1,2 +1,2 @@ -DFDC Airfoil Type · DuctAPE.jl

DFDC Airfoil Type

The DFDC Airfoil type is very similar to the XROTOR airfoil type, but includes additions for cascade corrections based on stagger and solidity. The cascade corrections aren't particularly accurate, but they do apply ballpark effects resulting from high solidity blade sections. The main benefit to this airfoil type is its simplicity and that the post-stall behavior is already in a format allowing more robust convergence of the DuctAPE solvers.

DuctAPE.C4Blade.DFDCairfoilType

Fields:

  • alpha0::Float : zero lift angle of attack
  • clmax::Float : maximum cl
  • clmin::Float : minimum cl
  • dclda::Float : lift curve slope (1/radians)
  • dclda_stall::Float : lift curve slope post-stall (1/radians)
  • dcl_stall::Float : cl increment from initial to total stall.
  • cdmin::Float : minimum cd
  • cldmin::Float : cl at cdmin
  • dcddcl2::Float : quadratic curve factor for cl vs cd curve $\left(\frac{d(c_d)}{d(c_l^2)}\right)$
  • cmcon::Float : pitching moment constant (unused right now)
  • Re_ref::Float : reference Reynolds number at which cd values apply
  • Re_exp::Float : Reynolds number exponent scaling $\left( c_d = c_d(Re/Re_{ref})^{Re_{exp}}\right)$ should be 0.2 for fully laminar and 0.5 for fully turbulent
  • mcrit::Float : critical Mach number
source
+DFDC Airfoil Type · DuctAPE.jl

DFDC Airfoil Type

The DFDC Airfoil type is very similar to the XROTOR airfoil type, but includes additions for cascade corrections based on stagger and solidity. The cascade corrections aren't particularly accurate, but they do apply ballpark effects resulting from high solidity blade sections. The main benefit to this airfoil type is its simplicity and that the post-stall behavior is already in a format allowing more robust convergence of the DuctAPE solvers.

DuctAPE.C4Blade.DFDCairfoilType

Fields:

  • alpha0::Float : zero lift angle of attack
  • clmax::Float : maximum cl
  • clmin::Float : minimum cl
  • dclda::Float : lift curve slope (1/radians)
  • dclda_stall::Float : lift curve slope post-stall (1/radians)
  • dcl_stall::Float : cl increment from initial to total stall.
  • cdmin::Float : minimum cd
  • cldmin::Float : cl at cdmin
  • dcddcl2::Float : quadratic curve factor for cl vs cd curve $\left(\frac{d(c_d)}{d(c_l^2)}\right)$
  • cmcon::Float : pitching moment constant (unused right now)
  • Re_ref::Float : reference Reynolds number at which cd values apply
  • Re_exp::Float : Reynolds number exponent scaling $\left( c_d = c_d(Re/Re_{ref})^{Re_{exp}}\right)$ should be 0.2 for fully laminar and 0.5 for fully turbulent
  • mcrit::Float : critical Mach number
  • correct_for_mach::Bool : flag to add Prandtl-Glauert correction
  • correct_for_cascade::Bool : flag to add cascade corrections
  • correct_for_reynolds::Bool : flag to add reynolds drag correction
  • correct_for_transonic::Bool : flag to add drag correction above critical mach number
source
diff --git a/dev/C4Blade/airfoil_types/actuator_disk/index.html b/dev/C4Blade/airfoil_types/actuator_disk/index.html index ec798a29..43b972df 100644 --- a/dev/C4Blade/airfoil_types/actuator_disk/index.html +++ b/dev/C4Blade/airfoil_types/actuator_disk/index.html @@ -1,2 +1,2 @@ -Actuator Disk Type · DuctAPE.jl

Actuator Disk Type

Warning

Actuator disk types are currently in development and not ready for general use.

DuctAPE currently implements an actuator disk type that can be used to directly define the rotor blade circulation.

DuctAPE.C4Blade.ADMType

Fields:

  • prescribed_circulation::Float=0.0 : Prescribed circulation strength
  • prescribed_source_strength::Float=0.0 : Prescribed source panel strength
source
+Actuator Disk Type · DuctAPE.jl

Actuator Disk Type

Warning

Actuator disk types are currently in development and not ready for general use.

DuctAPE currently implements an actuator disk type that can be used to directly define the rotor blade circulation.

DuctAPE.C4Blade.ADMType

Fields:

  • prescribed_circulation::Float=0.0 : Prescribed circulation strength
  • prescribed_source_strength::Float=0.0 : Prescribed source panel strength
source
diff --git a/dev/C4Blade/airfoil_types/cascade/index.html b/dev/C4Blade/airfoil_types/cascade/index.html index 127c2fde..27cda8fe 100644 --- a/dev/C4Blade/airfoil_types/cascade/index.html +++ b/dev/C4Blade/airfoil_types/cascade/index.html @@ -1,4 +1,4 @@ Cascade Types · DuctAPE.jl

Cascade Types

Warning

Cascade types are currently in development and not ready for general use.

Cascade types are defined analogous to CCBlade airfoil types. Instead of angle of attack, however, cascade types take in both inflow and stagger angles. In addition, cascade types are dependent on local solidity.

DuctAPE.C4Blade.InReStSoMaCASType
InReStSoMaCAS(inflow, Re, stagger, solidity, Mach, cl, cd, info)
 InReStSoMaCAS(inflow, Re, stagger, solidity, Mach, cl, cd)
-InReStSoMaCAS(filenames::Matrix{String}; radians=true)

Data is fit recursively with Akima splines.

Arguments:

  • inflow::Vector{Float64}: inflow angles
  • Re::Vector{Float64}: Reynolds numbers
  • stagger::Vector{Float64}: stagger angles
  • solidity::Vector{Float64}: local solidity
  • Mach::Vector{Float64}: Mach numbers
  • cl::Array{Float64}: lift coefficients where cl[i, j, k, ell] corresponds to stagger[i], Re[j], Mach[k], solidity[ell]
  • cd::Array{Float64}: drag coefficients where cd[i, j, k, ell] corresponds to stagger[i], Re[j], Mach[k], solidity[ell]
  • info::String: a description of this airfoil data (just informational)

or files with one per Re/Stagger/Solidty/Mach combination

Arguments:

  • filenames::Matrix{String}: name/path of files to read in. filenames[i, j, k, ell] corresponds to Re[i] Stagger[j] Stagger[k] and Solidity[k] with each in ascending order.
  • radians::Bool: true if angle of attack in file is given in radians
source
DuctAPE.C4Blade.interp5dMethod
 interp5d(interp1d, x1data, x2data, x3data, x4data, fdata, x1pt, x2pt, x3pt, x4pt)

Same as FLOWMath.interp4d, ex1cept in five dimensions.

source
DuctAPE.C4Blade.parsecascadefileMethod
parsefile(filename, radians, solidity)

Cascade version of parsefile function from CCBlade. Assumes stagger is given before reynolds and Mach number, and solidity is given after

source
DuctAPE.C4Blade.writecascadefileMethod
writecascadefile(filename, info, Re, Mach, stagger, inflow, cl, cd, radians)

Cascade version of writecascadefile function from CCBlade. Writes solidity after Mach number

source
+InReStSoMaCAS(filenames::Matrix{String}; radians=true)

Data is fit recursively with Akima splines.

Arguments:

or files with one per Re/Stagger/Solidty/Mach combination

Arguments:

source
DuctAPE.C4Blade.interp5dMethod
 interp5d(interp1d, x1data, x2data, x3data, x4data, fdata, x1pt, x2pt, x3pt, x4pt)

Same as FLOWMath.interp4d, ex1cept in five dimensions.

source
DuctAPE.C4Blade.parsecascadefileMethod
parsefile(filename, radians, solidity)

Cascade version of parsefile function from CCBlade. Assumes stagger is given before reynolds and Mach number, and solidity is given after

source
DuctAPE.C4Blade.writecascadefileMethod
writecascadefile(filename, info, Re, Mach, stagger, inflow, cl, cd, radians)

Cascade version of writecascadefile function from CCBlade. Writes solidity after Mach number

source
diff --git a/dev/C4Blade/api/index.html b/dev/C4Blade/api/index.html index ed415e30..b2665590 100644 --- a/dev/C4Blade/api/index.html +++ b/dev/C4Blade/api/index.html @@ -1,2 +1,2 @@ -API Reference · DuctAPE.jl
+API Reference · DuctAPE.jl
diff --git a/dev/C4Blade/corrections/index.html b/dev/C4Blade/corrections/index.html index e636badd..5c9d2257 100644 --- a/dev/C4Blade/corrections/index.html +++ b/dev/C4Blade/corrections/index.html @@ -9,7 +9,7 @@ cd_cutoff_slope=0.9, N=20, blend_hardness=50 -)

Cuts off coefficient vs alpha curve at min and max coefficient and places rest of curve from -pi to min coeff and max coeff to pi according to user defined clcutoffslope (default 0.1)

Arguments:

Keyword Arguments:

Returns:

source

Various other correction methods are available, including the cascade corrections inherent in the DuctAPE.C4Blade.DFDCairfoil type. The following methods are in addition to the various corrections available alongside the CCBlade Airfoil Types.

DuctAPE.C4Blade.corrected_clcdMethod
corrected_clcd(af::AlphaReAF, alpha, Re, Mach, solidity, stagger; kwargs...)

Evaluates and applies on-the-fly corrections for airfoil lift and drag. On-the-fly airfoil polar corrections include solidity/stagger corrections, Prandtl-Glauert compressibility corrections, and transonic lift limits and drag additions.

corrected_clcd!(cl, cd, af::AlphaReAF, Re, alpha, Mach, solidity, stagger; kwargs...)

Evaluates and applies on-the-fly corrections for airfoil lift and drag in place.

corrected_clcd!(cl, cd, Mach, solidity, stagger; kwargs...)

Applies on-the-fly corrections for airfoil lift and drag in place.

corrected_clcd!(cl, cd, af::AlphaAF, alpha, Re, Mach, solidity, stagger; kwargs...)

Evaluates and applies on-the-fly corrections, including Reynolds corrections, for airfoil lift and drag in place

corrected_clcd(cas::InReStSoMaCAS, inflow, Re, Mach, solidity, stagger)

Evaluates cascade lift and drag.

Arguments:

Coefficients

  • cl::Float : local lift coefficient
  • cd::Float : local drag coefficient

Airfoil Object

  • af::AlphaReAF : airfoil object of CCBlade type dependent on angle of attack and Reynolds number

or

  • af::AlphaAF : airfoil object of CCBlade type dependent on angle of attack only

or

  • cas::InReStSoMaCAS : cascade object depentent on inflow angle, Reynolds number, stagger, solidity, and Mach number.

Flow Angle

  • alpha::Float : angle of attack, radians. Used with airfoil types

or

  • inflow::Float : inflow angle, radians. Used with cascade types

Flow Conditions

  • Re::Float : Reynolds number
  • Mach::Float : Mach number

Geometry

  • solidity::Float : Local solidity
  • stagger::Float : Stagger angle, radians

Keyword Arguments:

  • mcrit::Float=0.7 : Critical Mach number

rotorzloc airfoil type parameters for post-stall behavior

  • dcl_stall::Float=0.1 : change in cl from incipient to total stall, used in transonic lift limiter correction
  • dclda_stall::Float=0.1 : Post-stall lift curve slope

Correction factors that were hard coded in rotorzloc and DFDC

  • cdmfactor::Float=10.0 :
  • clmfactor::Float=0.25 :
  • mexp::Float=3.0 :
  • cdmstall::Float=0.1 :
  • cdmdd::Float=0.0020 :

Smoothing Paramters

  • ssblend_hardness::Float=100.0 : sigmoid blending hardness for solidity/stagger corrections
  • transblendhardness::Float=75.0 : sigmoid blending hardness for transonic corrections
  • absdx::Float=0.0625 : smooth absolute value Δα (radians) for transonic drag addition

Miscellaneous

  • verbose::Bool=false : Boolean of whether to print warnings, etc.
source
DuctAPE.C4Blade.prandtl_glauert!Method
prandtl_glauert!(cl, ma)

In place version of pradtl_glauert.

source
DuctAPE.C4Blade.prandtl_glauertMethod
prandtl_glauert(cl, ma)

Applies Prandtl-Glauert correction

Arguments:

  • cl::Float : local lift coefficient

Returns

  • cl_corr::AbstractVector{Float} : corrected lift coefficients
source
DuctAPE.C4Blade.prandtl_glauert_factorMethod
prandtl_glauert_factor(mach; verbose=false, blend_range=0.02)

Smoothed Prandtl-Glauert Mach correction factor

Arguments:

  • mach::Float : Mach number

Keyword Arguments:

  • blend_range::Float=0.02 : range for blending factor and max cutoff (allowing Mach >= 1.0 for continuity)
source
DuctAPE.C4Blade.quadsplineMethod
quadspline(xdata, ydata, xpoint)

Sample data in quadratic spline at give point.

source
DuctAPE.C4Blade.re_drag!Method
re_drag!(cd, re, re_ref; re_exp=0.5)

In-place version of re_drag.

source
DuctAPE.C4Blade.re_dragMethod
re_drag(cd, re, re_ref; re_exp=0.5)

Arguments:

  • cd::AbstractVector{Float} : input drag coefficients
  • re::Float : Current Reynolds number
  • re_ref::Float : Reference Reynolds number (at which the cd's were generated)

Keyword Arguments:

  • re_exp::Float=0.5 : should be 0.2 for laminar and 0.5 for turbulent flow

Returns:

  • cd_corr::AbstractVector{Float} : Reynolds corrected drag coefficients
source
DuctAPE.C4Blade.solidity_and_stagger!Method
solidity_and_stagger!(cl, solidity, stagger; blend_hardness=100)

In-place version of solidity_and_stagger.

source
DuctAPE.C4Blade.solidity_and_staggerMethod
solidity_and_stagger(cl, solidity, stagger; blend_hardness=100)

Apply smoothed Wallis' cascade correction (see solidity_and_stagger_factor_smooth) to local lift.

Arguments:

  • cl::AbstractVector{Float} : input lift coefficients
  • solidity::Float : local solidity
  • stagger::Float : local stagger (in radians)

Keyword Arguments:

  • blend_hardness::Float=100 : hardness of smoothing blends

Returns:

  • cl_corr::AbstractVector{Float} : corrected lift coefficients.
source
DuctAPE.C4Blade.solidity_and_stagger_factorMethod
solidity_and_stagger_factor(solidity, stagger; blend_hardness=100)

Correction for airfoil data used in a high-solidity cascade application. Correction is used in DFDC airfoils nominally and come from quadratic fits to curves in fig 6-29 "Axial Flow Fans and Ducts" by Wallis (1983). Note that the corrections are really only meant for Wallis' custom airfoil design and specific conditions mentioned in the book.

Arguments:

  • solidity::Float : local solidity
  • stagger::Float : local stagger (in radians)

Keyword Arguments:

  • blend_hardness::Float=100 : hardness for smoothing blends
source
DuctAPE.C4Blade.solidity_and_stagger_factor_smoothMethod
solidity_and_stagger_factor_smooth(solidity, stagger; blend_hardness=100)

A smoothed version of solidity_and_stagger_factor.

Arguments:

  • solidity::Float : local solidity
  • stagger::Float : local stagger (in radians)

Keyword Arguments:

  • blend_hardness::Float=100 : hardness for smoothing blends
source
DuctAPE.C4Blade.stall_limitersMethod
stall_limiters(
+)

Cuts off coefficient vs alpha curve at min and max coefficient and places rest of curve from -pi to min coeff and max coeff to pi according to user defined clcutoffslope (default 0.1)

Arguments:

  • aoa::AbstractVector{Float} : input angles of attack, in radians
  • cl::AbstractVector{Float} : input lift coefficients
  • cd::AbstractVector{Float} : input drag coefficients

Keyword Arguments:

  • clminid::Float=nothing : manually set index for minimum cl
  • clmaxid::Float=nothing : manually set index for maximum cl
  • cl_cutoff_slope::Float=0.1 : "post-stall" slope for cl
  • cd_cutoff_slope::Float=0.1 : "post-stall" slope for cd
  • blend_hardness::Float=50 : hardenss of blend between nominal polar and post-stall modifications.

Returns:

  • aoa_ext::AbstractVector{Float} : angles of attack for modified polar, in radians
  • cl_ext::AbstractVector{Float} : modified lift coefficients
  • cd_ext::AbstractVector{Float} : modified drag coefficients
source

Various other correction methods are available, including the cascade corrections inherent in the DuctAPE.C4Blade.DFDCairfoil type. The following methods are in addition to the various corrections available alongside the CCBlade Airfoil Types.

DuctAPE.C4Blade.corrected_clcdMethod
corrected_clcd(af::AlphaReAF, alpha, Re, Mach, solidity, stagger; kwargs...)

Evaluates and applies on-the-fly corrections for airfoil lift and drag. On-the-fly airfoil polar corrections include solidity/stagger corrections, Prandtl-Glauert compressibility corrections, and transonic lift limits and drag additions.

corrected_clcd!(cl, cd, af::AlphaReAF, Re, alpha, Mach, solidity, stagger; kwargs...)

Evaluates and applies on-the-fly corrections for airfoil lift and drag in place.

corrected_clcd!(cl, cd, Mach, solidity, stagger; kwargs...)

Applies on-the-fly corrections for airfoil lift and drag in place.

corrected_clcd!(cl, cd, af::AlphaAF, alpha, Re, Mach, solidity, stagger; kwargs...)

Evaluates and applies on-the-fly corrections, including Reynolds corrections, for airfoil lift and drag in place

corrected_clcd(cas::InReStSoMaCAS, inflow, Re, Mach, solidity, stagger)

Evaluates cascade lift and drag.

Arguments:

Coefficients

  • cl::Float : local lift coefficient
  • cd::Float : local drag coefficient

Airfoil Object

  • af::AlphaReAF : airfoil object of CCBlade type dependent on angle of attack and Reynolds number

or

  • af::AlphaAF : airfoil object of CCBlade type dependent on angle of attack only

or

  • cas::InReStSoMaCAS : cascade object depentent on inflow angle, Reynolds number, stagger, solidity, and Mach number.

Flow Angle

  • alpha::Float : angle of attack, radians. Used with airfoil types

or

  • inflow::Float : inflow angle, radians. Used with cascade types

Flow Conditions

  • Re::Float : Reynolds number
  • Mach::Float : Mach number

Geometry

  • solidity::Float : Local solidity
  • stagger::Float : Stagger angle, radians

Keyword Arguments:

  • mcrit::Float=0.7 : Critical Mach number

rotorzloc airfoil type parameters for post-stall behavior

  • dcl_stall::Float=0.1 : change in cl from incipient to total stall, used in transonic lift limiter correction
  • dclda_stall::Float=0.1 : Post-stall lift curve slope

Correction factors that were hard coded in rotorzloc and DFDC

  • cdmfactor::Float=10.0 :
  • clmfactor::Float=0.25 :
  • mexp::Float=3.0 :
  • cdmstall::Float=0.1 :
  • cdmdd::Float=0.0020 :

Smoothing Paramters

  • ssblend_hardness::Float=100.0 : sigmoid blending hardness for solidity/stagger corrections
  • transblendhardness::Float=75.0 : sigmoid blending hardness for transonic corrections
  • absdx::Float=0.0625 : smooth absolute value Δα (radians) for transonic drag addition

Miscellaneous

  • verbose::Bool=false : Boolean of whether to print warnings, etc.
source
DuctAPE.C4Blade.prandtl_glauert!Method
prandtl_glauert!(cl, ma)

In place version of pradtl_glauert.

source
DuctAPE.C4Blade.prandtl_glauertMethod
prandtl_glauert(cl, ma)

Applies Prandtl-Glauert correction

Arguments:

  • cl::Float : local lift coefficient

Returns

  • cl_corr::AbstractVector{Float} : corrected lift coefficients
source
DuctAPE.C4Blade.prandtl_glauert_factorMethod
prandtl_glauert_factor(mach; verbose=false, blend_range=0.02)

Smoothed Prandtl-Glauert Mach correction factor

Arguments:

  • mach::Float : Mach number

Keyword Arguments:

  • blend_range::Float=0.02 : range for blending factor and max cutoff (allowing Mach >= 1.0 for continuity)
source
DuctAPE.C4Blade.quadsplineMethod
quadspline(xdata, ydata, xpoint)

Sample data in quadratic spline at give point.

source
DuctAPE.C4Blade.re_drag!Method
re_drag!(cd, re, re_ref; re_exp=0.5)

In-place version of re_drag.

source
DuctAPE.C4Blade.re_dragMethod
re_drag(cd, re, re_ref; re_exp=0.5)

Arguments:

  • cd::AbstractVector{Float} : input drag coefficients
  • re::Float : Current Reynolds number
  • re_ref::Float : Reference Reynolds number (at which the cd's were generated)

Keyword Arguments:

  • re_exp::Float=0.5 : should be 0.2 for laminar and 0.5 for turbulent flow

Returns:

  • cd_corr::AbstractVector{Float} : Reynolds corrected drag coefficients
source
DuctAPE.C4Blade.solidity_and_stagger!Method
solidity_and_stagger!(cl, solidity, stagger; blend_hardness=100)

In-place version of solidity_and_stagger.

source
DuctAPE.C4Blade.solidity_and_staggerMethod
solidity_and_stagger(cl, solidity, stagger; blend_hardness=100)

Apply smoothed Wallis' cascade correction (see solidity_and_stagger_factor_smooth) to local lift.

Arguments:

  • cl::AbstractVector{Float} : input lift coefficients
  • solidity::Float : local solidity
  • stagger::Float : local stagger (in radians)

Keyword Arguments:

  • blend_hardness::Float=100 : hardness of smoothing blends

Returns:

  • cl_corr::AbstractVector{Float} : corrected lift coefficients.
source
DuctAPE.C4Blade.solidity_and_stagger_factorMethod
solidity_and_stagger_factor(solidity, stagger; blend_hardness=100)

Correction for airfoil data used in a high-solidity cascade application. Correction is used in DFDC airfoils nominally and come from quadratic fits to curves in fig 6-29 "Axial Flow Fans and Ducts" by Wallis (1983). Note that the corrections are really only meant for Wallis' custom airfoil design and specific conditions mentioned in the book.

Arguments:

  • solidity::Float : local solidity
  • stagger::Float : local stagger (in radians)

Keyword Arguments:

  • blend_hardness::Float=100 : hardness for smoothing blends
source
DuctAPE.C4Blade.solidity_and_stagger_factor_smoothMethod
solidity_and_stagger_factor_smooth(solidity, stagger; blend_hardness=100)

A smoothed version of solidity_and_stagger_factor.

Arguments:

  • solidity::Float : local solidity
  • stagger::Float : local stagger (in radians)

Keyword Arguments:

  • blend_hardness::Float=100 : hardness for smoothing blends
source
DuctAPE.C4Blade.stall_limitersMethod
stall_limiters(
     aoa,
     cl,
     cd;
@@ -19,7 +19,7 @@
     cd_cutoff_slope=0.9,
     N=20,
     blend_hardness=50
-)

Cuts off coefficient vs alpha curve at min and max coefficient and places rest of curve from -pi to min coeff and max coeff to pi according to user defined clcutoffslope (default 0.1)

Arguments:

  • aoa::AbstractVector{Float} : input angles of attack, in radians
  • cl::AbstractVector{Float} : input lift coefficients
  • cd::AbstractVector{Float} : input drag coefficients

Keyword Arguments:

  • clminid::Float=nothing : manually set index for minimum cl
  • clmaxid::Float=nothing : manually set index for maximum cl
  • cl_cutoff_slope::Float=0.1 : "post-stall" slope for cl
  • cd_cutoff_slope::Float=0.1 : "post-stall" slope for cd
  • blend_hardness::Float=50 : hardenss of blend between nominal polar and post-stall modifications.

Returns:

  • aoa_ext::AbstractVector{Float} : angles of attack for modified polar, in radians
  • cl_ext::AbstractVector{Float} : modified lift coefficients
  • cd_ext::AbstractVector{Float} : modified drag coefficients
source
DuctAPE.C4Blade.transonic_drag_addition!Method
transonic_drag_addition!(
+)

Cuts off coefficient vs alpha curve at min and max coefficient and places rest of curve from -pi to min coeff and max coeff to pi according to user defined clcutoffslope (default 0.1)

Arguments:

  • aoa::AbstractVector{Float} : input angles of attack, in radians
  • cl::AbstractVector{Float} : input lift coefficients
  • cd::AbstractVector{Float} : input drag coefficients

Keyword Arguments:

  • clminid::Float=nothing : manually set index for minimum cl
  • clmaxid::Float=nothing : manually set index for maximum cl
  • cl_cutoff_slope::Float=0.1 : "post-stall" slope for cl
  • cd_cutoff_slope::Float=0.1 : "post-stall" slope for cd
  • blend_hardness::Float=50 : hardenss of blend between nominal polar and post-stall modifications.

Returns:

  • aoa_ext::AbstractVector{Float} : angles of attack for modified polar, in radians
  • cl_ext::AbstractVector{Float} : modified lift coefficients
  • cd_ext::AbstractVector{Float} : modified drag coefficients
source
DuctAPE.C4Blade.transonic_drag_addition!Method
transonic_drag_addition!(
     cd,
     cl,
     clcdmin,
@@ -32,7 +32,7 @@
     cdmstall=0.1000,
     absdx=0.0625,
     blend_hardness=50,
-)

Smoothed, vecotrized, in-place version of transonic_drag_addition.

Different Arguments:

  • cd::AbstractVector{Float} : vector of drag coefficients
  • cl::AbstractVector{Float} : vector of lift coefficients

Additional Keyword Argument:

  • blend_hardness::Float=50 : hardenss of smoothing blends
source
DuctAPE.C4Blade.transonic_drag_additionMethod
transonic_drag_addition(
+)

Smoothed, vecotrized, in-place version of transonic_drag_addition.

Different Arguments:

  • cd::AbstractVector{Float} : vector of drag coefficients
  • cl::AbstractVector{Float} : vector of lift coefficients

Additional Keyword Argument:

  • blend_hardness::Float=50 : hardenss of smoothing blends
source
DuctAPE.C4Blade.transonic_drag_additionMethod
transonic_drag_addition(
     cd,
     cl,
     clcdmin,
@@ -44,7 +44,7 @@
     cdmdd=0.0020,
     cdmstall=0.1000,
     absdx=0.0625,
-)

Drag augmentation due to transonic effects as found in XROTOR and DFDC. Note this is nominally applied to DFDC airfoil evaluation.

Arguments:

  • cd::Float : input drag coefficient
  • cl::Float : input lift coefficient
  • clcdmin::Float : lift coefficient at minimum drag coefficient.
  • mach::Float : Mach number

Keyword Arguments

  • mcrit::Float=0.7 : critical Mach number
  • cdmfactor::Float=10.0 : factor hard coded in XROTOR and DFDC
  • clmfactor::Float=0.25 : factor hard coded in XROTOR and DFDC
  • mexp::Float=3.0 : factor hard coded in XROTOR and DFDC
  • cdmstall::Float=0.1000 : factor hard coded in XROTOR and DFDC
  • absdx::Float=0.0625 : smoothing factor for smooth absolute value function

Returns:

  • cl_corr:Float : corrected lift coefficient
source
DuctAPE.C4Blade.transonic_lift_limiterMethod
transonic_lift_limiter(
+)

Drag augmentation due to transonic effects as found in XROTOR and DFDC. Note this is nominally applied to DFDC airfoil evaluation.

Arguments:

  • cd::Float : input drag coefficient
  • cl::Float : input lift coefficient
  • clcdmin::Float : lift coefficient at minimum drag coefficient.
  • mach::Float : Mach number

Keyword Arguments

  • mcrit::Float=0.7 : critical Mach number
  • cdmfactor::Float=10.0 : factor hard coded in XROTOR and DFDC
  • clmfactor::Float=0.25 : factor hard coded in XROTOR and DFDC
  • mexp::Float=3.0 : factor hard coded in XROTOR and DFDC
  • cdmstall::Float=0.1000 : factor hard coded in XROTOR and DFDC
  • absdx::Float=0.0625 : smoothing factor for smooth absolute value function

Returns:

  • cl_corr:Float : corrected lift coefficient
source
DuctAPE.C4Blade.transonic_lift_limiterMethod
transonic_lift_limiter(
     cl,
     mach,
     clcdmin,
@@ -58,7 +58,7 @@
     clmfactor=0.25,
     mexp=3.0,
     cdmstall=0.1000,
-)

Airfoil polar corrections due to transonic effects as found in XROTOR and DFDC. Note that this correction is done nominally in the DFDC airfoil evaluation.

Arguments:

  • cl::Float : input lift coefficient
  • mach::Float : Mach number
  • clcdmin::Float : lift coefficient at minimum drag coefficient.
  • clmax::Float : maximum lift coefficient
  • clmin::Float : minimum lift coefficient
  • dclda::Float : lift-curve slope
  • mcrit::Float=0.7 : critical Mach number
  • dcl_stall::Float=0.1 : cl increment from initial to total stall
  • dclda_stall::Float=0.1 : lift curve slope post-stall (1/radians)
  • cdmfactor::Float=10.0 : factor hard coded in XROTOR and DFDC
  • clmfactor::Float=0.25 : factor hard coded in XROTOR and DFDC
  • mexp::Float=3.0 : factor hard coded in XROTOR and DFDC
  • cdmstall::Float=0.1000 : factor hard coded in XROTOR and DFDC

Returns:

  • cl_corr:Float : corrected lift coefficient
source
DuctAPE.C4Blade.transonic_lift_limiter_smooth!Method
transonic_lift_limiter_smooth!(
+)

Airfoil polar corrections due to transonic effects as found in XROTOR and DFDC. Note that this correction is done nominally in the DFDC airfoil evaluation.

Arguments:

  • cl::Float : input lift coefficient
  • mach::Float : Mach number
  • clcdmin::Float : lift coefficient at minimum drag coefficient.
  • clmax::Float : maximum lift coefficient
  • clmin::Float : minimum lift coefficient
  • dclda::Float : lift-curve slope
  • mcrit::Float=0.7 : critical Mach number
  • dcl_stall::Float=0.1 : cl increment from initial to total stall
  • dclda_stall::Float=0.1 : lift curve slope post-stall (1/radians)
  • cdmfactor::Float=10.0 : factor hard coded in XROTOR and DFDC
  • clmfactor::Float=0.25 : factor hard coded in XROTOR and DFDC
  • mexp::Float=3.0 : factor hard coded in XROTOR and DFDC
  • cdmstall::Float=0.1000 : factor hard coded in XROTOR and DFDC

Returns:

  • cl_corr:Float : corrected lift coefficient
source
DuctAPE.C4Blade.transonic_lift_limiter_smooth!Method
transonic_lift_limiter_smooth!(
     cl,
     mach,
     clcdmin,
@@ -73,4 +73,4 @@
     mexp=3.0,
     cdmstall=0.1000,
     blend_hardness=50,
-)

Smoothed, vectorized, in-place version of transonic_lift_limiter.

Different Arguments:

  • cl::AbstractVector{Float} : vector of lift coefficients

Additional Keyword Argument:

  • blend_hardness::Float=50 : hardenss of smoothing blends
source
+)

Smoothed, vectorized, in-place version of transonic_lift_limiter.

Different Arguments:

Additional Keyword Argument:

source diff --git a/dev/C4Blade/intro/index.html b/dev/C4Blade/intro/index.html index 54b60604..34cabf28 100644 --- a/dev/C4Blade/intro/index.html +++ b/dev/C4Blade/intro/index.html @@ -1,2 +1,2 @@ -Intro · DuctAPE.jl
+Intro · DuctAPE.jl
diff --git a/dev/DuctAPE/advanced_usage/manual_repaneling/index.html b/dev/DuctAPE/advanced_usage/manual_repaneling/index.html index 71be6fbf..36278512 100644 --- a/dev/DuctAPE/advanced_usage/manual_repaneling/index.html +++ b/dev/DuctAPE/advanced_usage/manual_repaneling/index.html @@ -1,2 +1,2 @@ -- · DuctAPE.jl

Circumventing the Automated Geometry Re-paneling

It is not advised to circument the automated geometry re-paneling, but if it must be done, the user needs to provide duct, centerbody, and wake nodes conforming to compatible geometry formatting. The best use case for this is to use previously generated geometry or perhaps geometry exported from DFDC.

The process is not simple, but is possible. You would have to manually run the dispatches of precompute_parameters that take in the the repaneled body nodes and wake grid. These dispatches exist for this purpose, but there is, by design, no convenience functions at this time to aid the user in easily bypassing the automated repaneling.

+- · DuctAPE.jl

Circumventing the Automated Geometry Re-paneling

It is not advised to circument the automated geometry re-paneling, but if it must be done, the user needs to provide duct, centerbody, and wake nodes conforming to compatible geometry formatting. The best use case for this is to use previously generated geometry or perhaps geometry exported from DFDC.

The process is not simple, but is possible. You would have to manually run the dispatches of precompute_parameters that take in the the repaneled body nodes and wake grid. These dispatches exist for this purpose, but there is, by design, no convenience functions at this time to aid the user in easily bypassing the automated repaneling.

diff --git a/dev/DuctAPE/advanced_usage/option/index.html b/dev/DuctAPE/advanced_usage/option/index.html index b9632b69..a379d3b8 100644 --- a/dev/DuctAPE/advanced_usage/option/index.html +++ b/dev/DuctAPE/advanced_usage/option/index.html @@ -10,8 +10,8 @@ TIo<:IntegrationOptions, TSo<:SolverOptionsType, WS<:GridSolverOptionsType, -}

Type containing (nearly) all the available user options.

Fields

General Options

Pre-processing Options

Geometry ee-interpolation and generation options :

paneling options

Integration Options

Post-processing Options

Solving Options

source

Options are selected through the set_options function

DuctAPE.set_optionsFunction
set_options(; kwargs...)
-set_options(multipoint; kwargs...)

Set the options for DuctAPE to use.

Note that the vast majority of the available options are defined through keyword arguments. See the documentation for the various option types for more information.

Arguments

  • multipoint::AbstractArray{OperatingPoint} : a vector of operating points to use if running a multi-point analysis.
source

There are three main sub-option objects for quadrature, wake geometry solver, and aerodyanmic solver; these are explained in more detail below. In addition, there are various options for pre- and post-processing as well as miscellaneous options for things such as supressing warnings and printing verbose statements throughout the analysis, which can be seen in the docstring above.

Quadrature

There are several implementations for different quadrature approaches depending on user desires; they include:

The default method is Gauss-Legendre quadrature using 8 sample points for both the nominal and singular integrals. To modify the quadrature methods and settings, an IntegrationOptions struct needs to be passed to the set_options method.

DuctAPE.IntegrationOptionsType
struct IntegrationOptions{TN<:IntegrationMethod,TS<:IntegrationMethod}

A struct used to hold the integration options for both the nominal and singular cases.

Fields

  • nominal::IntegrationMethod=GaussLegendre(8) : the integration options to use for the nominal case.
  • singular::IntegrationMethod=GaussLegendre(8) : the integration options to use for the self-induced case.
source

The IntegraionOptions type takes in two objects of type IntegrationMethod, one for the nominal integrals, and one for the singular integrals. These methods can be mixed and matched between quadrature methods as well as settings.

For example, if one wanted to use a 10-point Gauss-Legendre method for the nominal integrals, and a order 7 Gauss-Kronrod method with an absolute tolerance of 2e-16 the following would need to be included in the set_options call:

# set nominal options using a GaussLegendre object (which is an InterationMethod type)
+}

Type containing (nearly) all the available user options.

Fields

General Options

Pre-processing Options

Geometry ee-interpolation and generation options :

paneling options

Integration Options

Post-processing Options

Solving Options

source

Options are selected through the set_options function

DuctAPE.set_optionsFunction
set_options(; kwargs...)
+set_options(multipoint; kwargs...)

Set the options for DuctAPE to use.

Note that the vast majority of the available options are defined through keyword arguments. See the documentation for the various option types for more information.

Arguments

  • multipoint::AbstractArray{OperatingPoint} : a vector of operating points to use if running a multi-point analysis.
source

There are three main sub-option objects for quadrature, wake geometry solver, and aerodyanmic solver; these are explained in more detail below. In addition, there are various options for pre- and post-processing as well as miscellaneous options for things such as supressing warnings and printing verbose statements throughout the analysis, which can be seen in the docstring above.

Quadrature

There are several implementations for different quadrature approaches depending on user desires; they include:

The default method is Gauss-Legendre quadrature using 8 sample points for both the nominal and singular integrals. To modify the quadrature methods and settings, an IntegrationOptions struct needs to be passed to the set_options method.

DuctAPE.IntegrationOptionsType
struct IntegrationOptions{TN<:IntegrationMethod,TS<:IntegrationMethod}

A struct used to hold the integration options for both the nominal and singular cases.

Fields

  • nominal::IntegrationMethod=GaussLegendre(8) : the integration options to use for the nominal case.
  • singular::IntegrationMethod=GaussLegendre(8) : the integration options to use for the self-induced case.
source

The IntegraionOptions type takes in two objects of type IntegrationMethod, one for the nominal integrals, and one for the singular integrals. These methods can be mixed and matched between quadrature methods as well as settings.

For example, if one wanted to use a 10-point Gauss-Legendre method for the nominal integrals, and a order 7 Gauss-Kronrod method with an absolute tolerance of 2e-16 the following would need to be included in the set_options call:

# set nominal options using a GaussLegendre object (which is an InterationMethod type)
 # note that a convenience method is used here that takes in the number of points and
 #calculates the appropriate sample locations and weights.
 nominal_integration_method = DuctAPE.GaussLegendre(10)
@@ -28,7 +28,7 @@
 )
 
 # example of calling the set_options function
-options = DuctAPE.set_options(; integration_options=integration_options)

Elliptic Grid Solvers

As part of the pre-process, an elliptic grid defining the wake geometry is solved with a system of Poisson equations. For this solve there currently two options:

The SLOR (successive line over relaxation) is the method employed by DFDC, and can be used by itself, or as a preconditioner to a Newton solve (using NLsolve.jl).

Selection of solver and solver settings follows the same pattern as with the quadrature settings, in that the user must pass the appropriate GridSolverOptionsType into the set_options call.

For the SLOR method alone, the type is

DuctAPE.SLORGridSolverOptionsType
struct SLORGridSolverOptions{TB,TF,TI} <: GridSolverOptionsType

Options for SLOR (successive line over relaxation) elliptic grid solver.

Fields

  • iteration_limit::TI = 100 : maximum number of iterations
  • atol::TF = 1e-9 : absolute convergence tolerance
  • `converged::AbstractArray{TB} = [false]
source

And for the SLOR+Newton method, the type is

DuctAPE.GridSolverOptionsType
struct GridSolverOptions{TB,TF,TI,TSym} <: GridSolverOptionsType

Options for SLOR + Newton elliptic grid solver.

Fields

  • iteration_limit::TI = 10 : maximum number of iterations
  • atol::TF = 1e-14 : absolute convergence tolerance
  • algorithm::TSym = :newton : algorithm to use in NLsolve.jl
  • autodiff::TSym = :forward : differentiation method to use in NLsolve.jl
  • converged::AbstractArray{TB} = [false]
source

As an example, this is the input that would be required to use the SLOR+Newton method with an absolute convergence tolerance of 1e-12, and also including the quadrature settings from above:

# define wake grid solver settings
+options = DuctAPE.set_options(; integration_options=integration_options)

Elliptic Grid Solvers

As part of the pre-process, an elliptic grid defining the wake geometry is solved with a system of Poisson equations. For this solve there currently two options:

The SLOR (successive line over relaxation) is the method employed by DFDC, and can be used by itself, or as a preconditioner to a Newton solve (using NLsolve.jl).

Selection of solver and solver settings follows the same pattern as with the quadrature settings, in that the user must pass the appropriate GridSolverOptionsType into the set_options call.

For the SLOR method alone, the type is

DuctAPE.SLORGridSolverOptionsType
struct SLORGridSolverOptions{TB,TF,TI} <: GridSolverOptionsType

Options for SLOR (successive line over relaxation) elliptic grid solver.

Fields

  • iteration_limit::TI = 100 : maximum number of iterations
  • atol::TF = 1e-9 : absolute convergence tolerance
  • `converged::AbstractArray{TB} = [false]
source

And for the SLOR+Newton method, the type is

DuctAPE.GridSolverOptionsType
struct GridSolverOptions{TB,TF,TI,TSym} <: GridSolverOptionsType

Options for SLOR + Newton elliptic grid solver.

Fields

  • iteration_limit::TI = 10 : maximum number of iterations
  • atol::TF = 1e-14 : absolute convergence tolerance
  • algorithm::TSym = :newton : algorithm to use in NLsolve.jl
  • autodiff::TSym = :forward : differentiation method to use in NLsolve.jl
  • converged::AbstractArray{TB} = [false]
source

As an example, this is the input that would be required to use the SLOR+Newton method with an absolute convergence tolerance of 1e-12, and also including the quadrature settings from above:

# define wake grid solver settings
 wake_solve_options = DuctAPE.GridSolverOptions(; atol=1e-12)
 
 # set all options
@@ -81,4 +81,4 @@
         converged=fill(false, (2, nop)), # flags for each solver and each operating point
         iterations=zeros(Int, (2, nop)), # counts for each solver and each operating point
     ),
-)
+) diff --git a/dev/DuctAPE/advanced_usage/outputs/index.html b/dev/DuctAPE/advanced_usage/outputs/index.html index 1fcd0a8b..37674d02 100644 --- a/dev/DuctAPE/advanced_usage/outputs/index.html +++ b/dev/DuctAPE/advanced_usage/outputs/index.html @@ -18,4 +18,4 @@ checkoutfileexists=options.checkoutfileexists, output_tuple_name=options.output_tuple_name, verbose=options.verbose, -)

Post-process a converged nonlinear solve solution.

Arguments

Keyword Arguments

Returns

outs::NamedTuple : A named tuple containing all the output values including

source

Returning the Pre-process Objects

Sometimes, it may be desireable to return the pre-process objects, including:

In this case, we can use the return_inputs keyword argument when calling the analyze function to return a named tuple containing those pre-process objects.

outs, ins, success_flag = dt.analyze(propulsor; return_inputs=true)
+)

Post-process a converged nonlinear solve solution.

Arguments

Keyword Arguments

Returns

outs::NamedTuple : A named tuple containing all the output values including

source

Returning the Pre-process Objects

Sometimes, it may be desireable to return the pre-process objects, including:

In this case, we can use the return_inputs keyword argument when calling the analyze function to return a named tuple containing those pre-process objects.

outs, ins, success_flag = dt.analyze(propulsor; return_inputs=true)
diff --git a/dev/DuctAPE/advanced_usage/precompilation/index.html b/dev/DuctAPE/advanced_usage/precompilation/index.html index f1ca0397..504ba30d 100644 --- a/dev/DuctAPE/advanced_usage/precompilation/index.html +++ b/dev/DuctAPE/advanced_usage/precompilation/index.html @@ -1,6 +1,6 @@ Preallocation · DuctAPE.jl

Pre-compiling the Caches

There are several available caches that can be precompiled to help speed up multiple analyses. The first is a cache used for intermediate calculations in the pre- and post-processing phases of the analysis. It can be preallocated using allocate_prepost_container_cache

DuctAPE.allocate_prepost_container_cacheFunction
allocate_prepost_container_cache(paneling_constants::PanelingConstants)
-allocate_prepost_container_cache(problem_dimensions::ProblemDimensions)

Allocate the pre- and post-processing cache (used for intermediate calculations) based on paneling constants or problem dimensions.

Arguments

  • paneling_constants::PanelingConstants : a PanelingConstants object

OR

  • problem_dimensions::ProblemDimensions : a ProblemDimensions object

Keyword Arguments

  • fd_chunk_size::Int=12 : chunk size to use for PreallocationTools caches. Note that the automated chuck size for DuctAPE will always be the ForwardDiff threshold of 12 due to the size of the system, so it will be best to leave this at the default unless further development allows for chunk size selection for individual solvers.
  • levels::Int=1 : levels for nested duals. Note that since ImplicitAD is being used for all solves, there should be no need for more than 1 level.

Returns

  • prepost_container_caching::NamedTuple : a Named Tuple containing:
    • prepost_container_cache::PreallocationTools.DiffCache : the cache
    • prepost_container_cache_dims::NamedTuple : a named tuple containing the dimensions used for reshaping the cache when needed.
source

The second is a cache containing parameters used in the solver, in other words, the results of the pre-processing phase. It can be preallocated using allocate_solve_parameter_cache.

DuctAPE.allocate_solve_parameter_cacheFunction
allocate_solve_parameter_cache(
+allocate_prepost_container_cache(problem_dimensions::ProblemDimensions)

Allocate the pre- and post-processing cache (used for intermediate calculations) based on paneling constants or problem dimensions.

Arguments

  • paneling_constants::PanelingConstants : a PanelingConstants object

OR

  • problem_dimensions::ProblemDimensions : a ProblemDimensions object

Keyword Arguments

  • fd_chunk_size::Int=12 : chunk size to use for PreallocationTools caches. Note that the automated chuck size for DuctAPE will always be the ForwardDiff threshold of 12 due to the size of the system, so it will be best to leave this at the default unless further development allows for chunk size selection for individual solvers.
  • levels::Int=1 : levels for nested duals. Note that since ImplicitAD is being used for all solves, there should be no need for more than 1 level.

Returns

  • prepost_container_caching::NamedTuple : a Named Tuple containing:
    • prepost_container_cache::PreallocationTools.DiffCache : the cache
    • prepost_container_cache_dims::NamedTuple : a named tuple containing the dimensions used for reshaping the cache when needed.
source

The second is a cache containing parameters used in the solver, in other words, the results of the pre-processing phase. It can be preallocated using allocate_solve_parameter_cache.

DuctAPE.allocate_solve_parameter_cacheFunction
allocate_solve_parameter_cache(
     solve_type::SolverOptionsType,
     paneling_constants::PanelingConstants;
     fd_chunk_size=12,
@@ -11,7 +11,7 @@
     problem_dimensions::ProblemDimensions;
     fd_chunk_size=12,
     levels=1
-)

Allocate the solve parameter cache for parameters passed into the solver(s).

Arguments

  • solve_type::SolverOptionsType : Solver options type used for dispatch
  • paneling_constants::PanelingConstants : a PanlingConstants object used for sizing

OR

  • problem_dimensions::ProblemDimensions : a ProblemDimensions object used for sizing

Keyword Arguments

  • fd_chunk_size::Int=12 : chunk size to use for PreallocationTools caches. Note that the automated chuck size for DuctAPE will always be the ForwardDiff threshold of 12 due to the size of the system, so it will be best to leave this at the default unless further development allows for chunk size selection for individual solvers.
  • levels::Int=1 : levels for nested duals. Note that since ImplicitAD is being used for all solves, there should be no need for more than 1 level.

Returns

  • solve_parameter_caching::NamedTuple : a Named Tuple containing:
    • solve_parameter_cache::PreallocationTools.DiffCache : the cache
    • solve_parameter_cache_dims::NamedTuple : a named tuple containing the dimensions used for reshaping the cache when needed.
source

The final precompileable cache is for intermediate calculations within the solve and can be preallocated using allocate_solve_container_cache

DuctAPE.allocate_solve_container_cacheFunction
allocate_solve_container_cache(
+)

Allocate the solve parameter cache for parameters passed into the solver(s).

Arguments

  • solve_type::SolverOptionsType : Solver options type used for dispatch
  • paneling_constants::PanelingConstants : a PanlingConstants object used for sizing

OR

  • problem_dimensions::ProblemDimensions : a ProblemDimensions object used for sizing

Keyword Arguments

  • fd_chunk_size::Int=12 : chunk size to use for PreallocationTools caches. Note that the automated chuck size for DuctAPE will always be the ForwardDiff threshold of 12 due to the size of the system, so it will be best to leave this at the default unless further development allows for chunk size selection for individual solvers.
  • levels::Int=1 : levels for nested duals. Note that since ImplicitAD is being used for all solves, there should be no need for more than 1 level.

Returns

  • solve_parameter_caching::NamedTuple : a Named Tuple containing:
    • solve_parameter_cache::PreallocationTools.DiffCache : the cache
    • solve_parameter_cache_dims::NamedTuple : a named tuple containing the dimensions used for reshaping the cache when needed.
source

The final precompileable cache is for intermediate calculations within the solve and can be preallocated using allocate_solve_container_cache

DuctAPE.allocate_solve_container_cacheFunction
allocate_solve_container_cache(
     solve_type::SolverOptionsType,
     paneling_constants::PanelingConstants;
     fd_chunk_size=12,
@@ -22,11 +22,11 @@
     problem_dimensions::ProblemDimensions;
     fd_chunk_size=12,
     levels=1,
-)

Allocate the solve cache (used for intermediate calculations) based on paneling constants or problem dimensions.

Arguments

  • paneling_constants::PanelingConstants : a PanelingConstants object

OR

  • problem_dimensions::ProblemDimensions : a ProblemDimensions object

Keyword Arguments

  • fd_chunk_size::Int=12 : chunk size to use for PreallocationTools caches. Note that the automated chuck size for DuctAPE will always be the ForwardDiff threshold of 12 due to the size of the system, so it will be best to leave this at the default unless further development allows for chunk size selection for individual solvers.
  • levels::Int=1 : levels for nested duals. Note that since ImplicitAD is being used for all solves, there should be no need for more than 1 level.

Returns

  • solve_container_caching::NamedTuple : a Named Tuple containing:
    • solve_container_cache::PreallocationTools.DiffCache : the cache
    • solve_container_cache_dims::NamedTuple : a named tuple containing the dimensions used for reshaping the cache when needed.
source

You may run all these simultaneously using the initialize_all_caches function.

DuctAPE.initialize_all_cachesFunction
initialize_all_caches(solver_options, paneling_constants)

Convenience function to initialize all caches before calling analysis.

Arguments

  • solver_options::SolverOptionsType : solver options used for cache allocation dispatch
  • paneling_constants::PanelingConstants : PanelingConstants object upon which all cache sizing depends

Keyword Arguments

  • fd_chunk_size::Int=12 : chunk size to use for PreallocationTools caches. Note that the automated chuck size for DuctAPE will always be the ForwardDiff threshold of 12 due to the size of the system, so it will be best to leave this at the default unless further development allows for chunk size selection for individual solvers.
  • levels::Int=1 : levels for nested duals. Note that since ImplicitAD is being used for all solves, there should be no need for more than 1 level.

Returns

  • prepost_container_caching::NamedTuple : A named tuple containing the PreallocationTools DiffCache and a named tuple with relevant dimensions for accessing the cache.
  • solve_parameter_caching::NamedTuple : A named tuple containing the PreallocationTools DiffCache and a named tuple with relevant dimensions for accessing the cache.
  • solve_container_caching::NamedTuple : A named tuple containing the PreallocationTools DiffCache and a named tuple with relevant dimensions for accessing the cache.
source

How to pass the caches into an analysis

The precompiled caches can be passed in via keyword arguments to the analysis functions. If they are not, they are generated as the first step in the analysis.

DuctAPE.analyzeFunction
analyze(
+)

Allocate the solve cache (used for intermediate calculations) based on paneling constants or problem dimensions.

Arguments

  • paneling_constants::PanelingConstants : a PanelingConstants object

OR

  • problem_dimensions::ProblemDimensions : a ProblemDimensions object

Keyword Arguments

  • fd_chunk_size::Int=12 : chunk size to use for PreallocationTools caches. Note that the automated chuck size for DuctAPE will always be the ForwardDiff threshold of 12 due to the size of the system, so it will be best to leave this at the default unless further development allows for chunk size selection for individual solvers.
  • levels::Int=1 : levels for nested duals. Note that since ImplicitAD is being used for all solves, there should be no need for more than 1 level.

Returns

  • solve_container_caching::NamedTuple : a Named Tuple containing:
    • solve_container_cache::PreallocationTools.DiffCache : the cache
    • solve_container_cache_dims::NamedTuple : a named tuple containing the dimensions used for reshaping the cache when needed.
source

You may run all these simultaneously using the initialize_all_caches function.

DuctAPE.initialize_all_cachesFunction
initialize_all_caches(solver_options, paneling_constants)

Convenience function to initialize all caches before calling analysis.

Arguments

  • solver_options::SolverOptionsType : solver options used for cache allocation dispatch
  • paneling_constants::PanelingConstants : PanelingConstants object upon which all cache sizing depends

Keyword Arguments

  • fd_chunk_size::Int=12 : chunk size to use for PreallocationTools caches. Note that the automated chuck size for DuctAPE will always be the ForwardDiff threshold of 12 due to the size of the system, so it will be best to leave this at the default unless further development allows for chunk size selection for individual solvers.
  • levels::Int=1 : levels for nested duals. Note that since ImplicitAD is being used for all solves, there should be no need for more than 1 level.

Returns

  • prepost_container_caching::NamedTuple : A named tuple containing the PreallocationTools DiffCache and a named tuple with relevant dimensions for accessing the cache.
  • solve_parameter_caching::NamedTuple : A named tuple containing the PreallocationTools DiffCache and a named tuple with relevant dimensions for accessing the cache.
  • solve_container_caching::NamedTuple : A named tuple containing the PreallocationTools DiffCache and a named tuple with relevant dimensions for accessing the cache.
source

How to pass the caches into an analysis

The precompiled caches can be passed in via keyword arguments to the analysis functions. If they are not, they are generated as the first step in the analysis.

DuctAPE.analyzeFunction
analyze(
     propulsor::Propulsor,
     options::Options=set_options();
     prepost_container_caching=nothing,
     solve_parameter_caching=nothing,
     solve_container_caching=nothing,
     return_inputs=false,
-)

Analyze propulsor, including preprocessing.

Arguments

  • propulsor::Propulsor : Propulsor input object (see docstring for Propulsor type)
  • options::Options=set_options() : Options object (see set_options and related functions)

Keyword Arguments

  • prepost_container_caching=nothing : Output of allocate_prepost_container_cache
  • solve_parameter_caching=nothing : Output of allocate_solve_parameter_container_cache
  • solve_container_caching=nothing : Output of allocate_solve_container_cache
  • return_inputs=false : flag as to whether or not to return the pre-processed inputs

Returns

  • outs::NamedTuple : Named Tuple of various analysis outputs (see docstring for postprocess for details), note, if linear system decomposition fails, no solve is performed and an empty vector is returned.
  • ins::NamedTuple : Named Tuple of various pre-processed inputs (e.g. panels and body linear system), will only be returned if return_inputs=true
  • convergence_flag : Flag for successful solve convergence
source
+)

Analyze propulsor, including preprocessing.

Arguments

Keyword Arguments

Returns

source diff --git a/dev/DuctAPE/api/api_index/index.html b/dev/DuctAPE/api/api_index/index.html index cd934d8a..0d44a4ee 100644 --- a/dev/DuctAPE/api/api_index/index.html +++ b/dev/DuctAPE/api/api_index/index.html @@ -1,2 +1,2 @@ -API Index · DuctAPE.jl

Index

+API Index · DuctAPE.jl

Index

diff --git a/dev/DuctAPE/api/private_api/index.html b/dev/DuctAPE/api/private_api/index.html index acd75d83..b9b5ab17 100644 --- a/dev/DuctAPE/api/private_api/index.html +++ b/dev/DuctAPE/api/private_api/index.html @@ -1,2 +1,2 @@ -Private API · DuctAPE.jl
+Private API · DuctAPE.jl
diff --git a/dev/DuctAPE/api/private_postprocess/index.html b/dev/DuctAPE/api/private_postprocess/index.html index ff8f7f21..6c3a1710 100644 --- a/dev/DuctAPE/api/private_postprocess/index.html +++ b/dev/DuctAPE/api/private_postprocess/index.html @@ -18,7 +18,7 @@ checkoutfileexists=options.checkoutfileexists, output_tuple_name=options.output_tuple_name, verbose=options.verbose, -)

Post-process a converged nonlinear solve solution.

Arguments

Keyword Arguments

Returns

outs::NamedTuple : A named tuple containing all the output values including

source

Velocities

DuctAPE.get_body_tangential_velocitiesFunction
get_body_tangential_velocities(
+)

Post-process a converged nonlinear solve solution.

Arguments

  • solver_options::SolverOptionsType : A SolverOptionsType object (also used for dispatch)
  • converged_states::Vector{Float} : the converged state variables
  • prepost_containers::NamedTuple : the named tuple containing pre-allocated containers for the pre- and post-processing intermediate calculations
  • solve_container_cache::NamedTuple : the cache and dimensions for intermediate values in the residual calculation
  • solve_parameter_cache_vector::Vector{Float} : the applicably typed cache vector for the solve parameters
  • solve_parameter_cache_dims::NamedTuple : the dimensions of the solver parameters
  • operating_point::OperatingPoint : the operating point being analyzed
  • reference_parameters::ReferenceParameters : a ReferenceParameters object
  • A_bb_LU::LinearAlgebra.LU : LinearAlgebra LU factorization of the LHS matrix
  • airfoils::Vector{AFType} : A matrix of airfoil types associated with each of the blade elements
  • idmaps::NamedTuple : A named tuple containing index mapping used in bookkeeping throughout solve and post-process
  • problem_dimensions::ProblemDimensions : A ProblemDimensions object

Keyword Arguments

  • multipoint_index::Vector{Int} : a one-dimensional vector containing the index of which multipoint analysis operating point is being analyzed.
  • write_outputs=options.write_outputs::Vector{Bool} : a vector with the same length as number of multipoints indicating if the outputs should be saved.
  • outfile=options.outfile::Vector{String} : a vector of file paths/names for where outputs should be written
  • checkoutfileexists=options.checkoutfileexists::Bool : a flag for whether existing files should be checked for or if blind overwriting is okay.
  • output_tuple_name=options.output_tuple_name::Vector{String} : the variable name(s) of the named tuple of outputs to be written.
  • verbose::Bool=false : flag to print verbose statements

Returns

outs::NamedTuple : A named tuple containing all the output values including

  • bodies
    • panel_strengths
    • total_thrust
    • thrust_comp
    • induced_efficiency
    • cp_in
    • cp_out
    • cp_casing_in
    • cp_casing_out
    • casing_zpts
    • cp_nacelle_in
    • cp_nacelle_out
    • nacelle_zpts
    • cp_centerbody_in
    • cp_centerbody_out
    • centerbody_zpts
    • Vtot_in
    • Vtot_out
    • Vtot_prejump
    • vtot_body
    • vtot_jump
    • vtot_wake
    • vtot_rotors
    • Vtan_in
    • Vtan_out
    • vtan_casing_in
    • vtan_casing_out
    • vtan_nacelle_in
    • vtan_nacelle_out
    • vtan_centerbody_in
    • vtan_centerbody_out
  • rotors
    • circulation
    • panel_strengths
    • efficiency
    • inviscid_thrust
    • inviscid_thrust_dist
    • viscous_thrust
    • viscous_thrust_dist
    • thrust
    • CT
    • inviscid_torque
    • inviscid_torque_dist
    • viscous_torque
    • viscous_torque_dist
    • torque
    • CQ
    • inviscid_power
    • inviscid_power_dist
    • viscous_power
    • viscous_power_dist
    • power
    • CP
    • cl
    • cd
    • alpha
    • beta1
    • blade_normal_force_per_unit_span
    • blade_tangential_force_per_unit_span
  • wake
    • panel_strengths
  • totals
    • thrust
    • torque
    • power
    • CT
    • CQ
    • CP
    • total_efficiency
    • ideal_efficiency
  • intermediate_solve_values
    • vz_rotor
    • vtheta_rotor
    • Cm_wake
    • reynolds
    • mach
    • Cz_rotor
    • Ctheta_rotor
    • Cmag_rotor
    • Gamma_tilde
    • H_tilde
    • deltaGamma2
    • deltaH
    • vz_wake
    • vr_wake
    • Cm_avg
source

Velocities

DuctAPE.get_body_tangential_velocitiesFunction
get_body_tangential_velocities(
     gamb,
     gamw,
     sigr,
@@ -36,9 +36,9 @@
     centerbody_panel_ids_along_centerbody_wake_interface,
     duct_panel_ids_along_casing_wake_interface,
     num_casing_panels,
-)

Get the tangential velocities along the body surfaces.

Arguments

  • gamb::Vector{Float} : the body panel strengths
  • gamw::Vector{Float} : the wake panel strengths
  • sigr::Vector{Float} : the rotor panel strengths
  • ivb::NamedTuple : the unit induced velocities on the bodies
  • Vinf::Vector{Float} : one element vector containing the freestream magnitude
  • totnode::Int : total number of nodes between all bodies
  • totpanel::Int : total number of panels between all bodies
  • nnode::Vector{Int} : number of nodes in each body
  • npanel::Vector{Int} : number of panels in each body.
  • tangent::Matrix{Float} : unit tangent vectors for each panel
  • controlpoints::Matrix{Float} : control point locations for each panel
  • endpanelidxs::Matrix{Int} : the indices of the first and last panels for each body
  • wake_panel_ids_along_centerbody_wake_interface::Vector{Int} : the indices of the wake panels coincident with the centerbody panels
  • wake_panel_ids_along_casing_wake_interface::Vector{Int} : the indices of the wake panels coincident with the duct casing (inner surface) panels
  • centerbody_panel_ids_along_centerbody_wake_interface::Vector{Int} : the indices of the centerbody panels coincident with the wake panels
  • duct_panel_ids_along_casing_wake_interface::Vector{Int} : the indices of the duct panels coincident with the wake panels
  • num_casing_panels::Int : the number of panels between the leading and trailing edge of the duct on the duct inner side (casing)

Returns

  • vtan_tuple::NamedTuple : a named tuple containing the body tangential surface velocities and various useful breakdowns thereof.
source
DuctAPE.get_body_tangential_velocities!Function

function getbodytangentialvelocities!( vtantuple, gamb, gamw, sigr, ivb, Vinf, totnode, totpanel, nnode, npanel, tangent, controlpoints, endpanelidxs, wakepanelidsalongcenterbodywakeinterface, wakepanelidsalongcasingwakeinterface, centerbodypanelidsalongcenterbodywakeinterface, ductpanelidsalongcasingwakeinterface, zpts, )

In-place version of get_body_tangential_velocities.

Additional Arguments

  • zpts::NamedTuple : a named tuple containing the z-coordinates of the control points of the duct casing, duct nacelle, and centerbody.
source
DuctAPE.calculate_vthetaFunction
calculate_vtheta(Gamma_tilde, r)

Calculate tangential velocity for a given net circulation and radial location

Arguments

  • Gamma_tilde::Matrix{Float} : Sum of upstream circulation values
  • r::Matrix{Float} : blade element radial positions
source
DuctAPE.calculate_induced_velocities_on_bodywakeFunction
calculate_induced_velocities_on_bodywake(
+)

Get the tangential velocities along the body surfaces.

Arguments

  • gamb::Vector{Float} : the body panel strengths
  • gamw::Vector{Float} : the wake panel strengths
  • sigr::Vector{Float} : the rotor panel strengths
  • ivb::NamedTuple : the unit induced velocities on the bodies
  • Vinf::Vector{Float} : one element vector containing the freestream magnitude
  • totnode::Int : total number of nodes between all bodies
  • totpanel::Int : total number of panels between all bodies
  • nnode::Vector{Int} : number of nodes in each body
  • npanel::Vector{Int} : number of panels in each body.
  • tangent::Matrix{Float} : unit tangent vectors for each panel
  • controlpoints::Matrix{Float} : control point locations for each panel
  • endpanelidxs::Matrix{Int} : the indices of the first and last panels for each body
  • wake_panel_ids_along_centerbody_wake_interface::Vector{Int} : the indices of the wake panels coincident with the centerbody panels
  • wake_panel_ids_along_casing_wake_interface::Vector{Int} : the indices of the wake panels coincident with the duct casing (inner surface) panels
  • centerbody_panel_ids_along_centerbody_wake_interface::Vector{Int} : the indices of the centerbody panels coincident with the wake panels
  • duct_panel_ids_along_casing_wake_interface::Vector{Int} : the indices of the duct panels coincident with the wake panels
  • num_casing_panels::Int : the number of panels between the leading and trailing edge of the duct on the duct inner side (casing)

Returns

  • vtan_tuple::NamedTuple : a named tuple containing the body tangential surface velocities and various useful breakdowns thereof.
source
DuctAPE.get_body_tangential_velocities!Function

function getbodytangentialvelocities!( vtantuple, gamb, gamw, sigr, ivb, Vinf, totnode, totpanel, nnode, npanel, tangent, controlpoints, endpanelidxs, wakepanelidsalongcenterbodywakeinterface, wakepanelidsalongcasingwakeinterface, centerbodypanelidsalongcenterbodywakeinterface, ductpanelidsalongcasingwakeinterface, zpts, )

In-place version of get_body_tangential_velocities.

Additional Arguments

  • zpts::NamedTuple : a named tuple containing the z-coordinates of the control points of the duct casing, duct nacelle, and centerbody.
source
DuctAPE.calculate_vthetaFunction
calculate_vtheta(Gamma_tilde, r)

Calculate tangential velocity for a given net circulation and radial location

Arguments

  • Gamma_tilde::Matrix{Float} : Sum of upstream circulation values
  • r::Matrix{Float} : blade element radial positions
source
DuctAPE.calculate_induced_velocities_on_bodywakeFunction
calculate_induced_velocities_on_bodywake(
     vz_w, vr_w, gamw, vz_r, vr_r, sigr, vz_b, vr_b, gamb, Vinf
-)

Calculate the induced velocities on one of the body wakes (unit velocity inputs determine which one)

Arguments

  • vz_w::Matrix{Float} : unit axial induced velocity of the wake onto the body wake
  • vr_w::Matrix{Float} : unit radial induced velocity of the wake onto the body wake
  • gamw::Vector{Float} : wake panel strengths
  • vz_r::Matrix{Float} : unit axial induced velocity of the rotor onto the body wake
  • vr_r::Matrix{Float} : unit radial induced velocity of the rotor onto the body wake
  • sigr::Vector{Float} : rotor panel strengths
  • vz_b::Matrix{Float} : unit axial induced velocity of the bodies onto the body wake
  • vr_b::Matrix{Float} : unit radial induced velocity of the bodies onto the body wake
  • gamb::Vector{Float} : body panel strengths
  • Vinf::Vector{Float} : one element vector containing the velocity magnitude
source

Pressures

DuctAPE.steady_cpFunction
steady_cp(Vs, Vinf, Vref)

Calculate steady pressure coefficients for a given surface velocity.

Arguments

  • Vs::Vector{Float} : the surface velocities
  • Vinf::Vector{Float} : one element vector with freestream mangnitude
  • Vref::Vector{Float} : one element vector with reference velocity used for non-dimensionalization

Returns

  • cp::Vector{Float} : the steady pressure coefficients
source
DuctAPE.steady_cp!Function
steady_cp!(cp, Vs, Vinf, Vref)

In-place verison of steady_cp.

source
DuctAPE.calculate_entropy_jumpsFunction
calculate_entropy_jumps(sigr, Cz_rotor)

Calculate jumps in entropy across the disks.

Arguments

  • sigr::Matrix{Float} : rotor source panel strengths
  • Cz_rotor::Vector{Float} : absolute axial velocity on rotor blade elements

Returns

  • deltaS::Vector{Float} : entropy jump across rotor disks
source
DuctAPE.calculate_rotor_jumpsFunction
calculate_rotor_jumps(Gamr, Omega, B, sigr, Cz_rotor)

Calculate net circulation and enthalpy and entropy disk jumps

Arguments

  • Gamr::Matrix{Float} : Blade element circulation strengths
  • Omega::Vector{Float} : rotor rotation rates
  • B::Vector{Float} : blade count for each rotor (usually integers but could be a float)
  • sigr::Matrix{Float} : rotor source panel strengths
  • Cz_rotor::Vector{Float} : absolute axial velocity on rotor blade elements

Returns

  • Gamma_tilde::Matrix{Float} : net upstream circulation
  • Htilde::Matrix{Float} : net upstream enthalpy jumps
  • Stilde::Matrix{Float} : net upstream entropy jumps
source
DuctAPE.delta_cpFunction
delta_cp(deltaH, deltaS, Ctheta, Vref)

Calculate change in pressure coefficient aft of rotor, due to rotor

Arguments

  • deltaH::Vector{Float} : Enthalpy jumps across disks
  • deltaS::Vector{Float} : Entropy jumps across disks`
  • Ctheta::Vector{Float} : tangenetial velocity
  • Vref::Vector{Float} : reference velocity for non-dimensionalization

Returns

  • delta_cp::Vector{Float} : pressure rises due to rotor disks
source
DuctAPE.calculate_body_delta_cp!Function
calculate_body_delta_cp!(cp, Gamr, sigr, Cz_rotor, Vref, Omega, B, cpr, casing_panel_ids_aft_of_rotors, centerbody_panel_ids_aft_of_rotors)

Augment surface pressure by change in pressure coefficient due to rotors specifically on the body panels aft of the rotors.

Arguments

  • cp::Vector{Float} : steady pressure coeffients, modified in-place to include rotor effects.
  • Gamr::Matrix{Float} : Blade element circulation strengths
  • sigr::Matrix{Float} : rotor source panel strengths
  • Cz_rotor::Vector{Float} : absolute axial velocity on rotor blade elements
  • Vref::Vector{Float} : one element vector with reference velocity used for non-dimensionalization
  • Omega::Vector{Float} : rotor rotation rates
  • B::Vector{Float} : blade count for each rotor (usually integers but could be a float)
  • cpr::Vector{Float} : control point radial positions of body panels
  • casing_panel_ids_aft_of_rotors::Vector{Int} : duct indices of control point radial positions aft of rotors
  • centerbody_panel_ids_aft_of_rotors::Vector{Int} : centerbody indices of control point radial positions aft of rotors
source
DuctAPE.calculate_bodywake_delta_cpFunction
calculate_bodywake_delta_cp(Gamr, sigr, Cz_rotor, Vref, Omega, B, cpr; body="duct")

Calculate change in pressure coefficient due to rotors specifically on the body wakes

Arguments

  • Gamr::Matrix{Float} : Blade element circulation strengths
  • sigr::Matrix{Float} : rotor source panel strengths
  • Cz_rotor::Vector{Float} : absolute axial velocity on rotor blade elements
  • Vref::Vector{Float} : one element vector with reference velocity used for non-dimensionalization
  • Omega::Vector{Float} : rotor rotation rates
  • B::Vector{Float} : blade count for each rotor (usually integers but could be a float)
  • cpr::Vector{Float} : control point radial positions of body wake "panels"

Keyword Arguments

  • body::String="duct" : flag as to whether the body in question is a duct or centerbody.
source
DuctAPE.get_body_cpsFunction

getbodycps( Vtanin, Vtanout, Gamr, sigr, Czrotor, Vinf, Vref, B, Omega, casingpanelidsaftofrotors, centerbodypanelidsaftof_rotors, controlpoints, endpanelidxs, zpts, )

Description

Arguments

  • Vtan_in::Vector{Float} : Tangential velocity on the inside of the body panels
  • Vtan_out::Vector{Float} : Tangential velocity on the outside of the body panels
  • Gamr::Matrix{Float} : Blade element circulation strengths
  • sigr::Matrix{Float} : rotor source panel strengths
  • Cz_rotor::Vector{Float} : absolute axial velocity on rotor blade elements
  • Vinf::Vector{Float} : one element vector with freestream mangnitude
  • Vref::Vector{Float} : one element vector with reference velocity used for non-dimensionalization
  • B::Vector{Float} : blade count for each rotor (usually integers but could be a float)
  • Omega::Vector{Float} : rotor rotation rates
  • casing_panel_ids_aft_of_rotors::Vector{Int} : duct indices of control point radial positions aft of rotors
  • centerbody_panel_ids_aft_of_rotors::Vector{Int} : centerbody indices of control point radial positions aft of rotors
  • controlpoints::Matrix{Float} : control point locations for each panel
  • endpanelidxs::Matrix{Int} : the indices of the first and last panels for each body
  • zpts::NamedTuple : a named tuple containing the z-coordinates of the control points of the duct casing, duct nacelle, and centerbody.

Returns

  • cp_tuple::NamedTuple : body surface velocities and various useful breakdowns thereof.
source
DuctAPE.get_body_cps!Function
get_body_cps!(
+)

Calculate the induced velocities on one of the body wakes (unit velocity inputs determine which one)

Arguments

  • vz_w::Matrix{Float} : unit axial induced velocity of the wake onto the body wake
  • vr_w::Matrix{Float} : unit radial induced velocity of the wake onto the body wake
  • gamw::Vector{Float} : wake panel strengths
  • vz_r::Matrix{Float} : unit axial induced velocity of the rotor onto the body wake
  • vr_r::Matrix{Float} : unit radial induced velocity of the rotor onto the body wake
  • sigr::Vector{Float} : rotor panel strengths
  • vz_b::Matrix{Float} : unit axial induced velocity of the bodies onto the body wake
  • vr_b::Matrix{Float} : unit radial induced velocity of the bodies onto the body wake
  • gamb::Vector{Float} : body panel strengths
  • Vinf::Vector{Float} : one element vector containing the velocity magnitude
source

Pressures

DuctAPE.steady_cpFunction
steady_cp(Vs, Vinf, Vref)

Calculate steady pressure coefficients for a given surface velocity.

Arguments

  • Vs::Vector{Float} : the surface velocities
  • Vinf::Vector{Float} : one element vector with freestream mangnitude
  • Vref::Vector{Float} : one element vector with reference velocity used for non-dimensionalization

Returns

  • cp::Vector{Float} : the steady pressure coefficients
source
DuctAPE.steady_cp!Function
steady_cp!(cp, Vs, Vinf, Vref)

In-place verison of steady_cp.

source
DuctAPE.calculate_entropy_jumpsFunction
calculate_entropy_jumps(sigr, Cz_rotor)

Calculate jumps in entropy across the disks.

Arguments

  • sigr::Matrix{Float} : rotor source panel strengths
  • Cz_rotor::Vector{Float} : absolute axial velocity on rotor blade elements

Returns

  • deltaS::Vector{Float} : entropy jump across rotor disks
source
DuctAPE.calculate_rotor_jumpsFunction
calculate_rotor_jumps(Gamr, Omega, B, sigr, Cz_rotor)

Calculate net circulation and enthalpy and entropy disk jumps

Arguments

  • Gamr::Matrix{Float} : Blade element circulation strengths
  • Omega::Vector{Float} : rotor rotation rates
  • B::Vector{Float} : blade count for each rotor (usually integers but could be a float)
  • sigr::Matrix{Float} : rotor source panel strengths
  • Cz_rotor::Vector{Float} : absolute axial velocity on rotor blade elements

Returns

  • Gamma_tilde::Matrix{Float} : net upstream circulation
  • Htilde::Matrix{Float} : net upstream enthalpy jumps
  • Stilde::Matrix{Float} : net upstream entropy jumps
source
DuctAPE.delta_cpFunction
delta_cp(deltaH, deltaS, Ctheta, Vref)

Calculate change in pressure coefficient aft of rotor, due to rotor

Arguments

  • deltaH::Vector{Float} : Enthalpy jumps across disks
  • deltaS::Vector{Float} : Entropy jumps across disks`
  • Ctheta::Vector{Float} : tangenetial velocity
  • Vref::Vector{Float} : reference velocity for non-dimensionalization

Returns

  • delta_cp::Vector{Float} : pressure rises due to rotor disks
source
DuctAPE.calculate_body_delta_cp!Function
calculate_body_delta_cp!(cp, Gamr, sigr, Cz_rotor, Vref, Omega, B, cpr, casing_panel_ids_aft_of_rotors, centerbody_panel_ids_aft_of_rotors)

Augment surface pressure by change in pressure coefficient due to rotors specifically on the body panels aft of the rotors.

Arguments

  • cp::Vector{Float} : steady pressure coeffients, modified in-place to include rotor effects.
  • Gamr::Matrix{Float} : Blade element circulation strengths
  • sigr::Matrix{Float} : rotor source panel strengths
  • Cz_rotor::Vector{Float} : absolute axial velocity on rotor blade elements
  • Vref::Vector{Float} : one element vector with reference velocity used for non-dimensionalization
  • Omega::Vector{Float} : rotor rotation rates
  • B::Vector{Float} : blade count for each rotor (usually integers but could be a float)
  • cpr::Vector{Float} : control point radial positions of body panels
  • casing_panel_ids_aft_of_rotors::Vector{Int} : duct indices of control point radial positions aft of rotors
  • centerbody_panel_ids_aft_of_rotors::Vector{Int} : centerbody indices of control point radial positions aft of rotors
source
DuctAPE.calculate_bodywake_delta_cpFunction
calculate_bodywake_delta_cp(Gamr, sigr, Cz_rotor, Vref, Omega, B, cpr; body="duct")

Calculate change in pressure coefficient due to rotors specifically on the body wakes

Arguments

  • Gamr::Matrix{Float} : Blade element circulation strengths
  • sigr::Matrix{Float} : rotor source panel strengths
  • Cz_rotor::Vector{Float} : absolute axial velocity on rotor blade elements
  • Vref::Vector{Float} : one element vector with reference velocity used for non-dimensionalization
  • Omega::Vector{Float} : rotor rotation rates
  • B::Vector{Float} : blade count for each rotor (usually integers but could be a float)
  • cpr::Vector{Float} : control point radial positions of body wake "panels"

Keyword Arguments

  • body::String="duct" : flag as to whether the body in question is a duct or centerbody.
source
DuctAPE.get_body_cpsFunction

getbodycps( Vtanin, Vtanout, Gamr, sigr, Czrotor, Vinf, Vref, B, Omega, casingpanelidsaftofrotors, centerbodypanelidsaftof_rotors, controlpoints, endpanelidxs, zpts, )

Description

Arguments

  • Vtan_in::Vector{Float} : Tangential velocity on the inside of the body panels
  • Vtan_out::Vector{Float} : Tangential velocity on the outside of the body panels
  • Gamr::Matrix{Float} : Blade element circulation strengths
  • sigr::Matrix{Float} : rotor source panel strengths
  • Cz_rotor::Vector{Float} : absolute axial velocity on rotor blade elements
  • Vinf::Vector{Float} : one element vector with freestream mangnitude
  • Vref::Vector{Float} : one element vector with reference velocity used for non-dimensionalization
  • B::Vector{Float} : blade count for each rotor (usually integers but could be a float)
  • Omega::Vector{Float} : rotor rotation rates
  • casing_panel_ids_aft_of_rotors::Vector{Int} : duct indices of control point radial positions aft of rotors
  • centerbody_panel_ids_aft_of_rotors::Vector{Int} : centerbody indices of control point radial positions aft of rotors
  • controlpoints::Matrix{Float} : control point locations for each panel
  • endpanelidxs::Matrix{Int} : the indices of the first and last panels for each body
  • zpts::NamedTuple : a named tuple containing the z-coordinates of the control points of the duct casing, duct nacelle, and centerbody.

Returns

  • cp_tuple::NamedTuple : body surface velocities and various useful breakdowns thereof.
source
DuctAPE.get_body_cps!Function
get_body_cps!(
     cp_tuple,
     Vtan_in,
     Vtan_out,
@@ -54,7 +54,7 @@
     controlpoints,
     endpanelidxs,
     zpts,
-)

In-place version of get_body_cps.

source
DuctAPE.get_bodywake_cpsFunction
get_bodywake_cps(
+)

In-place version of get_body_cps.

source
DuctAPE.get_bodywake_cpsFunction
get_bodywake_cps(
     Gamr,
     vz_w,
     vr_w,
@@ -72,21 +72,21 @@
     Vinf,
     Vref;
     body="duct",
-)

Calculate the pressure coefficient distributions on one of the body wakes

Arguments

  • Gamr::Matrix{Float} : Blade element circulation strengths
  • vz_w::Matrix{Float} : unit axial induced velocity of the wake onto the body wake
  • vr_w::Matrix{Float} : unit radial induced velocity of the wake onto the body wake
  • gamw::Vector{Float} : wake panel strengths
  • vz_r::Matrix{Float} : unit axial induced velocity of the rotor onto the body wake
  • vr_r::Matrix{Float} : unit radial induced velocity of the rotor onto the body wake
  • sigr::Vector{Float} : rotor panel strengths
  • vz_b::Matrix{Float} : unit axial induced velocity of the bodies onto the body wake
  • vr_b::Matrix{Float} : unit radial induced velocity of the bodies onto the body wake
  • gamb::Vector{Float} : body panel strengths
  • panels::NamedTuple : A named tuple containing bodywake "panel" geometries
  • Cz_rotor::Vector{Float} : absolute axial velocity on rotor blade elements
  • Omega::Vector{Float} : rotor rotation rates
  • B::Vector{Float} : blade count for each rotor (usually integers but could be a float)
  • Vinf::Vector{Float} : one element vector containing the velocity magnitude
  • Vref::Vector{Float} : one element vector with reference velocity used for non-dimensionalization

Keyword Arguments

  • body::String="duct" : flag as to whether the body in question is a duct or centerbody.
source
DuctAPE.forces_from_pressureFunction
forces_from_pressure(cp_in, cp_out, panels; rhoinf=1.225, Vref=1.0)

Calculate dimensional and non-dimensional axial force on a single body

Arguments

  • cp_in::Vector{Float} : pressure coefficient on inside of body surfaces
  • cp_out::Vector{Float} : pressure coefficients on outside of body surfaces
  • panels::NamedTuple : A named tuple containing panel geometry information

Keyword Arguments

  • rhoinf::Float=1.225 : reference density for non-dimensionalization
  • Vref::Float=1.0 : reference velocity for non-dimensionalization

Returns

  • thrust::Vector{Float} : dimensional axial force
  • force_coeff::Vector{Float} : non-dimensional axial force
source
DuctAPE.forces_from_pressure!Function
forces_from_pressure!(CFx, cfx, cp_in, cp_out, panels; rhoinf=1.225, Vref=1.0)

In-place version of forces_from_pressure.

source
DuctAPE.forces_from_TEpanels!Function
forces_from_TEpanels!(
+)

Calculate the pressure coefficient distributions on one of the body wakes

Arguments

  • Gamr::Matrix{Float} : Blade element circulation strengths
  • vz_w::Matrix{Float} : unit axial induced velocity of the wake onto the body wake
  • vr_w::Matrix{Float} : unit radial induced velocity of the wake onto the body wake
  • gamw::Vector{Float} : wake panel strengths
  • vz_r::Matrix{Float} : unit axial induced velocity of the rotor onto the body wake
  • vr_r::Matrix{Float} : unit radial induced velocity of the rotor onto the body wake
  • sigr::Vector{Float} : rotor panel strengths
  • vz_b::Matrix{Float} : unit axial induced velocity of the bodies onto the body wake
  • vr_b::Matrix{Float} : unit radial induced velocity of the bodies onto the body wake
  • gamb::Vector{Float} : body panel strengths
  • panels::NamedTuple : A named tuple containing bodywake "panel" geometries
  • Cz_rotor::Vector{Float} : absolute axial velocity on rotor blade elements
  • Omega::Vector{Float} : rotor rotation rates
  • B::Vector{Float} : blade count for each rotor (usually integers but could be a float)
  • Vinf::Vector{Float} : one element vector containing the velocity magnitude
  • Vref::Vector{Float} : one element vector with reference velocity used for non-dimensionalization

Keyword Arguments

  • body::String="duct" : flag as to whether the body in question is a duct or centerbody.
source
DuctAPE.forces_from_pressureFunction
forces_from_pressure(cp_in, cp_out, panels; rhoinf=1.225, Vref=1.0)

Calculate dimensional and non-dimensional axial force on a single body

Arguments

  • cp_in::Vector{Float} : pressure coefficient on inside of body surfaces
  • cp_out::Vector{Float} : pressure coefficients on outside of body surfaces
  • panels::NamedTuple : A named tuple containing panel geometry information

Keyword Arguments

  • rhoinf::Float=1.225 : reference density for non-dimensionalization
  • Vref::Float=1.0 : reference velocity for non-dimensionalization

Returns

  • thrust::Vector{Float} : dimensional axial force
  • force_coeff::Vector{Float} : non-dimensional axial force
source
DuctAPE.forces_from_pressure!Function
forces_from_pressure!(CFx, cfx, cp_in, cp_out, panels; rhoinf=1.225, Vref=1.0)

In-place version of forces_from_pressure.

source
DuctAPE.forces_from_TEpanels!Function
forces_from_TEpanels!(
     thrust, force_coeff, cp_in, cp_out, panels; rhoinf=1.225, Vref=1.0
-)

Add force induced by trailing edge gap panels to total forces.

Arguments

  • thrust::Vector{Float} : dimensional axial force
  • force_coeff::Vector{Float} : non-dimensional axial force
  • cp_in::Vector{Float} : pressure coefficient on inside of body surfaces
  • cp_out::Vector{Float} : pressure coefficients on outside of body surfaces
  • panels::NamedTuple : A named tuple containing panel geometry information

Keyword Arguments

  • rhoinf::Float=1.225 : reference density for non-dimensionalization
  • Vref::Float=1.0 : reference velocity for non-dimensionalization
source

Rotor Performance

DuctAPE.inviscid_rotor_thrustFunction
inviscid_rotor_thrust(Ctheta_rotor, Gamma_tilde, rotor_panel_length, rhoinf)

Calculate inviscid rotor thrust.

Arguments

  • Ctheta_rotor::Vector{Float} : Absolute tangential velocity on rotor blade elements
  • Gamma_tilde::Matrix{Float} : net upstream rotor circulation
  • rotor_panel_length::Vector{Float} : dimensional lengths on which blade element values apply
  • rhoinf::Float : freestream density

Returns

  • Tinv::Vector{Float} : inviscid dimensional thrust
  • dTi::Vector{Float} : inviscid dimensional thrust distribution
source
DuctAPE.inviscid_rotor_thrust!Function
inviscid_rotor_thrust!(
+)

Add force induced by trailing edge gap panels to total forces.

Arguments

  • thrust::Vector{Float} : dimensional axial force
  • force_coeff::Vector{Float} : non-dimensional axial force
  • cp_in::Vector{Float} : pressure coefficient on inside of body surfaces
  • cp_out::Vector{Float} : pressure coefficients on outside of body surfaces
  • panels::NamedTuple : A named tuple containing panel geometry information

Keyword Arguments

  • rhoinf::Float=1.225 : reference density for non-dimensionalization
  • Vref::Float=1.0 : reference velocity for non-dimensionalization
source

Rotor Performance

DuctAPE.inviscid_rotor_thrustFunction
inviscid_rotor_thrust(Ctheta_rotor, Gamma_tilde, rotor_panel_length, rhoinf)

Calculate inviscid rotor thrust.

Arguments

  • Ctheta_rotor::Vector{Float} : Absolute tangential velocity on rotor blade elements
  • Gamma_tilde::Matrix{Float} : net upstream rotor circulation
  • rotor_panel_length::Vector{Float} : dimensional lengths on which blade element values apply
  • rhoinf::Float : freestream density

Returns

  • Tinv::Vector{Float} : inviscid dimensional thrust
  • dTi::Vector{Float} : inviscid dimensional thrust distribution
source
DuctAPE.inviscid_rotor_thrust!Function
inviscid_rotor_thrust!(
     Tinv, dTi, Ctheta_rotor, Gamma_tilde, rotor_panel_length, rhoinf
-)

In-place version of inviscid_rotor_thrust.

source
DuctAPE.viscous_rotor_thrustFunction
viscous_rotor_thrust(
+)

In-place version of inviscid_rotor_thrust.

source
DuctAPE.viscous_rotor_thrustFunction
viscous_rotor_thrust(
     Cz_rotor, Cmag_rotor, B, chord, rotor_panel_length, cd, rhoinf
-)

Calculate visous rotor "thrust."

Arguments

  • Cz_rotor::Vector{Float} : Absolute axial velocity on rotor blade elements
  • Cmag_rotor::Vector{Float} : Absolute inflow velocity magnitude on rotor blade elements
  • B::Vector{Float} : blade count for each rotor (usually integers but could be a float)
  • chord::Vector{Float} : blade element chord lengths
  • rotor_panel_length::Vector{Float} : dimensional lengths on which blade element values apply
  • cd::Vector{Float} : drag coefficient for each blade element
  • rhoinf::Float : freestream density

Returns

  • Tvisc::Vector{Float} : viscous dimensional thrust
  • dTv::Vector{Float} : viscous dimensional thrust distribution
source
DuctAPE.viscous_rotor_thrust!Function
viscous_rotor_thrust!(
+)

Calculate visous rotor "thrust."

Arguments

  • Cz_rotor::Vector{Float} : Absolute axial velocity on rotor blade elements
  • Cmag_rotor::Vector{Float} : Absolute inflow velocity magnitude on rotor blade elements
  • B::Vector{Float} : blade count for each rotor (usually integers but could be a float)
  • chord::Vector{Float} : blade element chord lengths
  • rotor_panel_length::Vector{Float} : dimensional lengths on which blade element values apply
  • cd::Vector{Float} : drag coefficient for each blade element
  • rhoinf::Float : freestream density

Returns

  • Tvisc::Vector{Float} : viscous dimensional thrust
  • dTv::Vector{Float} : viscous dimensional thrust distribution
source
DuctAPE.viscous_rotor_thrust!Function
viscous_rotor_thrust!(
     Tvisc, dTv, Cz_rotor, Cmag_rotor, B, chord, rotor_panel_length, cd, rhoinf
-)

In-place version of viscous_rotor_thrust.

source
DuctAPE.inviscid_rotor_torqueFunction
inviscid_rotor_torque(
+)

In-place version of viscous_rotor_thrust.

source
DuctAPE.inviscid_rotor_torqueFunction
inviscid_rotor_torque(
     Cz_rotor, rotor_panel_center, rotor_panel_length, Gamma_tilde, rhoinf
-)

Calculate inviscid rotor torque.

Arguments

  • Cz_rotor::Vector{Float} : Absolute axial velocity on rotor blade elements
  • rotor_panel_center::Vector{Float} : radial location of rotor blade elements
  • rotor_panel_length::Vector{Float} : dimensional lengths on which blade element values apply
  • Gamma_tilde::Matrix{Float} : net upstream rotor circulation
  • rhoinf::Float : freestream density

Returns

  • Qinv::Vector{Float} : inviscid dimensional thrust
  • dQi::Vector{Float} : inviscid dimensional thrust distribution
source
DuctAPE.inviscid_rotor_torque!Function
inviscid_rotor_torque!(
+)

Calculate inviscid rotor torque.

Arguments

  • Cz_rotor::Vector{Float} : Absolute axial velocity on rotor blade elements
  • rotor_panel_center::Vector{Float} : radial location of rotor blade elements
  • rotor_panel_length::Vector{Float} : dimensional lengths on which blade element values apply
  • Gamma_tilde::Matrix{Float} : net upstream rotor circulation
  • rhoinf::Float : freestream density

Returns

  • Qinv::Vector{Float} : inviscid dimensional thrust
  • dQi::Vector{Float} : inviscid dimensional thrust distribution
source
DuctAPE.inviscid_rotor_torque!Function
inviscid_rotor_torque!(
     Qinv, dQi, Cz_rotor, rotor_panel_center, rotor_panel_length, Gamma_tilde, rhoinf
-)

In-place version of inviscid_rotor_torque.

source
DuctAPE.viscous_rotor_torqueFunction
viscous_rotor_torque(
+)

In-place version of inviscid_rotor_torque.

source
DuctAPE.viscous_rotor_torqueFunction
viscous_rotor_torque(
     Ctheta_rotor, Cmag_rotor, B, chord, rotor_panel_center, rotor_panel_length, cd, rhoinf
-)

Calculate viscous rotor torque.

Arguments

  • Ctheta_rotor::Vector{Float} : Absolute tangential velocity on rotor blade elements
  • Cmag_rotor::Vector{Float} : Absolute inflow velocity magnitude on rotor blade elements
  • B::Vector{Float} : blade count for each rotor (usually integers but could be a float)
  • chord::Vector{Float} : blade element chord lengths
  • rotor_panel_center::Vector{Float} : radial location of rotor blade elements
  • rotor_panel_length::Vector{Float} : dimensional lengths on which blade element values apply
  • cd::Vector{Float} : drag coefficient for each blade element
  • rhoinf::Float : freestream density

Returns

  • Qvisc::Vector{Float} : viscous dimensional thrust
  • dQv::Vector{Float} : viscous dimensional thrust distribution
source
DuctAPE.viscous_rotor_torque!Function
viscous_rotor_torque!(
+)

Calculate viscous rotor torque.

Arguments

  • Ctheta_rotor::Vector{Float} : Absolute tangential velocity on rotor blade elements
  • Cmag_rotor::Vector{Float} : Absolute inflow velocity magnitude on rotor blade elements
  • B::Vector{Float} : blade count for each rotor (usually integers but could be a float)
  • chord::Vector{Float} : blade element chord lengths
  • rotor_panel_center::Vector{Float} : radial location of rotor blade elements
  • rotor_panel_length::Vector{Float} : dimensional lengths on which blade element values apply
  • cd::Vector{Float} : drag coefficient for each blade element
  • rhoinf::Float : freestream density

Returns

  • Qvisc::Vector{Float} : viscous dimensional thrust
  • dQv::Vector{Float} : viscous dimensional thrust distribution
source
DuctAPE.viscous_rotor_torque!Function
viscous_rotor_torque!(
     Qvisc,
     dQv,
     Ctheta_rotor,
@@ -97,4 +97,4 @@
     rotor_panel_length,
     cd,
     rhoinf
-)

In-place version of viscous_rotor_torque.

source
DuctAPE.rotor_powerFunction
rotor_power(Q, dQ, Omega)

Calculate power from torque and rotation rate.

Arguments

  • Q::Vector{Float} : dimensional thrust
  • dQ::Vector{Float} : dimensional thrust distribution
  • Omega::Vector{Float} : rotor rotation rates

Returns

  • P::Vector{Float} : dimensional power
  • dP::Vector{Float} : dimensional thrust distribution
source
DuctAPE.rotor_power!Function
rotor_power!(P, dP, Q, dQ, Omega)

In-place version of rotor_power.

source
DuctAPE.get_total_efficiencyFunction
get_total_efficiency(total_thrust, total_power, Vinf)

Get total efficiency.

Arguments

  • total_thrust::Vector{Float} : total thrust
  • total_power::Vector{Float} : total power
  • Vinf::Vector{Float} : one element vector freestream velocity magnitude

Returns

  • `total_efficiency::Vector{Float} : total efficiency
source
DuctAPE.get_total_efficiency!Function
get_total_efficiency!(eta, total_thrust, total_power, Vinf)

In-place version of get_total_efficiency.

source
DuctAPE.get_induced_efficiencyFunction
get_induced_efficiency(Tinv, Tduct, Pinv, Vinf)

Get rotor efficiency induced by presence of the duct.

Arguments

  • Tinv::Vector{Float} : inviscid dimensional thrust
  • Tduct::Vector{Float} : duct thrust
  • Pinv::Vector{Float} : inviscid dimensional power
  • Vinf::Vector{Float} : one element vector freestream velocity magnitude

Returns

  • induced_efficiency::Vector{Float} : rotor efficiency induced by duct
source
DuctAPE.get_induced_efficiency!Function
get_induced_efficiency!(eta_inv, Tinv, Tduct, Pinv, Vinf)

In-place version of get_induced_efficiency.

source
DuctAPE.get_ideal_efficiencyFunction
get_ideal_efficiency(total_thrust, rhoinf, Vinf, Rref)

Compute ducted fan ideal efficiency

Arguments

  • total_thrust::Vector{Float} : total thrust from rotors and duct
  • rhoinf::Float : freestream density
  • Vinf::Vector{Float} : one element vector freestream velocity magnitude
  • Rref::Vector{Float} : one element vector reference rotor tip radius

Returns

  • ideal_efficiency::Vector{Float} : ideal ducted fan efficiency
source
DuctAPE.tqpcoeffFunction
tqpcoeff(thrust, torque, power, rhoinf, Omega, Rref)

Calculate non-dimensional thrust, torque, and power coefficients

Arguments

  • thrust::Vector{Float} : dimensional thrust
  • torque::Vector{Float} : dimensional torque
  • power::Vector{Float} : dimensional power
  • rhoinf::Float : freestream density
  • Omega::Vector{Float} : rotor rotation rates
  • Rref::Vector{Float} : one element vector reference rotor tip radius

Returns

  • CT::Vector{Float} : thrust coefficient
  • CQ::Vector{Float} : torque coefficient
  • CP::Vector{Float} : power coefficient
source
DuctAPE.tqpcoeff!Function
tqpcoeff!(CT, CQ, CP, thrust, torque, power, rhoinf, Omega, Rref)

In-place version of tqpcoeff.

source
DuctAPE.get_blade_loadsFunction
get_blade_loads(Cmag_rotor, beta1, cl, cd, chords, rhoinf)

Get loading along blades.

Arguments

  • Cmag_rotor::Vector{Float} : blade element inflow magnitudes
  • beta1::Vector{Float} : blade element inflow angles
  • cl::Vector{Float} : blade element lift coefficients
  • cd::Vector{Float} : blade element drag coefficients
  • chords::Vector{Float} : blade element chord lengths
  • rhoinf::Vector{Float} : one element freestream density

Returns

  • Np::Vector{Float} : blade loading per unit length in the normal direction: N'
  • Tp::Vector{Float} : blade loading per unit length in the tangential direction: T'
source
DuctAPE.get_blade_loads!Function
get_blade_loads!(Np, Tp, Cmag_rotor, beta1, cl, cd, chords, rhoinf, cache)

In-place version of get_blade_loads.

source
+)

In-place version of viscous_rotor_torque.

source
DuctAPE.rotor_powerFunction
rotor_power(Q, dQ, Omega)

Calculate power from torque and rotation rate.

Arguments

  • Q::Vector{Float} : dimensional thrust
  • dQ::Vector{Float} : dimensional thrust distribution
  • Omega::Vector{Float} : rotor rotation rates

Returns

  • P::Vector{Float} : dimensional power
  • dP::Vector{Float} : dimensional thrust distribution
source
DuctAPE.rotor_power!Function
rotor_power!(P, dP, Q, dQ, Omega)

In-place version of rotor_power.

source
DuctAPE.get_total_efficiencyFunction
get_total_efficiency(total_thrust, total_power, Vinf)

Get total efficiency.

Arguments

  • total_thrust::Vector{Float} : total thrust
  • total_power::Vector{Float} : total power
  • Vinf::Vector{Float} : one element vector freestream velocity magnitude

Returns

  • `total_efficiency::Vector{Float} : total efficiency
source
DuctAPE.get_total_efficiency!Function
get_total_efficiency!(eta, total_thrust, total_power, Vinf)

In-place version of get_total_efficiency.

source
DuctAPE.get_induced_efficiencyFunction
get_induced_efficiency(Tinv, Tduct, Pinv, Vinf)

Get rotor efficiency induced by presence of the duct.

Arguments

  • Tinv::Vector{Float} : inviscid dimensional thrust
  • Tduct::Vector{Float} : duct thrust
  • Pinv::Vector{Float} : inviscid dimensional power
  • Vinf::Vector{Float} : one element vector freestream velocity magnitude

Returns

  • induced_efficiency::Vector{Float} : rotor efficiency induced by duct
source
DuctAPE.get_induced_efficiency!Function
get_induced_efficiency!(eta_inv, Tinv, Tduct, Pinv, Vinf)

In-place version of get_induced_efficiency.

source
DuctAPE.get_ideal_efficiencyFunction
get_ideal_efficiency(total_thrust, rhoinf, Vinf, Rref)

Compute ducted fan ideal efficiency

Arguments

  • total_thrust::Vector{Float} : total thrust from rotors and duct
  • rhoinf::Float : freestream density
  • Vinf::Vector{Float} : one element vector freestream velocity magnitude
  • Rref::Vector{Float} : one element vector reference rotor tip radius

Returns

  • ideal_efficiency::Vector{Float} : ideal ducted fan efficiency
source
DuctAPE.tqpcoeffFunction
tqpcoeff(thrust, torque, power, rhoinf, Omega, Rref)

Calculate non-dimensional thrust, torque, and power coefficients

Arguments

  • thrust::Vector{Float} : dimensional thrust
  • torque::Vector{Float} : dimensional torque
  • power::Vector{Float} : dimensional power
  • rhoinf::Float : freestream density
  • Omega::Vector{Float} : rotor rotation rates
  • Rref::Vector{Float} : one element vector reference rotor tip radius

Returns

  • CT::Vector{Float} : thrust coefficient
  • CQ::Vector{Float} : torque coefficient
  • CP::Vector{Float} : power coefficient
source
DuctAPE.tqpcoeff!Function
tqpcoeff!(CT, CQ, CP, thrust, torque, power, rhoinf, Omega, Rref)

In-place version of tqpcoeff.

source
DuctAPE.get_blade_loadsFunction
get_blade_loads(Cmag_rotor, beta1, cl, cd, chords, rhoinf)

Get loading along blades.

Arguments

  • Cmag_rotor::Vector{Float} : blade element inflow magnitudes
  • beta1::Vector{Float} : blade element inflow angles
  • cl::Vector{Float} : blade element lift coefficients
  • cd::Vector{Float} : blade element drag coefficients
  • chords::Vector{Float} : blade element chord lengths
  • rhoinf::Vector{Float} : one element freestream density

Returns

  • Np::Vector{Float} : blade loading per unit length in the normal direction: N'
  • Tp::Vector{Float} : blade loading per unit length in the tangential direction: T'
source
DuctAPE.get_blade_loads!Function
get_blade_loads!(Np, Tp, Cmag_rotor, beta1, cl, cd, chords, rhoinf, cache)

In-place version of get_blade_loads.

source
diff --git a/dev/DuctAPE/api/private_prelims/index.html b/dev/DuctAPE/api/private_prelims/index.html index 805b9d70..08777ec8 100644 --- a/dev/DuctAPE/api/private_prelims/index.html +++ b/dev/DuctAPE/api/private_prelims/index.html @@ -3,14 +3,14 @@ grid_solver_options=SLORGridSolverOptions(), solver_options=CSORSolverOptions(), kwargs..., -)

Convenience function to select options used in DFDC.

source
function DFDC_options(
+)

Convenience function to select options used in DFDC.

source
function DFDC_options(
     multipoint;
     grid_solver_options=SLORGridSolverOptions(),
     solver_options=CSORSolverOptions(),
     kwargs...,
-)

Convenience function to select options used in DFDC and run multipoint analysis.

Arguments

  • multipoint::Vector : doesn't need to be anything but a vector of the length of multipoints.
source
DuctAPE.ConvergenceTypeType
abstract type ConvergenceType

Used in dispatching the CSOR (controlled successive over relaxation) residual as relative or absolute.

source
DuctAPE.RelativeType
struct Relative <: ConvergenceType

Used to dispatch the relative residual for CSOR (controlled successive over relaxation) method

source
DuctAPE.AbsoluteType
struct Absolute <: ConvergenceType

Used to dispatch the absolute residual for CSOR (controlled successive over relaxation) method

source
DuctAPE.SolverOptionsTypeType
abstract type SolverOptionsType

Used for solver dispatch.

source
DuctAPE.ExternalSolverOptionsType
abstract type ExternalSolverOptions <: SolverOptionsType

Used for solver dispatch.

source
DuctAPE.PolyAlgorithmOptionsType
abstract type PolyAlgorithmOptions <: SolverOptionsType

Used for solver dispatch.

source
DuctAPE.GridSolverOptionsTypeType
abstract type GridSolverOptionsType

Used for elliptic grid solver dispatch

source
DuctAPE.IntegrationMethodType
abstract type IntegrationMethod

Used in integration method dispatch

source

Bookkeeping

DuctAPE.get_problem_dimensionsFunction
get_problem_dimensions(paneling_constants::PanelingConstants)
-get_problem_dimensions(body_vortex_panels, rotor_source_panels, wake_vortex_panels)

Determine all relevant dimensions to the problem based either on the paneling_constants or the panels themselves.

Arguments

  • paneling_constants::PanelingConstants : Rotor (and possibly stator) geometric paramters.

Returns

  • problem_dimensions::ProblemDimensions : ProblemDimensions object.
source
source

Caching

Allocation

The following are various helper functions used in preallocating the various caches.

DuctAPE.initialize_all_cachesFunction
initialize_all_caches(solver_options, paneling_constants)

Convenience function to initialize all caches before calling analysis.

Arguments

  • solver_options::SolverOptionsType : solver options used for cache allocation dispatch
  • paneling_constants::PanelingConstants : PanelingConstants object upon which all cache sizing depends

Keyword Arguments

  • fd_chunk_size::Int=12 : chunk size to use for PreallocationTools caches. Note that the automated chuck size for DuctAPE will always be the ForwardDiff threshold of 12 due to the size of the system, so it will be best to leave this at the default unless further development allows for chunk size selection for individual solvers.
  • levels::Int=1 : levels for nested duals. Note that since ImplicitAD is being used for all solves, there should be no need for more than 1 level.

Returns

  • prepost_container_caching::NamedTuple : A named tuple containing the PreallocationTools DiffCache and a named tuple with relevant dimensions for accessing the cache.
  • solve_parameter_caching::NamedTuple : A named tuple containing the PreallocationTools DiffCache and a named tuple with relevant dimensions for accessing the cache.
  • solve_container_caching::NamedTuple : A named tuple containing the PreallocationTools DiffCache and a named tuple with relevant dimensions for accessing the cache.
source
DuctAPE.allocate_wake_panel_container!Function
allocate_wake_panel_containers!(total_length, problem_dimensions::ProblemDimensions)

A helper function is assembling the prepostcontainercache.

Arguments

  • total_length::Vector{Int} : a one-element vector used to store the total length in order to know how large of a cache to allocate. Is updated in place.
  • problem_dimensions::ProblemDimensions : a ProblemDimensions object

Returns

  • wake_vortex_panels::NamedTuple : A named containing the dimensions needed to reshape the cache with regards to the wake vortex panel object
source
DuctAPE.allocate_panel_containers!Function
allocate_panel_containers!(total_length, problem_dimensions::ProblemDimensions)

A helper function is assembling the prepostcontainercache.

Arguments

  • total_length::Vector{Int} : a one-element vector used to store the total length in order to know how large of a cache to allocate. Is updated in place.
  • problem_dimensions::ProblemDimensions : a ProblemDimensions object

Returns

  • panels::NamedTuple : A named tuple of named tuples containing the dimensions needed to reshape the cache with regards to the panel objects
source
DuctAPE.allocate_panel_container!Function
allocate_panel_container!(total_length, nn, np, tn, tp, nb)

A helper function is assembling the prepostcontainercache.

Arguments

  • total_length::Vector{Int} : a one-element vector used to store the total length in order to know how large of a cache to allocate. Is updated in place.
  • nn::Int : number of nodes in each body, rotor, or wake sheet
  • np::Int : number of panels in each body, rotor, or wake sheet
  • tn::Int : number of total nodes among the bodies, rotors, or wake sheets
  • tp::Int : number of total panels among the bodies, rotors, or wake sheets
  • nb::Int : number of bodies, rotors, or wake sheets

Returns

  • panel::NamedTuple : A named containing the dimensions needed to reshape the cache with regards to an arbitrary panel set
source
DuctAPE.allocate_body_panel_container!Function
allocate_body_panel_containers!(total_length, problem_dimensions::ProblemDimensions)

A helper function is assembling the prepostcontainercache.

Arguments

  • total_length::Vector{Int} : a one-element vector used to store the total length in order to know how large of a cache to allocate. Is updated in place.
  • problem_dimensions::ProblemDimensions : a ProblemDimensions object

Returns

  • body_vortex_panels::NamedTuple : A named tuple containing the dimensions needed to reshape the cache with regards to the body vortex panel object
source
DuctAPE.allocate_rotor_panel_container!Function
allocate_rotor_panel_containers!(total_length, problem_dimensions::ProblemDimensions)

A helper function is assembling the prepostcontainercache.

Arguments

  • total_length::Vector{Int} : a one-element vector used to store the total length in order to know how large of a cache to allocate. Is updated in place.
  • problem_dimensions::ProblemDimensions : a ProblemDimensions object

Returns

  • rotor_source_panels::NamedTuple : A named containing the dimensions needed to reshape the cache with regards to the rotor source panel object
source
DuctAPE.allocate_solve_parameter_extras!Function
allocate_solve_parameter_extras!(
+)

Convenience function to select options used in DFDC and run multipoint analysis.

Arguments

  • multipoint::Vector : doesn't need to be anything but a vector of the length of multipoints.
source
DuctAPE.ConvergenceTypeType
abstract type ConvergenceType

Used in dispatching the CSOR (controlled successive over relaxation) residual as relative or absolute.

source
DuctAPE.RelativeType
struct Relative <: ConvergenceType

Used to dispatch the relative residual for CSOR (controlled successive over relaxation) method

source
DuctAPE.AbsoluteType
struct Absolute <: ConvergenceType

Used to dispatch the absolute residual for CSOR (controlled successive over relaxation) method

source
DuctAPE.SolverOptionsTypeType
abstract type SolverOptionsType

Used for solver dispatch.

source
DuctAPE.ExternalSolverOptionsType
abstract type ExternalSolverOptions <: SolverOptionsType

Used for solver dispatch.

source
DuctAPE.PolyAlgorithmOptionsType
abstract type PolyAlgorithmOptions <: SolverOptionsType

Used for solver dispatch.

source
DuctAPE.GridSolverOptionsTypeType
abstract type GridSolverOptionsType

Used for elliptic grid solver dispatch

source
DuctAPE.IntegrationMethodType
abstract type IntegrationMethod

Used in integration method dispatch

source

Bookkeeping

DuctAPE.get_problem_dimensionsFunction
get_problem_dimensions(paneling_constants::PanelingConstants)
+get_problem_dimensions(body_vortex_panels, rotor_source_panels, wake_vortex_panels)

Determine all relevant dimensions to the problem based either on the paneling_constants or the panels themselves.

Arguments

  • paneling_constants::PanelingConstants : Rotor (and possibly stator) geometric paramters.

Returns

  • problem_dimensions::ProblemDimensions : ProblemDimensions object.
source
source

Caching

Allocation

The following are various helper functions used in preallocating the various caches.

DuctAPE.initialize_all_cachesFunction
initialize_all_caches(solver_options, paneling_constants)

Convenience function to initialize all caches before calling analysis.

Arguments

  • solver_options::SolverOptionsType : solver options used for cache allocation dispatch
  • paneling_constants::PanelingConstants : PanelingConstants object upon which all cache sizing depends

Keyword Arguments

  • fd_chunk_size::Int=12 : chunk size to use for PreallocationTools caches. Note that the automated chuck size for DuctAPE will always be the ForwardDiff threshold of 12 due to the size of the system, so it will be best to leave this at the default unless further development allows for chunk size selection for individual solvers.
  • levels::Int=1 : levels for nested duals. Note that since ImplicitAD is being used for all solves, there should be no need for more than 1 level.

Returns

  • prepost_container_caching::NamedTuple : A named tuple containing the PreallocationTools DiffCache and a named tuple with relevant dimensions for accessing the cache.
  • solve_parameter_caching::NamedTuple : A named tuple containing the PreallocationTools DiffCache and a named tuple with relevant dimensions for accessing the cache.
  • solve_container_caching::NamedTuple : A named tuple containing the PreallocationTools DiffCache and a named tuple with relevant dimensions for accessing the cache.
source
DuctAPE.allocate_wake_panel_container!Function
allocate_wake_panel_containers!(total_length, problem_dimensions::ProblemDimensions)

A helper function is assembling the prepostcontainercache.

Arguments

  • total_length::Vector{Int} : a one-element vector used to store the total length in order to know how large of a cache to allocate. Is updated in place.
  • problem_dimensions::ProblemDimensions : a ProblemDimensions object

Returns

  • wake_vortex_panels::NamedTuple : A named containing the dimensions needed to reshape the cache with regards to the wake vortex panel object
source
DuctAPE.allocate_panel_containers!Function
allocate_panel_containers!(total_length, problem_dimensions::ProblemDimensions)

A helper function is assembling the prepostcontainercache.

Arguments

  • total_length::Vector{Int} : a one-element vector used to store the total length in order to know how large of a cache to allocate. Is updated in place.
  • problem_dimensions::ProblemDimensions : a ProblemDimensions object

Returns

  • panels::NamedTuple : A named tuple of named tuples containing the dimensions needed to reshape the cache with regards to the panel objects
source
DuctAPE.allocate_panel_container!Function
allocate_panel_container!(total_length, nn, np, tn, tp, nb)

A helper function is assembling the prepostcontainercache.

Arguments

  • total_length::Vector{Int} : a one-element vector used to store the total length in order to know how large of a cache to allocate. Is updated in place.
  • nn::Int : number of nodes in each body, rotor, or wake sheet
  • np::Int : number of panels in each body, rotor, or wake sheet
  • tn::Int : number of total nodes among the bodies, rotors, or wake sheets
  • tp::Int : number of total panels among the bodies, rotors, or wake sheets
  • nb::Int : number of bodies, rotors, or wake sheets

Returns

  • panel::NamedTuple : A named containing the dimensions needed to reshape the cache with regards to an arbitrary panel set
source
DuctAPE.allocate_body_panel_container!Function
allocate_body_panel_containers!(total_length, problem_dimensions::ProblemDimensions)

A helper function is assembling the prepostcontainercache.

Arguments

  • total_length::Vector{Int} : a one-element vector used to store the total length in order to know how large of a cache to allocate. Is updated in place.
  • problem_dimensions::ProblemDimensions : a ProblemDimensions object

Returns

  • body_vortex_panels::NamedTuple : A named tuple containing the dimensions needed to reshape the cache with regards to the body vortex panel object
source
DuctAPE.allocate_rotor_panel_container!Function
allocate_rotor_panel_containers!(total_length, problem_dimensions::ProblemDimensions)

A helper function is assembling the prepostcontainercache.

Arguments

  • total_length::Vector{Int} : a one-element vector used to store the total length in order to know how large of a cache to allocate. Is updated in place.
  • problem_dimensions::ProblemDimensions : a ProblemDimensions object

Returns

  • rotor_source_panels::NamedTuple : A named containing the dimensions needed to reshape the cache with regards to the rotor source panel object
source
DuctAPE.allocate_solve_parameter_extras!Function
allocate_solve_parameter_extras!(
     solver_options::SolverOptionsType, input_length, total_length
-)

Includes additional caching for various solvers. Currently only does anything for SIAMFANLEOptions types.

Arguments

  • input_length::Int : the number of state variables in the solver
  • total_length::Vector{Int} : a one-element vector used to store the total length in order to know how large of a cache to allocate. Is updated in place.

Returns

  • solve_parameter_extras::NamedTuple : A named tuple containing dimensions related to extra caching parameters used in various solvers.
source
DuctAPE.allocate_grid_parameter_cacheFunction
allocate_grid_parameter_cache(pg, x, n)

Allocate a cache used inside the elliptic grid solve.

Arguments

  • pg::AbstractArray{Float,3} : the proposed grid array
  • x::AbstractVector{Float} : the array of ξ values used in the solve
  • n::AbstractVector{Float} : the array of η values used in the solve

Returns

  • grid_parameter_cache::NamedTuple : A named tuple containing the PreallocationTools DiffCache and dimensions for accessing it.
source
DuctAPE.allocate_integration_containersFunction
allocate_integration_containers(
+)

Includes additional caching for various solvers. Currently only does anything for SIAMFANLEOptions types.

Arguments

  • input_length::Int : the number of state variables in the solver
  • total_length::Vector{Int} : a one-element vector used to store the total length in order to know how large of a cache to allocate. Is updated in place.

Returns

  • solve_parameter_extras::NamedTuple : A named tuple containing dimensions related to extra caching parameters used in various solvers.
source
DuctAPE.allocate_grid_parameter_cacheFunction
allocate_grid_parameter_cache(pg, x, n)

Allocate a cache used inside the elliptic grid solve.

Arguments

  • pg::AbstractArray{Float,3} : the proposed grid array
  • x::AbstractVector{Float} : the array of ξ values used in the solve
  • n::AbstractVector{Float} : the array of η values used in the solve

Returns

  • grid_parameter_cache::NamedTuple : A named tuple containing the PreallocationTools DiffCache and dimensions for accessing it.
source
DuctAPE.allocate_integration_containersFunction
allocate_integration_containers(
     integration_options::IntegrationMethod, dispatch_type; cache_size=20
-)

Description

Arguments

  • integration_options::IntegrationMethod : options for integration used for dispatch and to size cache
  • dispatch_type:: : an object with eltype(dispatch_type) with which to define the type for cache initialization.

Keyword Arguments

  • cache_size::Int=20 : size needed for intermediate calculations for integration.

Returns

  • integration_containers::NamedTuple : A named tuple containing the cache(s) needed for integration.
source

Reshaping

The following are used internally to reshape the cache vectors into more usable formats.

DuctAPE.withdraw_prepost_container_cacheFunction
withdraw_prepost_container_cache(vec, dims)

Reshape the prepost cache vector using the saved dimensions tuple.

Arguments

  • vec::Vector{Float} : vector cache of pre- and post-processing intermediate containers.
  • dims::NamedTuple : Named tuple containing the indices and shape of the various items stored in the cache vector.

Returns

  • prepost_container_caching::NamedTuple : Named tuple containing reshaped views of sections of the cache vector.
source
DuctAPE.withdraw_solve_parameter_cacheFunction
withdraw_solve_parameter_cache(solver_options::SolverOptionsType, vec, dims)

Reshape the solve parameter cache vector using the saved dimensions tuple.

Arguments

  • solver_options::SolverOptionsType : Solver options type for dispatch.
  • vec::Vector{Float} : vector cache of pre- and post-processing intermediate containers.
  • dims::NamedTuple : Named tuple containing the indices and shape of the various items stored in the cache vector.

Returns

  • solve_parameter_caching::NamedTuple : Named tuple containing reshaped views of sections of the cache vector.
source
DuctAPE.withdraw_solve_container_cacheFunction
withdraw_solve_container_cache(solver_options::SolverOptionsType, vec, dims)

Reshape the intermediate solve container cache vector using the saved dimensions tuple.

Arguments

  • solver_options::SolverOptionsType : Solver options type for dispatch.
  • vec::Vector{Float} : vector cache of pre- and post-processing intermediate containers.
  • dims::NamedTuple : Named tuple containing the indices and shape of the various items stored in the cache vector.

Returns

  • solve_container_caching::NamedTuple : Named tuple containing reshaped views of sections of the cache vector.
source
DuctAPE.withdraw_grid_parameter_cacheFunction
withdraw_grid_parameter_cache(vec, dims)

Reshape the cache used inside the elliptic grid solve.

Arguments

  • vec::Vector{Float} : the cache vector
  • dims::NamedTuple : the named tuple of dimensions used to reshape the cache vector

Returns

  • proposed_grid::AbstractArray{Float,3} : the proposed grid array
  • xi::AbstractVector{Float} : the array of ξ values used in the solve
  • eta::AbstractVector{Float} : the array of η values used in the solve
source
+)

Description

Arguments

Keyword Arguments

Returns

source

Reshaping

The following are used internally to reshape the cache vectors into more usable formats.

DuctAPE.withdraw_prepost_container_cacheFunction
withdraw_prepost_container_cache(vec, dims)

Reshape the prepost cache vector using the saved dimensions tuple.

Arguments

  • vec::Vector{Float} : vector cache of pre- and post-processing intermediate containers.
  • dims::NamedTuple : Named tuple containing the indices and shape of the various items stored in the cache vector.

Returns

  • prepost_container_caching::NamedTuple : Named tuple containing reshaped views of sections of the cache vector.
source
DuctAPE.withdraw_solve_parameter_cacheFunction
withdraw_solve_parameter_cache(solver_options::SolverOptionsType, vec, dims)

Reshape the solve parameter cache vector using the saved dimensions tuple.

Arguments

  • solver_options::SolverOptionsType : Solver options type for dispatch.
  • vec::Vector{Float} : vector cache of pre- and post-processing intermediate containers.
  • dims::NamedTuple : Named tuple containing the indices and shape of the various items stored in the cache vector.

Returns

  • solve_parameter_caching::NamedTuple : Named tuple containing reshaped views of sections of the cache vector.
source
DuctAPE.withdraw_solve_container_cacheFunction
withdraw_solve_container_cache(solver_options::SolverOptionsType, vec, dims)

Reshape the intermediate solve container cache vector using the saved dimensions tuple.

Arguments

  • solver_options::SolverOptionsType : Solver options type for dispatch.
  • vec::Vector{Float} : vector cache of pre- and post-processing intermediate containers.
  • dims::NamedTuple : Named tuple containing the indices and shape of the various items stored in the cache vector.

Returns

  • solve_container_caching::NamedTuple : Named tuple containing reshaped views of sections of the cache vector.
source
DuctAPE.withdraw_grid_parameter_cacheFunction
withdraw_grid_parameter_cache(vec, dims)

Reshape the cache used inside the elliptic grid solve.

Arguments

  • vec::Vector{Float} : the cache vector
  • dims::NamedTuple : the named tuple of dimensions used to reshape the cache vector

Returns

  • proposed_grid::AbstractArray{Float,3} : the proposed grid array
  • xi::AbstractVector{Float} : the array of ξ values used in the solve
  • eta::AbstractVector{Float} : the array of η values used in the solve
source
diff --git a/dev/DuctAPE/api/private_preprocess/index.html b/dev/DuctAPE/api/private_preprocess/index.html index f5bcea2f..81607fb4 100644 --- a/dev/DuctAPE/api/private_preprocess/index.html +++ b/dev/DuctAPE/api/private_preprocess/index.html @@ -12,7 +12,7 @@ ndp, riiw, nrotor, -)

Set values for index map to be used throughout solve and post-process.

Arguments

Returns

source
DuctAPE.precompute_parametersFunction
precompute_parameters(
+)

Set values for index map to be used throughout solve and post-process.

Arguments

  • npanels : paneling_constants.npanels
  • ncenterbody_inlet : paneling_constants.ncenterbody_inlet
  • nwake_sheets : paneling_constants.nwake_sheets
  • dte_minus_cbte : paneling_constants.dte_minus_cbte
  • wnm : wake_vortex_panels.nodemap
  • wenids : wake_vortex_panels.endnodeidxs
  • nwp : problem_dimensions.nwp
  • nwsp : problem_dimensions.nwsp
  • nbn : problem_dimensions.nbn
  • ndp : body_vortex_panels.npanel[1]
  • riiw : rotor_indices_in_wake
  • nrotor : problem_dimensions.nrotor

Returns

  • idmaps::NamedTuple : A named tuple containing index mapping used in bookkeeping throughout solve and post-process
source
DuctAPE.precompute_parametersFunction
precompute_parameters(
     propulsor;
     grid_solver_options=GridSolverOptions(),
     integration_options=IntegrationOptions(),
@@ -23,7 +23,7 @@
     finterp=(x,y,xp)->FLOWMath.akima(x,y,xp,2.0*eps(),eps()),
     silence_warnings=true,
     verbose=false,
-)

Out of place main pre-processing function that computes all the required parameters for the solve.

Arguments

  • propulsor::Propulsor : A Propuslor object

Keyword Arguments

  • grid_solver_options::GridSolverOptionsType=GridSolverOptions() : A GridSolverOptionsType object
  • integration_options::IntegrationMethod=IntegrationOptions() : An IntegrationMethod object
  • autoshiftduct::Bool=true : flag to shift duct geometry based on rotor tip radius
  • itcpshift::Float=0.05 : value used in positioning the internal pseudo control point in the solid bodies. Default is DFDC hard-coded value.
  • axistol::Float=1e-15 : tolerance for how close to the axis of rotation to be considered on the axis.
  • tegaptol::Float=1e1 * eps() : tolerance for how large of a trailing edge gap is considered a gap.
  • finterp::Function=FLOWMath.akima : interpolation method for re-interpolating body coordinates
  • silence_warnings::Bool=true : flag to silence warnings
  • verbose::Bool=false : flag to print verbose statements

Returns

  • ivr::NamedTuple : A named tuple containing arrays of induced velocities on the rotors
  • ivw::NamedTuple : A named tuple containing arrays of induced velocities on the wake
  • ivb::NamedTuple : A named tuple containing arrays of induced velocities on the bodies
  • linsys::NamedTuple : A named tuple containing cacheable data for the linear system, including:
    • A_bb::Array{Float} : AIC (LHS) matrix for the panel method system
    • b_bf::Array{Float} : Initial system RHS vector based on freestrem magnitude
    • A_br::Array{Float} : Unit normal velocity from rotors onto body panels
    • A_pr::Array{Float} : Unit normal velocity from rotors onto body internal psuedo control points
    • A_bw::Array{Float} : Unit normal velocity from wake onto body panels
    • A_pw::Array{Float} : Unit normal velocity from wake onto body internal psuedo control points
  • A_bb_LU::LinearAlgebra.LU : LinearAlgebra LU factorization of the LHS matrix
  • lu_decomp_flag::Vector{Bool} : flag for whether factorization was successful
  • blade_elements::NamedTuple : A named tuple containing cacheable blade element information (see docs for interpolate_blade_elements)
  • airfoils::Vector{AFType} : A matrix of airfoil types associated with each of the blade elements
  • wakeK::Matrix{Float} : A matrix of precomputed geometric constants used in the calculation of the wake vortex strengths
  • idmaps::NamedTuple : A named tuple containing index mapping used in bookkeeping throughout solve and post-process
  • panels::NamedTuple : A named tuple of panel objects including:
    • body_vortex_panels::NamedTuple : the named tuple containing the body vortex panel information
    • rotor_source_panels::NamedTuple : the named tuple containing the rotor source panel information
    • wake_vortex_panels::NamedTuple : the named tuple containing the wake vortex panel information
  • problem_dimensions::ProblemDimensions : A ProblemDimensions object
source
precompute_parameters(
+)

Out of place main pre-processing function that computes all the required parameters for the solve.

Arguments

  • propulsor::Propulsor : A Propuslor object

Keyword Arguments

  • grid_solver_options::GridSolverOptionsType=GridSolverOptions() : A GridSolverOptionsType object
  • integration_options::IntegrationMethod=IntegrationOptions() : An IntegrationMethod object
  • autoshiftduct::Bool=true : flag to shift duct geometry based on rotor tip radius
  • itcpshift::Float=0.05 : value used in positioning the internal pseudo control point in the solid bodies. Default is DFDC hard-coded value.
  • axistol::Float=1e-15 : tolerance for how close to the axis of rotation to be considered on the axis.
  • tegaptol::Float=1e1 * eps() : tolerance for how large of a trailing edge gap is considered a gap.
  • finterp::Function=FLOWMath.akima : interpolation method for re-interpolating body coordinates
  • silence_warnings::Bool=true : flag to silence warnings
  • verbose::Bool=false : flag to print verbose statements

Returns

  • ivr::NamedTuple : A named tuple containing arrays of induced velocities on the rotors
  • ivw::NamedTuple : A named tuple containing arrays of induced velocities on the wake
  • ivb::NamedTuple : A named tuple containing arrays of induced velocities on the bodies
  • linsys::NamedTuple : A named tuple containing cacheable data for the linear system, including:
    • A_bb::Array{Float} : AIC (LHS) matrix for the panel method system
    • b_bf::Array{Float} : Initial system RHS vector based on freestrem magnitude
    • A_br::Array{Float} : Unit normal velocity from rotors onto body panels
    • A_pr::Array{Float} : Unit normal velocity from rotors onto body internal psuedo control points
    • A_bw::Array{Float} : Unit normal velocity from wake onto body panels
    • A_pw::Array{Float} : Unit normal velocity from wake onto body internal psuedo control points
  • A_bb_LU::LinearAlgebra.LU : LinearAlgebra LU factorization of the LHS matrix
  • lu_decomp_flag::Vector{Bool} : flag for whether factorization was successful
  • blade_elements::NamedTuple : A named tuple containing cacheable blade element information (see docs for interpolate_blade_elements)
  • airfoils::Vector{AFType} : A matrix of airfoil types associated with each of the blade elements
  • wakeK::Matrix{Float} : A matrix of precomputed geometric constants used in the calculation of the wake vortex strengths
  • idmaps::NamedTuple : A named tuple containing index mapping used in bookkeeping throughout solve and post-process
  • panels::NamedTuple : A named tuple of panel objects including:
    • body_vortex_panels::NamedTuple : the named tuple containing the body vortex panel information
    • rotor_source_panels::NamedTuple : the named tuple containing the rotor source panel information
    • wake_vortex_panels::NamedTuple : the named tuple containing the wake vortex panel information
  • problem_dimensions::ProblemDimensions : A ProblemDimensions object
source
precompute_parameters(
     rp_duct_coordinates,
     rp_centerbody_coordinates,
     wake_grid,
@@ -40,7 +40,7 @@
     tegaptol=1e1 * eps(),
     silence_warnings=true,
     verbose=false,
-)

An alternate version of precompute_parameters allowing for user defined geometry that does not go through a re-panling step (use with caution).

The first inputs are the outputs of the reinterpolate_geometry and get_blade_ends_from_body_geometry functions.

source
DuctAPE.precompute_parameters!Function
precompute_parameters!(
+)

An alternate version of precompute_parameters allowing for user defined geometry that does not go through a re-panling step (use with caution).

The first inputs are the outputs of the reinterpolate_geometry and get_blade_ends_from_body_geometry functions.

source
DuctAPE.precompute_parameters!Function
precompute_parameters!(
     ivr,
     ivw,
     blade_element_cache,
@@ -58,7 +58,7 @@
     finterp=(x,y,xp)->FLOWMath.akima(x,y,xp,2.0*eps(),eps()),
     silence_warnings=true,
     verbose=false,
-)

In-place version of precompute_parameters.

source
precompute_parameters!(
+)

In-place version of precompute_parameters.

source
precompute_parameters!(
     ivr,
     ivw,
     blade_element_cache,
@@ -80,7 +80,7 @@
     finterp=(x,y,xp)->FLOWMath.akima(x,y,xp,2.0*eps(),eps()),
     silence_warnings=true,
     verbose=false,
-)

In-place version of the precompute_parameters function by-passing the geometry reinterpolateion. (Use with caution)

source

Geometry

DuctAPE.reinterpolate_geometryFunction
reinterpolate_geometry(
+)

In-place version of the precompute_parameters function by-passing the geometry reinterpolateion. (Use with caution)

source

Geometry

DuctAPE.reinterpolate_geometryFunction
reinterpolate_geometry(
     problem_dimensions,
     duct_coordinates,
     centerbody_coordinates,
@@ -91,7 +91,7 @@
     finterp=(x,y,xp)->FLOWMath.akima(x,y,xp,2.0*eps(),eps()),
     verbose=false,
     silence_warnings=true,
-)

Re-interpolate the body geometry and return compatible body and way geometry.

Arguments

  • problem_dimensions::ProblemDimensions : A ProblemDimensions object
  • duct_coordinates::Matrix{Float} : [z,r] coordinates of duct geometry
  • centerbody_coordinates::Matrix{Float} : [z,r] coordinates of centerbody geometry
  • rotorstator_parameters::RotorStatorParameters : A RotorStatorParameters object
  • paneling_constants::PanelingConstants : A PanelingConstants object

Keyword Arguments

  • autoshiftduct::Bool=true : flag to shift duct geometry based on rotor tip radius
  • grid_solver_options::SolverOptionsType=GridSolverOptions() : options for the wake grid position solver
  • finterp::Function=FLOWMath.akima : interpolation method for re-interpolating body coordinates
  • verbose::Bool=false : flag to print verbose statements
  • silence_warnings::Bool=true : flag to silence warnings

Returns

  • wake_grid::Array{Float} : array containig the z and r elliptic grid points defning the wake geometry.
  • rp_duct_coordinates::Matrix{Float} : matrix containing the re-paneled duct coordinates
  • rp_centerbody_coordinates::Matrix{Float} : matrix containing the re-paneled centerbody coordinates
  • rotor_indices_in_wake::Vector{Int} : vector containing the indices of where in the wake the rotors reside (used later to define the rotor panel edges).
source
DuctAPE.reinterpolate_geometry!Function
reinterpolate_geometry!(
+)

Re-interpolate the body geometry and return compatible body and way geometry.

Arguments

  • problem_dimensions::ProblemDimensions : A ProblemDimensions object
  • duct_coordinates::Matrix{Float} : [z,r] coordinates of duct geometry
  • centerbody_coordinates::Matrix{Float} : [z,r] coordinates of centerbody geometry
  • rotorstator_parameters::RotorStatorParameters : A RotorStatorParameters object
  • paneling_constants::PanelingConstants : A PanelingConstants object

Keyword Arguments

  • autoshiftduct::Bool=true : flag to shift duct geometry based on rotor tip radius
  • grid_solver_options::SolverOptionsType=GridSolverOptions() : options for the wake grid position solver
  • finterp::Function=FLOWMath.akima : interpolation method for re-interpolating body coordinates
  • verbose::Bool=false : flag to print verbose statements
  • silence_warnings::Bool=true : flag to silence warnings

Returns

  • wake_grid::Array{Float} : array containig the z and r elliptic grid points defning the wake geometry.
  • rp_duct_coordinates::Matrix{Float} : matrix containing the re-paneled duct coordinates
  • rp_centerbody_coordinates::Matrix{Float} : matrix containing the re-paneled centerbody coordinates
  • rotor_indices_in_wake::Vector{Int} : vector containing the indices of where in the wake the rotors reside (used later to define the rotor panel edges).
source
DuctAPE.reinterpolate_geometry!Function
reinterpolate_geometry!(
     wake_grid,
     rp_duct_coordinates,
     rp_centerbody_coordinates,
@@ -106,7 +106,7 @@
     finterp=(x,y,xp)->FLOWMath.akima(x,y,xp,2.0*eps(),eps()),
     verbose=false,
     silence_warnings=true,
-)

In-place version of reinterpolate_geometry.

source
DuctAPE.generate_all_panelsFunction
generate_all_panels(
+)

In-place version of reinterpolate_geometry.

source
DuctAPE.generate_all_panelsFunction
generate_all_panels(
     rp_duct_coordinates,
     rp_centerbody_coordinates,
     nwake_sheets,
@@ -117,7 +117,7 @@
     axistol=1e-15,
     tegaptol=1e1 * eps(),
     silence_warnings=true,
-)

Function that calls all of the various panel generation functions are returns a named tuple containing all the panels

Arguments

  • rp_duct_coordinates::Matrix{Float} : matrix containing the re-paneled duct coordinates
  • rp_centerbody_coordinates::Matrix{Float} : matrix containing the re-paneled centerbody coordinates
  • nwake_sheets::Int : number of wake sheets
  • rotor_indices_in_wake::Vector{Int} : vector containing the indices of where in the wake the rotors reside (used later to define the rotor panel edges).
  • rotorzloc:Vector{Float} : axial locations of rotor lifting lines (contained in RotorStatorParameters)
  • wake_grid::Array{Float} : array containig the z and r elliptic grid points defning the wake geometry.

Keyword Arguments

  • itcpshift::Float=0.05 : value used in positioning the internal pseudo control point in the solid bodies. Default is DFDC hard-coded value.
  • axistol::Float=1e-15 : tolerance for how close to the axis of rotation to be considered on the axis.
  • tegaptol::Float=1e1 * eps() : tolerance for how large of a trailing edge gap is considered a gap.
  • silence_warnings::Bool=true : flag to silence warnings

Returns

  • panels::NamedTuple : A named tuple of named tuples containing paneling information, including:
    • body_vortex_panels::NamedTuple
    • rotor_source_panels::NamedTuple
    • wake_vortex_panels::NamedTuple
source
DuctAPE.generate_all_panels!Function
generate_all_panels!(
+)

Function that calls all of the various panel generation functions are returns a named tuple containing all the panels

Arguments

  • rp_duct_coordinates::Matrix{Float} : matrix containing the re-paneled duct coordinates
  • rp_centerbody_coordinates::Matrix{Float} : matrix containing the re-paneled centerbody coordinates
  • nwake_sheets::Int : number of wake sheets
  • rotor_indices_in_wake::Vector{Int} : vector containing the indices of where in the wake the rotors reside (used later to define the rotor panel edges).
  • rotorzloc:Vector{Float} : axial locations of rotor lifting lines (contained in RotorStatorParameters)
  • wake_grid::Array{Float} : array containig the z and r elliptic grid points defning the wake geometry.

Keyword Arguments

  • itcpshift::Float=0.05 : value used in positioning the internal pseudo control point in the solid bodies. Default is DFDC hard-coded value.
  • axistol::Float=1e-15 : tolerance for how close to the axis of rotation to be considered on the axis.
  • tegaptol::Float=1e1 * eps() : tolerance for how large of a trailing edge gap is considered a gap.
  • silence_warnings::Bool=true : flag to silence warnings

Returns

  • panels::NamedTuple : A named tuple of named tuples containing paneling information, including:
    • body_vortex_panels::NamedTuple
    • rotor_source_panels::NamedTuple
    • wake_vortex_panels::NamedTuple
source
DuctAPE.generate_all_panels!Function
generate_all_panels!(
     panels,
     wake_grid,
     rp_duct_coordinates,
@@ -129,14 +129,14 @@
     axistol=1e-15,
     tegaptol=1e1 * eps(),
     silence_warnings=true,
-)

In-place version of generate_all_panels.

source

Wake

DuctAPE.discretize_wakeFunction
discretize_wake(
+)

In-place version of generate_all_panels.

source

Wake

DuctAPE.discretize_wakeFunction
discretize_wake(
     duct_coordinates,
     centerbody_coordinates,
     rotorzloc, # rotor axial locations
     wake_length,
     npanels,
     dte_minus_cbte;
-)

Calculate wake sheet panel node z-coordinates.

Arguments

  • duct_coordinates::Matrix{Float} : Array of input duct coordinates
  • centerbody_coordinates::Matrix{Float} : Array of input centerbody_coordinates coordinates
  • rotorzloc ::Vector{Float} : rotor axial locations
  • wake_length::Float : non-dimensional length of wake to extend beyond aft-most body trailing edge.
  • npanels::Vector{Int} : A vector of the number of panels between each discrete point. For example: [number of panels between the rotors; number of panels between the stator and the first trailing edge; number of panels between the trailing edges; number of panels between the last trailing edge and the end of the wake]
  • dte_minus_cbte::Float : indicator as to whether the duct trailing edge minus the centerbody trailing edge is positive, zero, or negative.
source
DuctAPE.generate_wake_gridFunction
generate_wake_grid(
+)

Calculate wake sheet panel node z-coordinates.

Arguments

  • duct_coordinates::Matrix{Float} : Array of input duct coordinates
  • centerbody_coordinates::Matrix{Float} : Array of input centerbody_coordinates coordinates
  • rotorzloc ::Vector{Float} : rotor axial locations
  • wake_length::Float : non-dimensional length of wake to extend beyond aft-most body trailing edge.
  • npanels::Vector{Int} : A vector of the number of panels between each discrete point. For example: [number of panels between the rotors; number of panels between the stator and the first trailing edge; number of panels between the trailing edges; number of panels between the last trailing edge and the end of the wake]
  • dte_minus_cbte::Float : indicator as to whether the duct trailing edge minus the centerbody trailing edge is positive, zero, or negative.
source
DuctAPE.generate_wake_gridFunction
generate_wake_grid(
     problem_dimensions,
     rp_duct_coordinates,
     rp_centerbody_coordinates,
@@ -147,7 +147,7 @@
     grid_solver_options=GridSolverOptions(),
     verbose=false,
     silence_warnings=true,
-)

Initialize and solve for elliptic grid on which wake sheets are defined.

Arguments

  • problem_dimensions:: : A ProblemDimensions object
  • rp_duct_coordinates:: : repaneled duct coordinates
  • rp_centerbody_coordinates:: : repaneled centerbody coordinates
  • Rhub1:: : Hub radius of first rotor
  • Rtip1:: : Tip radius of first rotor
  • tip_gap1:: : Tip gap of first rotor (MUST BE ZERO for now)
  • zwake:: : axial positions of wake sheet panel nodes

Keyword Arguments

  • grid_solver_options::GridSolverOptionsType=GridSolverOptions() : options for solving the elliptic grid.
  • verbose::Bool=false : flag to print verbose statements
  • silence_warnings::Bool=true : flag to supress warnings

Returns

  • wake_grid::Array{Float,3} : 3D Array of axial and radial wake_grid points after solution of elliptic system.
source
DuctAPE.generate_wake_grid!Function
generate_wake_grid!(
+)

Initialize and solve for elliptic grid on which wake sheets are defined.

Arguments

  • problem_dimensions:: : A ProblemDimensions object
  • rp_duct_coordinates:: : repaneled duct coordinates
  • rp_centerbody_coordinates:: : repaneled centerbody coordinates
  • Rhub1:: : Hub radius of first rotor
  • Rtip1:: : Tip radius of first rotor
  • tip_gap1:: : Tip gap of first rotor (MUST BE ZERO for now)
  • zwake:: : axial positions of wake sheet panel nodes

Keyword Arguments

  • grid_solver_options::GridSolverOptionsType=GridSolverOptions() : options for solving the elliptic grid.
  • verbose::Bool=false : flag to print verbose statements
  • silence_warnings::Bool=true : flag to supress warnings

Returns

  • wake_grid::Array{Float,3} : 3D Array of axial and radial wake_grid points after solution of elliptic system.
source
DuctAPE.generate_wake_grid!Function
generate_wake_grid!(
     wake_grid,
     rp_duct_coordinates,
     rp_centerbody_coordinates,
@@ -158,16 +158,16 @@
     grid_solver_options=grid_solver_options,
     verbose=false,
     silence_warnings=true,
-)

In-place version of generate_wake_grid.

source
DuctAPE.initialize_wake_gridFunction
initialize_wake_grid(rp_duct_coordinates, rp_centerbody_coordinates, zwake, rwake)

Initialize the wake grid.

Arguments:

  • rp_duct_coordinates::Matrix{Float} : The re-paneled duct coordinates
  • rp_centerbody_coordinates::Matrix{Float} : The re-paneled centerbody coordinates
  • zwake::Vector{Float} : The axial positions of the wake sheet panel nodes
  • rwake::Vector{Float} : The radial positions of the blade elements for the foremost rotor

Returns:

  • wake_grid::Array{Float,3} : 3D Array of axial and radial wake_grid points
source
DuctAPE.initialize_wake_grid!Function
initialize_wake_grid!(
+)

In-place version of generate_wake_grid.

source
DuctAPE.initialize_wake_gridFunction
initialize_wake_grid(rp_duct_coordinates, rp_centerbody_coordinates, zwake, rwake)

Initialize the wake grid.

Arguments:

  • rp_duct_coordinates::Matrix{Float} : The re-paneled duct coordinates
  • rp_centerbody_coordinates::Matrix{Float} : The re-paneled centerbody coordinates
  • zwake::Vector{Float} : The axial positions of the wake sheet panel nodes
  • rwake::Vector{Float} : The radial positions of the blade elements for the foremost rotor

Returns:

  • wake_grid::Array{Float,3} : 3D Array of axial and radial wake_grid points
source
DuctAPE.initialize_wake_grid!Function
initialize_wake_grid!(
     wake_grid, rp_duct_coordinates, rp_centerbody_coordinates, zwake, rwake
-)

In-place version of initialize_wake_grid.

source
DuctAPE.relax_grid!Function
relax_grid!(
+)

In-place version of initialize_wake_grid.

source
DuctAPE.relax_grid!Function
relax_grid!(
     grid_solver_options::GridSolverOptionsType,
     wake_grid;
     verbose=false,
     silence_warnings=true,
     tabchar="    ",
     ntab=1,
-)

Relax/Solve initial wake grid according to elliptic system of equations.

Arguments

  • `gridsolveroptions::GridSolverOptionsType' : options for elliptic grid solver
  • wake_grid::Array{Float,3} : Initialized wake grid

Keyword Arguments

  • `verbose=false::' : flag for printing verbose statements
  • `silence_warnings=true::' : flag for supressing warnings
  • `tabchar::String=" "::' : string to use for tabbing over verbose statements.
  • `ntab::Int=1' : number of tabs for printing verbose statements
source
relax_grid!(xg, rg, nxi, neta; iteration_limit, atol)

Relax wakegrid using elliptic wakegrid solver.

Arguments:

Keyword Arguments:

  • iteration_limit::Int : maximum number of iterations to run, default=100
  • atol::Float : convergence tolerance, default = 1e-9

Returns:

source
DuctAPE.generate_wake_panelsFunction
generate_wake_panels(wake_grid)

Generate paneling for each wake sheet emanating from the rotor blade elements.

Arguments:

  • wake_grid::Array{Float,3} : axial and radial locations of each wake_grid point (after relaxation/solution)

Returns:

  • wake_vortex_panels::NamedTuple : A named tuple of panel values describing the wake vortex panels
source
DuctAPE.generate_wake_panels!Function
generate_wake_panels!(wake_panels, wake_grid)

In-place version of generate_wake_panels.

source
DuctAPE.get_wake_kFunction
get_wake_k(r, nwn)

Calculate geometric constant for use in later calculation of wake panel node strengths.

Arguments

  • r::Vector{Float} : Vector of wake panel node radial positions

Returns

  • K::Vector{Float} : Vector of geometric constants used in calculation of panel node strengths.
source
DuctAPE.get_wake_k!Function
get_wake_k!(K, r)

In-place version of get_wake_k.

source

Bodies

DuctAPE.reinterpolate_bodies!Function
reinterpolate_bodies!(
+)

Relax/Solve initial wake grid according to elliptic system of equations.

Arguments

  • `gridsolveroptions::GridSolverOptionsType' : options for elliptic grid solver
  • wake_grid::Array{Float,3} : Initialized wake grid

Keyword Arguments

  • `verbose=false::' : flag for printing verbose statements
  • `silence_warnings=true::' : flag for supressing warnings
  • `tabchar::String=" "::' : string to use for tabbing over verbose statements.
  • `ntab::Int=1' : number of tabs for printing verbose statements
source
relax_grid!(xg, rg, nxi, neta; iteration_limit, atol)

Relax wakegrid using elliptic wakegrid solver.

Arguments:

Keyword Arguments:

  • iteration_limit::Int : maximum number of iterations to run, default=100
  • atol::Float : convergence tolerance, default = 1e-9

Returns:

source
DuctAPE.generate_wake_panelsFunction
generate_wake_panels(wake_grid)

Generate paneling for each wake sheet emanating from the rotor blade elements.

Arguments:

  • wake_grid::Array{Float,3} : axial and radial locations of each wake_grid point (after relaxation/solution)

Returns:

  • wake_vortex_panels::NamedTuple : A named tuple of panel values describing the wake vortex panels
source
DuctAPE.generate_wake_panels!Function
generate_wake_panels!(wake_panels, wake_grid)

In-place version of generate_wake_panels.

source
DuctAPE.get_wake_kFunction
get_wake_k(r, nwn)

Calculate geometric constant for use in later calculation of wake panel node strengths.

Arguments

  • r::Vector{Float} : Vector of wake panel node radial positions

Returns

  • K::Vector{Float} : Vector of geometric constants used in calculation of panel node strengths.
source
DuctAPE.get_wake_k!Function
get_wake_k!(K, r)

In-place version of get_wake_k.

source

Bodies

DuctAPE.reinterpolate_bodies!Function
reinterpolate_bodies!(
     rp_duct_coordinates,
     rp_centerbody_coordinates,
     duct_coordinates,
@@ -176,13 +176,13 @@
     ncenterbody_inlet,
     nduct_inlet;
     finterp=FLOWMath.akima,
-)

Reinterpolate duct and centerbody coordinates in order to make them compatible with the calculated wake sheet panel axial positions.

Arguments

  • rp_duct_coordinates::Matrix{Float} : the re-paneled duct coordinates
  • rp_centerbody_coordinates::Matrix{Float} : the re-paneled centerbody coordinates
  • duct_coordinates::Matrix{Float} : the input duct coordinates
  • centerbody_coordinates::Matrix{Float} : the input centerbody coordinates
  • zwake::Matrix{Float} : the wake sheet panel node axial positions
  • ncenterbody_inlet::Matrix{Float} : the number of panels to use for the centerbody inlet
  • nduct_inlet::Matrix{Float} : the number of panels to use for the duct inlet

Keyword Arguments

  • finterp::Function=FLOWMath.akima : interpolation method
source
DuctAPE.place_duct!Function
place_duct!(rp_duct_coordinates, Rtip, rotorzloc, tip_gap)

Transform the duct radial coordinates such that the leading rotor radius touches the duct wall.

Note that this function is called AFTER the repanling function is called, such that the rotorzloc locations should line up directly with the duct and centerbody coordinates.

Arguments

  • rp_duct_coordinates::Matrix{Float} : the re-paneled duct coordinates
  • Rtip::Vector{Float} : Tip radii for the rotor(s)
  • rotorzloc::Vector{Float} : axial position(s) of the rotor(s)
  • tip_gap::Vector{Float} : tip gap for the fore-most rotor (MUST BE ZERO for now)
source

Rotors

DuctAPE.interpolate_blade_elementsFunction
interpolate_blade_elements(
+)

Reinterpolate duct and centerbody coordinates in order to make them compatible with the calculated wake sheet panel axial positions.

Arguments

  • rp_duct_coordinates::Matrix{Float} : the re-paneled duct coordinates
  • rp_centerbody_coordinates::Matrix{Float} : the re-paneled centerbody coordinates
  • duct_coordinates::Matrix{Float} : the input duct coordinates
  • centerbody_coordinates::Matrix{Float} : the input centerbody coordinates
  • zwake::Matrix{Float} : the wake sheet panel node axial positions
  • ncenterbody_inlet::Matrix{Float} : the number of panels to use for the centerbody inlet
  • nduct_inlet::Matrix{Float} : the number of panels to use for the duct inlet

Keyword Arguments

  • finterp::Function=FLOWMath.akima : interpolation method
source
DuctAPE.place_duct!Function
place_duct!(rp_duct_coordinates, Rtip, rotorzloc, tip_gap)

Transform the duct radial coordinates such that the leading rotor radius touches the duct wall.

Note that this function is called AFTER the repanling function is called, such that the rotorzloc locations should line up directly with the duct and centerbody coordinates.

Arguments

  • rp_duct_coordinates::Matrix{Float} : the re-paneled duct coordinates
  • Rtip::Vector{Float} : Tip radii for the rotor(s)
  • rotorzloc::Vector{Float} : axial position(s) of the rotor(s)
  • tip_gap::Vector{Float} : tip gap for the fore-most rotor (MUST BE ZERO for now)
source

Rotors

DuctAPE.interpolate_blade_elementsFunction
interpolate_blade_elements(
     rsp, Rtips, Rhubs, rotor_panel_centers, nbe; finterp=FLOWMath.linear
-)

Interpolate blade elements based on RotorStatorParameters inputs and number of desired blade elements (from number of wake sheet in PanelingConstants input)

Arguments

  • rsp::RotorStatorParameters : A RotorStatorParameters object
  • `Rtips::Vector{Float}' : Vector of rotor tip radii
  • `Rhubs::Vector{Float}' : Vector of rotor hub radii
  • `rotorpanelcenters::Vector{Float}' : Vector of rotor panel centers
  • nbe::Int : number of blade elements per rotor

Keyword Arguments

  • finterp::Function=FLOWMath.linear : interpolation method (note, using Akima splines as is done for the body geometry can lead to negative chord in some cases)

Returns

  • blade_element_cache::NamedTuple : A named tuple containing the cacheable blade element information excluding the airfoil data.
  • airfoils::NamedTuple : A named tuple containing vectors of inner and outer airfoil polar data for each blade element, used in interpolating the input data at blade element locations.
source
DuctAPE.interpolate_blade_elements!Function
interpolate_blade_elements!(
+)

Interpolate blade elements based on RotorStatorParameters inputs and number of desired blade elements (from number of wake sheet in PanelingConstants input)

Arguments

  • rsp::RotorStatorParameters : A RotorStatorParameters object
  • `Rtips::Vector{Float}' : Vector of rotor tip radii
  • `Rhubs::Vector{Float}' : Vector of rotor hub radii
  • `rotorpanelcenters::Vector{Float}' : Vector of rotor panel centers
  • nbe::Int : number of blade elements per rotor

Keyword Arguments

  • finterp::Function=FLOWMath.linear : interpolation method (note, using Akima splines as is done for the body geometry can lead to negative chord in some cases)

Returns

  • blade_element_cache::NamedTuple : A named tuple containing the cacheable blade element information excluding the airfoil data.
  • airfoils::NamedTuple : A named tuple containing vectors of inner and outer airfoil polar data for each blade element, used in interpolating the input data at blade element locations.
source
DuctAPE.interpolate_blade_elements!Function
interpolate_blade_elements!(
     blade_element_cache, rsp, rotor_panel_centers, nbe; finterp=FLOWMath.linear
-)

In-place version of interpolate_blade_elements.

Returns

  • airfoils::NamedTuple : A named tuple containing vectors of inner and outer airfoil polar data for each blade element, used in interpolating the input data at blade element locations.
source
DuctAPE.get_blade_ends_from_body_geometryFunction
get_blade_ends_from_body_geometry(
+)

In-place version of interpolate_blade_elements.

Returns

  • airfoils::NamedTuple : A named tuple containing vectors of inner and outer airfoil polar data for each blade element, used in interpolating the input data at blade element locations.
source
DuctAPE.get_blade_ends_from_body_geometryFunction
get_blade_ends_from_body_geometry(
     rp_duct_coordinates, rp_centerbody_coordinates, tip_gaps, rotorzloc
-)

Obtain rotor hub and tip radii based on duct and centerbody geometry.

Arguments

  • var::type :
  • rp_duct_coordinates::Matrix{Float} : re-paneled duct coordinates
  • rp_centerbody_coordinates::Matrix{Float} : re-paneled centerbody coordinates
  • tip_gaps::Vector{Float} : gaps between blade tips and duct surface (MUST BE ZEROS for now)
  • rotorzloc::Vector{Float} : rotor lifting line axial positions.

Returns

  • Rtips::Vector{Float} : rotor tip radii
  • Rhubs::Vector{Float} : rotor hub radii
source
DuctAPE.get_blade_ends_from_body_geometry!Function
get_blade_ends_from_body_geometry!(
+)

Obtain rotor hub and tip radii based on duct and centerbody geometry.

Arguments

  • var::type :
  • rp_duct_coordinates::Matrix{Float} : re-paneled duct coordinates
  • rp_centerbody_coordinates::Matrix{Float} : re-paneled centerbody coordinates
  • tip_gaps::Vector{Float} : gaps between blade tips and duct surface (MUST BE ZEROS for now)
  • rotorzloc::Vector{Float} : rotor lifting line axial positions.

Returns

  • Rtips::Vector{Float} : rotor tip radii
  • Rhubs::Vector{Float} : rotor hub radii
source
DuctAPE.get_blade_ends_from_body_geometry!Function
get_blade_ends_from_body_geometry!(
     Rtip,
     Rhub,
     rp_duct_coordinates,
@@ -190,16 +190,16 @@
     tip_gaps,
     rotorzloc;
     silence_warnings=true,
-)

In-place version of get_blade_ends_from_body_geometry.

source
DuctAPE.get_local_solidityFunction
get_local_solidity(B, chord, r)

Calculate local solidity from local chord, radial position, and number of blades.

Arguments

  • B::Float : number of blades on rotor (usually an integer, but not necessarily).
  • chord::Vector{Float} : chord lengths at each radial station.
  • r::Vector{Float} : dimensional radial positions.

Returns

  • solidity::Vector{Float} : local solidity at each radial station
source
DuctAPE.get_staggerFunction
get_stagger(twists)

Convert twist angle to stagger angle

source
DuctAPE.generate_rotor_panelsFunction
generate_rotor_panels(rotorzloc, wake_grid, rotor_indices_in_wake, nwake_sheets)

Generate rotor panel objects.

Arguments

  • rotorzloc::Vector{Float} : rotor lifting line axial position
  • wake_grid::Array{Float,3} : wake elliptic grid axial and radial locations
  • rotor_indices_in_wake::Vector{Int} : indices of where along wake the rotors are placed
  • nwake_sheets::Int : number of wake sheets

Returns

  • rotor_source_panels::NamedTuple : A named tuple containing the rotor source panel variables.
source
DuctAPE.generate_rotor_panels!Function
generate_rotor_panels!(
+)

In-place version of get_blade_ends_from_body_geometry.

source
DuctAPE.get_local_solidityFunction
get_local_solidity(B, chord, r)

Calculate local solidity from local chord, radial position, and number of blades.

Arguments

  • B::Float : number of blades on rotor (usually an integer, but not necessarily).
  • chord::Vector{Float} : chord lengths at each radial station.
  • r::Vector{Float} : dimensional radial positions.

Returns

  • solidity::Vector{Float} : local solidity at each radial station
source
DuctAPE.get_staggerFunction
get_stagger(twists)

Convert twist angle to stagger angle

source
DuctAPE.generate_rotor_panelsFunction
generate_rotor_panels(rotorzloc, wake_grid, rotor_indices_in_wake, nwake_sheets)

Generate rotor panel objects.

Arguments

  • rotorzloc::Vector{Float} : rotor lifting line axial position
  • wake_grid::Array{Float,3} : wake elliptic grid axial and radial locations
  • rotor_indices_in_wake::Vector{Int} : indices of where along wake the rotors are placed
  • nwake_sheets::Int : number of wake sheets

Returns

  • rotor_source_panels::NamedTuple : A named tuple containing the rotor source panel variables.
source
DuctAPE.generate_rotor_panels!Function
generate_rotor_panels!(
     rotor_source_panels, rotorzloc, wake_grid, rotor_indices_in_wake, nwake_sheets
-)

In-place version of generate_rotor_panels.

source

Induced Velocities

DuctAPE.calculate_unit_induced_velocitiesFunction
calculate_unit_induced_velocities(problem_dimensions, panels, integration_options)

Calculate all the unit-induced velocties of all panels on all control points

Arguments

  • problem_dimensions::ProblemDimensions : A ProblemDimensions object
  • panels::NamedTuple : A named tuple containing all the paneling information
  • integration_options::IntegrationOptions : Options used for integration of velocity kernals across panels

Returns

  • ivr::NamedTuple : A named tuple containing arrays of induced velocities on the rotors
  • ivw::NamedTuple : A named tuple containing arrays of induced velocities on the wake
  • ivb::NamedTuple : A named tuple containing arrays of induced velocities on the bodies
source
DuctAPE.calculate_unit_induced_velocities!Function
calculate_unit_induced_velocities!(ivr, ivw, ivb, panels, integration_options)

In-place version of calculate_unit_induced_velocities.

source
DuctAPE.initialize_linear_systemFunction
initialize_linear_system(
+)

In-place version of generate_rotor_panels.

source

Induced Velocities

DuctAPE.calculate_unit_induced_velocitiesFunction
calculate_unit_induced_velocities(problem_dimensions, panels, integration_options)

Calculate all the unit-induced velocties of all panels on all control points

Arguments

  • problem_dimensions::ProblemDimensions : A ProblemDimensions object
  • panels::NamedTuple : A named tuple containing all the paneling information
  • integration_options::IntegrationOptions : Options used for integration of velocity kernals across panels

Returns

  • ivr::NamedTuple : A named tuple containing arrays of induced velocities on the rotors
  • ivw::NamedTuple : A named tuple containing arrays of induced velocities on the wake
  • ivb::NamedTuple : A named tuple containing arrays of induced velocities on the bodies
source
DuctAPE.calculate_unit_induced_velocities!Function
calculate_unit_induced_velocities!(ivr, ivw, ivb, panels, integration_options)

In-place version of calculate_unit_induced_velocities.

source
DuctAPE.initialize_linear_systemFunction
initialize_linear_system(
     ivb,
     body_vortex_panels,
     rotor_source_panels,
     wake_vortex_panels,
     Vinf,
     integration_options,
-)

Set up the linear system used in the panel method solve.

Arguments

  • ivb::NamedTuple : the named tuple containing all the unit induced velocities on the bodies
  • body_vortex_panels::NamedTuple : the named tuple containing the body vortex panel information
  • rotor_source_panels::NamedTuple : the named tuple containing the rotor source panel information
  • wake_vortex_panels::NamedTuple : the named tuple containing the wake vortex panel information
  • Vinf::Vector{Float} : the one-element vector containing the Freestream velocity magnitude
  • integration_options::IntegrationOptions : the integration options used in integrating the panel induced velocities

Returns

  • linsys::NamedTuple : A named tuple containing cacheable data for the linear system, including:
    • A_bb::Array{Float} : AIC (LHS) matrix for the panel method system
    • b_bf::Array{Float} : Initial system RHS vector based on freestrem magnitude
    • A_br::Array{Float} : Unit normal velocity from rotors onto body panels
    • A_pr::Array{Float} : Unit normal velocity from rotors onto body internal psuedo control points
    • A_bw::Array{Float} : Unit normal velocity from wake onto body panels
    • A_pw::Array{Float} : Unit normal velocity from wake onto body internal psuedo control points
  • A_bb_LU::LinearAlgebra.LU : LinearAlgebra LU factorization of the LHS matrix
  • lu_decomp_flag::Vector{Bool} : flag for whether factorization was successful
source
DuctAPE.initialize_linear_system!Function
initialize_linear_system!(
+)

Set up the linear system used in the panel method solve.

Arguments

  • ivb::NamedTuple : the named tuple containing all the unit induced velocities on the bodies
  • body_vortex_panels::NamedTuple : the named tuple containing the body vortex panel information
  • rotor_source_panels::NamedTuple : the named tuple containing the rotor source panel information
  • wake_vortex_panels::NamedTuple : the named tuple containing the wake vortex panel information
  • Vinf::Vector{Float} : the one-element vector containing the Freestream velocity magnitude
  • integration_options::IntegrationOptions : the integration options used in integrating the panel induced velocities

Returns

  • linsys::NamedTuple : A named tuple containing cacheable data for the linear system, including:
    • A_bb::Array{Float} : AIC (LHS) matrix for the panel method system
    • b_bf::Array{Float} : Initial system RHS vector based on freestrem magnitude
    • A_br::Array{Float} : Unit normal velocity from rotors onto body panels
    • A_pr::Array{Float} : Unit normal velocity from rotors onto body internal psuedo control points
    • A_bw::Array{Float} : Unit normal velocity from wake onto body panels
    • A_pw::Array{Float} : Unit normal velocity from wake onto body internal psuedo control points
  • A_bb_LU::LinearAlgebra.LU : LinearAlgebra LU factorization of the LHS matrix
  • lu_decomp_flag::Vector{Bool} : flag for whether factorization was successful
source
DuctAPE.initialize_linear_system!Function
initialize_linear_system!(
     linsys,
     ivb,
     body_vortex_panels,
@@ -208,14 +208,14 @@
     Vinf,
     intermediate_containers,
     integration_options,
-)

In-place version of initialize_linear_system.

source

Unit Induced Velocities

DuctAPE.calculate_xrmFunction
calculate_xrm(controlpoint, node)

Calculate xi, rho, and m for vortex and/or source ring induced velocity calculation.

Returns zeros if ring is on (or approximately on) the axis of rotation (zero radius).

Arguments

  • controlpoint::Vector{Float} [z r] coordinates of point being influenced
  • node::Vector{Float} : [z r] coordinates of singularity ring

Returns

  • xi::Float : normalized relative axial position
  • rho::Float : normalized relative radial position
  • m::Float : Elliptic integral input
  • rj::Float : radial position of the ring
source
DuctAPE.calculate_xrm!Function
calculate_xrm!(cache_vec, controlpoint, node)

In-place version of calculate_xrm.

Cache_vec is a vector used to hold intermediate values as well as the outputs.

source
DuctAPE.get_ellipticsFunction
get_elliptics(m)

Calculate value of elliptic functions for the given geometry parameter.

Arguments

  • m::Float : Elliptic Function parameter

Returns

  • K::Float : K(m), value of elliptic function of the first kind at m.
  • E::Float : E(m), value of eeliptic function of the second kind at m.
source
DuctAPE.vortex_ring_vzFunction
vortex_ring_vz(xi, rho, m, r_influence, influence_length)

Axial velocity induced by axisymmetric vortex ring.

Uses equivalent smoke ring induced velocity for self-induction, and returns zero if vortex ring is on axis of rotation (zero radius).

Arguments

  • xi::Float : normalized z-coordinate, (z-zo)/ro
  • rho::Float : normalized r-coordinate, r/ro
  • m::Float : Elliptic Integral parameter, 4rho/sqrt(xi^2+(rho+1)^2)
  • r_influence::Float : radial location of vortex ring, ro
  • influence_length::Float : length of panel used in calculating self-induction

Returns

  • vz::Float : axially induced velocity of vortex ring
source
DuctAPE.vortex_ring_vz!Function
vortex_ring_vz!(xi, rho, m, r_influence, influence_length, cache_vec)

Same as vortexringvz, but uses the cache_vec to store intermediate calculations.

source
DuctAPE.smoke_ring_vzFunction
smoke_ring_vz(r_influence, influence_length)

Equivalent "smoke" ring self-induced velocity.

Arguments

  • r_influence::Float : radial position of ring (i.e. the ring raidus)
  • influence_length::Float : length of influencing panel

Returs

  • vz::Float : axially induced velocity of vortex ring
source
DuctAPE.vortex_ring_vrFunction
vortex_ring_vr(xi, rho, m, r_influence)

Radial velocity induced by axisymmetric vortex ring.

Returns zero if vortex ring is on axis of rotation (zero radius), the point of influence is on the axis, or if self-inducing velocity.

Arguments

  • xi::Float : normalized z-coordinate, (z-zo)/ro
  • rho::Float : normalized r-coordinate, r/ro
  • m::Float : Elliptic Integral parameter, 4rho/sqrt(xi^2+(rho+1)^2)
  • r_influence::Float : radial location of vortex ring, ro

Returns

  • vr::Float : radially induced velocity of vortex ring
source
DuctAPE.vortex_ring_vr!Function
vortex_ring_vr!(xi, rho, m, r_influence, cache_vec)

Same as vortexringvr, but uses the cache_vec to store intermediate calculations.

source
DuctAPE.source_ring_vzFunction
source_ring_vz(xi, rho, m, r_influence)

Axial velocity induced by axisymmetric source ring.

Returns zero if source ring is on axis of rotation (zero radius), the point of influence is on the axis, or if self-inducing velocity.

Arguments:

  • xi::Float : normalized z-coordinate, (z-zo)/ro
  • rho::Float : normalized r-coordinate, r/ro
  • m::Float : Elliptic Integral parameter, 4rho/sqrt(xi^2+(rho+1)^2)
  • r_influence::Float : radial location of vortex ring, ro

Returns:

  • vz::Float : axially induced velocity of source ring
source
DuctAPE.source_ring_vz!Function
source_ring_vz!(xi, rho, m, r_influence, cache_vec)

Same as sourceringvz, but uses cache_vec to store intermediate values.

source
DuctAPE.source_ring_vrFunction
source_ring_vr(xi, rho, m, r_influence)

Radial velocity induced by axisymmetric source ring.

Returns zero if source ring is on axis of rotation (zero radius), the point of influence is on the axis, or if self-inducing velocity.

Arguments:

  • xi::Float : normalized z-coordinate, (z-zo)/ro
  • rho::Float : normalized r-coordinate, r/ro
  • m::Float : Elliptic Integral parameter, 4rho/sqrt(xi^2+(rho+1)^2)
  • r_influence::Float : radial location of vortex ring, ro

Returns:

  • vr::Float : radially induced velocity of source ring
source
DuctAPE.source_ring_vr!Function
source_ring_vr!(xi, rho, m, r_influence, cache_vec)

Same as sourceringvr, but uses cache_vec to store intermediate values.

source

Unit Induced Velocity Matrices

DuctAPE.induced_velocities_from_vortex_panels_on_pointsFunction
induced_velocities_from_vortex_panels_on_points(
+)

In-place version of initialize_linear_system.

source

Unit Induced Velocities

DuctAPE.calculate_xrmFunction
calculate_xrm(controlpoint, node)

Calculate xi, rho, and m for vortex and/or source ring induced velocity calculation.

Returns zeros if ring is on (or approximately on) the axis of rotation (zero radius).

Arguments

  • controlpoint::Vector{Float} [z r] coordinates of point being influenced
  • node::Vector{Float} : [z r] coordinates of singularity ring

Returns

  • xi::Float : normalized relative axial position
  • rho::Float : normalized relative radial position
  • m::Float : Elliptic integral input
  • rj::Float : radial position of the ring
source
DuctAPE.calculate_xrm!Function
calculate_xrm!(cache_vec, controlpoint, node)

In-place version of calculate_xrm.

Cache_vec is a vector used to hold intermediate values as well as the outputs.

source
DuctAPE.get_ellipticsFunction
get_elliptics(m)

Calculate value of elliptic functions for the given geometry parameter.

Arguments

  • m::Float : Elliptic Function parameter

Returns

  • K::Float : K(m), value of elliptic function of the first kind at m.
  • E::Float : E(m), value of eeliptic function of the second kind at m.
source
DuctAPE.vortex_ring_vzFunction
vortex_ring_vz(xi, rho, m, r_influence, influence_length)

Axial velocity induced by axisymmetric vortex ring.

Uses equivalent smoke ring induced velocity for self-induction, and returns zero if vortex ring is on axis of rotation (zero radius).

Arguments

  • xi::Float : normalized z-coordinate, (z-zo)/ro
  • rho::Float : normalized r-coordinate, r/ro
  • m::Float : Elliptic Integral parameter, 4rho/sqrt(xi^2+(rho+1)^2)
  • r_influence::Float : radial location of vortex ring, ro
  • influence_length::Float : length of panel used in calculating self-induction

Returns

  • vz::Float : axially induced velocity of vortex ring
source
DuctAPE.vortex_ring_vz!Function
vortex_ring_vz!(xi, rho, m, r_influence, influence_length, cache_vec)

Same as vortexringvz, but uses the cache_vec to store intermediate calculations.

source
DuctAPE.smoke_ring_vzFunction
smoke_ring_vz(r_influence, influence_length)

Equivalent "smoke" ring self-induced velocity.

Arguments

  • r_influence::Float : radial position of ring (i.e. the ring raidus)
  • influence_length::Float : length of influencing panel

Returs

  • vz::Float : axially induced velocity of vortex ring
source
DuctAPE.vortex_ring_vrFunction
vortex_ring_vr(xi, rho, m, r_influence)

Radial velocity induced by axisymmetric vortex ring.

Returns zero if vortex ring is on axis of rotation (zero radius), the point of influence is on the axis, or if self-inducing velocity.

Arguments

  • xi::Float : normalized z-coordinate, (z-zo)/ro
  • rho::Float : normalized r-coordinate, r/ro
  • m::Float : Elliptic Integral parameter, 4rho/sqrt(xi^2+(rho+1)^2)
  • r_influence::Float : radial location of vortex ring, ro

Returns

  • vr::Float : radially induced velocity of vortex ring
source
DuctAPE.vortex_ring_vr!Function
vortex_ring_vr!(xi, rho, m, r_influence, cache_vec)

Same as vortexringvr, but uses the cache_vec to store intermediate calculations.

source
DuctAPE.source_ring_vzFunction
source_ring_vz(xi, rho, m, r_influence)

Axial velocity induced by axisymmetric source ring.

Returns zero if source ring is on axis of rotation (zero radius), the point of influence is on the axis, or if self-inducing velocity.

Arguments:

  • xi::Float : normalized z-coordinate, (z-zo)/ro
  • rho::Float : normalized r-coordinate, r/ro
  • m::Float : Elliptic Integral parameter, 4rho/sqrt(xi^2+(rho+1)^2)
  • r_influence::Float : radial location of vortex ring, ro

Returns:

  • vz::Float : axially induced velocity of source ring
source
DuctAPE.source_ring_vz!Function
source_ring_vz!(xi, rho, m, r_influence, cache_vec)

Same as sourceringvz, but uses cache_vec to store intermediate values.

source
DuctAPE.source_ring_vrFunction
source_ring_vr(xi, rho, m, r_influence)

Radial velocity induced by axisymmetric source ring.

Returns zero if source ring is on axis of rotation (zero radius), the point of influence is on the axis, or if self-inducing velocity.

Arguments:

  • xi::Float : normalized z-coordinate, (z-zo)/ro
  • rho::Float : normalized r-coordinate, r/ro
  • m::Float : Elliptic Integral parameter, 4rho/sqrt(xi^2+(rho+1)^2)
  • r_influence::Float : radial location of vortex ring, ro

Returns:

  • vr::Float : radially induced velocity of source ring
source
DuctAPE.source_ring_vr!Function
source_ring_vr!(xi, rho, m, r_influence, cache_vec)

Same as sourceringvr, but uses cache_vec to store intermediate values.

source

Unit Induced Velocity Matrices

DuctAPE.induced_velocities_from_vortex_panels_on_pointsFunction
induced_velocities_from_vortex_panels_on_points(
     controlpoints,
     nodes,
     nodemap,
     influence_lengths,
     integration_options;
     integration_caches=nothing,
-)

Calculate axial and radial components of induced velocity for a set of control points due to a set of axisymmetric vortex panels (bands).

Used for getting the unit induced velocities due to the body panels on the rotor/wake as well as the unit induced velocity due to the wake on the body/rotor.

Arguments

  • controlpoints::Matrix{Float} [z r] coordinates of points being influenced
  • nodes::Matrix{Float} : [z r] coordinates of vortex rings
  • nodemap::Matrix{Int} : mapping from panel index to associated node indices
  • influence_lengths::Vector{Float} : lengths over which vortex ring influence is applied on the surface.
  • integration_options::IntegrationOptions : integration options

Keyword Arguments

  • integration_caches::NamedTuple=nothing : cache used in in-place quadrature functions.

Returns

  • VEL::Array{Float} : N-controlpoint x N-node x [vz, vr] array of induced velocity components
source
DuctAPE.induced_velocities_from_vortex_panels_on_points!Function
induced_velocities_from_vortex_panels_on_points!(
+)

Calculate axial and radial components of induced velocity for a set of control points due to a set of axisymmetric vortex panels (bands).

Used for getting the unit induced velocities due to the body panels on the rotor/wake as well as the unit induced velocity due to the wake on the body/rotor.

Arguments

  • controlpoints::Matrix{Float} [z r] coordinates of points being influenced
  • nodes::Matrix{Float} : [z r] coordinates of vortex rings
  • nodemap::Matrix{Int} : mapping from panel index to associated node indices
  • influence_lengths::Vector{Float} : lengths over which vortex ring influence is applied on the surface.
  • integration_options::IntegrationOptions : integration options

Keyword Arguments

  • integration_caches::NamedTuple=nothing : cache used in in-place quadrature functions.

Returns

  • VEL::Array{Float} : N-controlpoint x N-node x [vz, vr] array of induced velocity components
source
DuctAPE.induced_velocities_from_vortex_panels_on_points!Function
induced_velocities_from_vortex_panels_on_points!(
     VEL,
     controlpoint,
     node,
@@ -223,14 +223,14 @@
     influence_length,
     integration_options;
     integration_caches=nothing,
-)

In-place version of induced_velocities_from_vortex_panels_on_points.

source
DuctAPE.induced_velocities_from_source_panels_on_pointsFunction
induced_velocities_from_source_panels_on_points(
+)

In-place version of induced_velocities_from_vortex_panels_on_points.

source
DuctAPE.induced_velocities_from_source_panels_on_pointsFunction
induced_velocities_from_source_panels_on_points(
     controlpoints,
     nodes,
     nodemap,
     influence_lengths,
     integration_options;
     integration_caches=nothing,
-)

Calculate axial and radial components of induced velocity for a set of control points due to a set of axisymmetric source panels (bands)

Used for getting the unit induced velocities due to the body panels on the rotor/wake as well as the unit induced velocity due to the wake on the body/rotor.

Arguments

  • controlpoints::Matrix{Float} [z r] coordinates of points being influenced
  • nodes::Matrix{Float} : [z r] coordinates of vortex rings
  • nodemap::Matrix{Int} : mapping from panel index to associated node indices
  • influence_lengths::Vector{Float} : lengths over which vortex ring influence is applied on the surface.
  • integration_options::IntegrationOptions : integration options

Returns:

  • VEL::Array{Float} : N-controlpoint x N-node x [vz, vr] array of induced velocity components
source
DuctAPE.induced_velocities_from_source_panels_on_points!Function
induced_velocities_from_source_panels_on_points!(
+)

Calculate axial and radial components of induced velocity for a set of control points due to a set of axisymmetric source panels (bands)

Used for getting the unit induced velocities due to the body panels on the rotor/wake as well as the unit induced velocity due to the wake on the body/rotor.

Arguments

  • controlpoints::Matrix{Float} [z r] coordinates of points being influenced
  • nodes::Matrix{Float} : [z r] coordinates of vortex rings
  • nodemap::Matrix{Int} : mapping from panel index to associated node indices
  • influence_lengths::Vector{Float} : lengths over which vortex ring influence is applied on the surface.
  • integration_options::IntegrationOptions : integration options

Returns:

  • VEL::Array{Float} : N-controlpoint x N-node x [vz, vr] array of induced velocity components
source
DuctAPE.induced_velocities_from_source_panels_on_points!Function
induced_velocities_from_source_panels_on_points!(
     VEL,
     controlpoint,
     node,
@@ -238,7 +238,7 @@
     influence_length,
     integration_options;
     integration_caches=nothing,
-)

In-place version of induced_velocities_from_source_panels_on_points.

source
DuctAPE.induced_velocities_from_trailing_edge_gap_panel!Function
induced_velocities_from_trailing_edge_gap_panel!(
+)

In-place version of induced_velocities_from_source_panels_on_points.

source
DuctAPE.induced_velocities_from_trailing_edge_gap_panel!Function
induced_velocities_from_trailing_edge_gap_panel!(
     VEL,
     controlpoint,
     tenode,
@@ -249,9 +249,9 @@
     integration_options;
     wake=false,
     integration_caches=nothing,
-)

Calculate axial and radial components of induced velocity for a set of control points due to any trailing edge gap panels.

Used for getting the unit induced velocities due to the body body trailing edge gap panels on the body/rotor/wake.

Note, this function is also used to calculate the influence of the wake ends rather than modeling a semi-infinite fortex sheet.

Arguments

  • VEL::Array{Float} : N-controlpoint x N-node x [vz, vr] array of induced velocity components (modified in place)
  • controlpoints::Matrix{Float} [z r] coordinates of points being influenced
  • nodes::Matrix{Float} : [z r] coordinates of vortex rings
  • nodemap::Matrix{Int} : mapping from panel index to associated node indices
  • influence_lengths::Vector{Float} : lengths over which vortex ring influence is applied on the surface.
  • strengths::Matrix{Float} : vortex constant circulation values
  • integration_options::IntegrationOptions : integration options

Keyword Arguments

  • wake::Bool=false : flag to indicate if this is being used for a wake sheet.
  • integration_caches::NamedTuple=nothing : cache used in in-place quadrature functions.
source

Panel Method Velocity Functions

DuctAPE.vortex_aic_boundary_on_boundaryFunction
vortex_aic_boundary_on_boundary(
+)

Calculate axial and radial components of induced velocity for a set of control points due to any trailing edge gap panels.

Used for getting the unit induced velocities due to the body body trailing edge gap panels on the body/rotor/wake.

Note, this function is also used to calculate the influence of the wake ends rather than modeling a semi-infinite fortex sheet.

Arguments

  • VEL::Array{Float} : N-controlpoint x N-node x [vz, vr] array of induced velocity components (modified in place)
  • controlpoints::Matrix{Float} [z r] coordinates of points being influenced
  • nodes::Matrix{Float} : [z r] coordinates of vortex rings
  • nodemap::Matrix{Int} : mapping from panel index to associated node indices
  • influence_lengths::Vector{Float} : lengths over which vortex ring influence is applied on the surface.
  • strengths::Matrix{Float} : vortex constant circulation values
  • integration_options::IntegrationOptions : integration options

Keyword Arguments

  • wake::Bool=false : flag to indicate if this is being used for a wake sheet.
  • integration_caches::NamedTuple=nothing : cache used in in-place quadrature functions.
source

Panel Method Velocity Functions

DuctAPE.vortex_aic_boundary_on_boundaryFunction
vortex_aic_boundary_on_boundary(
     controlpoint, normal, node, nodemap, influence_length, integration_options
-)

Calculate panel method influence coefficients (V dot nhat) for a set of control points (on panels) due to a set of axisymmetric vortex rings (also on body surface)

Can be used for constructing the LHS influence Matrix for the panel method system.

Arguments

  • controlpoint::Matrix{Float} [z r] coordinates of points being influenced
  • normal::Matrix{Float} : unit normal vectors of the panels on which the control points are situated.
  • node::Matrix{Float} : [z r] coordinates of panel nodes (edges)
  • nodemap::Matrix{Int} : [1 2] node indices for each panel
  • influence_length::Vector{Float} : lengths of influencing panels
  • integration_options::IntegrationOptions : integration options

Returns

  • AICn::Matrix{Float} : N controlpoint x N+1 node array of V dot nhat values
source
DuctAPE.vortex_aic_boundary_on_boundary!Function
vortex_aic_boundary_on_boundary!(
+)

Calculate panel method influence coefficients (V dot nhat) for a set of control points (on panels) due to a set of axisymmetric vortex rings (also on body surface)

Can be used for constructing the LHS influence Matrix for the panel method system.

Arguments

  • controlpoint::Matrix{Float} [z r] coordinates of points being influenced
  • normal::Matrix{Float} : unit normal vectors of the panels on which the control points are situated.
  • node::Matrix{Float} : [z r] coordinates of panel nodes (edges)
  • nodemap::Matrix{Int} : [1 2] node indices for each panel
  • influence_length::Vector{Float} : lengths of influencing panels
  • integration_options::IntegrationOptions : integration options

Returns

  • AICn::Matrix{Float} : N controlpoint x N+1 node array of V dot nhat values
source
DuctAPE.vortex_aic_boundary_on_boundary!Function
vortex_aic_boundary_on_boundary!(
     AICn,
     controlpoint,
     normal,
@@ -260,7 +260,7 @@
     influence_length,
     integration_options;
     integration_caches=nothing,
-)

In-place verion of vortex_aic_boundary_on_boundary.

integration_caches is a named tuple containing caching for intermediate calculation values.

source
DuctAPE.vortex_aic_boundary_on_fieldFunction
vortex_aic_boundary_on_field(
+)

In-place verion of vortex_aic_boundary_on_boundary.

integration_caches is a named tuple containing caching for intermediate calculation values.

source
DuctAPE.vortex_aic_boundary_on_fieldFunction
vortex_aic_boundary_on_field(
     controlpoint,
     normal,
     node,
@@ -268,7 +268,7 @@
     influence_length,
     integration_options;
     integration_caches=nothing,
-)

Calculate panel method influence coefficients (V dot nhat) for a set of control points (NOT on panels) due to a set of axisymmetric vortex rings (on body surface)

Used for constructing portions of the panel method LHS matrix related to the pseudo control points in the bodies.

Arguments:

  • controlpoint::Matrix{Float} [z r] coordinates of points being influenced
  • normal::Matrix{Float} : unit normal vectors of the panels on which the control points are situated.
  • node::Matrix{Float} : [z r] coordinates of panel nodes (edges)
  • nodemap::Matrix{Int} : [1 2] node indices for each panel
  • influence_length::Vector{Float} : lengths of influencing panels
  • integration_options::IntegrationOptions : integration options

Keyword Arguments

  • integration_caches::NamedTuple=nothing : caches for intermediate values in integration.

Returns:

  • AICn::Matrix{Float} : N controlpoint x N+1 node array of V dot nhat values
source
DuctAPE.vortex_aic_boundary_on_field!Function
vortex_aic_boundary_on_field!(
+)

Calculate panel method influence coefficients (V dot nhat) for a set of control points (NOT on panels) due to a set of axisymmetric vortex rings (on body surface)

Used for constructing portions of the panel method LHS matrix related to the pseudo control points in the bodies.

Arguments:

  • controlpoint::Matrix{Float} [z r] coordinates of points being influenced
  • normal::Matrix{Float} : unit normal vectors of the panels on which the control points are situated.
  • node::Matrix{Float} : [z r] coordinates of panel nodes (edges)
  • nodemap::Matrix{Int} : [1 2] node indices for each panel
  • influence_length::Vector{Float} : lengths of influencing panels
  • integration_options::IntegrationOptions : integration options

Keyword Arguments

  • integration_caches::NamedTuple=nothing : caches for intermediate values in integration.

Returns:

  • AICn::Matrix{Float} : N controlpoint x N+1 node array of V dot nhat values
source
DuctAPE.vortex_aic_boundary_on_field!Function
vortex_aic_boundary_on_field!(
     AICn,
     controlpoint,
     normal,
@@ -277,7 +277,7 @@
     influence_length,
     integration_options;
     integration_caches=nothing,
-)

In-place version of vortex_aic_boundary_on_field.

source
DuctAPE.add_kutta!Function
add_kutta!(LHS, AICn, kids)

Add Kutta condition (γ1 + γN = 0) to LHS matrix.

  • LHS::Matrix{Float} : a pre-allocated (zeros) full size left-hand side matrix
  • AICn::Matrix{Float} : influence coefficients for panels/nodes
  • kids::Vector{Int} : [1 2] indices of where to put 1's for kutta condition
source
DuctAPE.add_te_gap_aic!Function
add_te_gap_aic!(
+)

In-place version of vortex_aic_boundary_on_field.

source
DuctAPE.add_kutta!Function
add_kutta!(LHS, AICn, kids)

Add Kutta condition (γ1 + γN = 0) to LHS matrix.

  • LHS::Matrix{Float} : a pre-allocated (zeros) full size left-hand side matrix
  • AICn::Matrix{Float} : influence coefficients for panels/nodes
  • kids::Vector{Int} : [1 2] indices of where to put 1's for kutta condition
source
DuctAPE.add_te_gap_aic!Function
add_te_gap_aic!(
     AICn,
     controlpoint,
     normal,
@@ -289,7 +289,7 @@
     integration_options;
     wake=false,
     integration_caches=nothing,
-)

Add trailing edge gap aerodynmic influence coefficient contributions to the AIC matrix.

Arguments

  • AICn::Matrix{Float} : N controlpoint x N+1 node array of V dot nhat values
  • controlpoint::Matrix{Float} [z r] coordinates of points being influenced
  • normal::Matrix{Float} : unit normal vectors of the panels on which the control points are situated.
  • tenode::Matrix{Float} : [z r] coordinates of trailing edge panel nodes (edges)
  • teinfluence_length::Vector{Float} : lengths of influencing trailing edge panels
  • tendotn::Matrix{Float} : nhat of trailing edge panel dotted with nhat of adjacent panels
  • tencrossn::Matrix{Float} : nhat of trailing edge panel crossed with nhat of adjacent panels
  • teadjnodeidxs::Matrix{Float} : indices of nodes adjacent to trailing edge panel
  • integration_options::IntegrationOptions : integration options

Keyword Arguments

  • wake::Bool=false : flag as to whether this function is being applied to a wake sheet.
  • integration_caches::NamedTuple=nothing : caches for intermediate values in integration.
source
DuctAPE.source_aicFunction
source_aic(
+)

Add trailing edge gap aerodynmic influence coefficient contributions to the AIC matrix.

Arguments

  • AICn::Matrix{Float} : N controlpoint x N+1 node array of V dot nhat values
  • controlpoint::Matrix{Float} [z r] coordinates of points being influenced
  • normal::Matrix{Float} : unit normal vectors of the panels on which the control points are situated.
  • tenode::Matrix{Float} : [z r] coordinates of trailing edge panel nodes (edges)
  • teinfluence_length::Vector{Float} : lengths of influencing trailing edge panels
  • tendotn::Matrix{Float} : nhat of trailing edge panel dotted with nhat of adjacent panels
  • tencrossn::Matrix{Float} : nhat of trailing edge panel crossed with nhat of adjacent panels
  • teadjnodeidxs::Matrix{Float} : indices of nodes adjacent to trailing edge panel
  • integration_options::IntegrationOptions : integration options

Keyword Arguments

  • wake::Bool=false : flag as to whether this function is being applied to a wake sheet.
  • integration_caches::NamedTuple=nothing : caches for intermediate values in integration.
source
DuctAPE.source_aicFunction
source_aic(
     controlpoint,
     normal,
     node,
@@ -297,7 +297,7 @@
     influence_length,
     integration_options;
     integration_caches=nothing,
-)

Calculate panel method influence coefficients (V dot nhat) for a set of control points (on panels) due to a set of axisymmetric source rings not on body surface.

Can be used for constructing the RHS boundary conditions due to rotor source panels.

Arguments

  • controlpoint::Matrix{Float} [z r] coordinates of points being influenced
  • normal::Matrix{Float} : unit normal vectors of the panels on which the control points are situated.
  • node::Matrix{Float} : [z r] coordinates of panel nodes (edges)
  • nodemap::Matrix{Int} : [1 2] node indices for each panel
  • influence_length::Vector{Float} : lengths of influencing panels
  • integration_options::IntegrationOptions : integration options

Keyword Arguments

  • integration_caches::NamedTuple=nothing : caches for intermediate values in integration.

Returns

  • AICn::Matrix{Float} : N controlpoint x N+1 node array of V dot nhat values
source
DuctAPE.source_aic!Function
source_aic!(
+)

Calculate panel method influence coefficients (V dot nhat) for a set of control points (on panels) due to a set of axisymmetric source rings not on body surface.

Can be used for constructing the RHS boundary conditions due to rotor source panels.

Arguments

  • controlpoint::Matrix{Float} [z r] coordinates of points being influenced
  • normal::Matrix{Float} : unit normal vectors of the panels on which the control points are situated.
  • node::Matrix{Float} : [z r] coordinates of panel nodes (edges)
  • nodemap::Matrix{Int} : [1 2] node indices for each panel
  • influence_length::Vector{Float} : lengths of influencing panels
  • integration_options::IntegrationOptions : integration options

Keyword Arguments

  • integration_caches::NamedTuple=nothing : caches for intermediate values in integration.

Returns

  • AICn::Matrix{Float} : N controlpoint x N+1 node array of V dot nhat values
source
DuctAPE.source_aic!Function
source_aic!(
     AICn,
     controlpoint,
     normal,
@@ -306,31 +306,31 @@
     influence_length,
     integration_options;
     integration_caches=nothing,
-)

In-place version of source_aic.

source
DuctAPE.freestream_influence_vectorFunction
freestream_influence_vector(normals, Vinfmat)

Calculate RHS contributions due to freestream.

Note that the freestream is assumed to have zero radial component in the underlying theory, but here we allow an arbitrary 2D vector for velocity for taking the dot product easier.

Arguments

  • normals::Matrix{Float} : unit normal vectors of the panels on which the control points are situated.
  • Vinfmat::Matrix{Float} : [z r] components of freestream velocity (r's should be zero)

Returns

  • RHS::Vector{Float} : vector of normal components of freestream velocity on input panels
source
DuctAPE.freestream_influence_vector!Function
freestream_influence_vector!(RHS, normals, Vinfmat)

In-place version of freestream_influence_vector.

source
DuctAPE.assemble_lhs_matrixFunction
assemble_lhs_matrix(
+)

In-place version of source_aic.

source
DuctAPE.freestream_influence_vectorFunction
freestream_influence_vector(normals, Vinfmat)

Calculate RHS contributions due to freestream.

Note that the freestream is assumed to have zero radial component in the underlying theory, but here we allow an arbitrary 2D vector for velocity for taking the dot product easier.

Arguments

  • normals::Matrix{Float} : unit normal vectors of the panels on which the control points are situated.
  • Vinfmat::Matrix{Float} : [z r] components of freestream velocity (r's should be zero)

Returns

  • RHS::Vector{Float} : vector of normal components of freestream velocity on input panels
source
DuctAPE.freestream_influence_vector!Function
freestream_influence_vector!(RHS, normals, Vinfmat)

In-place version of freestream_influence_vector.

source
DuctAPE.assemble_lhs_matrixFunction
assemble_lhs_matrix(
     AICn, AICpcp, npanel, nnode, totpanel, totnode, prescribednodeidxs; dummyval=1.0
-)

Assemble the LHS matrix of the panel method.

Arguments

  • AICn::Matrix{Float} : N controlpoint x N+1 node array of V dot nhat values
  • AICpcp::Matrix{Float} : Nbodies controlpoint x N+1 node array of V dot nhat values (influence on psuedo control points)
  • npanel::Vector{Int} : number of panels comprising each body
  • nnode::Vector{Int} : number of nodes comprising each body
  • totpanel::Int : total number of panels
  • totnode::Int : total number of nodes
  • prescribednodeidxs::Vector{Int} : indices of nodes with prescribed strengths (those on the axis of rotation).

Keyword Arguments

  • dummyval::Float=1.0 : value for dummy input for prescribed and internal control points in the system. Do not change except for debugging purposes.

Returns

  • LHS::Matrix{Float} : The full LHS matrix for the panel method.
source
DuctAPE.assemble_lhs_matrix!Function
assemble_lhs_matrix!(
+)

Assemble the LHS matrix of the panel method.

Arguments

  • AICn::Matrix{Float} : N controlpoint x N+1 node array of V dot nhat values
  • AICpcp::Matrix{Float} : Nbodies controlpoint x N+1 node array of V dot nhat values (influence on psuedo control points)
  • npanel::Vector{Int} : number of panels comprising each body
  • nnode::Vector{Int} : number of nodes comprising each body
  • totpanel::Int : total number of panels
  • totnode::Int : total number of nodes
  • prescribednodeidxs::Vector{Int} : indices of nodes with prescribed strengths (those on the axis of rotation).

Keyword Arguments

  • dummyval::Float=1.0 : value for dummy input for prescribed and internal control points in the system. Do not change except for debugging purposes.

Returns

  • LHS::Matrix{Float} : The full LHS matrix for the panel method.
source
DuctAPE.assemble_lhs_matrix!Function
assemble_lhs_matrix!(
     LHS, AICn, AICpcp, npanel, nnode, totpanel, totnode, prescribednodeidxs; dummyval=1.0
-)

In-place version of assemble_lhs_matrix.

source
DuctAPE.factorize_LHSFunction
factorize_LHS(A::AbstractMatrix)

Returns the LU decomposition of A.

source
DuctAPE.factorize_LHS!Function
factorize_LHS!(Apivot::AbstractMatrix, A::AbstractMatrix)

Returns the LU decomposition of A using Apivot as storage memory to pivot leaving A unchanged.

source
DuctAPE.assemble_rhs_matrixFunction
assemble_rhs_matrix(
+)

In-place version of assemble_lhs_matrix.

source
DuctAPE.factorize_LHSFunction
factorize_LHS(A::AbstractMatrix)

Returns the LU decomposition of A.

source
DuctAPE.factorize_LHS!Function
factorize_LHS!(Apivot::AbstractMatrix, A::AbstractMatrix)

Returns the LU decomposition of A using Apivot as storage memory to pivot leaving A unchanged.

source
DuctAPE.assemble_rhs_matrixFunction
assemble_rhs_matrix(
     vdnb, vdnpcp, npanel, nnode, totpanel, totnode, prescribednodeidxs
-)

Arguments

  • vdnb::Vector{Float} : V dot nhat for body panels
  • vdnpcp::Vector{Float} : V dot nhat for pseudo control points
  • npanel::Vector{Int} : number of panels comprising each body
  • nnode::Vector{Int} : number of nodes comprising each body
  • totpanel::Int : total number of body panels
  • totnode::Int : total number of body nodes
  • prescribednodeidxs::Vector{Int} : indices of nodes with prescribed strengths (those on the axis of rotation)

Returns

  • RHS::Vector{Float} : the RHS vector of the panel method.
source
DuctAPE.assemble_rhs_matrix!Function
assemble_rhs_matrix!(
+)

Arguments

  • vdnb::Vector{Float} : V dot nhat for body panels
  • vdnpcp::Vector{Float} : V dot nhat for pseudo control points
  • npanel::Vector{Int} : number of panels comprising each body
  • nnode::Vector{Int} : number of nodes comprising each body
  • totpanel::Int : total number of body panels
  • totnode::Int : total number of body nodes
  • prescribednodeidxs::Vector{Int} : indices of nodes with prescribed strengths (those on the axis of rotation)

Returns

  • RHS::Vector{Float} : the RHS vector of the panel method.
source
DuctAPE.assemble_rhs_matrix!Function
assemble_rhs_matrix!(
     RHS, vdnb, vdnpcp, npanel, nnode, totpanel, totnode, prescribednodeidxs
-)

In-place version of assemble_rhs_matrix.

source
DuctAPE.calculate_normal_velocityFunction
calculate_normal_velocity(velocity_vector, normal)

Calculate normal velocity_vector (V dot nhat).

Arguments

  • velocity_vector::Matrix{Float} : velocity vector [z r] on each panel
  • normal::Matrix{Float} : the panel unit normals

Returns

  • AIC::Matrix{Float} : V dot n on each panel
source
DuctAPE.calculate_normal_velocity!Function
calculate_normal_velocity!(AIC, velocity_vector, normal)

In-place version of calculate_normal_velocity.

source

Quadrature

Integrands

DuctAPE.nominal_vortex_induced_velocity_sampleFunction
nominal_vortex_induced_velocity_sample(
+)

In-place version of assemble_rhs_matrix.

source
DuctAPE.calculate_normal_velocityFunction
calculate_normal_velocity(velocity_vector, normal)

Calculate normal velocity_vector (V dot nhat).

Arguments

  • velocity_vector::Matrix{Float} : velocity vector [z r] on each panel
  • normal::Matrix{Float} : the panel unit normals

Returns

  • AIC::Matrix{Float} : V dot n on each panel
source
DuctAPE.calculate_normal_velocity!Function
calculate_normal_velocity!(AIC, velocity_vector, normal)

In-place version of calculate_normal_velocity.

source

Quadrature

Integrands

DuctAPE.nominal_vortex_induced_velocity_sampleFunction
nominal_vortex_induced_velocity_sample(
     t, node1, node2, influence_length, controlpoint, cache_vec; nondimrange=(0.0, 1.0)
-)

Calculate the velocity induced by a linear vortex panel on a point.

Arguments

  • t::Float : sample point in range (0,1) selected by quadrature method.
  • node1::Vector{Float} : first panel node (edge) position.
  • node2::Vector{Float} : second panel node (edge) position.
  • influence_length::Float : dimensional length of panel.
  • controlpoint::Vector{Float} : controlpoint position
  • cache_vec::Vector{Float} : cache for intermediate calculations

Keyword Arguments

  • nondimrange::Tuple=(0.0,1.0) : Non-dimensional range describing the panel length. Do not change excpet for debugging purposes. Note, can also be a vector.

Returns

  • V::Matrix{Float} : 2x2 matrix of axial and radial induced velocities from each of the nodes.
source
DuctAPE.nominal_vortex_induced_velocity_sample!Function
nominal_vortex_induced_velocity_sample!(
+)

Calculate the velocity induced by a linear vortex panel on a point.

Arguments

  • t::Float : sample point in range (0,1) selected by quadrature method.
  • node1::Vector{Float} : first panel node (edge) position.
  • node2::Vector{Float} : second panel node (edge) position.
  • influence_length::Float : dimensional length of panel.
  • controlpoint::Vector{Float} : controlpoint position
  • cache_vec::Vector{Float} : cache for intermediate calculations

Keyword Arguments

  • nondimrange::Tuple=(0.0,1.0) : Non-dimensional range describing the panel length. Do not change excpet for debugging purposes. Note, can also be a vector.

Returns

  • V::Matrix{Float} : 2x2 matrix of axial and radial induced velocities from each of the nodes.
source
DuctAPE.nominal_vortex_induced_velocity_sample!Function
nominal_vortex_induced_velocity_sample!(
     V, t, node1, node2, influence_length, controlpoint, cache_vec; nondimrange=(0.0, 1.0)
-)

In-place version of nominal_vortex_induced_velocity_sample.

source
DuctAPE.subtracted_singular_vortex_influenceFunction
subtracted_singular_vortex_influence(node, controlpoint)

Calculate the singular portions of the self-induced vortex panel influence to subtract off the integral in the separation of singularity method.

Arguments

  • node::Vector{Float} : node position
  • controlpoint::Vector{Float} : controlpoint position

Returns

  • axial::Float : axial direction influence
  • radial::Float : radial direction influence
source
DuctAPE.subtracted_singular_vortex_influence!Function
subtracted_singular_vortex_influence!(node, controlpoint, cache_vec)

Somewhat in-place version of subtracted_singular_vortex_influence.

Arguments

  • node::Vector{Float} : node position
  • controlpoint::Vector{Float} : controlpoint position
  • cache_vec::Vector{Float} : used to store intermediate values.

Returns

  • axial::Float : axial direction influence
  • radial::Float : radial direction influence
source
DuctAPE.analytically_integrated_vortex_influenceFunction
analytically_integrated_vortex_influence(r, influence_length)

Analytical approximation of the singular portions of the self-induced vortex panel velocities to be added back in as part of the separation of singularity method.

Arguments

  • r::Float : radial position of self-induced control point
  • influence_length::Float : dimensional length of the panel

Returns

  • V::Vector{Float} : axial and radial induced velocities
source
DuctAPE.analytically_integrated_vortex_influence!Function
analytically_integrated_vortex_influence!(V, r, influence_length)

In-place version of analytically_integrated_vortex_influence.

source
DuctAPE.self_vortex_induced_velocity_sampleFunction
self_vortex_induced_velocity_sample(
+)

In-place version of nominal_vortex_induced_velocity_sample.

source
DuctAPE.subtracted_singular_vortex_influenceFunction
subtracted_singular_vortex_influence(node, controlpoint)

Calculate the singular portions of the self-induced vortex panel influence to subtract off the integral in the separation of singularity method.

Arguments

  • node::Vector{Float} : node position
  • controlpoint::Vector{Float} : controlpoint position

Returns

  • axial::Float : axial direction influence
  • radial::Float : radial direction influence
source
DuctAPE.subtracted_singular_vortex_influence!Function
subtracted_singular_vortex_influence!(node, controlpoint, cache_vec)

Somewhat in-place version of subtracted_singular_vortex_influence.

Arguments

  • node::Vector{Float} : node position
  • controlpoint::Vector{Float} : controlpoint position
  • cache_vec::Vector{Float} : used to store intermediate values.

Returns

  • axial::Float : axial direction influence
  • radial::Float : radial direction influence
source
DuctAPE.analytically_integrated_vortex_influenceFunction
analytically_integrated_vortex_influence(r, influence_length)

Analytical approximation of the singular portions of the self-induced vortex panel velocities to be added back in as part of the separation of singularity method.

Arguments

  • r::Float : radial position of self-induced control point
  • influence_length::Float : dimensional length of the panel

Returns

  • V::Vector{Float} : axial and radial induced velocities
source
DuctAPE.analytically_integrated_vortex_influence!Function
analytically_integrated_vortex_influence!(V, r, influence_length)

In-place version of analytically_integrated_vortex_influence.

source
DuctAPE.self_vortex_induced_velocity_sampleFunction
self_vortex_induced_velocity_sample(
     t, node1, node2, influence_length, controlpoint, cache_vec; nondimrange=(0.0, 1.0)
-)

Calculate the velocity induced by a linear vortex panel on a point at the midpoint between the panel edges.

Arguments

  • t::Float : sample point in range (0,1) selected by quadrature method.
  • node1::Vector{Float} : first panel node (edge) position.
  • node2::Vector{Float} : second panel node (edge) position.
  • influence_length::Float : dimensional length of panel.
  • controlpoint::Vector{Float} : controlpoint position
  • cache_vec::Vector{Float} : cache for intermediate calculations

Keyword Arguments

  • nondimrange::Tuple=(0.0,1.0) : Non-dimensional range describing the panel length. Do not change excpet for debugging purposes. Note, can also be a vector.

Returns

  • V::Matrix{Float} : 2x2 matrix of axial and radial induced velocities from each of the nodes.
source
DuctAPE.self_vortex_induced_velocity_sample!Function
self_vortex_induced_velocity_sample!(
+)

Calculate the velocity induced by a linear vortex panel on a point at the midpoint between the panel edges.

Arguments

  • t::Float : sample point in range (0,1) selected by quadrature method.
  • node1::Vector{Float} : first panel node (edge) position.
  • node2::Vector{Float} : second panel node (edge) position.
  • influence_length::Float : dimensional length of panel.
  • controlpoint::Vector{Float} : controlpoint position
  • cache_vec::Vector{Float} : cache for intermediate calculations

Keyword Arguments

  • nondimrange::Tuple=(0.0,1.0) : Non-dimensional range describing the panel length. Do not change excpet for debugging purposes. Note, can also be a vector.

Returns

  • V::Matrix{Float} : 2x2 matrix of axial and radial induced velocities from each of the nodes.
source
DuctAPE.self_vortex_induced_velocity_sample!Function
self_vortex_induced_velocity_sample!(
     V, t, node1, node2, influence_length, controlpoint, cache_vec; nondimrange=(0.0, 1.0)
-)

In-place version of self_vortex_induced_velocity_sample.

source
DuctAPE.nominal_source_induced_velocity_sampleFunction
nominal_source_induced_velocity_sample(
+)

In-place version of self_vortex_induced_velocity_sample.

source
DuctAPE.nominal_source_induced_velocity_sampleFunction
nominal_source_induced_velocity_sample(
     t, node1, node2, influence_length, controlpoint, cache_vec; nondimrange=(0.0, 1.0)
-)

Calculate the velocity induced by a source panel on a point.

Arguments

  • t::Float : sample point in range (0,1) selected by quadrature method.
  • node1::Vector{Float} : first panel node (edge) position.
  • node2::Vector{Float} : second panel node (edge) position.
  • influence_length::Float : dimensional length of panel.
  • controlpoint::Vector{Float} : controlpoint position
  • cache_vec::Vector{Float} : cache for intermediate calculations

Keyword Arguments

  • nondimrange::Tuple=(0.0,1.0) : Non-dimensional range describing the panel length. Do not change excpet for debugging purposes. Note, can also be a vector.

Returns

  • V::Matrix{Float} : 2x2 matrix of axial and radial induced velocities from each of the nodes.
source
DuctAPE.nominal_source_induced_velocity_sample!Function
nominal_source_induced_velocity_sample!(
+)

Calculate the velocity induced by a source panel on a point.

Arguments

  • t::Float : sample point in range (0,1) selected by quadrature method.
  • node1::Vector{Float} : first panel node (edge) position.
  • node2::Vector{Float} : second panel node (edge) position.
  • influence_length::Float : dimensional length of panel.
  • controlpoint::Vector{Float} : controlpoint position
  • cache_vec::Vector{Float} : cache for intermediate calculations

Keyword Arguments

  • nondimrange::Tuple=(0.0,1.0) : Non-dimensional range describing the panel length. Do not change excpet for debugging purposes. Note, can also be a vector.

Returns

  • V::Matrix{Float} : 2x2 matrix of axial and radial induced velocities from each of the nodes.
source
DuctAPE.nominal_source_induced_velocity_sample!Function
nominal_source_induced_velocity_sample!(
     V, t, node1, node2, influence_length, controlpoint, cache_vec; nondimrange=(0.0,1.0)
-)

In-place version of nominal_source_induced_velocity_sample.

source
DuctAPE.subtracted_singular_source_influenceFunction
subtracted_singular_source_influence(node, controlpoint)

Calculate the singular portions of the self-induced source panel influence to subtract off the integral in the separation of singularity method.

Arguments

  • node::Vector{Float} : node position
  • controlpoint::Vector{Float} : controlpoint position

Returns

  • axial::Float : axial direction influence
  • radial::Float : radial direction influence
source
DuctAPE.subtracted_singular_source_influence!Function
subtracted_singular_source_influence!(node, controlpoint, cache_vec)

In-place version of subtracted_singular_source_influence.

source
DuctAPE.analytically_integrated_source_influenceFunction
analytically_integrated_source_influence(r, influence_length)

In-place version of analytically_integrated_source_influence.

source
DuctAPE.analytically_integrated_source_influence!Function
analytically_integrated_source_influence(r, influence_length)

Analytical approximation of the singular portions of the self-induced source panel velocities to be added back in as part of the separation of singularity method.

Arguments

  • r::Float : radial position of self-induced control point
  • influence_length::Float : dimensional length of the panel

Returns

  • V::Vector{Float} : axial and radial induced velocities
source
DuctAPE.self_source_induced_velocity_sampleFunction
self_source_induced_velocity_sample(
+)

In-place version of nominal_source_induced_velocity_sample.

source
DuctAPE.subtracted_singular_source_influenceFunction
subtracted_singular_source_influence(node, controlpoint)

Calculate the singular portions of the self-induced source panel influence to subtract off the integral in the separation of singularity method.

Arguments

  • node::Vector{Float} : node position
  • controlpoint::Vector{Float} : controlpoint position

Returns

  • axial::Float : axial direction influence
  • radial::Float : radial direction influence
source
DuctAPE.subtracted_singular_source_influence!Function
subtracted_singular_source_influence!(node, controlpoint, cache_vec)

In-place version of subtracted_singular_source_influence.

source
DuctAPE.analytically_integrated_source_influenceFunction
analytically_integrated_source_influence(r, influence_length)

In-place version of analytically_integrated_source_influence.

source
DuctAPE.analytically_integrated_source_influence!Function
analytically_integrated_source_influence(r, influence_length)

Analytical approximation of the singular portions of the self-induced source panel velocities to be added back in as part of the separation of singularity method.

Arguments

  • r::Float : radial position of self-induced control point
  • influence_length::Float : dimensional length of the panel

Returns

  • V::Vector{Float} : axial and radial induced velocities
source
DuctAPE.self_source_induced_velocity_sampleFunction
self_source_induced_velocity_sample(
     t, node1, node2, influence_length, controlpoint, cache_vec; nondimrange=(0.0, 1.0)
-)

Calculate the velocity induced by a linear source panel on a point at the midpoint between the panel edges.

Arguments

  • t::Float : sample point in range (0,1) selected by quadrature method.
  • node1::Vector{Float} : first panel node (edge) position.
  • node2::Vector{Float} : second panel node (edge) position.
  • influence_length::Float : dimensional length of panel.
  • controlpoint::Vector{Float} : controlpoint position
  • cache_vec::Vector{Float} : cache for intermediate calculations

Keyword Arguments

  • nondimrange::Tuple=(0.0,1.0) : Non-dimensional range describing the panel length. Do not change excpet for debugging purposes. Note, can also be a vector.

Returns

  • V::Matrix{Float} : 2x2 matrix of axial and radial induced velocities from each of the nodes.
source
DuctAPE.self_source_induced_velocity_sample!Function
self_source_induced_velocity_sample!(
+)

Calculate the velocity induced by a linear source panel on a point at the midpoint between the panel edges.

Arguments

  • t::Float : sample point in range (0,1) selected by quadrature method.
  • node1::Vector{Float} : first panel node (edge) position.
  • node2::Vector{Float} : second panel node (edge) position.
  • influence_length::Float : dimensional length of panel.
  • controlpoint::Vector{Float} : controlpoint position
  • cache_vec::Vector{Float} : cache for intermediate calculations

Keyword Arguments

  • nondimrange::Tuple=(0.0,1.0) : Non-dimensional range describing the panel length. Do not change excpet for debugging purposes. Note, can also be a vector.

Returns

  • V::Matrix{Float} : 2x2 matrix of axial and radial induced velocities from each of the nodes.
source
DuctAPE.self_source_induced_velocity_sample!Function
self_source_induced_velocity_sample!(
     V, t, node1, node2, influence_length, controlpoint, cache_vec; nondimrange=(0.0, 1.0)
-)

In-place version of self_source_induced_velocity_sample.

source

Integrals

DuctAPE.nominal_vortex_panel_integrationFunction
nominal_vortex_panel_integration(
+)

In-place version of self_source_induced_velocity_sample.

source

Integrals

DuctAPE.nominal_vortex_panel_integrationFunction
nominal_vortex_panel_integration(
     integration_options,
     node1,
     node2,
@@ -338,7 +338,7 @@
     controlpoint,
     containers;
     debug=false,
-)

Integration of vortex panel induced velocity on a point far away.

Arguments

  • integration_options::IntegrationMethod : options for itegration methods
  • node1::Vector{Float} : first panel node (edge) position.
  • node2::Vector{Float} : second panel node (edge) position.
  • influence_length::Float : dimensional length of panel.
  • controlpoint::Vector{Float} : controlpoint position
  • containers::NamedTuple : cache for intermediate calculations

Keyword Arguments

  • debug::Bool=false : if true, some methods will return the estimation error.

Returns

  • V::Matrix{Float} : velocity components due to the jth and j+1th nodes in the format: [vz_j vr_j; vz_{j+1} vr_{j+1}]
source
DuctAPE.nominal_vortex_panel_integration!Function
nominal_vortex_panel_integration!(
+)

Integration of vortex panel induced velocity on a point far away.

Arguments

  • integration_options::IntegrationMethod : options for itegration methods
  • node1::Vector{Float} : first panel node (edge) position.
  • node2::Vector{Float} : second panel node (edge) position.
  • influence_length::Float : dimensional length of panel.
  • controlpoint::Vector{Float} : controlpoint position
  • containers::NamedTuple : cache for intermediate calculations

Keyword Arguments

  • debug::Bool=false : if true, some methods will return the estimation error.

Returns

  • V::Matrix{Float} : velocity components due to the jth and j+1th nodes in the format: [vz_j vr_j; vz_{j+1} vr_{j+1}]
source
DuctAPE.nominal_vortex_panel_integration!Function
nominal_vortex_panel_integration!(
     integration_options,
     V,
     node1,
@@ -347,7 +347,7 @@
     controlpoint,
     containers;
     debug=false,
-)

In-place version of nominal_vortex_panel_integration.

source
DuctAPE.self_vortex_panel_integrationFunction
self_vortex_panel_integration(
+)

In-place version of nominal_vortex_panel_integration.

source
DuctAPE.self_vortex_panel_integrationFunction
self_vortex_panel_integration(
     integration_options,
     node1,
     node2,
@@ -355,7 +355,7 @@
     controlpoint,
     containers;
     debug=false,
-)

Integration of linear vortex panel self-induced velocity.

Arguments

  • integration_options::IntegrationMethod : options for itegration methods
  • node1::Vector{Float} : first panel node (edge) position.
  • node2::Vector{Float} : second panel node (edge) position.
  • influence_length::Float : dimensional length of panel.
  • controlpoint::Vector{Float} : controlpoint position
  • containers::NamedTuple : cache for intermediate calculations

Keyword Arguments

  • debug::Bool=false : if true, some methods will return the estimation error.

Returns

  • V::Matrix{Float} : velocity components due to the jth and j+1th nodes in the format: [vz_j vr_j; vz_{j+1} vr_{j+1}]
source
DuctAPE.self_vortex_panel_integration!Function
self_vortex_panel_integration!(
+)

Integration of linear vortex panel self-induced velocity.

Arguments

  • integration_options::IntegrationMethod : options for itegration methods
  • node1::Vector{Float} : first panel node (edge) position.
  • node2::Vector{Float} : second panel node (edge) position.
  • influence_length::Float : dimensional length of panel.
  • controlpoint::Vector{Float} : controlpoint position
  • containers::NamedTuple : cache for intermediate calculations

Keyword Arguments

  • debug::Bool=false : if true, some methods will return the estimation error.

Returns

  • V::Matrix{Float} : velocity components due to the jth and j+1th nodes in the format: [vz_j vr_j; vz_{j+1} vr_{j+1}]
source
DuctAPE.self_vortex_panel_integration!Function
self_vortex_panel_integration!(
     integration_options,
     V,
     node1,
@@ -364,7 +364,7 @@
     controlpoint,
     containers;
     debug=false,
-)

In-place version of self_vortex_panel_integration.

source
DuctAPE.nominal_source_panel_integrationFunction
nominal_source_panel_integration(
+)

In-place version of self_vortex_panel_integration.

source
DuctAPE.nominal_source_panel_integrationFunction
nominal_source_panel_integration(
     integration_options,
     node1,
     node2,
@@ -372,7 +372,7 @@
     controlpoint,
     containers;
     debug=false,
-)

Integration of source panel induced velocity on a point far away.

Arguments

  • integration_options::IntegrationMethod : options for itegration methods
  • node1::Vector{Float} : first panel node (edge) position.
  • node2::Vector{Float} : second panel node (edge) position.
  • influence_length::Float : dimensional length of panel.
  • controlpoint::Vector{Float} : controlpoint position
  • containers::NamedTuple : cache for intermediate calculations

Keyword Arguments

  • debug::Bool=false : if true, some methods will return the estimation error.

Returns

  • V::Matrix{Float} : velocity components due to the jth and j+1th nodes in the format: [vz_j vr_j; vz_{j+1} vr_{j+1}]
source
DuctAPE.nominal_source_panel_integration!Function
nominal_source_panel_integration!(
+)

Integration of source panel induced velocity on a point far away.

Arguments

  • integration_options::IntegrationMethod : options for itegration methods
  • node1::Vector{Float} : first panel node (edge) position.
  • node2::Vector{Float} : second panel node (edge) position.
  • influence_length::Float : dimensional length of panel.
  • controlpoint::Vector{Float} : controlpoint position
  • containers::NamedTuple : cache for intermediate calculations

Keyword Arguments

  • debug::Bool=false : if true, some methods will return the estimation error.

Returns

  • V::Matrix{Float} : velocity components due to the jth and j+1th nodes in the format: [vz_j vr_j; vz_{j+1} vr_{j+1}]
source
DuctAPE.nominal_source_panel_integration!Function
nominal_source_panel_integration!(
     integration_options,
     V,
     node1,
@@ -381,7 +381,7 @@
     controlpoint,
     containers;
     debug=false,
-)

In-place version of nominal_source_panel_integration.

source
DuctAPE.self_source_panel_integrationFunction
self_source_panel_integration(
+)

In-place version of nominal_source_panel_integration.

source
DuctAPE.self_source_panel_integrationFunction
self_source_panel_integration(
     integration_options,
     node1,
     node2,
@@ -389,7 +389,7 @@
     controlpoint,
     containers;
     debug=false,
-)

Integration of linear source panel self-induced velocity.

Arguments

  • integration_options::IntegrationMethod : options for itegration methods
  • node1::Vector{Float} : first panel node (edge) position.
  • node2::Vector{Float} : second panel node (edge) position.
  • influence_length::Float : dimensional length of panel.
  • controlpoint::Vector{Float} : controlpoint position
  • containers::NamedTuple : cache for intermediate calculations

Keyword Arguments

  • debug::Bool=false : if true, some methods will return the estimation error.

Returns

  • V::Matrix{Float} : velocity components due to the jth and j+1th nodes in the format: [vz_j vr_j; vz_{j+1} vr_{j+1}]
source
DuctAPE.self_source_panel_integration!Function
self_source_panel_integration!(
+)

Integration of linear source panel self-induced velocity.

Arguments

  • integration_options::IntegrationMethod : options for itegration methods
  • node1::Vector{Float} : first panel node (edge) position.
  • node2::Vector{Float} : second panel node (edge) position.
  • influence_length::Float : dimensional length of panel.
  • controlpoint::Vector{Float} : controlpoint position
  • containers::NamedTuple : cache for intermediate calculations

Keyword Arguments

  • debug::Bool=false : if true, some methods will return the estimation error.

Returns

  • V::Matrix{Float} : velocity components due to the jth and j+1th nodes in the format: [vz_j vr_j; vz_{j+1} vr_{j+1}]
source
DuctAPE.self_source_panel_integration!Function
self_source_panel_integration!(
     integration_options,
     V,
     node1,
@@ -398,7 +398,7 @@
     controlpoint,
     containers;
     debug=false,
-)

In-place version of self_source_panel_integration.

source
DuctAPE.extrapolate!Function
extrapolate!(V, err, fh; power=2, atol=1e-6)

Performs Richardson extrapolation on an array fh for use in Romberg integration.

Arguments

  • V::Matrix{Float} : velocity components due to the jth and j+1th nodes in the format: [vz_j vr_j; vz_{j+1} vr_{j+1}]
  • err::Vector{Float} : estimated errors in velocity approximation
  • fh::Tuple : (f(h), h) tuples (in order of decreasing |h|)
source

State Initialization

DuctAPE.initialize_velocitiesFunction
initialize_velocities(
+)

In-place version of self_source_panel_integration.

source
DuctAPE.extrapolate!Function
extrapolate!(V, err, fh; power=2, atol=1e-6)

Performs Richardson extrapolation on an array fh for use in Romberg integration.

Arguments

  • V::Matrix{Float} : velocity components due to the jth and j+1th nodes in the format: [vz_j vr_j; vz_{j+1} vr_{j+1}]
  • err::Vector{Float} : estimated errors in velocity approximation
  • fh::Tuple : (f(h), h) tuples (in order of decreasing |h|)
source

State Initialization

DuctAPE.initialize_velocitiesFunction
initialize_velocities(
     solver_options::SolverOptionsType,
     operating_point,
     blade_elements,
@@ -407,7 +407,7 @@
     ivw,
     body_totnodes,
     wake_panel_sheet_be_map,
-)

Initialize velocity state variables.

Arguments

  • solver_options::SolverOptionsType : solver options type for dispatch
  • operating_point::OperatingPoint : an OperatingPoint object
  • blade_elements::NamedTuple : A named tuple containing the blade element geometry and airfoil information.
  • linsys::NamedTuple : A named tuple containing the panel method linear system information.
  • ivr::NamedTuple : A named tuple containing the unit induced velocities on the rotors
  • ivw::NamedTuple : A named tuple containing the unit induced velocities on the wake
  • body_totnodes::Int : the total number of panel nodes comprising the duct and centerbody geometry
  • wake_panel_sheet_be_map::Matrix{Int} : An index map from the wake panels to the nearest ahead rotor blade element along the wake sheets

Returns

  • vz_rotor::Vector{Float} : a vector of the velocity state variables associated with the rotor axially induced velocity
  • vtheta_rotor::Vector{Float} : a vector of the velocity state variables associated with the rotor tangentially induced velocity
  • Cm_wake::Vector{Float} : a vector of the velocity state variables associated with the wake control point meridional velocity
source
DuctAPE.initialize_velocities!Function

function initializevelocities!( solveroptions::SolverOptionsType, vzrotor, vthetarotor, Cmwake, operatingpoint, bladeelements, linsys, ivr, ivw, bodytotnodes, wakepanelsheetbemap, )

In-place version of initialize_velocities.

source
DuctAPE.initialize_strengths!Function
initialize_strengths!(
+)

Initialize velocity state variables.

Arguments

  • solver_options::SolverOptionsType : solver options type for dispatch
  • operating_point::OperatingPoint : an OperatingPoint object
  • blade_elements::NamedTuple : A named tuple containing the blade element geometry and airfoil information.
  • linsys::NamedTuple : A named tuple containing the panel method linear system information.
  • ivr::NamedTuple : A named tuple containing the unit induced velocities on the rotors
  • ivw::NamedTuple : A named tuple containing the unit induced velocities on the wake
  • body_totnodes::Int : the total number of panel nodes comprising the duct and centerbody geometry
  • wake_panel_sheet_be_map::Matrix{Int} : An index map from the wake panels to the nearest ahead rotor blade element along the wake sheets

Returns

  • vz_rotor::Vector{Float} : a vector of the velocity state variables associated with the rotor axially induced velocity
  • vtheta_rotor::Vector{Float} : a vector of the velocity state variables associated with the rotor tangentially induced velocity
  • Cm_wake::Vector{Float} : a vector of the velocity state variables associated with the wake control point meridional velocity
source
DuctAPE.initialize_velocities!Function

function initializevelocities!( solveroptions::SolverOptionsType, vzrotor, vthetarotor, Cmwake, operatingpoint, bladeelements, linsys, ivr, ivw, bodytotnodes, wakepanelsheetbemap, )

In-place version of initialize_velocities.

source
DuctAPE.initialize_strengths!Function
initialize_strengths!(
     solver_options::SolverOptionsType,
     Gamr,
     sigr,
@@ -425,7 +425,7 @@
     wake_node_sheet_be_map,
     wake_node_ids_along_casing_wake_interface,
     wake_node_ids_along_centerbody_wake_interface,
-)

Initialize strength state variables.

Arguments

  • solver_options::SolverOptionsType : solver options type for dispatch
  • Gamr::Vector{Float} : Rotor circulation state variables (modified in place)
  • sigr::Vector{Float} : Rotor panel strength state variables (modified in place)
  • gamw::Vector{Float} : Wake panel strength state variables (modified in place)
  • operating_point::OperatingPoint : an OperatingPoint object
  • blade_elements::NamedTuple : A named tuple containing the blade element geometry and airfoil information.
  • linsys::NamedTuple : A named tuple containing the panel method linear system information.
  • ivr::NamedTuple : A named tuple containing the unit induced velocities on the rotors
  • ivw::NamedTuple : A named tuple containing the unit induced velocities on the wake
  • wakeK::Vector{Float} : geometric constants of wake nodes used in calculating wake strengths
  • body_totnodes::Int : the total number of panel nodes comprising the duct and centerbody geometry
  • wake_nodemap::Matrix{Int} : an index map of wake panel to the associated node indices
  • wake_endnodeidxs::Matrix{Int} : the node indices of the start and end of the wake sheets.
  • wake_panel_sheet_be_map::Matrix{Int} : An index map from the wake panels to the nearest ahead rotor blade element along the wake sheets
  • wake_node_sheet_be_map::Matrix{Int} : An index map from the wake nodes to the nearest ahead rotor blade element along the wake sheets
  • wake_node_ids_along_casing_wake_interface::type : An index map indicating which wake nodes interface with the duct wall
  • wake_node_ids_along_centerbody_wake_interface::type : An index map indicating which wake nodes interface with the centerbody wall
source
function initialize_strengths!(
+)

Initialize strength state variables.

Arguments

  • solver_options::SolverOptionsType : solver options type for dispatch
  • Gamr::Vector{Float} : Rotor circulation state variables (modified in place)
  • sigr::Vector{Float} : Rotor panel strength state variables (modified in place)
  • gamw::Vector{Float} : Wake panel strength state variables (modified in place)
  • operating_point::OperatingPoint : an OperatingPoint object
  • blade_elements::NamedTuple : A named tuple containing the blade element geometry and airfoil information.
  • linsys::NamedTuple : A named tuple containing the panel method linear system information.
  • ivr::NamedTuple : A named tuple containing the unit induced velocities on the rotors
  • ivw::NamedTuple : A named tuple containing the unit induced velocities on the wake
  • wakeK::Vector{Float} : geometric constants of wake nodes used in calculating wake strengths
  • body_totnodes::Int : the total number of panel nodes comprising the duct and centerbody geometry
  • wake_nodemap::Matrix{Int} : an index map of wake panel to the associated node indices
  • wake_endnodeidxs::Matrix{Int} : the node indices of the start and end of the wake sheets.
  • wake_panel_sheet_be_map::Matrix{Int} : An index map from the wake panels to the nearest ahead rotor blade element along the wake sheets
  • wake_node_sheet_be_map::Matrix{Int} : An index map from the wake nodes to the nearest ahead rotor blade element along the wake sheets
  • wake_node_ids_along_casing_wake_interface::type : An index map indicating which wake nodes interface with the duct wall
  • wake_node_ids_along_centerbody_wake_interface::type : An index map indicating which wake nodes interface with the centerbody wall
source
function initialize_strengths!(
     solver_options::CSORSolverOptions,
     Gamr,
     sigr,
@@ -442,4 +442,4 @@
     wake_node_ids_along_centerbody_wake_interface;
     niter=10,
     rlx=0.5,
-)

Refactored from DFDC SUBROUTINE ROTINITBLD

From the subroutine notes: Sets reasonable initial circulation using current rotor blade geometry (chord, beta). Initial circulations are set w/o induced effects An iteration is done using the self-induced velocity from momentum theory to converge an approximate induced axial velocity

Arguments

  • solver_options::SolverOptionsType : solver options type for dispatch
  • Gamr::Vector{Float} : Rotor circulation state variables (modified in place)
  • sigr::Vector{Float} : Rotor panel strength state variables (modified in place)
  • gamw::Vector{Float} : Wake panel strength state variables (modified in place)
  • operating_point::OperatingPoint : an OperatingPoint object
  • blade_elements::NamedTuple : A named tuple containing the blade element geometry and airfoil information.
  • wakeK::Vector{Float} : geometric constants of wake nodes used in calculating wake strengths
  • wake_nodemap::Matrix{Int} : an index map of wake panel to the associated node indices
  • wake_endnodeidxs::Matrix{Int} : the node indices of the start and end of the wake sheets.
  • wake_panel_sheet_be_map::Matrix{Int} : An index map from the wake panels to the nearest ahead rotor blade element along the wake sheets
  • wake_node_sheet_be_map::Matrix{Int} : An index map from the wake nodes to the nearest ahead rotor blade element along the wake sheets
  • wake_node_ids_along_casing_wake_interface::type : An index map indicating which wake nodes interface with the duct wall
  • wake_node_ids_along_centerbody_wake_interface::type : An index map indicating which wake nodes interface with the centerbody wall

Keyword Arguments

  • rlx::Float=0.5 : factor for under-relaxation to reduce transients in CL

Returns

source
+)

Refactored from DFDC SUBROUTINE ROTINITBLD

From the subroutine notes: Sets reasonable initial circulation using current rotor blade geometry (chord, beta). Initial circulations are set w/o induced effects An iteration is done using the self-induced velocity from momentum theory to converge an approximate induced axial velocity

Arguments

Keyword Arguments

Returns

source diff --git a/dev/DuctAPE/api/private_process/index.html b/dev/DuctAPE/api/private_process/index.html index 86a348d5..98535b11 100644 --- a/dev/DuctAPE/api/private_process/index.html +++ b/dev/DuctAPE/api/private_process/index.html @@ -12,7 +12,7 @@ options::Options; solve_container_caching=nothing, return_inputs=false, -)

Identical to the single analyze function assuming setup_analysis has been called; except here we are running a single operating point for a multipoint analysis, and overwriting the operating point in the propulsor with the explicit operating point input.

source

Process

DuctAPE.processFunction
process(
+)

Identical to the single analyze function assuming setup_analysis has been called; except here we are running a single operating point for a multipoint analysis, and overwriting the operating point in the propulsor with the explicit operating point input.

source

Process

DuctAPE.processFunction
process(
     solver_options::SolverOptionsType,
     solve_parameter_cache_vector,
     solve_parameter_cache_dims,
@@ -21,12 +21,12 @@
     solve_container_caching,
     idmaps,
     options,
-)

Process (the step between pre-process and post-process) the solution, in other words: call the solver(s).

Arguments

  • solver_options::SolverOptionsType : the solver options contained in the options object, used for dispatch.
  • solve_parameter_cache_vector::Vector{Float} : The vector cache for parameters used in the solve.
  • solve_parameter_cache_dims::NamedTuple : A named tuple containing the dimensions of the solve parameters.
  • airfoils::NamedTuple : The airfoils to be interpolated that are associated with each blade element
  • A_bb_LU::LinearAlgebra.LU : The LU decomposition of the panel method LHS matrix
  • solve_container_caching::NamedTuple : A named tuple containing the cache and dimensions for the intermediate solve values.
  • idmaps::NamedTuple : The set of index maps used in various solve sub-functions
  • options::Options : User options

Returns

  • converged_states::Vector{Float} : The output of a call to ImplicitAD.implicit
source
DuctAPE.solveFunction
solve(sensitivity_parameters, const_cache; initial_guess=nothing)

A compact dispatch of solve that automatically dispatches based on the solveroptions contained in constcache.

source
solve(
+)

Process (the step between pre-process and post-process) the solution, in other words: call the solver(s).

Arguments

  • solver_options::SolverOptionsType : the solver options contained in the options object, used for dispatch.
  • solve_parameter_cache_vector::Vector{Float} : The vector cache for parameters used in the solve.
  • solve_parameter_cache_dims::NamedTuple : A named tuple containing the dimensions of the solve parameters.
  • airfoils::NamedTuple : The airfoils to be interpolated that are associated with each blade element
  • A_bb_LU::LinearAlgebra.LU : The LU decomposition of the panel method LHS matrix
  • solve_container_caching::NamedTuple : A named tuple containing the cache and dimensions for the intermediate solve values.
  • idmaps::NamedTuple : The set of index maps used in various solve sub-functions
  • options::Options : User options

Returns

  • converged_states::Vector{Float} : The output of a call to ImplicitAD.implicit
source
DuctAPE.solveFunction
solve(sensitivity_parameters, const_cache; initial_guess=nothing)

A compact dispatch of solve that automatically dispatches based on the solveroptions contained in constcache.

source
solve(
     solver_options::SolverOptionsType,
     sensitivity_parameters,
     const_cache;
     initial_guess=nothing,
-)

Converge the residual, solving for the state variables that do so.

Arguments

  • solver_options::SolverOptionsType : SolverOptionsType used for dispatch
  • sensitivity_parameters::Vector{Float} : Sensitivity parameters for solve (parameters passed in through ImplicitAD)
  • const_cache::NamedTuple : A named tuple containing constants and caching helpers.

Keyword Arguments

  • initial_guess=nothing::Vector{Float} : An optional manually provided initial guess (contained in the sensitivity parameters anyway).

Returns

  • converged_states::Vector{Float} : the states for which the residual has converged.
source

Residuals

CSOR
DuctAPE.CSOR_residual!Function
CSOR_residual!(resid, state_variables, sensitivity_parameters, constants)

The in-place residual used for the CSOR solve method.

Arguments

  • resid::Vector{Float} : In-place residual.
  • state_variables::Vector{Float} : The state variables
  • sensitivity_parameters::Vector{Float} : The parameters to which the solution is sensitive.
  • constants::NamedTuple : Various constants required in the solve

Returns

  • state_variables::Vector{Float} : The state variables (modified in place)
source
DuctAPE.compute_CSOR_residual!Function
compute_CSOR_residual!(
+)

Converge the residual, solving for the state variables that do so.

Arguments

  • solver_options::SolverOptionsType : SolverOptionsType used for dispatch
  • sensitivity_parameters::Vector{Float} : Sensitivity parameters for solve (parameters passed in through ImplicitAD)
  • const_cache::NamedTuple : A named tuple containing constants and caching helpers.

Keyword Arguments

  • initial_guess=nothing::Vector{Float} : An optional manually provided initial guess (contained in the sensitivity parameters anyway).

Returns

  • converged_states::Vector{Float} : the states for which the residual has converged.
source

Residuals

CSOR
DuctAPE.CSOR_residual!Function
CSOR_residual!(resid, state_variables, sensitivity_parameters, constants)

The in-place residual used for the CSOR solve method.

Arguments

  • resid::Vector{Float} : In-place residual.
  • state_variables::Vector{Float} : The state variables
  • sensitivity_parameters::Vector{Float} : The parameters to which the solution is sensitive.
  • constants::NamedTuple : Various constants required in the solve

Returns

  • state_variables::Vector{Float} : The state variables (modified in place)
source
DuctAPE.compute_CSOR_residual!Function
compute_CSOR_residual!(
     resid,
     solver_options,
     solve_containers,
@@ -41,7 +41,7 @@
     wakeK,
     idmaps;
     verbose=false,
-)

Description

Arguments

  • resid::Vector{Float} : the residual vector
  • solver_options::SolverOptionsType : solver options (used for convergence criteria)
  • solve_containers::NamedTuple : cache for intermediate solve values
  • Gamr::type : Blade element circulation strengths
  • sigr::type : Rotor source panel strengths
  • gamw::type : Wake vortex panel strengths
  • operating_point::NamedTuple : Named tuple containing operating_point information
  • ivr::NamedTuple : unit induced velocities on rotor(s)
  • ivw::NamedTuple : unit induced velocities on wake
  • linsys::NamedTuple : vectors and matricies comprising the panel method linear system
  • blade_elements::NamedTuple : blade element geometry and airfoil polar information
  • wakeK::Vector{Float} : geometric constants used in caculating wake strengths
  • idmaps::NamedTuple : index maps used throughout solve

Keyword Arguments

  • verbose::Bool=false : Flag to print verbose statements
source
compute_CSOR_residual!(
+)

Description

Arguments

  • resid::Vector{Float} : the residual vector
  • solver_options::SolverOptionsType : solver options (used for convergence criteria)
  • solve_containers::NamedTuple : cache for intermediate solve values
  • Gamr::type : Blade element circulation strengths
  • sigr::type : Rotor source panel strengths
  • gamw::type : Wake vortex panel strengths
  • operating_point::NamedTuple : Named tuple containing operating_point information
  • ivr::NamedTuple : unit induced velocities on rotor(s)
  • ivw::NamedTuple : unit induced velocities on wake
  • linsys::NamedTuple : vectors and matricies comprising the panel method linear system
  • blade_elements::NamedTuple : blade element geometry and airfoil polar information
  • wakeK::Vector{Float} : geometric constants used in caculating wake strengths
  • idmaps::NamedTuple : index maps used throughout solve

Keyword Arguments

  • verbose::Bool=false : Flag to print verbose statements
source
compute_CSOR_residual!(
     resid,
     solver_options,
     solve_containers,
@@ -56,7 +56,7 @@
     wakeK,
     idmaps;
     verbose=false,
-)

Description

Arguments

  • resid::Vector{Float} : the residual vector
  • solver_options::SolverOptionsType : solver options (used for convergence criteria)
  • solve_containers::NamedTuple : cache for intermediate solve values
  • Gamr::type : Blade element circulation strengths
  • sigr::type : Rotor source panel strengths
  • gamw::type : Wake vortex panel strengths
  • operating_point::NamedTuple : Named tuple containing operating_point information
  • ivr::NamedTuple : unit induced velocities on rotor(s)
  • ivw::NamedTuple : unit induced velocities on wake
  • linsys::NamedTuple : vectors and matricies comprising the panel method linear system
  • blade_elements::NamedTuple : blade element geometry and airfoil polar information
  • wakeK::Vector{Float} : geometric constants used in caculating wake strengths
  • idmaps::NamedTuple : index maps used throughout solve

Keyword Arguments

  • verbose::Bool=false : Flag to print verbose statements
source
DuctAPE.relax_Gamr!Function
relax_Gamr!(
+)

Description

Arguments

  • resid::Vector{Float} : the residual vector
  • solver_options::SolverOptionsType : solver options (used for convergence criteria)
  • solve_containers::NamedTuple : cache for intermediate solve values
  • Gamr::type : Blade element circulation strengths
  • sigr::type : Rotor source panel strengths
  • gamw::type : Wake vortex panel strengths
  • operating_point::NamedTuple : Named tuple containing operating_point information
  • ivr::NamedTuple : unit induced velocities on rotor(s)
  • ivw::NamedTuple : unit induced velocities on wake
  • linsys::NamedTuple : vectors and matricies comprising the panel method linear system
  • blade_elements::NamedTuple : blade element geometry and airfoil polar information
  • wakeK::Vector{Float} : geometric constants used in caculating wake strengths
  • idmaps::NamedTuple : index maps used throughout solve

Keyword Arguments

  • verbose::Bool=false : Flag to print verbose statements
source
DuctAPE.relax_Gamr!Function
relax_Gamr!(
     Gamr,
     delta_prev_mat,
     delta_mat,
@@ -69,7 +69,7 @@
     pf1=0.4,
     pf2=0.5,
     test=false,
-)

Apply relaxed step to Gamr.

Arguments

  • Gamr::Array{Float} : Array of rotor circulations (columns = rotors, rows = blade elements), updated in place
  • delta_prev_mat::Array{Float} : Array of previous iteration's differences in circulation values, updated in place
  • delta_mat::Array{Float} : Array of current iteration's differences in circulation values
  • B::Vector{Float} : number of blades on each rotor
  • nrf::Float=0.4 : nominal relaxation factor
  • bt1::Float=0.2 : backtrack factor 1
  • bt2::Float=0.6 : backtrack factor 2
  • pf1::Float=0.4 : press forward factor 1
  • pf2::Float=0.5 : press forward factor 2
source
relax_Gamr!(
+)

Apply relaxed step to Gamr.

Arguments

  • Gamr::Array{Float} : Array of rotor circulations (columns = rotors, rows = blade elements), updated in place
  • delta_prev_mat::Array{Float} : Array of previous iteration's differences in circulation values, updated in place
  • delta_mat::Array{Float} : Array of current iteration's differences in circulation values
  • B::Vector{Float} : number of blades on each rotor
  • nrf::Float=0.4 : nominal relaxation factor
  • bt1::Float=0.2 : backtrack factor 1
  • bt2::Float=0.6 : backtrack factor 2
  • pf1::Float=0.4 : press forward factor 1
  • pf2::Float=0.5 : press forward factor 2
source
relax_Gamr!(
     Gamr,
     delta_prev_mat,
     delta_mat,
@@ -81,17 +81,17 @@
     pf1=0.4,
     pf2=0.5,
     test=false,
-)

Apply relaxed step to Gamr.

Arguments

  • Gamr::Array{Float} : Array of rotor circulations (columns = rotors, rows = blade elements), updated in place
  • delta_prev_mat::Array{Float} : Array of previous iteration's differences in circulation values, updated in place
  • delta_mat::Array{Float} : Array of current iteration's differences in circulation values
  • B::Vector{Float} : number of blades on each rotor
  • nrf::Float=0.4 : nominal relaxation factor
  • bt1::Float=0.2 : backtrack factor 1
  • bt2::Float=0.6 : backtrack factor 2
  • pf1::Float=0.4 : press forward factor 1
  • pf2::Float=0.5 : press forward factor 2
source
DuctAPE.relax_gamw!Function
relax_gamw!(
+)

Apply relaxed step to Gamr.

Arguments

  • Gamr::Array{Float} : Array of rotor circulations (columns = rotors, rows = blade elements), updated in place
  • delta_prev_mat::Array{Float} : Array of previous iteration's differences in circulation values, updated in place
  • delta_mat::Array{Float} : Array of current iteration's differences in circulation values
  • B::Vector{Float} : number of blades on each rotor
  • nrf::Float=0.4 : nominal relaxation factor
  • bt1::Float=0.2 : backtrack factor 1
  • bt2::Float=0.6 : backtrack factor 2
  • pf1::Float=0.4 : press forward factor 1
  • pf2::Float=0.5 : press forward factor 2
source
DuctAPE.relax_gamw!Function
relax_gamw!(
     gamw, delta_prev, delta, maxdeltagamw; nrf=0.4, btw=0.6, pfw=1.2, test=false
-)

Apply relaxed step to gamw.

Arguments

  • gamw::Array{Float} : Array of rotor circulations (columns = rotors, rows = blade elements), updated in place
  • delta_prev_mat::Array{Float} : Array of previous iteration's differences in circulation values, updated in place
  • delta_mat::Array{Float} : Array of current iteration's differences in circulation values
  • B::Vector{Float} : number of blades on each rotor
  • nrf::Float=0.4 : nominal relaxation factor
  • bt1::Float=0.2 : backtrack factor 1
  • bt2::Float=0.6 : backtrack factor 2
  • pf1::Float=0.4 : press forward factor 1
  • pf2::Float=0.5 : press forward factor 2
source
relax_gamw!(
+)

Apply relaxed step to gamw.

Arguments

  • gamw::Array{Float} : Array of rotor circulations (columns = rotors, rows = blade elements), updated in place
  • delta_prev_mat::Array{Float} : Array of previous iteration's differences in circulation values, updated in place
  • delta_mat::Array{Float} : Array of current iteration's differences in circulation values
  • B::Vector{Float} : number of blades on each rotor
  • nrf::Float=0.4 : nominal relaxation factor
  • bt1::Float=0.2 : backtrack factor 1
  • bt2::Float=0.6 : backtrack factor 2
  • pf1::Float=0.4 : press forward factor 1
  • pf2::Float=0.5 : press forward factor 2
source
relax_gamw!(
     gamw, delta_prev, delta; nrf=0.4, btw=0.6, pfw=1.2, test=false
-)

Apply relaxed step to gamw.

Arguments

  • gamw::Array{Float} : Array of rotor circulations (columns = rotors, rows = blade elements), updated in place
  • delta_prev_mat::Array{Float} : Array of previous iteration's differences in circulation values, updated in place
  • delta_mat::Array{Float} : Array of current iteration's differences in circulation values
  • B::Vector{Float} : number of blades on each rotor
  • nrf::Float=0.4 : nominal relaxation factor
  • bt1::Float=0.2 : backtrack factor 1
  • bt2::Float=0.6 : backtrack factor 2
  • pf1::Float=0.4 : press forward factor 1
  • pf2::Float=0.5 : press forward factor 2
source
DuctAPE.apply_relaxation_scheduleFunction
apply_relaxation_schedule(
+)

Apply relaxed step to gamw.

Arguments

  • gamw::Array{Float} : Array of rotor circulations (columns = rotors, rows = blade elements), updated in place
  • delta_prev_mat::Array{Float} : Array of previous iteration's differences in circulation values, updated in place
  • delta_mat::Array{Float} : Array of current iteration's differences in circulation values
  • B::Vector{Float} : number of blades on each rotor
  • nrf::Float=0.4 : nominal relaxation factor
  • bt1::Float=0.2 : backtrack factor 1
  • bt2::Float=0.6 : backtrack factor 2
  • pf1::Float=0.4 : press forward factor 1
  • pf2::Float=0.5 : press forward factor 2
source
DuctAPE.apply_relaxation_scheduleFunction
apply_relaxation_schedule(
     resid::AbstractVector, solver_options::TS
-) where {TS<:SolverOptionsType}

Apply custom relaxation schedule to all relaxation factor inputs based on residual values.

Arguments

  • resid::AbstractVector{Float} : current residual values
  • solver_options::SolverOptionsType : SolverOptions containing relaxation schedule

Returns

  • nrf::Float : nominal relaxation factor
  • bt1::Float : backtrack factor 1
  • bt2::Float : backtrack factor 2
  • pf1::Float : press forward factor 1
  • pf2::Float : press forward factor 2
source
apply_relaxation_schedule(resid, nominal, schedule)

Apply custom relaxation schedule to a single relaxation factor input.

Arguments

  • resid::Float : residual value
  • nominal::Float : nominal relaxation value
  • schedule::AbstractVector{AbstractVector{Float}} : values between which to interpolate to scale the nominal relaxation value.

Returns

  • rf::Float : the updated relaxation factor
source
DuctAPE.update_CSOR_residual_values!Function
update_CSOR_residual_values!(
+) where {TS<:SolverOptionsType}

Apply custom relaxation schedule to all relaxation factor inputs based on residual values.

Arguments

  • resid::AbstractVector{Float} : current residual values
  • solver_options::SolverOptionsType : SolverOptions containing relaxation schedule

Returns

  • nrf::Float : nominal relaxation factor
  • bt1::Float : backtrack factor 1
  • bt2::Float : backtrack factor 2
  • pf1::Float : press forward factor 1
  • pf2::Float : press forward factor 2
source
apply_relaxation_schedule(resid, nominal, schedule)

Apply custom relaxation schedule to a single relaxation factor input.

Arguments

  • resid::Float : residual value
  • nominal::Float : nominal relaxation value
  • schedule::AbstractVector{AbstractVector{Float}} : values between which to interpolate to scale the nominal relaxation value.

Returns

  • rf::Float : the updated relaxation factor
source
DuctAPE.update_CSOR_residual_values!Function
update_CSOR_residual_values!(
     convergence_type::ConvergenceType, resid, maxBGamr, maxdeltaBGamr, maxdeltagamw, Vconv
-)

Update CSOR residual values in place.

Arguments

  • convergence_type::ConvergenceType : used for dispatch of relative or absolute residual values.
  • resid::Vector{Float} : residual values modified in place
  • maxBGamr::Float : Maximum value of B*Gamr among all blade elements
  • maxdeltaBGamr::Float : Maximum change in B*Gamr between iterations among all blade elements
  • maxdeltagamw::Vector{Float} : Maximum change in gamw among all wake nodes (one element)
  • Vconv::Float : Reference velocity upon which the relative convergence criteria is based (one element)
source
DuctAPE.check_CSOR_convergence!Function
check_CSOR_convergence!(
+)

Update CSOR residual values in place.

Arguments

  • convergence_type::ConvergenceType : used for dispatch of relative or absolute residual values.
  • resid::Vector{Float} : residual values modified in place
  • maxBGamr::Float : Maximum value of B*Gamr among all blade elements
  • maxdeltaBGamr::Float : Maximum change in B*Gamr between iterations among all blade elements
  • maxdeltagamw::Vector{Float} : Maximum change in gamw among all wake nodes (one element)
  • Vconv::Float : Reference velocity upon which the relative convergence criteria is based (one element)
source
DuctAPE.check_CSOR_convergence!Function
check_CSOR_convergence!(
     conv, resid; f_circ=1e-3, f_dgamw=2e-4, convergence_type=Relative(), verbose=false
-)

Description

Arguments

  • conv::Vector{Float} : container holding convergence flag
  • resid::Vector{Float} : residual vector

Keyword Arguments

  • f_circ::Float=1e-3 : convergence criteria for circulation residual
  • f_dgamw::Float=2e-4 : convergence criteria for wake strength residual
  • convergence_type::ConvergenceType=Relative() : convergence type (absolute or relative) for print statements
  • verbose::Bool=false : flag for verbose print statements
source
External Solvers
DuctAPE.system_residualFunction
system_residual(state_variables, sensitivity_parameters, constants)

The residual function for external solvers.

Arguments

  • state_variables::Vector{Float} : the state variables
  • sensitivity_parameters::Vector{Float} : parameters to which the solution derivatives are sensitive
  • constants::NamedTuple : parameters to which the solution derivatives are constant

Returs

  • resid::Vector{Float} : residual vector
source
DuctAPE.system_residual!Function
system_residual!(resid, state_variables, sensitivity_parameters, constants)

In-place version of system_residual.

source
DuctAPE.update_system_residual!Function
update_system_residual!(
+)

Description

Arguments

  • conv::Vector{Float} : container holding convergence flag
  • resid::Vector{Float} : residual vector

Keyword Arguments

  • f_circ::Float=1e-3 : convergence criteria for circulation residual
  • f_dgamw::Float=2e-4 : convergence criteria for wake strength residual
  • convergence_type::ConvergenceType=Relative() : convergence type (absolute or relative) for print statements
  • verbose::Bool=false : flag for verbose print statements
source
External Solvers
DuctAPE.system_residualFunction
system_residual(state_variables, sensitivity_parameters, constants)

The residual function for external solvers.

Arguments

  • state_variables::Vector{Float} : the state variables
  • sensitivity_parameters::Vector{Float} : parameters to which the solution derivatives are sensitive
  • constants::NamedTuple : parameters to which the solution derivatives are constant

Returs

  • resid::Vector{Float} : residual vector
source
DuctAPE.system_residual!Function
system_residual!(resid, state_variables, sensitivity_parameters, constants)

In-place version of system_residual.

source
DuctAPE.update_system_residual!Function
update_system_residual!(
     solver_options::SolverOptionsType
     resid,
     vz_est,
@@ -101,7 +101,7 @@
     Cm_est,
     Cm_wake,
     solve_parameter_cache_dims,
-)

Update the residual for external solvers.

Arguments

  • `solver_options::SolverOptionsType
  • resid::Vector{Float} : residual vector
  • vz_est::Vector{Float} : axial induced rotor velocity estimate container
  • vz_rotor::Vector{Float} : axial induced rotor velocity state container
  • vtheta_est::Vector{Float} : tangential induced rotor velocity estimate container
  • vtheta_rotor::Vector{Float} : tangential induced rotor velocity state container
  • Cm_est::Vector{Float} : absolute meridional wake control point velocity estimate container
  • Cm_wake::Vector{Float} : absolute meridional wake control point velocity state container
  • solve_parameter_cache_dims::Vector{Float} : dimensions of state vectors to use in accessing the residual vector
source
DuctAPE.estimate_states!Function
estimate_states!(
+)

Update the residual for external solvers.

Arguments

  • `solver_options::SolverOptionsType
  • resid::Vector{Float} : residual vector
  • vz_est::Vector{Float} : axial induced rotor velocity estimate container
  • vz_rotor::Vector{Float} : axial induced rotor velocity state container
  • vtheta_est::Vector{Float} : tangential induced rotor velocity estimate container
  • vtheta_rotor::Vector{Float} : tangential induced rotor velocity state container
  • Cm_est::Vector{Float} : absolute meridional wake control point velocity estimate container
  • Cm_wake::Vector{Float} : absolute meridional wake control point velocity state container
  • solve_parameter_cache_dims::Vector{Float} : dimensions of state vectors to use in accessing the residual vector
source
DuctAPE.estimate_states!Function
estimate_states!(
     solve_containers,
     vz_rotor,
     vtheta_rotor,
@@ -114,6 +114,6 @@
     wakeK,
     idmaps;
     verbose=false,
-)

Estimate velocity states.

Arguments

  • solve_containers::NamedTuple : cache for intermediate values in solve
  • vz_rotor::Vector{Float} : axial induced rotor velocity state container
  • vtheta_rotor::Vector{Float} : tangential induced rotor velocity state container
  • Cm_wake::Vector{Float} : absolute meridional wake control point velocity state container
  • operating_point::NamedTuple : Named tuple containing operating_point information
  • ivr::NamedTuple : unit induced velocities on rotor(s)
  • ivw::NamedTuple : unit induced velocities on wake
  • linsys::NamedTuple : vectors and matricies comprising the panel method linear system
  • blade_elements::NamedTuple : blade element geometry and airfoil polar information
  • wakeK::Vector{Float} : geometric constants used in caculating wake strengths
  • idmaps::NamedTuple : index maps used throughout solve

Keyword Arguments

  • verbose::Bool=false : flag for verbose print statements
source

Solve Utilities

DuctAPE.extract_initial_guessFunction
extract_initial_guess(
+)

Estimate velocity states.

Arguments

  • solve_containers::NamedTuple : cache for intermediate values in solve
  • vz_rotor::Vector{Float} : axial induced rotor velocity state container
  • vtheta_rotor::Vector{Float} : tangential induced rotor velocity state container
  • Cm_wake::Vector{Float} : absolute meridional wake control point velocity state container
  • operating_point::NamedTuple : Named tuple containing operating_point information
  • ivr::NamedTuple : unit induced velocities on rotor(s)
  • ivw::NamedTuple : unit induced velocities on wake
  • linsys::NamedTuple : vectors and matricies comprising the panel method linear system
  • blade_elements::NamedTuple : blade element geometry and airfoil polar information
  • wakeK::Vector{Float} : geometric constants used in caculating wake strengths
  • idmaps::NamedTuple : index maps used throughout solve

Keyword Arguments

  • verbose::Bool=false : flag for verbose print statements
source

Solve Utilities

DuctAPE.extract_initial_guessFunction
extract_initial_guess(
     solver_options::SolverOptionsType, sensitivity_parameters, state_dims
-)

Extract initial guess from the solve parameters cache vector.

Arguments

  • solver_options::SolverOptionsType : used for dispatch
  • sensitivity_parameters::Vector{Float} : vector form of solve parameter cache passed into the solver.
  • state_dims::NamedTuple : dimensions and indices of state variables within the solve parameter cache vector

Returns

  • initial_guess::Vector{Float}` : a vector of the solver initial guess
source
DuctAPE.extract_state_variablesFunction
extract_state_variables(solver_options::SolverOptionsType, vars, dims)

Reshape the state variables from a single vector, to multiple arrays.

Arguments

Returns if solver_options <: CSORSolverOptions

  • Gamr::type : Blade element circulation strengths
  • sigr::type : Rotor source panel strengths
  • gamw::type : Wake vortex panel strengths

Returns if solver_options <: Union{ExternalSolverOptions, PolyAlgorithmOptions}

  • vz_rotor::Vector{Float} : axial induced rotor velocity state container
  • vtheta_rotor::Vector{Float} : tangential induced rotor velocity state container
  • Cm_wake::Vector{Float} : absolute meridional wake control point velocity state container
source
+)

Extract initial guess from the solve parameters cache vector.

Arguments

Returns

source
DuctAPE.extract_state_variablesFunction
extract_state_variables(solver_options::SolverOptionsType, vars, dims)

Reshape the state variables from a single vector, to multiple arrays.

Arguments

Returns if solver_options <: CSORSolverOptions

  • Gamr::type : Blade element circulation strengths
  • sigr::type : Rotor source panel strengths
  • gamw::type : Wake vortex panel strengths

Returns if solver_options <: Union{ExternalSolverOptions, PolyAlgorithmOptions}

  • vz_rotor::Vector{Float} : axial induced rotor velocity state container
  • vtheta_rotor::Vector{Float} : tangential induced rotor velocity state container
  • Cm_wake::Vector{Float} : absolute meridional wake control point velocity state container
source
diff --git a/dev/DuctAPE/api/private_utilities/index.html b/dev/DuctAPE/api/private_utilities/index.html index 7a74ab36..0c1b0048 100644 --- a/dev/DuctAPE/api/private_utilities/index.html +++ b/dev/DuctAPE/api/private_utilities/index.html @@ -1,3 +1,3 @@ -Utilities · DuctAPE.jl

Utility Functions

DuctAPE.promote_propulsor_typeFunction
promote_propulsor_type(propulsor)

Convenience function for promoting types based on any potential elements of the propulsor object dependent on optimization design variables.

Arguments

  • propulsor::Propulsor : the propulsor input

Returns

  • TP::Type : the promoted type
source
DuctAPE.update_operating_point!Function
update_operating_point!(op_old, op_new)

Overwrites all the values of an OperatingPoint object with another OperatingPoint object's values (or NamedTuple with the same field names).

Arguments

  • op_old::OperatingPoint : the OperatingPoint to be overwritten (can also be a NamedTuple with the same field names as an OperatingPoint).
  • op_new::OperatingPoint : the OperatingPoint values to be used (can also be a NamedTuple with the same field names as an OperatingPoint).
source
DuctAPE.isscalarFunction
isscalar(x::T) where {T} = isscalar(T)
-isscalar(::Type{T}) where {T} = BroadcastStyle(T) isa Broadcast.DefaultArrayStyle{0}

Determines if the input is a scalar. Note that Base.BroadcastStyle is imported.

source
DuctAPE.dotFunction
dot(A, B) = sum(a * b for (a, b) in zip(A, B))

A faster dot product.

source
DuctAPE.linear_transformFunction
linear_transform(range1, range2, values)

Linear transfrom of values from range (source_range[1], source_range[end]) to (target_range[1], target_range[end])

Arguments

  • source_range::Vector{Float} : range values come from (can also be a Tuple)
  • target_range::Vector{Float} : range onto which we are transforming (can also be a Tuple)
  • source_values::Array{Float} : array of source values to transform

Returns

  • target_values::Array{Float} : array of transformed sourcevalues onto target range
source
DuctAPE.lfsFunction
lfs(shape)

Determines length from shape (output of size function).

source
DuctAPE.reset_containers!Function
reset_containers!(containers; exception_keys=[])

Resets all fields (not incluing any contained in exception keys) of containers–-which must be arrays, structs of arrays, or tuples of arrays–-to zeros.

source
DuctAPE.cache_dims!Function
cache_dims!(total_length, l, s)

A function that returns a named tuple containing an index range and shape and increases total_length by l.

This function is used heavily in the cache allocation functions for setting up the dimension maps used to access the vectorized caches.

Arguments

  • total_length::Vector{Int} : single element vector containing the current total length of the eventual cache vector. Modified in place.
  • l::Int : total length of the object in question
  • s::Int : size of the object in question

Returns

  • dims::NamedTuple : A named tuple containing index and shape fields
source
DuctAPE.write_dataFunction
write_data(outs, filename; checkoutfileexists=false)

Writes NamedTuples, specifically for writing out the output of the post_procces() function.

Arguments:

  • outs::NamedTuple : Named tuple to write to file.
  • filename::String : file name (including full desired path and file type) for file to write

Keyword Arguments:

  • output_tuple_name::String : desired variable name of written NamedTuple
  • checkoutfileexists::Bool=false : boolean for whether to check if the outfile already exists and whether or not to overwrite it.
source
+Utilities · DuctAPE.jl

Utility Functions

DuctAPE.promote_propulsor_typeFunction
promote_propulsor_type(propulsor)

Convenience function for promoting types based on any potential elements of the propulsor object dependent on optimization design variables.

Arguments

  • propulsor::Propulsor : the propulsor input

Returns

  • TP::Type : the promoted type
source
DuctAPE.update_operating_point!Function
update_operating_point!(op_old, op_new)

Overwrites all the values of an OperatingPoint object with another OperatingPoint object's values (or NamedTuple with the same field names).

Arguments

  • op_old::OperatingPoint : the OperatingPoint to be overwritten (can also be a NamedTuple with the same field names as an OperatingPoint).
  • op_new::OperatingPoint : the OperatingPoint values to be used (can also be a NamedTuple with the same field names as an OperatingPoint).
source
DuctAPE.isscalarFunction
isscalar(x::T) where {T} = isscalar(T)
+isscalar(::Type{T}) where {T} = BroadcastStyle(T) isa Broadcast.DefaultArrayStyle{0}

Determines if the input is a scalar. Note that Base.BroadcastStyle is imported.

source
DuctAPE.dotFunction
dot(A, B) = sum(a * b for (a, b) in zip(A, B))

A faster dot product.

source
DuctAPE.linear_transformFunction
linear_transform(range1, range2, values)

Linear transfrom of values from range (source_range[1], source_range[end]) to (target_range[1], target_range[end])

Arguments

  • source_range::Vector{Float} : range values come from (can also be a Tuple)
  • target_range::Vector{Float} : range onto which we are transforming (can also be a Tuple)
  • source_values::Array{Float} : array of source values to transform

Returns

  • target_values::Array{Float} : array of transformed sourcevalues onto target range
source
DuctAPE.lfsFunction
lfs(shape)

Determines length from shape (output of size function).

source
DuctAPE.reset_containers!Function
reset_containers!(containers; exception_keys=[])

Resets all fields (not incluing any contained in exception keys) of containers–-which must be arrays, structs of arrays, or tuples of arrays–-to zeros.

source
DuctAPE.cache_dims!Function
cache_dims!(total_length, l, s)

A function that returns a named tuple containing an index range and shape and increases total_length by l.

This function is used heavily in the cache allocation functions for setting up the dimension maps used to access the vectorized caches.

Arguments

  • total_length::Vector{Int} : single element vector containing the current total length of the eventual cache vector. Modified in place.
  • l::Int : total length of the object in question
  • s::Int : size of the object in question

Returns

  • dims::NamedTuple : A named tuple containing index and shape fields
source
DuctAPE.write_dataFunction
write_data(outs, filename; checkoutfileexists=false)

Writes NamedTuples, specifically for writing out the output of the post_procces() function.

Arguments:

  • outs::NamedTuple : Named tuple to write to file.
  • filename::String : file name (including full desired path and file type) for file to write

Keyword Arguments:

  • output_tuple_name::String : desired variable name of written NamedTuple
  • checkoutfileexists::Bool=false : boolean for whether to check if the outfile already exists and whether or not to overwrite it.
source
diff --git a/dev/DuctAPE/api/public_api/index.html b/dev/DuctAPE/api/public_api/index.html index b4a02e54..e48e1e59 100644 --- a/dev/DuctAPE/api/public_api/index.html +++ b/dev/DuctAPE/api/public_api/index.html @@ -1,15 +1,15 @@ -Public API Reference · DuctAPE.jl

Public API

Input Types

DuctAPE.PropulsorType
Propulsor(duct_coordinates, centerbody_coordinates, rotorstator_parameters, operating_point, paneling_constants, reference_parameters)

Arguments

  • duct_coordinates::AbstractMatrix : The [z, r] coordinates of the duct geometry beginning at the inner (casing) side trailing edge and proceeding clockwise. Note that the duct geometry absolute radial position does not need to be included here if the autoshiftduct option is selected.
  • centerbody_coordinates::AbstractMatrix : The [z, r] coordinates of the centerbody beginning at the leading edge and ending at the trailing edge. Note that the leading edge is assumed to be placed at a radial distance of 0.0 from the axis of rotation.
  • operating_point::OperatingPoint : The operating point values.
  • paneling_constants::PanelingConstants : Constants used in re-paneling the geometry.
  • rotorstator_parameters::RotorStatorParameters : Rotor (and possibly stator) geometric paramters.
  • reference_parameters::ReferenceParameters : Reference Parameters.
source
DuctAPE.RotorStatorParametersType
RotorStatorParameters(
+Public API Reference · DuctAPE.jl

Public API

Input Types

DuctAPE.PropulsorType
Propulsor(duct_coordinates, centerbody_coordinates, rotorstator_parameters, operating_point, paneling_constants, reference_parameters)

Arguments

  • duct_coordinates::AbstractMatrix : The [z, r] coordinates of the duct geometry beginning at the inner (casing) side trailing edge and proceeding clockwise. Note that the duct geometry absolute radial position does not need to be included here if the autoshiftduct option is selected.
  • centerbody_coordinates::AbstractMatrix : The [z, r] coordinates of the centerbody beginning at the leading edge and ending at the trailing edge. Note that the leading edge is assumed to be placed at a radial distance of 0.0 from the axis of rotation.
  • operating_point::OperatingPoint : The operating point values.
  • paneling_constants::PanelingConstants : Constants used in re-paneling the geometry.
  • rotorstator_parameters::RotorStatorParameters : Rotor (and possibly stator) geometric paramters.
  • reference_parameters::ReferenceParameters : Reference Parameters.
source
DuctAPE.RotorStatorParametersType
RotorStatorParameters(
     B, rotorzloc, r, Rhub, Rtip, chords, twists, tip_gap, airfoils, fliplift
-)

Composite type containing the rotor(s) geometric properties.

Note that the actual struct requires the inputs to be arrays, but there is a constructor function that will take in scalars and automatically build the array-based struct.

Arguments

  • B::AbstractVector{Float} : The number of blades for each rotor. May not be an integer, but usually is.
  • rotorzloc::AbstractVector{Float} : Dimensional, axial position of each rotor.
  • r::AbstractArray{Float} : Non-dimensional radial locations of each blade element.
  • Rhub::AbstractVector{Float} : Dimensional hub radius of rotor. (may be changed if it does not match the radial position of the centerbody geometry at the selected rotorzloc.
  • Rtip::AbstractVector{Float} : Dimensional tip radius of rotor. Is used to determine the radial position of the duct if the autoshiftduct option is selected.
  • chords::AbstractArray{Float} : Dimensional chord lengths of the blade elements.
  • twists::AbstractArray{Float} : Blade element angles, in radians.
  • tip_gap::AbstractVector{Float} : Currently unused, do not set to anything other than zeros.
  • airfoils::AbstractArray{AFType} : Airfoil types describing the airfoil polars for each blade element. Currently only fully tested with C4Blade.DFDCairfoil types.
  • fliplift::AbstractVector{Bool} : flag to indicate if the airfoil lift values should be flipped or not.
source
DuctAPE.OperatingPointType
OperatingPoint(Vinf, rhoinf, muinf, asound, Omega)

Propulsor operating point information.

Note that the actual struct requires the inputs to be arrays, but there is a constructor function that will take in scalars and automatically build the array-based struct.

Also note that even though each field is required to be a vector, only Omega should have more than one entry, and only then if there are more than one rotor. The purpose behind having vector rather than constant scalar inputs here is for ease of redefinition in an optimization setting when freestream design variables may be present.

Arguments

  • Vinf::AbstractVector{Float} : Freestream velocity magnitude (which is only in the axial direction).
  • rhoinf::AbstractVector{Float} : Freestream density
  • muinf::AbstractVector{Float} : Freestream viscosity
  • asound::AbstractVector{Float} : Freestream speed of sound
  • Omega::AbstractVector{Float} : Rotor rototation rate(s)
source
DuctAPE.PanelingConstantsType
PanelingConstants(
+)

Composite type containing the rotor(s) geometric properties.

Note that the actual struct requires the inputs to be arrays, but there is a constructor function that will take in scalars and automatically build the array-based struct.

Arguments

  • B::AbstractVector{Float} : The number of blades for each rotor. May not be an integer, but usually is.
  • rotorzloc::AbstractVector{Float} : Dimensional, axial position of each rotor.
  • r::AbstractArray{Float} : Non-dimensional radial locations of each blade element.
  • Rhub::AbstractVector{Float} : Dimensional hub radius of rotor. (may be changed if it does not match the radial position of the centerbody geometry at the selected rotorzloc.
  • Rtip::AbstractVector{Float} : Dimensional tip radius of rotor. Is used to determine the radial position of the duct if the autoshiftduct option is selected.
  • chords::AbstractArray{Float} : Dimensional chord lengths of the blade elements.
  • twists::AbstractArray{Float} : Blade element angles, in radians.
  • tip_gap::AbstractVector{Float} : Currently unused, do not set to anything other than zeros.
  • airfoils::AbstractArray{AFType} : Airfoil types describing the airfoil polars for each blade element. Currently only fully tested with C4Blade.DFDCairfoil types.
  • fliplift::AbstractVector{Bool} : flag to indicate if the airfoil lift values should be flipped or not.
source
DuctAPE.OperatingPointType
OperatingPoint(Vinf, rhoinf, muinf, asound, Omega)

Propulsor operating point information.

Note that the actual struct requires the inputs to be arrays, but there is a constructor function that will take in scalars and automatically build the array-based struct.

Also note that even though each field is required to be a vector, only Omega should have more than one entry, and only then if there are more than one rotor. The purpose behind having vector rather than constant scalar inputs here is for ease of redefinition in an optimization setting when freestream design variables may be present.

Arguments

  • Vinf::AbstractVector{Float} : Freestream velocity magnitude (which is only in the axial direction).
  • rhoinf::AbstractVector{Float} : Freestream density
  • muinf::AbstractVector{Float} : Freestream viscosity
  • asound::AbstractVector{Float} : Freestream speed of sound
  • Omega::AbstractVector{Float} : Rotor rototation rate(s)
source
DuctAPE.PanelingConstantsType
PanelingConstants(
     nduct_inlet,
     ncenterbody_inlet,
     npanels,
     dte_minus_cbte,
     nwake_sheets,
     wake_length=1.0,
-)

Constants used in re-paneling geometry.

Note that unlike other input structures, this one, in general, does not define fields as vectors. This is because these values should not change throughout an optimization, even if the geometry may change. Otherwise, discontinuities could be experienced.

Arguments

  • nduct_inlet::Int : The number of panels to use for the duct inlet (this number is used for both the casing and nacelle re-paneling)
  • ncenterbody_inlet::Int : The number of panels to use for the centerbody inlet.
  • npanels::AbstractVector{Int} : A vector containing the number of panels between discrete locations inside the wake. Specifically, the number of panels between the rotors, between the last rotor and the first body trailing edge, between the body trailing edges (if different), and between the last body trailing edge and the end of the wake. The length of this vector should be N+1 (where N is the number of rotors) if the duct and centerbody trailing edges are aligned, and N+2 if not.
  • dte_minus_cbte::Float : An indicator concerning the hub and duct trailing edge relative locations. Should be set to -1 if the duct trailing edge axial position minus the centerbody trailing edge axial position is negative, +1 if positive (though any positive or negative number will suffice), and zero if the trailing edges are aligned.
  • nwake_sheets::Int : The number of wake sheets to use. Note this will also be setting the number of blade elements to use.
  • wake_length::Float=1.0 : Non-dimensional (based on the length from the foremost body leading edge and the aftmost body trailing edge) length of the wake extending behind the aftmost body trailing edge.
source
DuctAPE.ReferenceParametersType
ReferenceParameters(Vref, Rref)

Reference parameters for post-process non-dimensionalization.

Note that the actual struct requires the inputs to be arrays, but there is a constructor function that will take in scalars and automatically build the array-based struct.

Arguments

  • Vref::AbstractVector{Float} : Reference velocity.
  • Rref::AbstractVector{Float} : Reference rotor tip radius.
source

Preallocations

DuctAPE.allocate_prepost_container_cacheFunction
allocate_prepost_container_cache(paneling_constants::PanelingConstants)
-allocate_prepost_container_cache(problem_dimensions::ProblemDimensions)

Allocate the pre- and post-processing cache (used for intermediate calculations) based on paneling constants or problem dimensions.

Arguments

  • paneling_constants::PanelingConstants : a PanelingConstants object

OR

  • problem_dimensions::ProblemDimensions : a ProblemDimensions object

Keyword Arguments

  • fd_chunk_size::Int=12 : chunk size to use for PreallocationTools caches. Note that the automated chuck size for DuctAPE will always be the ForwardDiff threshold of 12 due to the size of the system, so it will be best to leave this at the default unless further development allows for chunk size selection for individual solvers.
  • levels::Int=1 : levels for nested duals. Note that since ImplicitAD is being used for all solves, there should be no need for more than 1 level.

Returns

  • prepost_container_caching::NamedTuple : a Named Tuple containing:
    • prepost_container_cache::PreallocationTools.DiffCache : the cache
    • prepost_container_cache_dims::NamedTuple : a named tuple containing the dimensions used for reshaping the cache when needed.
source
DuctAPE.allocate_solve_parameter_cacheFunction
allocate_solve_parameter_cache(
+)

Constants used in re-paneling geometry.

Note that unlike other input structures, this one, in general, does not define fields as vectors. This is because these values should not change throughout an optimization, even if the geometry may change. Otherwise, discontinuities could be experienced.

Arguments

  • nduct_inlet::Int : The number of panels to use for the duct inlet (this number is used for both the casing and nacelle re-paneling)
  • ncenterbody_inlet::Int : The number of panels to use for the centerbody inlet.
  • npanels::AbstractVector{Int} : A vector containing the number of panels between discrete locations inside the wake. Specifically, the number of panels between the rotors, between the last rotor and the first body trailing edge, between the body trailing edges (if different), and between the last body trailing edge and the end of the wake. The length of this vector should be N+1 (where N is the number of rotors) if the duct and centerbody trailing edges are aligned, and N+2 if not.
  • dte_minus_cbte::Float : An indicator concerning the hub and duct trailing edge relative locations. Should be set to -1 if the duct trailing edge axial position minus the centerbody trailing edge axial position is negative, +1 if positive (though any positive or negative number will suffice), and zero if the trailing edges are aligned.
  • nwake_sheets::Int : The number of wake sheets to use. Note this will also be setting the number of blade elements to use.
  • wake_length::Float=1.0 : Non-dimensional (based on the length from the foremost body leading edge and the aftmost body trailing edge) length of the wake extending behind the aftmost body trailing edge.
source
DuctAPE.ReferenceParametersType
ReferenceParameters(Vref, Rref)

Reference parameters for post-process non-dimensionalization.

Note that the actual struct requires the inputs to be arrays, but there is a constructor function that will take in scalars and automatically build the array-based struct.

Arguments

  • Vref::AbstractVector{Float} : Reference velocity.
  • Rref::AbstractVector{Float} : Reference rotor tip radius.
source

Preallocations

DuctAPE.allocate_prepost_container_cacheFunction
allocate_prepost_container_cache(paneling_constants::PanelingConstants)
+allocate_prepost_container_cache(problem_dimensions::ProblemDimensions)

Allocate the pre- and post-processing cache (used for intermediate calculations) based on paneling constants or problem dimensions.

Arguments

  • paneling_constants::PanelingConstants : a PanelingConstants object

OR

  • problem_dimensions::ProblemDimensions : a ProblemDimensions object

Keyword Arguments

  • fd_chunk_size::Int=12 : chunk size to use for PreallocationTools caches. Note that the automated chuck size for DuctAPE will always be the ForwardDiff threshold of 12 due to the size of the system, so it will be best to leave this at the default unless further development allows for chunk size selection for individual solvers.
  • levels::Int=1 : levels for nested duals. Note that since ImplicitAD is being used for all solves, there should be no need for more than 1 level.

Returns

  • prepost_container_caching::NamedTuple : a Named Tuple containing:
    • prepost_container_cache::PreallocationTools.DiffCache : the cache
    • prepost_container_cache_dims::NamedTuple : a named tuple containing the dimensions used for reshaping the cache when needed.
source
DuctAPE.allocate_solve_parameter_cacheFunction
allocate_solve_parameter_cache(
     solve_type::SolverOptionsType,
     paneling_constants::PanelingConstants;
     fd_chunk_size=12,
@@ -20,7 +20,7 @@
     problem_dimensions::ProblemDimensions;
     fd_chunk_size=12,
     levels=1
-)

Allocate the solve parameter cache for parameters passed into the solver(s).

Arguments

  • solve_type::SolverOptionsType : Solver options type used for dispatch
  • paneling_constants::PanelingConstants : a PanlingConstants object used for sizing

OR

  • problem_dimensions::ProblemDimensions : a ProblemDimensions object used for sizing

Keyword Arguments

  • fd_chunk_size::Int=12 : chunk size to use for PreallocationTools caches. Note that the automated chuck size for DuctAPE will always be the ForwardDiff threshold of 12 due to the size of the system, so it will be best to leave this at the default unless further development allows for chunk size selection for individual solvers.
  • levels::Int=1 : levels for nested duals. Note that since ImplicitAD is being used for all solves, there should be no need for more than 1 level.

Returns

  • solve_parameter_caching::NamedTuple : a Named Tuple containing:
    • solve_parameter_cache::PreallocationTools.DiffCache : the cache
    • solve_parameter_cache_dims::NamedTuple : a named tuple containing the dimensions used for reshaping the cache when needed.
source
DuctAPE.allocate_solve_container_cacheFunction
allocate_solve_container_cache(
+)

Allocate the solve parameter cache for parameters passed into the solver(s).

Arguments

  • solve_type::SolverOptionsType : Solver options type used for dispatch
  • paneling_constants::PanelingConstants : a PanlingConstants object used for sizing

OR

  • problem_dimensions::ProblemDimensions : a ProblemDimensions object used for sizing

Keyword Arguments

  • fd_chunk_size::Int=12 : chunk size to use for PreallocationTools caches. Note that the automated chuck size for DuctAPE will always be the ForwardDiff threshold of 12 due to the size of the system, so it will be best to leave this at the default unless further development allows for chunk size selection for individual solvers.
  • levels::Int=1 : levels for nested duals. Note that since ImplicitAD is being used for all solves, there should be no need for more than 1 level.

Returns

  • solve_parameter_caching::NamedTuple : a Named Tuple containing:
    • solve_parameter_cache::PreallocationTools.DiffCache : the cache
    • solve_parameter_cache_dims::NamedTuple : a named tuple containing the dimensions used for reshaping the cache when needed.
source
DuctAPE.allocate_solve_container_cacheFunction
allocate_solve_container_cache(
     solve_type::SolverOptionsType,
     paneling_constants::PanelingConstants;
     fd_chunk_size=12,
@@ -31,7 +31,7 @@
     problem_dimensions::ProblemDimensions;
     fd_chunk_size=12,
     levels=1,
-)

Allocate the solve cache (used for intermediate calculations) based on paneling constants or problem dimensions.

Arguments

  • paneling_constants::PanelingConstants : a PanelingConstants object

OR

  • problem_dimensions::ProblemDimensions : a ProblemDimensions object

Keyword Arguments

  • fd_chunk_size::Int=12 : chunk size to use for PreallocationTools caches. Note that the automated chuck size for DuctAPE will always be the ForwardDiff threshold of 12 due to the size of the system, so it will be best to leave this at the default unless further development allows for chunk size selection for individual solvers.
  • levels::Int=1 : levels for nested duals. Note that since ImplicitAD is being used for all solves, there should be no need for more than 1 level.

Returns

  • solve_container_caching::NamedTuple : a Named Tuple containing:
    • solve_container_cache::PreallocationTools.DiffCache : the cache
    • solve_container_cache_dims::NamedTuple : a named tuple containing the dimensions used for reshaping the cache when needed.
source

Options

General Options

DuctAPE.OptionsType
struct Options{
+)

Allocate the solve cache (used for intermediate calculations) based on paneling constants or problem dimensions.

Arguments

  • paneling_constants::PanelingConstants : a PanelingConstants object

OR

  • problem_dimensions::ProblemDimensions : a ProblemDimensions object

Keyword Arguments

  • fd_chunk_size::Int=12 : chunk size to use for PreallocationTools caches. Note that the automated chuck size for DuctAPE will always be the ForwardDiff threshold of 12 due to the size of the system, so it will be best to leave this at the default unless further development allows for chunk size selection for individual solvers.
  • levels::Int=1 : levels for nested duals. Note that since ImplicitAD is being used for all solves, there should be no need for more than 1 level.

Returns

  • solve_container_caching::NamedTuple : a Named Tuple containing:
    • solve_container_cache::PreallocationTools.DiffCache : the cache
    • solve_container_cache_dims::NamedTuple : a named tuple containing the dimensions used for reshaping the cache when needed.
source

Options

General Options

DuctAPE.OptionsType
struct Options{
     TB,
     TBwo,
     TF,
@@ -42,23 +42,23 @@
     TIo<:IntegrationOptions,
     TSo<:SolverOptionsType,
     WS<:GridSolverOptionsType,
-}

Type containing (nearly) all the available user options.

Fields

General Options

  • verbose::TB = false : flag to print verbose statements
  • silence_warnings::TB = true : flag to silence warnings
  • multipoint_index::TI = [1] : holds current index of multi-point solver (no need for user to change this usually)

Pre-processing Options

Geometry ee-interpolation and generation options :

  • finterp::Tin = FLOWMath.akima : interpolation method used for re-paneling bodies
  • autoshiftduct::TB = true : flag as to whether duct geometry should be shifted based on rotor tip location
  • lu_decomp_flag::TB = false : flag indicating if panel method LHS matrix factorization was successful

paneling options

  • itcpshift::TF = 0.05 : factor for internal trailing edge psuedo-panel placement (default is DFDC hard-coded value)
  • axistol::TF = 1e-15 : tolerance for how close the the axis of rotation should be considered on the axis
  • tegaptol::TF = 1e1 * eps() : tolerance for how large of a trailing edge gap should be considered a gap

Integration Options

  • integration_options::TIo = IntegrationOptions() : integration options

Post-processing Options

  • write_outputs::TBwo = [false] : Bool for whether to write the outputs of the analysis to an external file (slow)
  • outfile::TSf = ["outputs.jl"] : External output file name (including path information) for files to write
  • checkoutfileexists::TB = false : Flag for whether to check if file exists before overwriting
  • output_tuple_name::TSt = ["outs"] : variable name for named tuple written to out file

Solving Options

  • grid_solver_options::WS = GridSolverOptions() : elliptic grid solver options
  • solver_options::TSo = ChainSolverOptions() : solver options
source
DuctAPE.set_optionsFunction
set_options(; kwargs...)
-set_options(multipoint; kwargs...)

Set the options for DuctAPE to use.

Note that the vast majority of the available options are defined through keyword arguments. See the documentation for the various option types for more information.

Arguments

  • multipoint::AbstractArray{OperatingPoint} : a vector of operating points to use if running a multi-point analysis.
source

Integration Options

DuctAPE.IntegrationOptionsType
struct IntegrationOptions{TN<:IntegrationMethod,TS<:IntegrationMethod}

A struct used to hold the integration options for both the nominal and singular cases.

Fields

  • nominal::IntegrationMethod=GaussLegendre(8) : the integration options to use for the nominal case.
  • singular::IntegrationMethod=GaussLegendre(8) : the integration options to use for the self-induced case.
source
DuctAPE.GaussLegendreType
struct GaussLegendre{TN,TW} <: IntegrationMethod

Options for Gauss-Legendre integration method

Fields

  • sample_points::TN : Sample Points
  • weights::TW : Gauss weights
source
DuctAPE.GaussKronrodType
struct GaussKronrod{TF,TI} <: IntegrationMethod

Options for Gauss-Kronrod integration method

Fields

  • order::TI = 7 : order of Legendre polynomial to use on each interval
  • maxevales::TI = 10^7 : maximum number of evaluations in the adaptive method
  • atol::TF = 0.0 : absolute error tolerance. (note, if zero, QuadGK uses sqrt(eps()) relative tolerance).
source
DuctAPE.RombergType
struct Romberg{TF,TI} <: IntegrationMethod

Options for Romberg integration method

Fields

  • max_subdivisions::TI = 10 : maximum number of subdivisions. Note, total number of internvals is 2^N, where N is number of subdivisions.
  • atol::TF = 1e-6 : absolute error tolerance.
source

Solver Options

Elliptic Grid Solve

DuctAPE.SLORGridSolverOptionsType
struct SLORGridSolverOptions{TB,TF,TI} <: GridSolverOptionsType

Options for SLOR (successive line over relaxation) elliptic grid solver.

Fields

  • iteration_limit::TI = 100 : maximum number of iterations
  • atol::TF = 1e-9 : absolute convergence tolerance
  • `converged::AbstractArray{TB} = [false]
source
DuctAPE.GridSolverOptionsType
struct GridSolverOptions{TB,TF,TI,TSym} <: GridSolverOptionsType

Options for SLOR + Newton elliptic grid solver.

Fields

  • iteration_limit::TI = 10 : maximum number of iterations
  • atol::TF = 1e-14 : absolute convergence tolerance
  • algorithm::TSym = :newton : algorithm to use in NLsolve.jl
  • autodiff::TSym = :forward : differentiation method to use in NLsolve.jl
  • converged::AbstractArray{TB} = [false]
source

Aerodynamics Solve

DuctAPE.ChainSolverOptionsType
struct ChainSolverOptions{TB,TS<:Union{ExternalSolverOptions,PolyAlgorithmOptions}} <:PolyAlgorithmOptions

Options for Chain Solvers (try one solver, if it doesn't converge, try another)

Fields

  • `solvers::AbstractArray{TS} = [ NLsolveOptions(; algorithm=:anderson, atol=1e-12), MinpackOptions(; atol=1e-12), NonlinearSolveOptions(; algorithm=SimpleNonlinearSolve.SimpleNewtonRaphson, atol=1e-12, additional_kwargs=(; autodiff=SimpleNonlinearSolve.AutoForwardDiff()), ), ] : Vector of solver options to use.
  • converged::AbstractArray{TB} = [false] : flag to track if convergence took place.
source
DuctAPE.CompositeSolverOptionsType
struct CompositeSolverOptions{
+}

Type containing (nearly) all the available user options.

Fields

General Options

  • verbose::TB = false : flag to print verbose statements
  • silence_warnings::TB = true : flag to silence warnings
  • multipoint_index::TI = [1] : holds current index of multi-point solver (no need for user to change this usually)

Pre-processing Options

Geometry ee-interpolation and generation options :

  • finterp::Tin = FLOWMath.akima : interpolation method used for re-paneling bodies
  • autoshiftduct::TB = true : flag as to whether duct geometry should be shifted based on rotor tip location
  • lu_decomp_flag::TB = false : flag indicating if panel method LHS matrix factorization was successful

paneling options

  • itcpshift::TF = 0.05 : factor for internal trailing edge psuedo-panel placement (default is DFDC hard-coded value)
  • axistol::TF = 1e-15 : tolerance for how close the the axis of rotation should be considered on the axis
  • tegaptol::TF = 1e1 * eps() : tolerance for how large of a trailing edge gap should be considered a gap

Integration Options

  • integration_options::TIo = IntegrationOptions() : integration options

Post-processing Options

  • write_outputs::TBwo = [false] : Bool for whether to write the outputs of the analysis to an external file (slow)
  • outfile::TSf = ["outputs.jl"] : External output file name (including path information) for files to write
  • checkoutfileexists::TB = false : Flag for whether to check if file exists before overwriting
  • output_tuple_name::TSt = ["outs"] : variable name for named tuple written to out file

Solving Options

  • grid_solver_options::WS = GridSolverOptions() : elliptic grid solver options
  • solver_options::TSo = ChainSolverOptions() : solver options
source
DuctAPE.set_optionsFunction
set_options(; kwargs...)
+set_options(multipoint; kwargs...)

Set the options for DuctAPE to use.

Note that the vast majority of the available options are defined through keyword arguments. See the documentation for the various option types for more information.

Arguments

  • multipoint::AbstractArray{OperatingPoint} : a vector of operating points to use if running a multi-point analysis.
source

Integration Options

DuctAPE.IntegrationOptionsType
struct IntegrationOptions{TN<:IntegrationMethod,TS<:IntegrationMethod}

A struct used to hold the integration options for both the nominal and singular cases.

Fields

  • nominal::IntegrationMethod=GaussLegendre(8) : the integration options to use for the nominal case.
  • singular::IntegrationMethod=GaussLegendre(8) : the integration options to use for the self-induced case.
source
DuctAPE.GaussLegendreType
struct GaussLegendre{TN,TW} <: IntegrationMethod

Options for Gauss-Legendre integration method

Fields

  • sample_points::TN : Sample Points
  • weights::TW : Gauss weights
source
DuctAPE.GaussKronrodType
struct GaussKronrod{TF,TI} <: IntegrationMethod

Options for Gauss-Kronrod integration method

Fields

  • order::TI = 7 : order of Legendre polynomial to use on each interval
  • maxevales::TI = 10^7 : maximum number of evaluations in the adaptive method
  • atol::TF = 0.0 : absolute error tolerance. (note, if zero, QuadGK uses sqrt(eps()) relative tolerance).
source
DuctAPE.RombergType
struct Romberg{TF,TI} <: IntegrationMethod

Options for Romberg integration method

Fields

  • max_subdivisions::TI = 10 : maximum number of subdivisions. Note, total number of internvals is 2^N, where N is number of subdivisions.
  • atol::TF = 1e-6 : absolute error tolerance.
source

Solver Options

Elliptic Grid Solve

DuctAPE.SLORGridSolverOptionsType
struct SLORGridSolverOptions{TB,TF,TI} <: GridSolverOptionsType

Options for SLOR (successive line over relaxation) elliptic grid solver.

Fields

  • iteration_limit::TI = 100 : maximum number of iterations
  • atol::TF = 1e-9 : absolute convergence tolerance
  • `converged::AbstractArray{TB} = [false]
source
DuctAPE.GridSolverOptionsType
struct GridSolverOptions{TB,TF,TI,TSym} <: GridSolverOptionsType

Options for SLOR + Newton elliptic grid solver.

Fields

  • iteration_limit::TI = 10 : maximum number of iterations
  • atol::TF = 1e-14 : absolute convergence tolerance
  • algorithm::TSym = :newton : algorithm to use in NLsolve.jl
  • autodiff::TSym = :forward : differentiation method to use in NLsolve.jl
  • converged::AbstractArray{TB} = [false]
source

Aerodynamics Solve

DuctAPE.ChainSolverOptionsType
struct ChainSolverOptions{TB,TS<:Union{ExternalSolverOptions,PolyAlgorithmOptions}} <:PolyAlgorithmOptions

Options for Chain Solvers (try one solver, if it doesn't converge, try another)

Fields

  • `solvers::AbstractArray{TS} = [ NLsolveOptions(; algorithm=:anderson, atol=1e-12), MinpackOptions(; atol=1e-12), NonlinearSolveOptions(; algorithm=SimpleNonlinearSolve.SimpleNewtonRaphson, atol=1e-12, additional_kwargs=(; autodiff=SimpleNonlinearSolve.AutoForwardDiff()), ), ] : Vector of solver options to use.
  • converged::AbstractArray{TB} = [false] : flag to track if convergence took place.
source
DuctAPE.CompositeSolverOptionsType
struct CompositeSolverOptions{
     TB,TS<:Union{ExternalSolverOptions,PolyAlgorithmOptions}
-} <: PolyAlgorithmOptions

Options for Composite Solvers (start with a partial solve of one solve, then finish with another starting where the first left off).

Fields

  • `solvers::AbstractArray{TS} = [ NLsolveOptions(; algorithm=:newton, iteration_limit=3), NLsolveOptions(; algorithm=:anderson, atol=1e-12), ]' : Vector of solver options to use.
  • converged::AbstractArray{TB} = [false] : flag to track if convergence took place.
source
DuctAPE.NLsolveOptionsType
struct NLsolveOptions{TB,TF,TK,Tls,Tlsk,TSym} <: ExternalSolverOptions

Options for the NLsolve pacakge solvers

Fields

  • algorithm::TSym = :anderson : algorithm to use
  • additional_kwargs::TK = (;) : any additional keyword arguments for the solver
  • atol::TF = 1e-12 : absolute convergence tolerance
  • iteration_limit::TF = 25 : maximum number of iterations
  • linesearch_method::Tls = LineSearches.MoreThuente : line search method to use
  • linesearch_kwargs::Tlsk = (;) : any additional lineseach keyword arguments
  • converged::AbstractArray{TB} = [false] : flag to track if convergence took place.
source
DuctAPE.NonlinearSolveOptionsType
struct NonlinearSolveOptions{TA,TB,TF,TI,TT} <: ExternalSolverOptions

Options for the SimpleNonlinearSolve pacakge solvers

Fields

  • algorithm::TA = SimpleNonlinearSolve.SimpleNewtonRaphson : algorithm to use
  • additional_kwargs::TK = (;) : any additional keyword arguments for the solver
  • atol::TF = 1e-12 : absolute convergence tolerance
  • iteration_limit::TF = 25 : maximum number of iterations
  • converged::AbstractArray{TB} = [false] : flag to track if convergence took place.
source
DuctAPE.MinpackOptionsType
struct MinpackOptions{TB,TF,TI,TSym} <: ExternalSolverOptions

Options for the MINPACK's HYBRJ solver

Fields

  • algorithm::TSym = :hybr : algorithm to use in MINPACK.jl (hybr is HYBRJ when the jacobian is provided)
  • atol::TF = 1e-12 : absolute convergence tolerance
  • iteration_limit::TF = 100 : maximum number of iterations
  • converged::AbstractArray{TB} = [false] : flag to track if convergence took place.
source
DuctAPE.SIAMFANLEOptionsType
struct SIAMFANLEOptions{TA,TB,TF,TI,TK} <: ExternalSolverOptions

Options for the SIAMFANLEquations pacakge solvers

Fields

  • algorithm::TA = SIAMFANLEquations.nsoli : algorithm to use
  • rtol::TF = 0.0 : relative convergence tolerance
  • atol::TF = 1e-10 : absolute convergence tolerance
  • iteration_limit::TF = 1000 : maximum number of iterations
  • linear_iteration_limit::TF = 5 : maximum number of linear solve iterations (GMRES)
  • additional_kwargs::TK = (;) : any additional keyword arguments for the solver
  • converged::AbstractArray{TB} = [false] : flag to track if convergence took place.
source
DuctAPE.SpeedMappingOptionsType
struct SpeedMappingOptions{TB,TF,TI,TL,TSm,TU} <: ExternalSolverOptions

Options for the SpeedMapping.jl package solver

Fields

  • `orders::AbstractArray{TI} = [3, 2]
  • sig_min::TSm = 0 : maybe set to 1?
  • stabilize::TB = false : stabilizes before extrapolation
  • check_obj::TB = false : checks for inf's and nan's and starts from previous finite point
  • atol::TF = 1e-10 : absolute convergence tolerance
  • iteration_limit::TF = 1000 : maximum number of iterations
  • time_limit::TF = Inf : time limit in seconds
  • lower::TL = nothing : box lower bounds
  • upper::TU = nothing : box upper bounds
  • buffer::TF = 0.01 : if using bounds, buffer brings x inside bounds by buffer amountd
  • Lp::TF = Inf : p value for p-norm for convergence criteria
  • converged::AbstractArray{TB} = [false] : flag to track if convergence took place.
source
DuctAPE.FixedPointOptionsType
struct FixedPointOptions{TB,TF,TI} <: ExternalSolverOptions

Options for the FixedPoint.jl package solver

Fields

  • iteration_limit::TF = 1000 : maximum number of iterations
  • vel::TF = 0.9 : vel keyword argument, default is package default
  • ep::TF = 0.01 : ep keyword argument, default is package default
  • atol::TF = 1e-12 : absolute convergence tolerance
  • converged::AbstractArray{TB} = [false] : flag to track if convergence took place.
source
DuctAPE.CSORSolverOptionsType
struct CSORSolverOptions{TB,TC<:ConvergenceType,TF,TS} <: SolverOptionsType

Type containing all the options for the CSOR (controlled successive over relaxation) solver.

Note that the defaults match DFDC with the exception of the relaxation schedule, which is an experimental feature.

Fields

  • var::type :
  • verbose::TB = false : flag to print verbose statements
  • iteration_limit::TF = 1e2 : maximum number of iterations
  • nrf::TF = 0.4 : nominal relaxation factor
  • bt1::TF = 0.2 : backtracking factor 1
  • bt2::TF = 0.6 : backtracking factor 2
  • pf1::TF = 0.4 : press forward factor 1
  • pf2::TF = 0.5 : press forward factor 2
  • btw::TF = 0.6 : backtracking factor for wake
  • pfw::TF = 1.2 : press forward factor for wake
  • relaxation_schedule::TS = [[0.0;1e-14;1e-13;1e10]), [1.0;1.0;0.0;0.0])] : values used in spline definition for scaling the relaxation factors (second vector) after various convergence values (first vector).
  • f_circ::TF = 1e-3 : convergence tolerance for rotor circulation
  • f_dgamw::TF = 2e-4 : convergence tolerance for wake vortex strength
  • convergence_type::TC = Relative() : dispatch for relative or absolute convergence criteria.
  • Vconv::AbstractArray{TF} = [1.0] : velocity used in relative convergence criteria (should be set to Vref).
  • converged::AbstractArray{TB} = [false] : flag to track if convergence took place.
source

Preprocess

DuctAPE.setup_analysisFunction
setup_analysis(
+} <: PolyAlgorithmOptions

Options for Composite Solvers (start with a partial solve of one solve, then finish with another starting where the first left off).

Fields

  • `solvers::AbstractArray{TS} = [ NLsolveOptions(; algorithm=:newton, iteration_limit=3), NLsolveOptions(; algorithm=:anderson, atol=1e-12), ]' : Vector of solver options to use.
  • converged::AbstractArray{TB} = [false] : flag to track if convergence took place.
source
DuctAPE.NLsolveOptionsType
struct NLsolveOptions{TB,TF,TK,Tls,Tlsk,TSym} <: ExternalSolverOptions

Options for the NLsolve pacakge solvers

Fields

  • algorithm::TSym = :anderson : algorithm to use
  • additional_kwargs::TK = (;) : any additional keyword arguments for the solver
  • atol::TF = 1e-12 : absolute convergence tolerance
  • iteration_limit::TF = 25 : maximum number of iterations
  • linesearch_method::Tls = LineSearches.MoreThuente : line search method to use
  • linesearch_kwargs::Tlsk = (;) : any additional lineseach keyword arguments
  • converged::AbstractArray{TB} = [false] : flag to track if convergence took place.
source
DuctAPE.NonlinearSolveOptionsType
struct NonlinearSolveOptions{TA,TB,TF,TI,TT} <: ExternalSolverOptions

Options for the SimpleNonlinearSolve pacakge solvers

Fields

  • algorithm::TA = SimpleNonlinearSolve.SimpleNewtonRaphson : algorithm to use
  • additional_kwargs::TK = (;) : any additional keyword arguments for the solver
  • atol::TF = 1e-12 : absolute convergence tolerance
  • iteration_limit::TF = 25 : maximum number of iterations
  • converged::AbstractArray{TB} = [false] : flag to track if convergence took place.
source
DuctAPE.MinpackOptionsType
struct MinpackOptions{TB,TF,TI,TSym} <: ExternalSolverOptions

Options for the MINPACK's HYBRJ solver

Fields

  • algorithm::TSym = :hybr : algorithm to use in MINPACK.jl (hybr is HYBRJ when the jacobian is provided)
  • atol::TF = 1e-12 : absolute convergence tolerance
  • iteration_limit::TF = 100 : maximum number of iterations
  • converged::AbstractArray{TB} = [false] : flag to track if convergence took place.
source
DuctAPE.SIAMFANLEOptionsType
struct SIAMFANLEOptions{TA,TB,TF,TI,TK} <: ExternalSolverOptions

Options for the SIAMFANLEquations pacakge solvers

Fields

  • algorithm::TA = SIAMFANLEquations.nsoli : algorithm to use
  • rtol::TF = 0.0 : relative convergence tolerance
  • atol::TF = 1e-10 : absolute convergence tolerance
  • iteration_limit::TF = 1000 : maximum number of iterations
  • linear_iteration_limit::TF = 5 : maximum number of linear solve iterations (GMRES)
  • additional_kwargs::TK = (;) : any additional keyword arguments for the solver
  • converged::AbstractArray{TB} = [false] : flag to track if convergence took place.
source
DuctAPE.SpeedMappingOptionsType
struct SpeedMappingOptions{TB,TF,TI,TL,TSm,TU} <: ExternalSolverOptions

Options for the SpeedMapping.jl package solver

Fields

  • `orders::AbstractArray{TI} = [3, 2]
  • sig_min::TSm = 0 : maybe set to 1?
  • stabilize::TB = false : stabilizes before extrapolation
  • check_obj::TB = false : checks for inf's and nan's and starts from previous finite point
  • atol::TF = 1e-10 : absolute convergence tolerance
  • iteration_limit::TF = 1000 : maximum number of iterations
  • time_limit::TF = Inf : time limit in seconds
  • lower::TL = nothing : box lower bounds
  • upper::TU = nothing : box upper bounds
  • buffer::TF = 0.01 : if using bounds, buffer brings x inside bounds by buffer amountd
  • Lp::TF = Inf : p value for p-norm for convergence criteria
  • converged::AbstractArray{TB} = [false] : flag to track if convergence took place.
source
DuctAPE.FixedPointOptionsType
struct FixedPointOptions{TB,TF,TI} <: ExternalSolverOptions

Options for the FixedPoint.jl package solver

Fields

  • iteration_limit::TF = 1000 : maximum number of iterations
  • vel::TF = 0.9 : vel keyword argument, default is package default
  • ep::TF = 0.01 : ep keyword argument, default is package default
  • atol::TF = 1e-12 : absolute convergence tolerance
  • converged::AbstractArray{TB} = [false] : flag to track if convergence took place.
source
DuctAPE.CSORSolverOptionsType
struct CSORSolverOptions{TB,TC<:ConvergenceType,TF,TS} <: SolverOptionsType

Type containing all the options for the CSOR (controlled successive over relaxation) solver.

Note that the defaults match DFDC with the exception of the relaxation schedule, which is an experimental feature.

Fields

  • var::type :
  • verbose::TB = false : flag to print verbose statements
  • iteration_limit::TF = 1e2 : maximum number of iterations
  • nrf::TF = 0.4 : nominal relaxation factor
  • bt1::TF = 0.2 : backtracking factor 1
  • bt2::TF = 0.6 : backtracking factor 2
  • pf1::TF = 0.4 : press forward factor 1
  • pf2::TF = 0.5 : press forward factor 2
  • btw::TF = 0.6 : backtracking factor for wake
  • pfw::TF = 1.2 : press forward factor for wake
  • relaxation_schedule::TS = [[0.0;1e-14;1e-13;1e10]), [1.0;1.0;0.0;0.0])] : values used in spline definition for scaling the relaxation factors (second vector) after various convergence values (first vector).
  • f_circ::TF = 1e-3 : convergence tolerance for rotor circulation
  • f_dgamw::TF = 2e-4 : convergence tolerance for wake vortex strength
  • convergence_type::TC = Relative() : dispatch for relative or absolute convergence criteria.
  • Vconv::AbstractArray{TF} = [1.0] : velocity used in relative convergence criteria (should be set to Vref).
  • converged::AbstractArray{TB} = [false] : flag to track if convergence took place.
source

Preprocess

DuctAPE.setup_analysisFunction
setup_analysis(
     propulsor::Propulsor,
     options::Options=set_options();
     prepost_container_caching=nothing,
     solve_parameter_caching=nothing,
     solve_container_caching=nothing,
-)

Perform pre-processing and cache setup (as needed) for propuslor analysis.

Arguments

  • propulsor::Propulsor : Propulsor input object (see docstring for Propulsor type)
  • options::Options=set_options() : Options object (see set_options and related functions)

Keyword Arguments

  • prepost_container_caching=nothing : Output of allocate_prepost_container_cache
  • solve_parameter_caching=nothing : Output of allocate_solve_parameter_container_cache
  • solve_container_caching=nothing : Output of allocate_solve_container_cache

Returns

  • problem_dimensions::NamedTuple : Named Tuple contiaining bookkeeping information (problem dimensions)
  • prepost_containers::NamedTuple : Named Tuple containing reshaped views into the prepost cache
  • solve_parameter_cache_vector::Vector : Vector containing the relevant typed cache vector of solve parameters
  • solve_parameter_cache_dims::NamedTuple : Named Tuple containing dimensions used for reshaping the solve parameter cache
  • A_bb_LU::LinearAlgebra.LU : The LU factorization of the AIC matrix used in the panel method
  • lu_decomp_flag::Bool : flag indicating if the LU decomposition was successful
  • airfoils::Matrix{AFType} : Matrix contiaining the blade element airfoil polar objects
  • idmaps::NamedTuple : Named Tuple containing bookkeeping information (index mappings)
source

Analysis

DuctAPE.analyzeFunction
analyze(
+)

Perform pre-processing and cache setup (as needed) for propuslor analysis.

Arguments

  • propulsor::Propulsor : Propulsor input object (see docstring for Propulsor type)
  • options::Options=set_options() : Options object (see set_options and related functions)

Keyword Arguments

  • prepost_container_caching=nothing : Output of allocate_prepost_container_cache
  • solve_parameter_caching=nothing : Output of allocate_solve_parameter_container_cache
  • solve_container_caching=nothing : Output of allocate_solve_container_cache

Returns

  • problem_dimensions::NamedTuple : Named Tuple contiaining bookkeeping information (problem dimensions)
  • prepost_containers::NamedTuple : Named Tuple containing reshaped views into the prepost cache
  • solve_parameter_cache_vector::Vector : Vector containing the relevant typed cache vector of solve parameters
  • solve_parameter_cache_dims::NamedTuple : Named Tuple containing dimensions used for reshaping the solve parameter cache
  • A_bb_LU::LinearAlgebra.LU : The LU factorization of the AIC matrix used in the panel method
  • lu_decomp_flag::Bool : flag indicating if the LU decomposition was successful
  • airfoils::Matrix{AFType} : Matrix contiaining the blade element airfoil polar objects
  • idmaps::NamedTuple : Named Tuple containing bookkeeping information (index mappings)
source

Analysis

DuctAPE.analyzeFunction
analyze(
     propulsor::Propulsor,
     options::Options=set_options();
     prepost_container_caching=nothing,
     solve_parameter_caching=nothing,
     solve_container_caching=nothing,
     return_inputs=false,
-)

Analyze propulsor, including preprocessing.

Arguments

  • propulsor::Propulsor : Propulsor input object (see docstring for Propulsor type)
  • options::Options=set_options() : Options object (see set_options and related functions)

Keyword Arguments

  • prepost_container_caching=nothing : Output of allocate_prepost_container_cache
  • solve_parameter_caching=nothing : Output of allocate_solve_parameter_container_cache
  • solve_container_caching=nothing : Output of allocate_solve_container_cache
  • return_inputs=false : flag as to whether or not to return the pre-processed inputs

Returns

  • outs::NamedTuple : Named Tuple of various analysis outputs (see docstring for postprocess for details), note, if linear system decomposition fails, no solve is performed and an empty vector is returned.
  • ins::NamedTuple : Named Tuple of various pre-processed inputs (e.g. panels and body linear system), will only be returned if return_inputs=true
  • convergence_flag : Flag for successful solve convergence
source
analyze(
+)

Analyze propulsor, including preprocessing.

Arguments

  • propulsor::Propulsor : Propulsor input object (see docstring for Propulsor type)
  • options::Options=set_options() : Options object (see set_options and related functions)

Keyword Arguments

  • prepost_container_caching=nothing : Output of allocate_prepost_container_cache
  • solve_parameter_caching=nothing : Output of allocate_solve_parameter_container_cache
  • solve_container_caching=nothing : Output of allocate_solve_container_cache
  • return_inputs=false : flag as to whether or not to return the pre-processed inputs

Returns

  • outs::NamedTuple : Named Tuple of various analysis outputs (see docstring for postprocess for details), note, if linear system decomposition fails, no solve is performed and an empty vector is returned.
  • ins::NamedTuple : Named Tuple of various pre-processed inputs (e.g. panels and body linear system), will only be returned if return_inputs=true
  • convergence_flag : Flag for successful solve convergence
source
analyze(
     propulsor::Propulsor,
     prepost_containers,
     solve_parameter_cache_vector,
@@ -70,7 +70,7 @@
     options::Options=set_options();
     return_inputs=false,
     solve_container_caching=nothing,
-)

Analyze propulsor, assuming setup_analysis has been called and the outputs thereof are being passed in here.

Arguments

  • propulsor::Propulsor : Propulsor input object
  • prepost_containers::NamedTuple : An output from setup_analysis containing reshaped views into the prepost cache
  • solve_parameter_cache_vector::Vector : An output from setup_analysis containing the relevant typed cache vector of solve parameters
  • solve_parameter_cache_dims::NamedTuple : An output from setup_analysis containing dimensions used for reshaping the solve parameter cache
  • airfoils::Vector{AFType} : An output from setup_analysis contiaining the blade element airfoil polar objects
  • A_bb_LU::LinearAlgebra.LU : An output from setup_analysis that is the LU decomposition of the AIC matrix used in the panel method
  • idmaps::NamedTuple : An output from setup_analysis containing bookkeeping information (index mappings)
  • problem_dimensions::NamedTuple : An output from setup_analysis contiaining bookkeeping information (problem dimensions)
  • options::Options=set_options() : Options object

Keyword Arguments

  • solve_container_caching=nothing : Output of allocate_solve_container_cache
  • return_inputs=false : flag as to whether or not to return the pre-processed inputs

Returns

  • outs::NamedTuple : Named Tuple of various analysis outputs (see docstring for postprocess for details), note, if linear system decomposition fails, no solve is performed and an empty vector is returned.
  • ins::NamedTuple : Named Tuple of various pre-processed inputs (e.g. panels and body linear system), will only be returned if return_inputs=true
  • convergence_flag : Flag for successful solve convergence
source
analyze(
+)

Analyze propulsor, assuming setup_analysis has been called and the outputs thereof are being passed in here.

Arguments

  • propulsor::Propulsor : Propulsor input object
  • prepost_containers::NamedTuple : An output from setup_analysis containing reshaped views into the prepost cache
  • solve_parameter_cache_vector::Vector : An output from setup_analysis containing the relevant typed cache vector of solve parameters
  • solve_parameter_cache_dims::NamedTuple : An output from setup_analysis containing dimensions used for reshaping the solve parameter cache
  • airfoils::Vector{AFType} : An output from setup_analysis contiaining the blade element airfoil polar objects
  • A_bb_LU::LinearAlgebra.LU : An output from setup_analysis that is the LU decomposition of the AIC matrix used in the panel method
  • idmaps::NamedTuple : An output from setup_analysis containing bookkeeping information (index mappings)
  • problem_dimensions::NamedTuple : An output from setup_analysis contiaining bookkeeping information (problem dimensions)
  • options::Options=set_options() : Options object

Keyword Arguments

  • solve_container_caching=nothing : Output of allocate_solve_container_cache
  • return_inputs=false : flag as to whether or not to return the pre-processed inputs

Returns

  • outs::NamedTuple : Named Tuple of various analysis outputs (see docstring for postprocess for details), note, if linear system decomposition fails, no solve is performed and an empty vector is returned.
  • ins::NamedTuple : Named Tuple of various pre-processed inputs (e.g. panels and body linear system), will only be returned if return_inputs=true
  • convergence_flag : Flag for successful solve convergence
source
analyze(
     multipoint::AbstractVector{OperatingPoint},
     propulsor::Propulsor,
     options::Options=set_options();
@@ -78,7 +78,7 @@
     solve_parameter_caching=nothing,
     solve_container_caching=nothing,
     return_inputs=false,
-)

Analyze propulsor, including preprocessing, for a set of operating points.

Arguments

  • multipoint::AbstractVector{OperatingPoint} : Vector of Operating Points at which to analyze the propulsor (note that the operating point within the propulsor input will be overwritten with these)
  • propulsor::Propulsor : Propulsor input object
  • options::Options=set_options() : Options object

Keyword Arguments

  • prepost_container_caching=nothing : Output of allocate_prepost_container_cache
  • solve_parameter_caching=nothing : Output of allocate_solve_parameter_container_cache
  • solve_container_caching=nothing : Output of allocate_solve_container_cache
  • return_inputs=false : flag as to whether or not to return the pre-processed inputs

Returns

  • outs::Vector{NamedTuple} : Vector of named tuples of various analysis outputs (see docstring for postprocess for details), note, if linear system decomposition fails, no solve is performed and an empty vector is returned.
  • ins::NamedTuple : Named Tuple of various pre-processed inputs (e.g. panels and body linear system), will only be returned if return_inputs=true
  • convergence_flag : Flag for successful solve convergence
source
analyze(
+)

Analyze propulsor, including preprocessing, for a set of operating points.

Arguments

  • multipoint::AbstractVector{OperatingPoint} : Vector of Operating Points at which to analyze the propulsor (note that the operating point within the propulsor input will be overwritten with these)
  • propulsor::Propulsor : Propulsor input object
  • options::Options=set_options() : Options object

Keyword Arguments

  • prepost_container_caching=nothing : Output of allocate_prepost_container_cache
  • solve_parameter_caching=nothing : Output of allocate_solve_parameter_container_cache
  • solve_container_caching=nothing : Output of allocate_solve_container_cache
  • return_inputs=false : flag as to whether or not to return the pre-processed inputs

Returns

  • outs::Vector{NamedTuple} : Vector of named tuples of various analysis outputs (see docstring for postprocess for details), note, if linear system decomposition fails, no solve is performed and an empty vector is returned.
  • ins::NamedTuple : Named Tuple of various pre-processed inputs (e.g. panels and body linear system), will only be returned if return_inputs=true
  • convergence_flag : Flag for successful solve convergence
source
analyze(
     multipoint::Vector{OperatingPoint},
     propulsor::Propulsor,
     prepost_containers,
@@ -91,4 +91,4 @@
     options::Options=set_options();
     return_inputs=false,
     solve_container_caching=nothing,
-)

Analyze propulsor, assuming setup_analysis has been called and the inputs are being passed in here.

Arguments

  • multipoint::AbstractVector{OperatingPoint} : Vector of Operating Points at which to analyze the propulsor (note that the operating point within the propulsor input will be overwritten with these)
  • propulsor::Propulsor : Propulsor input object
  • prepost_containers::NamedTuple : An output from setup_analysis containing reshaped views into the prepost cache
  • solve_parameter_cache_vector::Vector : An output from setup_analysis containing the relevant typed cache vector of solve parameters
  • solve_parameter_cache_dims::NamedTuple : An output from setup_analysis containing dimensions used for reshaping the solve parameter cache
  • airfoils::Vector{AFType} : An output from setup_analysis contiaining the blade element airfoil polar objects
  • A_bb_LU::LinearAlgebra.LU : An output from setup_analysis that is the LU decomposition of the AIC matrix used in the panel method
  • idmaps::NamedTuple : An output from setup_analysis containing bookkeeping information (index mappings)
  • problem_dimensions::NamedTuple : An output from setup_analysis contiaining bookkeeping information (problem dimensions)
  • options::Options=set_options() : Options object

Keyword Arguments

  • solve_container_caching=nothing : Output of allocate_solve_container_cache
  • return_inputs=false : flag as to whether or not to return the pre-processed inputs

Returns

  • outs::Vector{NamedTuple} : Named Tuple of various analysis outputs (see docstring for postprocess for details), note, if linear system decomposition fails, no solve is performed and an empty vector is returned.
  • ins::NamedTuple : Named Tuple of various pre-processed inputs (e.g. panels and body linear system), will only be returned if return_inputs=true. Note that some inputs will be overwritten (e.g. the linear system RHS components related to the freestream) and only those associated with the final operating point will be returned.
  • convergence_flag : Flag for successful solve convergence
source

Miscellaneous

Airfoil/Geometry Manipulation

NACA 6-Series Cascade Geometry Generation

+)

Analyze propulsor, assuming setup_analysis has been called and the inputs are being passed in here.

Arguments

  • multipoint::AbstractVector{OperatingPoint} : Vector of Operating Points at which to analyze the propulsor (note that the operating point within the propulsor input will be overwritten with these)
  • propulsor::Propulsor : Propulsor input object
  • prepost_containers::NamedTuple : An output from setup_analysis containing reshaped views into the prepost cache
  • solve_parameter_cache_vector::Vector : An output from setup_analysis containing the relevant typed cache vector of solve parameters
  • solve_parameter_cache_dims::NamedTuple : An output from setup_analysis containing dimensions used for reshaping the solve parameter cache
  • airfoils::Vector{AFType} : An output from setup_analysis contiaining the blade element airfoil polar objects
  • A_bb_LU::LinearAlgebra.LU : An output from setup_analysis that is the LU decomposition of the AIC matrix used in the panel method
  • idmaps::NamedTuple : An output from setup_analysis containing bookkeeping information (index mappings)
  • problem_dimensions::NamedTuple : An output from setup_analysis contiaining bookkeeping information (problem dimensions)
  • options::Options=set_options() : Options object

Keyword Arguments

  • solve_container_caching=nothing : Output of allocate_solve_container_cache
  • return_inputs=false : flag as to whether or not to return the pre-processed inputs

Returns

  • outs::Vector{NamedTuple} : Named Tuple of various analysis outputs (see docstring for postprocess for details), note, if linear system decomposition fails, no solve is performed and an empty vector is returned.
  • ins::NamedTuple : Named Tuple of various pre-processed inputs (e.g. panels and body linear system), will only be returned if return_inputs=true. Note that some inputs will be overwritten (e.g. the linear system RHS components related to the freestream) and only those associated with the final operating point will be returned.
  • convergence_flag : Flag for successful solve convergence
source

Miscellaneous

Airfoil/Geometry Manipulation

NACA 6-Series Cascade Geometry Generation

diff --git a/dev/DuctAPE/theory/index.html b/dev/DuctAPE/theory/index.html index 1786d2b1..f83c7dd9 100644 --- a/dev/DuctAPE/theory/index.html +++ b/dev/DuctAPE/theory/index.html @@ -1,2 +1,2 @@ -Theory · DuctAPE.jl

Theory

For a brief overview of the theory behind DuctAPE, see:

  • Mehr, J. and Ning, A., "DuctAPE: A steady-state, axisymmetric ducted fan analysis code designed for gradient-based optimization.," AIAA Aviation Forum, July 2024.

For a more thorough dive into the details see this pdf document.

+Theory · DuctAPE.jl

Theory

For a brief overview of the theory behind DuctAPE, see:

  • Mehr, J. and Ning, A., "DuctAPE: A steady-state, axisymmetric ducted fan analysis code designed for gradient-based optimization.," AIAA Aviation Forum, July 2024.

For a more thorough dive into the details see this pdf document.

diff --git a/dev/DuctAPE/tutorial/f30479a7.svg b/dev/DuctAPE/tutorial/8298b59a.svg similarity index 81% rename from dev/DuctAPE/tutorial/f30479a7.svg rename to dev/DuctAPE/tutorial/8298b59a.svg index affbd9ca..745359bc 100644 --- a/dev/DuctAPE/tutorial/f30479a7.svg +++ b/dev/DuctAPE/tutorial/8298b59a.svg @@ -1,74 +1,74 @@ - + - + - + - - - - - - + + + + + + 0.0 - + 0.1 - + 0.2 - + 0.3 - + z - - - - - - - + + + + + + + 0.00 - + 0.05 - + 0.10 - + 0.15 - + 0.20 - + r - - - - - - + + + + + + Duct - - + + Center Body diff --git a/dev/DuctAPE/tutorial/db81a906.svg b/dev/DuctAPE/tutorial/c80dff45.svg similarity index 77% rename from dev/DuctAPE/tutorial/db81a906.svg rename to dev/DuctAPE/tutorial/c80dff45.svg index 94679079..4fc14659 100644 --- a/dev/DuctAPE/tutorial/db81a906.svg +++ b/dev/DuctAPE/tutorial/c80dff45.svg @@ -1,88 +1,88 @@ - + - + - + - - - - - - + + + + + + 0.0 - + 0.1 - + 0.2 - + 0.3 - + z - - - - - - - + + + + + + + 0.00 - + 0.05 - + 0.10 - + 0.15 - + 0.20 - + r - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + Duct - - + + Center Body - - + + Blade Elements diff --git a/dev/DuctAPE/tutorial/5f10b6fa.svg b/dev/DuctAPE/tutorial/dde32380.svg similarity index 78% rename from dev/DuctAPE/tutorial/5f10b6fa.svg rename to dev/DuctAPE/tutorial/dde32380.svg index f7273a03..f597a5a3 100644 --- a/dev/DuctAPE/tutorial/5f10b6fa.svg +++ b/dev/DuctAPE/tutorial/dde32380.svg @@ -1,206 +1,206 @@ - + - + - + - - - - - - - + + + + + + + 0.0 - + 0.5 - + 1.0 - + 1.5 - + 2.0 - + Advance Ratio - - - - - - + + + + + + 0.0 - + 0.2 - + 0.4 - + 0.6 - + Efficiency - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + DFDC - - + + DuctAPE - + - - - - - - - + + + + + + + 0.0 - + 0.5 - + 1.0 - + 1.5 - + 2.0 - + Advance Ratio - - - - - - - + + + + + + + 0.0 - + 0.2 - + 0.4 - + 0.6 - + 0.8 - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + DFDC Cp - - + + DFDC Ct - - + + DuctAPE Cp - - + + DuctAPE Ct diff --git a/dev/DuctAPE/tutorial/index.html b/dev/DuctAPE/tutorial/index.html index af40400d..ea7b82e6 100644 --- a/dev/DuctAPE/tutorial/index.html +++ b/dev/DuctAPE/tutorial/index.html @@ -1,6 +1,6 @@ Getting Started · DuctAPE.jl

Getting Started

The following is a basic tutorial on how to set up the inputs to, and run, an analysis of a ducted fan in DuctAPE.

We begin by loading the package, and optionally create a shorthand name.

using DuctAPE
-const dt = DuctAPE

Assemble Inputs

The next step is to create the input object of type Propulsor.

DuctAPE.PropulsorType
Propulsor(duct_coordinates, centerbody_coordinates, rotorstator_parameters, operating_point, paneling_constants, reference_parameters)

Arguments

  • duct_coordinates::AbstractMatrix : The [z, r] coordinates of the duct geometry beginning at the inner (casing) side trailing edge and proceeding clockwise. Note that the duct geometry absolute radial position does not need to be included here if the autoshiftduct option is selected.
  • centerbody_coordinates::AbstractMatrix : The [z, r] coordinates of the centerbody beginning at the leading edge and ending at the trailing edge. Note that the leading edge is assumed to be placed at a radial distance of 0.0 from the axis of rotation.
  • operating_point::OperatingPoint : The operating point values.
  • paneling_constants::PanelingConstants : Constants used in re-paneling the geometry.
  • rotorstator_parameters::RotorStatorParameters : Rotor (and possibly stator) geometric paramters.
  • reference_parameters::ReferenceParameters : Reference Parameters.
source

Body Geometry

We begin by defining a matrix of coordinates for the duct and another for the centerbody geometries, for example:

duct_coordinates = [
+const dt = DuctAPE

Assemble Inputs

The next step is to create the input object of type Propulsor.

DuctAPE.PropulsorType
Propulsor(duct_coordinates, centerbody_coordinates, rotorstator_parameters, operating_point, paneling_constants, reference_parameters)

Arguments

  • duct_coordinates::AbstractMatrix : The [z, r] coordinates of the duct geometry beginning at the inner (casing) side trailing edge and proceeding clockwise. Note that the duct geometry absolute radial position does not need to be included here if the autoshiftduct option is selected.
  • centerbody_coordinates::AbstractMatrix : The [z, r] coordinates of the centerbody beginning at the leading edge and ending at the trailing edge. Note that the leading edge is assumed to be placed at a radial distance of 0.0 from the axis of rotation.
  • operating_point::OperatingPoint : The operating point values.
  • paneling_constants::PanelingConstants : Constants used in re-paneling the geometry.
  • rotorstator_parameters::RotorStatorParameters : Rotor (and possibly stator) geometric paramters.
  • reference_parameters::ReferenceParameters : Reference Parameters.
source

Body Geometry

We begin by defining a matrix of coordinates for the duct and another for the centerbody geometries, for example:

duct_coordinates = [
     0.304466  0.158439
     0.294972  0.158441
     0.28113   0.158423
@@ -111,9 +111,9 @@
     centerbody_coordinates[:, 2];
     color=2,
     linewidth=2,
-    label="Center Body",
Example block output
Note

The body geometry coordinates must be input as columns of z (axial) and r (radial) coordinates, in that order.

Rotor Geometry

The next step is to assemble an object of type RotorStatorParameters which contains the geometric information required to define the rotor(s) and their respective blade elements.

DuctAPE.RotorStatorParametersType
RotorStatorParameters(
+    label="Center Body",
Example block output
Note

The body geometry coordinates must be input as columns of z (axial) and r (radial) coordinates, in that order.

Rotor Geometry

The next step is to assemble an object of type RotorStatorParameters which contains the geometric information required to define the rotor(s) and their respective blade elements.

DuctAPE.RotorStatorParametersType
RotorStatorParameters(
     B, rotorzloc, r, Rhub, Rtip, chords, twists, tip_gap, airfoils, fliplift
-)

Composite type containing the rotor(s) geometric properties.

Note that the actual struct requires the inputs to be arrays, but there is a constructor function that will take in scalars and automatically build the array-based struct.

Arguments

  • B::AbstractVector{Float} : The number of blades for each rotor. May not be an integer, but usually is.
  • rotorzloc::AbstractVector{Float} : Dimensional, axial position of each rotor.
  • r::AbstractArray{Float} : Non-dimensional radial locations of each blade element.
  • Rhub::AbstractVector{Float} : Dimensional hub radius of rotor. (may be changed if it does not match the radial position of the centerbody geometry at the selected rotorzloc.
  • Rtip::AbstractVector{Float} : Dimensional tip radius of rotor. Is used to determine the radial position of the duct if the autoshiftduct option is selected.
  • chords::AbstractArray{Float} : Dimensional chord lengths of the blade elements.
  • twists::AbstractArray{Float} : Blade element angles, in radians.
  • tip_gap::AbstractVector{Float} : Currently unused, do not set to anything other than zeros.
  • airfoils::AbstractArray{AFType} : Airfoil types describing the airfoil polars for each blade element. Currently only fully tested with C4Blade.DFDCairfoil types.
  • fliplift::AbstractVector{Bool} : flag to indicate if the airfoil lift values should be flipped or not.
source

In this example, we have a single rotor defined as follows.

# number of rotors
+)

Composite type containing the rotor(s) geometric properties.

Note that the actual struct requires the inputs to be arrays, but there is a constructor function that will take in scalars and automatically build the array-based struct.

Arguments

  • B::AbstractVector{Float} : The number of blades for each rotor. May not be an integer, but usually is.
  • rotorzloc::AbstractVector{Float} : Dimensional, axial position of each rotor.
  • r::AbstractArray{Float} : Non-dimensional radial locations of each blade element.
  • Rhub::AbstractVector{Float} : Dimensional hub radius of rotor. (may be changed if it does not match the radial position of the centerbody geometry at the selected rotorzloc.
  • Rtip::AbstractVector{Float} : Dimensional tip radius of rotor. Is used to determine the radial position of the duct if the autoshiftduct option is selected.
  • chords::AbstractArray{Float} : Dimensional chord lengths of the blade elements.
  • twists::AbstractArray{Float} : Blade element angles, in radians.
  • tip_gap::AbstractVector{Float} : Currently unused, do not set to anything other than zeros.
  • airfoils::AbstractArray{AFType} : Airfoil types describing the airfoil polars for each blade element. Currently only fully tested with C4Blade.DFDCairfoil types.
  • fliplift::AbstractVector{Bool} : flag to indicate if the airfoil lift values should be flipped or not.
source

In this example, we have a single rotor defined as follows.

# number of rotors
 B = 5
 
 # rotor axial location
@@ -206,7 +206,7 @@
     seriestype=:scatter,
     markersize=3,
     markerstrokewidth=0,
-    label="Blade Elements",
Example block output
Airfoils

Airfoil types for DuctAPE are currently contained in the C4Blade (Cascade Compatible CCBlade) sub-module of DuctAPE which is exported as c4b and also contains the various airfoil evaluation functions used for the blade element lookups. The available airfoil types include all the airfoil types from CCBlade, as well as DFDCairfoil which is an XROTOR-like parametric cascade polar used in DFDC. In addition there are untested cascade types with similar structure to CCBlades airfoil types called DTCascade. Furthermore, there is an experimental actuator disk model implemented via the ADM airfoil type in C4Blade.

Operating Point

Next we will assemble the operating point which contains information about the freestream as well as the rotor rotation rate(s).

DuctAPE.OperatingPointType
OperatingPoint(Vinf, rhoinf, muinf, asound, Omega)

Propulsor operating point information.

Note that the actual struct requires the inputs to be arrays, but there is a constructor function that will take in scalars and automatically build the array-based struct.

Also note that even though each field is required to be a vector, only Omega should have more than one entry, and only then if there are more than one rotor. The purpose behind having vector rather than constant scalar inputs here is for ease of redefinition in an optimization setting when freestream design variables may be present.

Arguments

  • Vinf::AbstractVector{Float} : Freestream velocity magnitude (which is only in the axial direction).
  • rhoinf::AbstractVector{Float} : Freestream density
  • muinf::AbstractVector{Float} : Freestream viscosity
  • asound::AbstractVector{Float} : Freestream speed of sound
  • Omega::AbstractVector{Float} : Rotor rototation rate(s)
source
# Freestream
+    label="Blade Elements",
Example block output
Airfoils

Airfoil types for DuctAPE are currently contained in the C4Blade (Cascade Compatible CCBlade) sub-module of DuctAPE which is exported as c4b and also contains the various airfoil evaluation functions used for the blade element lookups. The available airfoil types include all the airfoil types from CCBlade, as well as DFDCairfoil which is an XROTOR-like parametric cascade polar used in DFDC. In addition there are untested cascade types with similar structure to CCBlades airfoil types called DTCascade. Furthermore, there is an experimental actuator disk model implemented via the ADM airfoil type in C4Blade.

Operating Point

Next we will assemble the operating point which contains information about the freestream as well as the rotor rotation rate(s).

DuctAPE.OperatingPointType
OperatingPoint(Vinf, rhoinf, muinf, asound, Omega)

Propulsor operating point information.

Note that the actual struct requires the inputs to be arrays, but there is a constructor function that will take in scalars and automatically build the array-based struct.

Also note that even though each field is required to be a vector, only Omega should have more than one entry, and only then if there are more than one rotor. The purpose behind having vector rather than constant scalar inputs here is for ease of redefinition in an optimization setting when freestream design variables may be present.

Arguments

  • Vinf::AbstractVector{Float} : Freestream velocity magnitude (which is only in the axial direction).
  • rhoinf::AbstractVector{Float} : Freestream density
  • muinf::AbstractVector{Float} : Freestream viscosity
  • asound::AbstractVector{Float} : Freestream speed of sound
  • Omega::AbstractVector{Float} : Rotor rototation rate(s)
source
# Freestream
 Vinf = 0.0 # hover condition
 rhoinf = 1.226
 asound = 340.0
@@ -224,7 +224,7 @@
     dte_minus_cbte,
     nwake_sheets,
     wake_length=1.0,
-)

Constants used in re-paneling geometry.

Note that unlike other input structures, this one, in general, does not define fields as vectors. This is because these values should not change throughout an optimization, even if the geometry may change. Otherwise, discontinuities could be experienced.

Arguments

  • nduct_inlet::Int : The number of panels to use for the duct inlet (this number is used for both the casing and nacelle re-paneling)
  • ncenterbody_inlet::Int : The number of panels to use for the centerbody inlet.
  • npanels::AbstractVector{Int} : A vector containing the number of panels between discrete locations inside the wake. Specifically, the number of panels between the rotors, between the last rotor and the first body trailing edge, between the body trailing edges (if different), and between the last body trailing edge and the end of the wake. The length of this vector should be N+1 (where N is the number of rotors) if the duct and centerbody trailing edges are aligned, and N+2 if not.
  • dte_minus_cbte::Float : An indicator concerning the hub and duct trailing edge relative locations. Should be set to -1 if the duct trailing edge axial position minus the centerbody trailing edge axial position is negative, +1 if positive (though any positive or negative number will suffice), and zero if the trailing edges are aligned.
  • nwake_sheets::Int : The number of wake sheets to use. Note this will also be setting the number of blade elements to use.
  • wake_length::Float=1.0 : Non-dimensional (based on the length from the foremost body leading edge and the aftmost body trailing edge) length of the wake extending behind the aftmost body trailing edge.
source
# number of panels for the duct inlet
+)

Constants used in re-paneling geometry.

Note that unlike other input structures, this one, in general, does not define fields as vectors. This is because these values should not change throughout an optimization, even if the geometry may change. Otherwise, discontinuities could be experienced.

Arguments

source
# number of panels for the duct inlet
 nduct_inlet = 30
 
 # number of panels for the center body inlet
@@ -248,7 +248,7 @@
 # assemble paneling constants
 paneling_constants = dt.PanelingConstants(
     nduct_inlet, ncenterbody_inlet, npanels, dte_minus_cbte, nwake_sheets, wake_length
-)

Reference Parameters

The reference parameters are used in the post-processing non-dimensionalizations.

DuctAPE.ReferenceParametersType
ReferenceParameters(Vref, Rref)

Reference parameters for post-process non-dimensionalization.

Note that the actual struct requires the inputs to be arrays, but there is a constructor function that will take in scalars and automatically build the array-based struct.

Arguments

  • Vref::AbstractVector{Float} : Reference velocity.
  • Rref::AbstractVector{Float} : Reference rotor tip radius.
source
# reference velocity (close to average axial velocity at rotor in this case)
+)

Reference Parameters

The reference parameters are used in the post-processing non-dimensionalizations.

DuctAPE.ReferenceParametersType
ReferenceParameters(Vref, Rref)

Reference parameters for post-process non-dimensionalization.

Note that the actual struct requires the inputs to be arrays, but there is a constructor function that will take in scalars and automatically build the array-based struct.

Arguments

  • Vref::AbstractVector{Float} : Reference velocity.
  • Rref::AbstractVector{Float} : Reference rotor tip radius.
source
# reference velocity (close to average axial velocity at rotor in this case)
 Vref = 50.0
 
 # reference radius (usually tip radius of rotor)
@@ -264,14 +264,14 @@
     paneling_constants,
     reference_parameters,
 )

Set Options

The default options should be sufficient for just starting out and are set through the set_options function.

DuctAPE.set_optionsFunction
set_options(; kwargs...)
-set_options(multipoint; kwargs...)

Set the options for DuctAPE to use.

Note that the vast majority of the available options are defined through keyword arguments. See the documentation for the various option types for more information.

Arguments

  • multipoint::AbstractArray{OperatingPoint} : a vector of operating points to use if running a multi-point analysis.
source
options = dt.set_options()
Options{Bool, Vector{Bool}, Float64, Vector{Int64}, Vector{String}, Vector{String}, DuctAPE.var"#42#47", IntegrationOptions{GaussLegendre{Vector{Float64}, Vector{Float64}}, GaussLegendre{Vector{Float64}, Vector{Float64}}}, ChainSolverOptions{Bool, Int64, DuctAPE.ExternalSolverOptions}, SLORGridSolverOptions{Bool, Float64, Int64}}(false, true, [1], DuctAPE.var"#42#47"(), true, false, 0.05, 1.0e-15, 2.220446049250313e-15, IntegrationOptions{GaussLegendre{Vector{Float64}, Vector{Float64}}, GaussLegendre{Vector{Float64}, Vector{Float64}}}(GaussLegendre{Vector{Float64}, Vector{Float64}}([0.019855071751231856, 0.10166676129318664, 0.2372337950418355, 0.4082826787521751, 0.591717321247825, 0.7627662049581645, 0.8983332387068134, 0.9801449282487682], [0.05061426814518838, 0.11119051722668723, 0.15685332293894372, 0.18134189168918097, 0.18134189168918097, 0.15685332293894372, 0.11119051722668723, 0.05061426814518838]), GaussLegendre{Vector{Float64}, Vector{Float64}}([0.019855071751231856, 0.10166676129318664, 0.2372337950418355, 0.4082826787521751, 0.591717321247825, 0.7627662049581645, 0.8983332387068134, 0.9801449282487682], [0.05061426814518838, 0.11119051722668723, 0.15685332293894372, 0.18134189168918097, 0.18134189168918097, 0.15685332293894372, 0.11119051722668723, 0.05061426814518838])), Bool[0], ["outputs.jl"], false, ["outs"], SLORGridSolverOptions{Bool, Float64, Int64}(200, 2.220446049250313e-16, Bool[0], [0]), ChainSolverOptions{Bool, Int64, DuctAPE.ExternalSolverOptions}(DuctAPE.ExternalSolverOptions[NLsolveOptions{Bool, Float64, Int64, UnionAll, @NamedTuple{}, Symbol}(:anderson, 1.0e-12, 200, LineSearches.MoreThuente, NamedTuple(), Bool[0], [0]), MinpackOptions{Bool, Float64, Int64, Symbol}(:hybr, 1.0e-12, 100, Bool[0], [0]), NLsolveOptions{Bool, Float64, Int64, UnionAll, @NamedTuple{}, Symbol}(:newton, 1.0e-12, 20, LineSearches.MoreThuente, NamedTuple(), Bool[0], [0])], Bool[0, 0, 0], [0, 0, 0]))

For more advanced option selection, see the examples and API reference.

Run a Single Analysis

With the propulsor input build, and the options selected, we are now ready to run an analysis. This is done simply with the analyze function which dispatches the appropriate analysis, solve, and post-processing functions based on the selected options.

DuctAPE.analyzeMethod
analyze(
+set_options(multipoint; kwargs...)

Set the options for DuctAPE to use.

Note that the vast majority of the available options are defined through keyword arguments. See the documentation for the various option types for more information.

Arguments

  • multipoint::AbstractArray{OperatingPoint} : a vector of operating points to use if running a multi-point analysis.
source
options = dt.set_options()
Options{Bool, Vector{Bool}, Float64, Vector{Int64}, Vector{String}, Vector{String}, DuctAPE.var"#42#47", IntegrationOptions{GaussLegendre{Vector{Float64}, Vector{Float64}}, GaussLegendre{Vector{Float64}, Vector{Float64}}}, ChainSolverOptions{Bool, Int64, DuctAPE.ExternalSolverOptions}, SLORGridSolverOptions{Bool, Float64, Int64}}(false, true, [1], DuctAPE.var"#42#47"(), true, false, 0.05, 1.0e-15, 2.220446049250313e-15, IntegrationOptions{GaussLegendre{Vector{Float64}, Vector{Float64}}, GaussLegendre{Vector{Float64}, Vector{Float64}}}(GaussLegendre{Vector{Float64}, Vector{Float64}}([0.019855071751231856, 0.10166676129318664, 0.2372337950418355, 0.4082826787521751, 0.591717321247825, 0.7627662049581645, 0.8983332387068134, 0.9801449282487682], [0.05061426814518838, 0.11119051722668723, 0.15685332293894372, 0.18134189168918097, 0.18134189168918097, 0.15685332293894372, 0.11119051722668723, 0.05061426814518838]), GaussLegendre{Vector{Float64}, Vector{Float64}}([0.019855071751231856, 0.10166676129318664, 0.2372337950418355, 0.4082826787521751, 0.591717321247825, 0.7627662049581645, 0.8983332387068134, 0.9801449282487682], [0.05061426814518838, 0.11119051722668723, 0.15685332293894372, 0.18134189168918097, 0.18134189168918097, 0.15685332293894372, 0.11119051722668723, 0.05061426814518838])), Bool[0], ["outputs.jl"], false, ["outs"], SLORGridSolverOptions{Bool, Float64, Int64}(200, 2.220446049250313e-16, Bool[0], [0]), ChainSolverOptions{Bool, Int64, DuctAPE.ExternalSolverOptions}(DuctAPE.ExternalSolverOptions[NLsolveOptions{Bool, Float64, Int64, UnionAll, @NamedTuple{}, Symbol}(:anderson, 1.0e-12, 200, LineSearches.MoreThuente, NamedTuple(), Bool[0], [0]), MinpackOptions{Bool, Float64, Int64, Symbol}(:hybr, 1.0e-12, 100, Bool[0], [0]), NLsolveOptions{Bool, Float64, Int64, UnionAll, @NamedTuple{}, Symbol}(:newton, 1.0e-12, 20, LineSearches.MoreThuente, NamedTuple(), Bool[0], [0])], Bool[0, 0, 0], [0, 0, 0]))

For more advanced option selection, see the examples and API reference.

Run a Single Analysis

With the propulsor input build, and the options selected, we are now ready to run an analysis. This is done simply with the analyze function which dispatches the appropriate analysis, solve, and post-processing functions based on the selected options.

DuctAPE.analyzeMethod
analyze(
     propulsor::Propulsor,
     options::Options=set_options();
     prepost_container_caching=nothing,
     solve_parameter_caching=nothing,
     solve_container_caching=nothing,
     return_inputs=false,
-)

Analyze propulsor, including preprocessing.

Arguments

  • propulsor::Propulsor : Propulsor input object (see docstring for Propulsor type)
  • options::Options=set_options() : Options object (see set_options and related functions)

Keyword Arguments

  • prepost_container_caching=nothing : Output of allocate_prepost_container_cache
  • solve_parameter_caching=nothing : Output of allocate_solve_parameter_container_cache
  • solve_container_caching=nothing : Output of allocate_solve_container_cache
  • return_inputs=false : flag as to whether or not to return the pre-processed inputs

Returns

  • outs::NamedTuple : Named Tuple of various analysis outputs (see docstring for postprocess for details), note, if linear system decomposition fails, no solve is performed and an empty vector is returned.
  • ins::NamedTuple : Named Tuple of various pre-processed inputs (e.g. panels and body linear system), will only be returned if return_inputs=true
  • convergence_flag : Flag for successful solve convergence
source
outs, success_flag = dt.analyze(propulsor, options)

Single Run Outputs

There are many outputs contained in the named tuple output from the analyze function (see the post_process() docstring), but some that may be of immediate interest include:

# Total Thrust Coefficient
+)

Analyze propulsor, including preprocessing.

Arguments

Keyword Arguments

Returns

source
outs, success_flag = dt.analyze(propulsor, options)

Single Run Outputs

There are many outputs contained in the named tuple output from the analyze function (see the post_process() docstring), but some that may be of immediate interest include:

# Total Thrust Coefficient
 outs.totals.CT
0.9693509063670719
# Total Torque Coefficient
 outs.totals.CQ
0.10306885180217912

Run a Multi-Point Analysis

In the case that one wants to run the same geometry at several different operating points, for example: for a range of advance ratios, there is another dispatch of the analyze function that takes in an input, multipoint, that is a vector of operating points.

DuctAPE.analyzeMethod
analyze(
     multipoint::AbstractVector{OperatingPoint},
@@ -281,7 +281,7 @@
     solve_parameter_caching=nothing,
     solve_container_caching=nothing,
     return_inputs=false,
-)

Analyze propulsor, including preprocessing, for a set of operating points.

Arguments

  • multipoint::AbstractVector{OperatingPoint} : Vector of Operating Points at which to analyze the propulsor (note that the operating point within the propulsor input will be overwritten with these)
  • propulsor::Propulsor : Propulsor input object
  • options::Options=set_options() : Options object

Keyword Arguments

  • prepost_container_caching=nothing : Output of allocate_prepost_container_cache
  • solve_parameter_caching=nothing : Output of allocate_solve_parameter_container_cache
  • solve_container_caching=nothing : Output of allocate_solve_container_cache
  • return_inputs=false : flag as to whether or not to return the pre-processed inputs

Returns

  • outs::Vector{NamedTuple} : Vector of named tuples of various analysis outputs (see docstring for postprocess for details), note, if linear system decomposition fails, no solve is performed and an empty vector is returned.
  • ins::NamedTuple : Named Tuple of various pre-processed inputs (e.g. panels and body linear system), will only be returned if return_inputs=true
  • convergence_flag : Flag for successful solve convergence
source

Running a multi-point analysis on the example geometry given there, it might look something like this:

# - Advance Ratio Range - #
+)

Analyze propulsor, including preprocessing, for a set of operating points.

Arguments

Keyword Arguments

Returns

source

Running a multi-point analysis on the example geometry given there, it might look something like this:

# - Advance Ratio Range - #
 Js = range(0.0, 2.0; step=0.01)
 
 # - Calculate Vinfs - #
@@ -394,4 +394,4 @@
     label="DuctAPE Ct"
 )
 
-plot(pe, ppt; size=(700,350), layout=(1,2), margin=2mm)
Example block output +plot(pe, ppt; size=(700,350), layout=(1,2), margin=2mm)Example block output diff --git a/dev/assets/ductapelogo.svg b/dev/assets/ductapelogo.svg new file mode 100644 index 00000000..d8ad1697 --- /dev/null +++ b/dev/assets/ductapelogo.svg @@ -0,0 +1,53 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/dev/assets/gen_logo.jl b/dev/assets/gen_logo.jl index 3481b645..d43f2135 100644 --- a/dev/assets/gen_logo.jl +++ b/dev/assets/gen_logo.jl @@ -143,7 +143,14 @@ plot!( ) # axis of rotation -plot!([nz[1], wg[1, end, 1]], -0.001 * ones(2); color=plotsgray, label="", lw=lw - 1, linestyle=:dashdot) +plot!( + [nz[1], wg[1, end, 1]], + -0.001 * ones(2); + color=plotsgray, + label="", + lw=lw - 1, + linestyle=:dashdot, +) # plot!(nz[13] * ones(2), [-0.075, 0.075]; color=plotsgray, label="", lw=lw - 1) # plot!(nz[13] * ones(2) .+ 0.075, [-0.075, 0.075]; color=plotsgray, label="", lw=lw - 1) @@ -158,5 +165,7 @@ plot!([nz[1], wg[1, end, 1]], -0.001 * ones(2); color=plotsgray, label="", lw=lw ##### ----- SAVE ----- ##### plot!(; grid=false, background_color=nothing) -# savefig("logo.svg") -savefig("logo.png") +savefig("src/assets/logo.png") + +plot!(; background_color=:white, size=(600, 600)) +savefig("src/assets/ductapelogo.svg") diff --git a/dev/assets/logo.png b/dev/assets/logo.png index 55a8ad370584f1683dfc5d244c36458582c4133c..9d0471b7c9424564086b3ef5c9d48ab0c915f5c7 100644 GIT binary patch literal 99004 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

XM{dSF}!Vos{m<8 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 -Home · DuctAPE.jl

DuctAPE.jl [Ducted Axisymmetric Propulsor Evaluation]

Authors: Judd Mehr,

Contributers: Taylor McDonnell,

DuctAPE is a code for the aerodynamic evaluation of axisymmetric ducted propulsors designed for incompressible (low mach) applications. It is strongly influenced by the underlying theory of Ducted Fan Design Code (DFDC), utilizing a linear axisymmetric vortex panel method for duct and center body, blade element lifting line rotor representation, and wake model axisymmetrically smeared onto an elliptic grid for efficient computation. DuctAPE has been developed specifically for applications in gradient-based optimization settings.

Installation

pkg> add DuctAPE

Documentation

  • Start with Getting Started to get up and running.
  • The Advanced Usage tab includes several pages of additional information for customizing your usage.
  • The API tab contains public and private method descriptions.
  • The Theory tab contain several pages on the underlying theory of DuctAPE.
  • The C$^4$Blade tab contains documentation for the C$^4$Blade submodule used for airfoil/cascade management within DuctAPE as well as state initialization.

Citing

Mehr, J. and Ning, A., "DuctAPE: A steady-state, axisymmetric ducted fan analysis code designed for gradient-based optimization.," AIAA Aviation Forum, July 2024.

+Home · DuctAPE.jl

DuctAPE.jl [Ducted Axisymmetric Propulsor Evaluation]

Authors: Judd Mehr,

Contributers: Taylor McDonnell,

DuctAPE is a code for the aerodynamic evaluation of axisymmetric ducted propulsors designed for incompressible (low mach) applications. It is strongly influenced by the underlying theory of Ducted Fan Design Code (DFDC), utilizing a linear axisymmetric vortex panel method for duct and center body, blade element lifting line rotor representation, and wake model axisymmetrically smeared onto an elliptic grid for efficient computation. DuctAPE has been developed specifically for applications in gradient-based optimization settings.

Installation

pkg> add DuctAPE

Documentation

  • Start with Getting Started to get up and running.
  • The Advanced Usage tab includes several pages of additional information for customizing your usage.
  • The API tab contains public and private method descriptions.
  • The Theory tab contain several pages on the underlying theory of DuctAPE.
  • The C$^4$Blade tab contains documentation for the C$^4$Blade submodule used for airfoil/cascade management within DuctAPE as well as state initialization.

Citing

Mehr, J. and Ning, A., "DuctAPE: A steady-state, axisymmetric ducted fan analysis code designed for gradient-based optimization.," AIAA Aviation Forum, July 2024.

diff --git a/dev/search_index.js b/dev/search_index.js index 520f52b8..069b354d 100644 --- a/dev/search_index.js +++ b/dev/search_index.js @@ -1,3 +1,3 @@ var documenterSearchIndex = {"docs": -[{"location":"DuctAPE/advanced_usage/outputs/#Available-Outputs","page":"Outputs","title":"Available Outputs","text":"","category":"section"},{"location":"DuctAPE/advanced_usage/outputs/","page":"Outputs","title":"Outputs","text":"The output tuple contains many items. The post_process function docstring lists them:","category":"page"},{"location":"DuctAPE/advanced_usage/outputs/","page":"Outputs","title":"Outputs","text":"DuctAPE.post_process","category":"page"},{"location":"DuctAPE/advanced_usage/outputs/#DuctAPE.post_process-DuctAPE-advanced_usage-outputs","page":"Outputs","title":"DuctAPE.post_process","text":"post_process(\n solver_options,\n converged_states,\n prepost_containers,\n solve_container_caching,\n solve_parameter_cache_vector,\n solve_parameter_cache_dims,\n operating_point,\n reference_parameters,\n A_bb_LU,\n airfoils,\n idmaps,\n problem_dimensions,\n multipoint_index;\n write_outputs=options.write_outputs,\n outfile=options.outfile,\n checkoutfileexists=options.checkoutfileexists,\n output_tuple_name=options.output_tuple_name,\n verbose=options.verbose,\n)\n\nPost-process a converged nonlinear solve solution.\n\nArguments\n\nsolver_options::SolverOptionsType : A SolverOptionsType object (also used for dispatch)\nconverged_states::Vector{Float} : the converged state variables\nprepost_containers::NamedTuple : the named tuple containing pre-allocated containers for the pre- and post-processing intermediate calculations\nsolve_container_cache::NamedTuple : the cache and dimensions for intermediate values in the residual calculation\nsolve_parameter_cache_vector::Vector{Float} : the applicably typed cache vector for the solve parameters\nsolve_parameter_cache_dims::NamedTuple : the dimensions of the solver parameters\noperating_point::OperatingPoint : the operating point being analyzed\nreference_parameters::ReferenceParameters : a ReferenceParameters object\nA_bb_LU::LinearAlgebra.LU : LinearAlgebra LU factorization of the LHS matrix\nairfoils::Vector{AFType} : A matrix of airfoil types associated with each of the blade elements\nidmaps::NamedTuple : A named tuple containing index mapping used in bookkeeping throughout solve and post-process\nproblem_dimensions::ProblemDimensions : A ProblemDimensions object\n\nKeyword Arguments\n\nmultipoint_index::Vector{Int} : a one-dimensional vector containing the index of which multipoint analysis operating point is being analyzed.\nwrite_outputs=options.write_outputs::Vector{Bool} : a vector with the same length as number of multipoints indicating if the outputs should be saved.\noutfile=options.outfile::Vector{String} : a vector of file paths/names for where outputs should be written\ncheckoutfileexists=options.checkoutfileexists::Bool : a flag for whether existing files should be checked for or if blind overwriting is okay.\noutput_tuple_name=options.output_tuple_name::Vector{String} : the variable name(s) of the named tuple of outputs to be written.\nverbose::Bool=false : flag to print verbose statements\n\nReturns\n\nouts::NamedTuple : A named tuple containing all the output values including\n\nbodies\npanel_strengths\ntotal_thrust\nthrust_comp\ninduced_efficiency\ncp_in\ncp_out\ncp_casing_in\ncp_casing_out\ncasing_zpts\ncp_nacelle_in\ncp_nacelle_out\nnacelle_zpts\ncp_centerbody_in\ncp_centerbody_out\ncenterbody_zpts\nVtot_in\nVtot_out\nVtot_prejump\nvtot_body\nvtot_jump\nvtot_wake\nvtot_rotors\nVtan_in\nVtan_out\nvtan_casing_in\nvtan_casing_out\nvtan_nacelle_in\nvtan_nacelle_out\nvtan_centerbody_in\nvtan_centerbody_out\nrotors\ncirculation\npanel_strengths\nefficiency\ninviscid_thrust\ninviscid_thrust_dist\nviscous_thrust\nviscous_thrust_dist\nthrust\nCT\ninviscid_torque\ninviscid_torque_dist\nviscous_torque\nviscous_torque_dist\ntorque\nCQ\ninviscid_power\ninviscid_power_dist\nviscous_power\nviscous_power_dist\npower\nCP\ncl\ncd\nalpha\nbeta1\nblade_normal_force_per_unit_span\nblade_tangential_force_per_unit_span\nwake\npanel_strengths\ntotals\nthrust\ntorque\npower\nCT\nCQ\nCP\ntotal_efficiency\nideal_efficiency\nintermediate_solve_values\nvz_rotor\nvtheta_rotor\nCm_wake\nreynolds\nmach\nCz_rotor\nCtheta_rotor\nCmag_rotor\nGamma_tilde\nH_tilde\ndeltaGamma2\ndeltaH\nvz_wake\nvr_wake\nCm_avg\n\n\n\n\n\n","category":"function"},{"location":"DuctAPE/advanced_usage/outputs/#Returning-the-Pre-process-Objects","page":"Outputs","title":"Returning the Pre-process Objects","text":"","category":"section"},{"location":"DuctAPE/advanced_usage/outputs/","page":"Outputs","title":"Outputs","text":"Sometimes, it may be desireable to return the pre-process objects, including:","category":"page"},{"location":"DuctAPE/advanced_usage/outputs/","page":"Outputs","title":"Outputs","text":"panels which is a named tuple containing the body, rotor, and wake panel objects\nivb which are the unit induced velocities on the body panels\nsolve_parameter_tuple which contains all of the solver parameters\nblade_elements which contains all of the blade element geometry and airfoil information\nlinsys which contains all the linear system objects for the panel method\nidmaps which contains all the index mapping used throughout the solve and post-process.","category":"page"},{"location":"DuctAPE/advanced_usage/outputs/","page":"Outputs","title":"Outputs","text":"In this case, we can use the return_inputs keyword argument when calling the analyze function to return a named tuple containing those pre-process objects.","category":"page"},{"location":"DuctAPE/advanced_usage/outputs/","page":"Outputs","title":"Outputs","text":"outs, ins, success_flag = dt.analyze(propulsor; return_inputs=true)","category":"page"},{"location":"DuctAPE/advanced_usage/manual_repaneling/#Circumventing-the-Automated-Geometry-Re-paneling","page":"-","title":"Circumventing the Automated Geometry Re-paneling","text":"","category":"section"},{"location":"DuctAPE/advanced_usage/manual_repaneling/","page":"-","title":"-","text":"It is not advised to circument the automated geometry re-paneling, but if it must be done, the user needs to provide duct, centerbody, and wake nodes conforming to compatible geometry formatting. The best use case for this is to use previously generated geometry or perhaps geometry exported from DFDC.","category":"page"},{"location":"DuctAPE/advanced_usage/manual_repaneling/","page":"-","title":"-","text":"The process is not simple, but is possible. You would have to manually run the dispatches of precompute_parameters that take in the the repaneled body nodes and wake grid. These dispatches exist for this purpose, but there is, by design, no convenience functions at this time to aid the user in easily bypassing the automated repaneling.","category":"page"},{"location":"DuctAPE/advanced_usage/precompilation/#Pre-compiling-the-Caches","page":"Preallocation","title":"Pre-compiling the Caches","text":"","category":"section"},{"location":"DuctAPE/advanced_usage/precompilation/","page":"Preallocation","title":"Preallocation","text":"There are several available caches that can be precompiled to help speed up multiple analyses. The first is a cache used for intermediate calculations in the pre- and post-processing phases of the analysis. It can be preallocated using allocate_prepost_container_cache","category":"page"},{"location":"DuctAPE/advanced_usage/precompilation/","page":"Preallocation","title":"Preallocation","text":"DuctAPE.allocate_prepost_container_cache","category":"page"},{"location":"DuctAPE/advanced_usage/precompilation/#DuctAPE.allocate_prepost_container_cache-DuctAPE-advanced_usage-precompilation","page":"Preallocation","title":"DuctAPE.allocate_prepost_container_cache","text":"allocate_prepost_container_cache(paneling_constants::PanelingConstants)\nallocate_prepost_container_cache(problem_dimensions::ProblemDimensions)\n\nAllocate the pre- and post-processing cache (used for intermediate calculations) based on paneling constants or problem dimensions.\n\nArguments\n\npaneling_constants::PanelingConstants : a PanelingConstants object\n\nOR\n\nproblem_dimensions::ProblemDimensions : a ProblemDimensions object\n\nKeyword Arguments\n\nfd_chunk_size::Int=12 : chunk size to use for PreallocationTools caches. Note that the automated chuck size for DuctAPE will always be the ForwardDiff threshold of 12 due to the size of the system, so it will be best to leave this at the default unless further development allows for chunk size selection for individual solvers.\nlevels::Int=1 : levels for nested duals. Note that since ImplicitAD is being used for all solves, there should be no need for more than 1 level.\n\nReturns\n\nprepost_container_caching::NamedTuple : a Named Tuple containing:\nprepost_container_cache::PreallocationTools.DiffCache : the cache\nprepost_container_cache_dims::NamedTuple : a named tuple containing the dimensions used for reshaping the cache when needed.\n\n\n\n\n\n","category":"function"},{"location":"DuctAPE/advanced_usage/precompilation/","page":"Preallocation","title":"Preallocation","text":"The second is a cache containing parameters used in the solver, in other words, the results of the pre-processing phase. It can be preallocated using allocate_solve_parameter_cache.","category":"page"},{"location":"DuctAPE/advanced_usage/precompilation/","page":"Preallocation","title":"Preallocation","text":"DuctAPE.allocate_solve_parameter_cache","category":"page"},{"location":"DuctAPE/advanced_usage/precompilation/#DuctAPE.allocate_solve_parameter_cache-DuctAPE-advanced_usage-precompilation","page":"Preallocation","title":"DuctAPE.allocate_solve_parameter_cache","text":"allocate_solve_parameter_cache(\n solve_type::SolverOptionsType,\n paneling_constants::PanelingConstants;\n fd_chunk_size=12,\n levels=1,\n)\nallocate_solve_parameter_cache(\n solve_type::SolverOptionsType,\n problem_dimensions::ProblemDimensions;\n fd_chunk_size=12,\n levels=1\n)\n\nAllocate the solve parameter cache for parameters passed into the solver(s).\n\nArguments\n\nsolve_type::SolverOptionsType : Solver options type used for dispatch\npaneling_constants::PanelingConstants : a PanlingConstants object used for sizing\n\nOR\n\nproblem_dimensions::ProblemDimensions : a ProblemDimensions object used for sizing\n\nKeyword Arguments\n\nfd_chunk_size::Int=12 : chunk size to use for PreallocationTools caches. Note that the automated chuck size for DuctAPE will always be the ForwardDiff threshold of 12 due to the size of the system, so it will be best to leave this at the default unless further development allows for chunk size selection for individual solvers.\nlevels::Int=1 : levels for nested duals. Note that since ImplicitAD is being used for all solves, there should be no need for more than 1 level.\n\nReturns\n\nsolve_parameter_caching::NamedTuple : a Named Tuple containing:\nsolve_parameter_cache::PreallocationTools.DiffCache : the cache\nsolve_parameter_cache_dims::NamedTuple : a named tuple containing the dimensions used for reshaping the cache when needed.\n\n\n\n\n\n","category":"function"},{"location":"DuctAPE/advanced_usage/precompilation/","page":"Preallocation","title":"Preallocation","text":"The final precompileable cache is for intermediate calculations within the solve and can be preallocated using allocate_solve_container_cache","category":"page"},{"location":"DuctAPE/advanced_usage/precompilation/","page":"Preallocation","title":"Preallocation","text":"DuctAPE.allocate_solve_container_cache","category":"page"},{"location":"DuctAPE/advanced_usage/precompilation/#DuctAPE.allocate_solve_container_cache-DuctAPE-advanced_usage-precompilation","page":"Preallocation","title":"DuctAPE.allocate_solve_container_cache","text":"allocate_solve_container_cache(\n solve_type::SolverOptionsType,\n paneling_constants::PanelingConstants;\n fd_chunk_size=12,\n levels=1,\n)\nallocate_solve_container_cache(\n solve_type::SolverOptionsType,\n problem_dimensions::ProblemDimensions;\n fd_chunk_size=12,\n levels=1,\n)\n\nAllocate the solve cache (used for intermediate calculations) based on paneling constants or problem dimensions.\n\nArguments\n\npaneling_constants::PanelingConstants : a PanelingConstants object\n\nOR\n\nproblem_dimensions::ProblemDimensions : a ProblemDimensions object\n\nKeyword Arguments\n\nfd_chunk_size::Int=12 : chunk size to use for PreallocationTools caches. Note that the automated chuck size for DuctAPE will always be the ForwardDiff threshold of 12 due to the size of the system, so it will be best to leave this at the default unless further development allows for chunk size selection for individual solvers.\nlevels::Int=1 : levels for nested duals. Note that since ImplicitAD is being used for all solves, there should be no need for more than 1 level.\n\nReturns\n\nsolve_container_caching::NamedTuple : a Named Tuple containing:\nsolve_container_cache::PreallocationTools.DiffCache : the cache\nsolve_container_cache_dims::NamedTuple : a named tuple containing the dimensions used for reshaping the cache when needed.\n\n\n\n\n\n","category":"function"},{"location":"DuctAPE/advanced_usage/precompilation/","page":"Preallocation","title":"Preallocation","text":"You may run all these simultaneously using the initialize_all_caches function.","category":"page"},{"location":"DuctAPE/advanced_usage/precompilation/","page":"Preallocation","title":"Preallocation","text":"DuctAPE.initialize_all_caches","category":"page"},{"location":"DuctAPE/advanced_usage/precompilation/#DuctAPE.initialize_all_caches-DuctAPE-advanced_usage-precompilation","page":"Preallocation","title":"DuctAPE.initialize_all_caches","text":"initialize_all_caches(solver_options, paneling_constants)\n\nConvenience function to initialize all caches before calling analysis.\n\nArguments\n\nsolver_options::SolverOptionsType : solver options used for cache allocation dispatch\npaneling_constants::PanelingConstants : PanelingConstants object upon which all cache sizing depends\n\nKeyword Arguments\n\nfd_chunk_size::Int=12 : chunk size to use for PreallocationTools caches. Note that the automated chuck size for DuctAPE will always be the ForwardDiff threshold of 12 due to the size of the system, so it will be best to leave this at the default unless further development allows for chunk size selection for individual solvers.\nlevels::Int=1 : levels for nested duals. Note that since ImplicitAD is being used for all solves, there should be no need for more than 1 level.\n\nReturns\n\nprepost_container_caching::NamedTuple : A named tuple containing the PreallocationTools DiffCache and a named tuple with relevant dimensions for accessing the cache.\nsolve_parameter_caching::NamedTuple : A named tuple containing the PreallocationTools DiffCache and a named tuple with relevant dimensions for accessing the cache.\nsolve_container_caching::NamedTuple : A named tuple containing the PreallocationTools DiffCache and a named tuple with relevant dimensions for accessing the cache.\n\n\n\n\n\n","category":"function"},{"location":"DuctAPE/advanced_usage/precompilation/#How-to-pass-the-caches-into-an-analysis","page":"Preallocation","title":"How to pass the caches into an analysis","text":"","category":"section"},{"location":"DuctAPE/advanced_usage/precompilation/","page":"Preallocation","title":"Preallocation","text":"The precompiled caches can be passed in via keyword arguments to the analysis functions. If they are not, they are generated as the first step in the analysis.","category":"page"},{"location":"DuctAPE/advanced_usage/precompilation/","page":"Preallocation","title":"Preallocation","text":"DuctAPE.analyze(\n propulsor::Propulsor,\n options::Options=set_options())","category":"page"},{"location":"DuctAPE/advanced_usage/precompilation/#DuctAPE.analyze-DuctAPE-advanced_usage-precompilation","page":"Preallocation","title":"DuctAPE.analyze","text":"analyze(\n propulsor::Propulsor,\n options::Options=set_options();\n prepost_container_caching=nothing,\n solve_parameter_caching=nothing,\n solve_container_caching=nothing,\n return_inputs=false,\n)\n\nAnalyze propulsor, including preprocessing.\n\nArguments\n\npropulsor::Propulsor : Propulsor input object (see docstring for Propulsor type)\noptions::Options=set_options() : Options object (see set_options and related functions)\n\nKeyword Arguments\n\nprepost_container_caching=nothing : Output of allocate_prepost_container_cache\nsolve_parameter_caching=nothing : Output of allocate_solve_parameter_container_cache\nsolve_container_caching=nothing : Output of allocate_solve_container_cache\nreturn_inputs=false : flag as to whether or not to return the pre-processed inputs\n\nReturns\n\nouts::NamedTuple : Named Tuple of various analysis outputs (see docstring for postprocess for details), note, if linear system decomposition fails, no solve is performed and an empty vector is returned.\nins::NamedTuple : Named Tuple of various pre-processed inputs (e.g. panels and body linear system), will only be returned if return_inputs=true\nconvergence_flag : Flag for successful solve convergence\n\n\n\n\n\n","category":"function"},{"location":"DuctAPE/api/public_api/#Public-API","page":"Public API Reference","title":"Public API","text":"","category":"section"},{"location":"DuctAPE/api/public_api/","page":"Public API Reference","title":"Public API Reference","text":"Pages = [\"public_api.md\"]\nDepth = 5","category":"page"},{"location":"DuctAPE/api/public_api/#Input-Types","page":"Public API Reference","title":"Input Types","text":"","category":"section"},{"location":"DuctAPE/api/public_api/","page":"Public API Reference","title":"Public API Reference","text":"DuctAPE.Propulsor\nDuctAPE.RotorStatorParameters\nDuctAPE.OperatingPoint\nDuctAPE.PanelingConstants\nDuctAPE.ReferenceParameters","category":"page"},{"location":"DuctAPE/api/public_api/#DuctAPE.Propulsor","page":"Public API Reference","title":"DuctAPE.Propulsor","text":"Propulsor(duct_coordinates, centerbody_coordinates, rotorstator_parameters, operating_point, paneling_constants, reference_parameters)\n\nArguments\n\nduct_coordinates::AbstractMatrix : The [z, r] coordinates of the duct geometry beginning at the inner (casing) side trailing edge and proceeding clockwise. Note that the duct geometry absolute radial position does not need to be included here if the autoshiftduct option is selected.\ncenterbody_coordinates::AbstractMatrix : The [z, r] coordinates of the centerbody beginning at the leading edge and ending at the trailing edge. Note that the leading edge is assumed to be placed at a radial distance of 0.0 from the axis of rotation.\noperating_point::OperatingPoint : The operating point values.\npaneling_constants::PanelingConstants : Constants used in re-paneling the geometry.\nrotorstator_parameters::RotorStatorParameters : Rotor (and possibly stator) geometric paramters.\nreference_parameters::ReferenceParameters : Reference Parameters.\n\n\n\n\n\n","category":"type"},{"location":"DuctAPE/api/public_api/#DuctAPE.RotorStatorParameters","page":"Public API Reference","title":"DuctAPE.RotorStatorParameters","text":"RotorStatorParameters(\n B, rotorzloc, r, Rhub, Rtip, chords, twists, tip_gap, airfoils, fliplift\n)\n\nComposite type containing the rotor(s) geometric properties.\n\nNote that the actual struct requires the inputs to be arrays, but there is a constructor function that will take in scalars and automatically build the array-based struct.\n\nArguments\n\nB::AbstractVector{Float} : The number of blades for each rotor. May not be an integer, but usually is.\nrotorzloc::AbstractVector{Float} : Dimensional, axial position of each rotor.\nr::AbstractArray{Float} : Non-dimensional radial locations of each blade element.\nRhub::AbstractVector{Float} : Dimensional hub radius of rotor. (may be changed if it does not match the radial position of the centerbody geometry at the selected rotorzloc.\nRtip::AbstractVector{Float} : Dimensional tip radius of rotor. Is used to determine the radial position of the duct if the autoshiftduct option is selected.\nchords::AbstractArray{Float} : Dimensional chord lengths of the blade elements.\ntwists::AbstractArray{Float} : Blade element angles, in radians.\ntip_gap::AbstractVector{Float} : Currently unused, do not set to anything other than zeros.\nairfoils::AbstractArray{AFType} : Airfoil types describing the airfoil polars for each blade element. Currently only fully tested with C4Blade.DFDCairfoil types.\nfliplift::AbstractVector{Bool} : flag to indicate if the airfoil lift values should be flipped or not.\n\n\n\n\n\n","category":"type"},{"location":"DuctAPE/api/public_api/#DuctAPE.OperatingPoint","page":"Public API Reference","title":"DuctAPE.OperatingPoint","text":"OperatingPoint(Vinf, rhoinf, muinf, asound, Omega)\n\nPropulsor operating point information.\n\nNote that the actual struct requires the inputs to be arrays, but there is a constructor function that will take in scalars and automatically build the array-based struct.\n\nAlso note that even though each field is required to be a vector, only Omega should have more than one entry, and only then if there are more than one rotor. The purpose behind having vector rather than constant scalar inputs here is for ease of redefinition in an optimization setting when freestream design variables may be present.\n\nArguments\n\nVinf::AbstractVector{Float} : Freestream velocity magnitude (which is only in the axial direction).\nrhoinf::AbstractVector{Float} : Freestream density\nmuinf::AbstractVector{Float} : Freestream viscosity\nasound::AbstractVector{Float} : Freestream speed of sound\nOmega::AbstractVector{Float} : Rotor rototation rate(s)\n\n\n\n\n\n","category":"type"},{"location":"DuctAPE/api/public_api/#DuctAPE.PanelingConstants","page":"Public API Reference","title":"DuctAPE.PanelingConstants","text":"PanelingConstants(\n nduct_inlet,\n ncenterbody_inlet,\n npanels,\n dte_minus_cbte,\n nwake_sheets,\n wake_length=1.0,\n)\n\nConstants used in re-paneling geometry.\n\nNote that unlike other input structures, this one, in general, does not define fields as vectors. This is because these values should not change throughout an optimization, even if the geometry may change. Otherwise, discontinuities could be experienced.\n\nArguments\n\nnduct_inlet::Int : The number of panels to use for the duct inlet (this number is used for both the casing and nacelle re-paneling)\nncenterbody_inlet::Int : The number of panels to use for the centerbody inlet.\nnpanels::AbstractVector{Int} : A vector containing the number of panels between discrete locations inside the wake. Specifically, the number of panels between the rotors, between the last rotor and the first body trailing edge, between the body trailing edges (if different), and between the last body trailing edge and the end of the wake. The length of this vector should be N+1 (where N is the number of rotors) if the duct and centerbody trailing edges are aligned, and N+2 if not.\ndte_minus_cbte::Float : An indicator concerning the hub and duct trailing edge relative locations. Should be set to -1 if the duct trailing edge axial position minus the centerbody trailing edge axial position is negative, +1 if positive (though any positive or negative number will suffice), and zero if the trailing edges are aligned.\nnwake_sheets::Int : The number of wake sheets to use. Note this will also be setting the number of blade elements to use.\nwake_length::Float=1.0 : Non-dimensional (based on the length from the foremost body leading edge and the aftmost body trailing edge) length of the wake extending behind the aftmost body trailing edge.\n\n\n\n\n\n","category":"type"},{"location":"DuctAPE/api/public_api/#DuctAPE.ReferenceParameters","page":"Public API Reference","title":"DuctAPE.ReferenceParameters","text":"ReferenceParameters(Vref, Rref)\n\nReference parameters for post-process non-dimensionalization.\n\nNote that the actual struct requires the inputs to be arrays, but there is a constructor function that will take in scalars and automatically build the array-based struct.\n\nArguments\n\nVref::AbstractVector{Float} : Reference velocity.\nRref::AbstractVector{Float} : Reference rotor tip radius.\n\n\n\n\n\n","category":"type"},{"location":"DuctAPE/api/public_api/#Preallocations","page":"Public API Reference","title":"Preallocations","text":"","category":"section"},{"location":"DuctAPE/api/public_api/","page":"Public API Reference","title":"Public API Reference","text":"DuctAPE.allocate_prepost_container_cache\nDuctAPE.allocate_solve_parameter_cache\nDuctAPE.allocate_solve_container_cache","category":"page"},{"location":"DuctAPE/api/public_api/#DuctAPE.allocate_prepost_container_cache","page":"Public API Reference","title":"DuctAPE.allocate_prepost_container_cache","text":"allocate_prepost_container_cache(paneling_constants::PanelingConstants)\nallocate_prepost_container_cache(problem_dimensions::ProblemDimensions)\n\nAllocate the pre- and post-processing cache (used for intermediate calculations) based on paneling constants or problem dimensions.\n\nArguments\n\npaneling_constants::PanelingConstants : a PanelingConstants object\n\nOR\n\nproblem_dimensions::ProblemDimensions : a ProblemDimensions object\n\nKeyword Arguments\n\nfd_chunk_size::Int=12 : chunk size to use for PreallocationTools caches. Note that the automated chuck size for DuctAPE will always be the ForwardDiff threshold of 12 due to the size of the system, so it will be best to leave this at the default unless further development allows for chunk size selection for individual solvers.\nlevels::Int=1 : levels for nested duals. Note that since ImplicitAD is being used for all solves, there should be no need for more than 1 level.\n\nReturns\n\nprepost_container_caching::NamedTuple : a Named Tuple containing:\nprepost_container_cache::PreallocationTools.DiffCache : the cache\nprepost_container_cache_dims::NamedTuple : a named tuple containing the dimensions used for reshaping the cache when needed.\n\n\n\n\n\n","category":"function"},{"location":"DuctAPE/api/public_api/#DuctAPE.allocate_solve_parameter_cache","page":"Public API Reference","title":"DuctAPE.allocate_solve_parameter_cache","text":"allocate_solve_parameter_cache(\n solve_type::SolverOptionsType,\n paneling_constants::PanelingConstants;\n fd_chunk_size=12,\n levels=1,\n)\nallocate_solve_parameter_cache(\n solve_type::SolverOptionsType,\n problem_dimensions::ProblemDimensions;\n fd_chunk_size=12,\n levels=1\n)\n\nAllocate the solve parameter cache for parameters passed into the solver(s).\n\nArguments\n\nsolve_type::SolverOptionsType : Solver options type used for dispatch\npaneling_constants::PanelingConstants : a PanlingConstants object used for sizing\n\nOR\n\nproblem_dimensions::ProblemDimensions : a ProblemDimensions object used for sizing\n\nKeyword Arguments\n\nfd_chunk_size::Int=12 : chunk size to use for PreallocationTools caches. Note that the automated chuck size for DuctAPE will always be the ForwardDiff threshold of 12 due to the size of the system, so it will be best to leave this at the default unless further development allows for chunk size selection for individual solvers.\nlevels::Int=1 : levels for nested duals. Note that since ImplicitAD is being used for all solves, there should be no need for more than 1 level.\n\nReturns\n\nsolve_parameter_caching::NamedTuple : a Named Tuple containing:\nsolve_parameter_cache::PreallocationTools.DiffCache : the cache\nsolve_parameter_cache_dims::NamedTuple : a named tuple containing the dimensions used for reshaping the cache when needed.\n\n\n\n\n\n","category":"function"},{"location":"DuctAPE/api/public_api/#DuctAPE.allocate_solve_container_cache","page":"Public API Reference","title":"DuctAPE.allocate_solve_container_cache","text":"allocate_solve_container_cache(\n solve_type::SolverOptionsType,\n paneling_constants::PanelingConstants;\n fd_chunk_size=12,\n levels=1,\n)\nallocate_solve_container_cache(\n solve_type::SolverOptionsType,\n problem_dimensions::ProblemDimensions;\n fd_chunk_size=12,\n levels=1,\n)\n\nAllocate the solve cache (used for intermediate calculations) based on paneling constants or problem dimensions.\n\nArguments\n\npaneling_constants::PanelingConstants : a PanelingConstants object\n\nOR\n\nproblem_dimensions::ProblemDimensions : a ProblemDimensions object\n\nKeyword Arguments\n\nfd_chunk_size::Int=12 : chunk size to use for PreallocationTools caches. Note that the automated chuck size for DuctAPE will always be the ForwardDiff threshold of 12 due to the size of the system, so it will be best to leave this at the default unless further development allows for chunk size selection for individual solvers.\nlevels::Int=1 : levels for nested duals. Note that since ImplicitAD is being used for all solves, there should be no need for more than 1 level.\n\nReturns\n\nsolve_container_caching::NamedTuple : a Named Tuple containing:\nsolve_container_cache::PreallocationTools.DiffCache : the cache\nsolve_container_cache_dims::NamedTuple : a named tuple containing the dimensions used for reshaping the cache when needed.\n\n\n\n\n\n","category":"function"},{"location":"DuctAPE/api/public_api/#Options","page":"Public API Reference","title":"Options","text":"","category":"section"},{"location":"DuctAPE/api/public_api/#General-Options","page":"Public API Reference","title":"General Options","text":"","category":"section"},{"location":"DuctAPE/api/public_api/","page":"Public API Reference","title":"Public API Reference","text":"DuctAPE.Options\nDuctAPE.set_options","category":"page"},{"location":"DuctAPE/api/public_api/#DuctAPE.Options","page":"Public API Reference","title":"DuctAPE.Options","text":"struct Options{\n TB,\n TBwo,\n TF,\n TI,\n TSf,\n TSt,\n Tin,\n TIo<:IntegrationOptions,\n TSo<:SolverOptionsType,\n WS<:GridSolverOptionsType,\n}\n\nType containing (nearly) all the available user options.\n\nFields\n\nGeneral Options\n\nverbose::TB = false : flag to print verbose statements\nsilence_warnings::TB = true : flag to silence warnings\nmultipoint_index::TI = [1] : holds current index of multi-point solver (no need for user to change this usually)\n\nPre-processing Options\n\nGeometry ee-interpolation and generation options :\n\nfinterp::Tin = FLOWMath.akima : interpolation method used for re-paneling bodies\nautoshiftduct::TB = true : flag as to whether duct geometry should be shifted based on rotor tip location\nlu_decomp_flag::TB = false : flag indicating if panel method LHS matrix factorization was successful\n\npaneling options\n\nitcpshift::TF = 0.05 : factor for internal trailing edge psuedo-panel placement (default is DFDC hard-coded value)\naxistol::TF = 1e-15 : tolerance for how close the the axis of rotation should be considered on the axis\ntegaptol::TF = 1e1 * eps() : tolerance for how large of a trailing edge gap should be considered a gap\n\nIntegration Options\n\nintegration_options::TIo = IntegrationOptions() : integration options\n\nPost-processing Options\n\nwrite_outputs::TBwo = [false] : Bool for whether to write the outputs of the analysis to an external file (slow)\noutfile::TSf = [\"outputs.jl\"] : External output file name (including path information) for files to write\ncheckoutfileexists::TB = false : Flag for whether to check if file exists before overwriting\noutput_tuple_name::TSt = [\"outs\"] : variable name for named tuple written to out file\n\nSolving Options\n\ngrid_solver_options::WS = GridSolverOptions() : elliptic grid solver options\nsolver_options::TSo = ChainSolverOptions() : solver options\n\n\n\n\n\n","category":"type"},{"location":"DuctAPE/api/public_api/#DuctAPE.set_options","page":"Public API Reference","title":"DuctAPE.set_options","text":"set_options(; kwargs...)\nset_options(multipoint; kwargs...)\n\nSet the options for DuctAPE to use.\n\nNote that the vast majority of the available options are defined through keyword arguments. See the documentation for the various option types for more information.\n\nArguments\n\nmultipoint::AbstractArray{OperatingPoint} : a vector of operating points to use if running a multi-point analysis.\n\n\n\n\n\n","category":"function"},{"location":"DuctAPE/api/public_api/#Integration-Options","page":"Public API Reference","title":"Integration Options","text":"","category":"section"},{"location":"DuctAPE/api/public_api/","page":"Public API Reference","title":"Public API Reference","text":"DuctAPE.IntegrationOptions\nDuctAPE.GaussLegendre\nDuctAPE.GaussKronrod\nDuctAPE.Romberg","category":"page"},{"location":"DuctAPE/api/public_api/#DuctAPE.IntegrationOptions","page":"Public API Reference","title":"DuctAPE.IntegrationOptions","text":"struct IntegrationOptions{TN<:IntegrationMethod,TS<:IntegrationMethod}\n\nA struct used to hold the integration options for both the nominal and singular cases.\n\nFields\n\nnominal::IntegrationMethod=GaussLegendre(8) : the integration options to use for the nominal case.\nsingular::IntegrationMethod=GaussLegendre(8) : the integration options to use for the self-induced case.\n\n\n\n\n\n","category":"type"},{"location":"DuctAPE/api/public_api/#DuctAPE.GaussLegendre","page":"Public API Reference","title":"DuctAPE.GaussLegendre","text":"struct GaussLegendre{TN,TW} <: IntegrationMethod\n\nOptions for Gauss-Legendre integration method\n\nFields\n\nsample_points::TN : Sample Points\nweights::TW : Gauss weights\n\n\n\n\n\n","category":"type"},{"location":"DuctAPE/api/public_api/#DuctAPE.GaussKronrod","page":"Public API Reference","title":"DuctAPE.GaussKronrod","text":"struct GaussKronrod{TF,TI} <: IntegrationMethod\n\nOptions for Gauss-Kronrod integration method\n\nFields\n\norder::TI = 7 : order of Legendre polynomial to use on each interval\nmaxevales::TI = 10^7 : maximum number of evaluations in the adaptive method\natol::TF = 0.0 : absolute error tolerance. (note, if zero, QuadGK uses sqrt(eps()) relative tolerance).\n\n\n\n\n\n","category":"type"},{"location":"DuctAPE/api/public_api/#DuctAPE.Romberg","page":"Public API Reference","title":"DuctAPE.Romberg","text":"struct Romberg{TF,TI} <: IntegrationMethod\n\nOptions for Romberg integration method\n\nFields\n\nmax_subdivisions::TI = 10 : maximum number of subdivisions. Note, total number of internvals is 2^N, where N is number of subdivisions.\natol::TF = 1e-6 : absolute error tolerance.\n\n\n\n\n\n","category":"type"},{"location":"DuctAPE/api/public_api/#Solver-Options","page":"Public API Reference","title":"Solver Options","text":"","category":"section"},{"location":"DuctAPE/api/public_api/#Elliptic-Grid-Solve","page":"Public API Reference","title":"Elliptic Grid Solve","text":"","category":"section"},{"location":"DuctAPE/api/public_api/","page":"Public API Reference","title":"Public API Reference","text":"DuctAPE.SLORGridSolverOptions\nDuctAPE.GridSolverOptions","category":"page"},{"location":"DuctAPE/api/public_api/#DuctAPE.SLORGridSolverOptions","page":"Public API Reference","title":"DuctAPE.SLORGridSolverOptions","text":"struct SLORGridSolverOptions{TB,TF,TI} <: GridSolverOptionsType\n\nOptions for SLOR (successive line over relaxation) elliptic grid solver.\n\nFields\n\niteration_limit::TI = 100 : maximum number of iterations\natol::TF = 1e-9 : absolute convergence tolerance\n`converged::AbstractArray{TB} = [false]\n\n\n\n\n\n","category":"type"},{"location":"DuctAPE/api/public_api/#DuctAPE.GridSolverOptions","page":"Public API Reference","title":"DuctAPE.GridSolverOptions","text":"struct GridSolverOptions{TB,TF,TI,TSym} <: GridSolverOptionsType\n\nOptions for SLOR + Newton elliptic grid solver.\n\nFields\n\niteration_limit::TI = 10 : maximum number of iterations\natol::TF = 1e-14 : absolute convergence tolerance\nalgorithm::TSym = :newton : algorithm to use in NLsolve.jl\nautodiff::TSym = :forward : differentiation method to use in NLsolve.jl\nconverged::AbstractArray{TB} = [false]\n\n\n\n\n\n","category":"type"},{"location":"DuctAPE/api/public_api/#Aerodynamics-Solve","page":"Public API Reference","title":"Aerodynamics Solve","text":"","category":"section"},{"location":"DuctAPE/api/public_api/","page":"Public API Reference","title":"Public API Reference","text":"DuctAPE.ChainSolverOptions\nDuctAPE.CompositeSolverOptions\nDuctAPE.NLsolveOptions\nDuctAPE.NonlinearSolveOptions\nDuctAPE.MinpackOptions\nDuctAPE.SIAMFANLEOptions\nDuctAPE.SpeedMappingOptions\nDuctAPE.FixedPointOptions\nDuctAPE.CSORSolverOptions","category":"page"},{"location":"DuctAPE/api/public_api/#DuctAPE.ChainSolverOptions","page":"Public API Reference","title":"DuctAPE.ChainSolverOptions","text":"struct ChainSolverOptions{TB,TS<:Union{ExternalSolverOptions,PolyAlgorithmOptions}} <:PolyAlgorithmOptions\n\nOptions for Chain Solvers (try one solver, if it doesn't converge, try another)\n\nFields\n\n`solvers::AbstractArray{TS} = [ NLsolveOptions(; algorithm=:anderson, atol=1e-12), MinpackOptions(; atol=1e-12), NonlinearSolveOptions(; algorithm=SimpleNonlinearSolve.SimpleNewtonRaphson, atol=1e-12, additional_kwargs=(; autodiff=SimpleNonlinearSolve.AutoForwardDiff()), ), ] : Vector of solver options to use.\nconverged::AbstractArray{TB} = [false] : flag to track if convergence took place.\n\n\n\n\n\n","category":"type"},{"location":"DuctAPE/api/public_api/#DuctAPE.CompositeSolverOptions","page":"Public API Reference","title":"DuctAPE.CompositeSolverOptions","text":"struct CompositeSolverOptions{\n TB,TS<:Union{ExternalSolverOptions,PolyAlgorithmOptions}\n} <: PolyAlgorithmOptions\n\nOptions for Composite Solvers (start with a partial solve of one solve, then finish with another starting where the first left off).\n\nFields\n\n`solvers::AbstractArray{TS} = [ NLsolveOptions(; algorithm=:newton, iteration_limit=3), NLsolveOptions(; algorithm=:anderson, atol=1e-12), ]' : Vector of solver options to use.\nconverged::AbstractArray{TB} = [false] : flag to track if convergence took place.\n\n\n\n\n\n","category":"type"},{"location":"DuctAPE/api/public_api/#DuctAPE.NLsolveOptions","page":"Public API Reference","title":"DuctAPE.NLsolveOptions","text":"struct NLsolveOptions{TB,TF,TK,Tls,Tlsk,TSym} <: ExternalSolverOptions\n\nOptions for the NLsolve pacakge solvers\n\nFields\n\nalgorithm::TSym = :anderson : algorithm to use\nadditional_kwargs::TK = (;) : any additional keyword arguments for the solver\natol::TF = 1e-12 : absolute convergence tolerance\niteration_limit::TF = 25 : maximum number of iterations\nlinesearch_method::Tls = LineSearches.MoreThuente : line search method to use\nlinesearch_kwargs::Tlsk = (;) : any additional lineseach keyword arguments\nconverged::AbstractArray{TB} = [false] : flag to track if convergence took place.\n\n\n\n\n\n","category":"type"},{"location":"DuctAPE/api/public_api/#DuctAPE.NonlinearSolveOptions","page":"Public API Reference","title":"DuctAPE.NonlinearSolveOptions","text":"struct NonlinearSolveOptions{TA,TB,TF,TI,TT} <: ExternalSolverOptions\n\nOptions for the SimpleNonlinearSolve pacakge solvers\n\nFields\n\nalgorithm::TA = SimpleNonlinearSolve.SimpleNewtonRaphson : algorithm to use\nadditional_kwargs::TK = (;) : any additional keyword arguments for the solver\natol::TF = 1e-12 : absolute convergence tolerance\niteration_limit::TF = 25 : maximum number of iterations\nconverged::AbstractArray{TB} = [false] : flag to track if convergence took place.\n\n\n\n\n\n","category":"type"},{"location":"DuctAPE/api/public_api/#DuctAPE.MinpackOptions","page":"Public API Reference","title":"DuctAPE.MinpackOptions","text":"struct MinpackOptions{TB,TF,TI,TSym} <: ExternalSolverOptions\n\nOptions for the MINPACK's HYBRJ solver\n\nFields\n\nalgorithm::TSym = :hybr : algorithm to use in MINPACK.jl (hybr is HYBRJ when the jacobian is provided)\natol::TF = 1e-12 : absolute convergence tolerance\niteration_limit::TF = 100 : maximum number of iterations\nconverged::AbstractArray{TB} = [false] : flag to track if convergence took place.\n\n\n\n\n\n","category":"type"},{"location":"DuctAPE/api/public_api/#DuctAPE.SIAMFANLEOptions","page":"Public API Reference","title":"DuctAPE.SIAMFANLEOptions","text":"struct SIAMFANLEOptions{TA,TB,TF,TI,TK} <: ExternalSolverOptions\n\nOptions for the SIAMFANLEquations pacakge solvers\n\nFields\n\nalgorithm::TA = SIAMFANLEquations.nsoli : algorithm to use\nrtol::TF = 0.0 : relative convergence tolerance\natol::TF = 1e-10 : absolute convergence tolerance\niteration_limit::TF = 1000 : maximum number of iterations\nlinear_iteration_limit::TF = 5 : maximum number of linear solve iterations (GMRES)\nadditional_kwargs::TK = (;) : any additional keyword arguments for the solver\nconverged::AbstractArray{TB} = [false] : flag to track if convergence took place.\n\n\n\n\n\n","category":"type"},{"location":"DuctAPE/api/public_api/#DuctAPE.SpeedMappingOptions","page":"Public API Reference","title":"DuctAPE.SpeedMappingOptions","text":"struct SpeedMappingOptions{TB,TF,TI,TL,TSm,TU} <: ExternalSolverOptions\n\nOptions for the SpeedMapping.jl package solver\n\nFields\n\n`orders::AbstractArray{TI} = [3, 2]\nsig_min::TSm = 0 : maybe set to 1?\nstabilize::TB = false : stabilizes before extrapolation\ncheck_obj::TB = false : checks for inf's and nan's and starts from previous finite point\natol::TF = 1e-10 : absolute convergence tolerance\niteration_limit::TF = 1000 : maximum number of iterations\ntime_limit::TF = Inf : time limit in seconds\nlower::TL = nothing : box lower bounds\nupper::TU = nothing : box upper bounds\nbuffer::TF = 0.01 : if using bounds, buffer brings x inside bounds by buffer amountd\nLp::TF = Inf : p value for p-norm for convergence criteria\nconverged::AbstractArray{TB} = [false] : flag to track if convergence took place.\n\n\n\n\n\n","category":"type"},{"location":"DuctAPE/api/public_api/#DuctAPE.FixedPointOptions","page":"Public API Reference","title":"DuctAPE.FixedPointOptions","text":"struct FixedPointOptions{TB,TF,TI} <: ExternalSolverOptions\n\nOptions for the FixedPoint.jl package solver\n\nFields\n\niteration_limit::TF = 1000 : maximum number of iterations\nvel::TF = 0.9 : vel keyword argument, default is package default\nep::TF = 0.01 : ep keyword argument, default is package default\natol::TF = 1e-12 : absolute convergence tolerance\nconverged::AbstractArray{TB} = [false] : flag to track if convergence took place.\n\n\n\n\n\n","category":"type"},{"location":"DuctAPE/api/public_api/#DuctAPE.CSORSolverOptions","page":"Public API Reference","title":"DuctAPE.CSORSolverOptions","text":"struct CSORSolverOptions{TB,TC<:ConvergenceType,TF,TS} <: SolverOptionsType\n\nType containing all the options for the CSOR (controlled successive over relaxation) solver.\n\nNote that the defaults match DFDC with the exception of the relaxation schedule, which is an experimental feature.\n\nFields\n\nvar::type :\nverbose::TB = false : flag to print verbose statements\niteration_limit::TF = 1e2 : maximum number of iterations\nnrf::TF = 0.4 : nominal relaxation factor\nbt1::TF = 0.2 : backtracking factor 1\nbt2::TF = 0.6 : backtracking factor 2\npf1::TF = 0.4 : press forward factor 1\npf2::TF = 0.5 : press forward factor 2\nbtw::TF = 0.6 : backtracking factor for wake\npfw::TF = 1.2 : press forward factor for wake\nrelaxation_schedule::TS = [[0.0;1e-14;1e-13;1e10]), [1.0;1.0;0.0;0.0])] : values used in spline definition for scaling the relaxation factors (second vector) after various convergence values (first vector).\nf_circ::TF = 1e-3 : convergence tolerance for rotor circulation\nf_dgamw::TF = 2e-4 : convergence tolerance for wake vortex strength\nconvergence_type::TC = Relative() : dispatch for relative or absolute convergence criteria.\nVconv::AbstractArray{TF} = [1.0] : velocity used in relative convergence criteria (should be set to Vref).\nconverged::AbstractArray{TB} = [false] : flag to track if convergence took place.\n\n\n\n\n\n","category":"type"},{"location":"DuctAPE/api/public_api/#Preprocess","page":"Public API Reference","title":"Preprocess","text":"","category":"section"},{"location":"DuctAPE/api/public_api/","page":"Public API Reference","title":"Public API Reference","text":"DuctAPE.setup_analysis","category":"page"},{"location":"DuctAPE/api/public_api/#DuctAPE.setup_analysis","page":"Public API Reference","title":"DuctAPE.setup_analysis","text":"setup_analysis(\n propulsor::Propulsor,\n options::Options=set_options();\n prepost_container_caching=nothing,\n solve_parameter_caching=nothing,\n solve_container_caching=nothing,\n)\n\nPerform pre-processing and cache setup (as needed) for propuslor analysis.\n\nArguments\n\npropulsor::Propulsor : Propulsor input object (see docstring for Propulsor type)\noptions::Options=set_options() : Options object (see set_options and related functions)\n\nKeyword Arguments\n\nprepost_container_caching=nothing : Output of allocate_prepost_container_cache\nsolve_parameter_caching=nothing : Output of allocate_solve_parameter_container_cache\nsolve_container_caching=nothing : Output of allocate_solve_container_cache\n\nReturns\n\nproblem_dimensions::NamedTuple : Named Tuple contiaining bookkeeping information (problem dimensions)\nprepost_containers::NamedTuple : Named Tuple containing reshaped views into the prepost cache\nsolve_parameter_cache_vector::Vector : Vector containing the relevant typed cache vector of solve parameters\nsolve_parameter_cache_dims::NamedTuple : Named Tuple containing dimensions used for reshaping the solve parameter cache\nA_bb_LU::LinearAlgebra.LU : The LU factorization of the AIC matrix used in the panel method\nlu_decomp_flag::Bool : flag indicating if the LU decomposition was successful\nairfoils::Matrix{AFType} : Matrix contiaining the blade element airfoil polar objects\nidmaps::NamedTuple : Named Tuple containing bookkeeping information (index mappings)\n\n\n\n\n\n","category":"function"},{"location":"DuctAPE/api/public_api/#Analysis","page":"Public API Reference","title":"Analysis","text":"","category":"section"},{"location":"DuctAPE/api/public_api/","page":"Public API Reference","title":"Public API Reference","text":"DuctAPE.analyze","category":"page"},{"location":"DuctAPE/api/public_api/#DuctAPE.analyze","page":"Public API Reference","title":"DuctAPE.analyze","text":"analyze(\n propulsor::Propulsor,\n options::Options=set_options();\n prepost_container_caching=nothing,\n solve_parameter_caching=nothing,\n solve_container_caching=nothing,\n return_inputs=false,\n)\n\nAnalyze propulsor, including preprocessing.\n\nArguments\n\npropulsor::Propulsor : Propulsor input object (see docstring for Propulsor type)\noptions::Options=set_options() : Options object (see set_options and related functions)\n\nKeyword Arguments\n\nprepost_container_caching=nothing : Output of allocate_prepost_container_cache\nsolve_parameter_caching=nothing : Output of allocate_solve_parameter_container_cache\nsolve_container_caching=nothing : Output of allocate_solve_container_cache\nreturn_inputs=false : flag as to whether or not to return the pre-processed inputs\n\nReturns\n\nouts::NamedTuple : Named Tuple of various analysis outputs (see docstring for postprocess for details), note, if linear system decomposition fails, no solve is performed and an empty vector is returned.\nins::NamedTuple : Named Tuple of various pre-processed inputs (e.g. panels and body linear system), will only be returned if return_inputs=true\nconvergence_flag : Flag for successful solve convergence\n\n\n\n\n\nanalyze(\n propulsor::Propulsor,\n prepost_containers,\n solve_parameter_cache_vector,\n solve_parameter_cache_dims,\n airfoils,\n A_bb_LU,\n idmaps,\n problem_dimensions,\n options::Options=set_options();\n return_inputs=false,\n solve_container_caching=nothing,\n)\n\nAnalyze propulsor, assuming setup_analysis has been called and the outputs thereof are being passed in here.\n\nArguments\n\npropulsor::Propulsor : Propulsor input object\nprepost_containers::NamedTuple : An output from setup_analysis containing reshaped views into the prepost cache\nsolve_parameter_cache_vector::Vector : An output from setup_analysis containing the relevant typed cache vector of solve parameters\nsolve_parameter_cache_dims::NamedTuple : An output from setup_analysis containing dimensions used for reshaping the solve parameter cache\nairfoils::Vector{AFType} : An output from setup_analysis contiaining the blade element airfoil polar objects\nA_bb_LU::LinearAlgebra.LU : An output from setup_analysis that is the LU decomposition of the AIC matrix used in the panel method\nidmaps::NamedTuple : An output from setup_analysis containing bookkeeping information (index mappings)\nproblem_dimensions::NamedTuple : An output from setup_analysis contiaining bookkeeping information (problem dimensions)\noptions::Options=set_options() : Options object\n\nKeyword Arguments\n\nsolve_container_caching=nothing : Output of allocate_solve_container_cache\nreturn_inputs=false : flag as to whether or not to return the pre-processed inputs\n\nReturns\n\nouts::NamedTuple : Named Tuple of various analysis outputs (see docstring for postprocess for details), note, if linear system decomposition fails, no solve is performed and an empty vector is returned.\nins::NamedTuple : Named Tuple of various pre-processed inputs (e.g. panels and body linear system), will only be returned if return_inputs=true\nconvergence_flag : Flag for successful solve convergence\n\n\n\n\n\nanalyze(\n multipoint::AbstractVector{OperatingPoint},\n propulsor::Propulsor,\n options::Options=set_options();\n prepost_container_caching=nothing,\n solve_parameter_caching=nothing,\n solve_container_caching=nothing,\n return_inputs=false,\n)\n\nAnalyze propulsor, including preprocessing, for a set of operating points.\n\nArguments\n\nmultipoint::AbstractVector{OperatingPoint} : Vector of Operating Points at which to analyze the propulsor (note that the operating point within the propulsor input will be overwritten with these)\npropulsor::Propulsor : Propulsor input object\noptions::Options=set_options() : Options object\n\nKeyword Arguments\n\nprepost_container_caching=nothing : Output of allocate_prepost_container_cache\nsolve_parameter_caching=nothing : Output of allocate_solve_parameter_container_cache\nsolve_container_caching=nothing : Output of allocate_solve_container_cache\nreturn_inputs=false : flag as to whether or not to return the pre-processed inputs\n\nReturns\n\nouts::Vector{NamedTuple} : Vector of named tuples of various analysis outputs (see docstring for postprocess for details), note, if linear system decomposition fails, no solve is performed and an empty vector is returned.\nins::NamedTuple : Named Tuple of various pre-processed inputs (e.g. panels and body linear system), will only be returned if return_inputs=true\nconvergence_flag : Flag for successful solve convergence\n\n\n\n\n\nanalyze(\n multipoint::Vector{OperatingPoint},\n propulsor::Propulsor,\n prepost_containers,\n solve_parameter_cache_vector,\n solve_parameter_cache_dims,\n airfoils,\n A_bb_LU,\n idmaps,\n problem_dimensions,\n options::Options=set_options();\n return_inputs=false,\n solve_container_caching=nothing,\n)\n\nAnalyze propulsor, assuming setup_analysis has been called and the inputs are being passed in here.\n\nArguments\n\nmultipoint::AbstractVector{OperatingPoint} : Vector of Operating Points at which to analyze the propulsor (note that the operating point within the propulsor input will be overwritten with these)\npropulsor::Propulsor : Propulsor input object\nprepost_containers::NamedTuple : An output from setup_analysis containing reshaped views into the prepost cache\nsolve_parameter_cache_vector::Vector : An output from setup_analysis containing the relevant typed cache vector of solve parameters\nsolve_parameter_cache_dims::NamedTuple : An output from setup_analysis containing dimensions used for reshaping the solve parameter cache\nairfoils::Vector{AFType} : An output from setup_analysis contiaining the blade element airfoil polar objects\nA_bb_LU::LinearAlgebra.LU : An output from setup_analysis that is the LU decomposition of the AIC matrix used in the panel method\nidmaps::NamedTuple : An output from setup_analysis containing bookkeeping information (index mappings)\nproblem_dimensions::NamedTuple : An output from setup_analysis contiaining bookkeeping information (problem dimensions)\noptions::Options=set_options() : Options object\n\nKeyword Arguments\n\nsolve_container_caching=nothing : Output of allocate_solve_container_cache\nreturn_inputs=false : flag as to whether or not to return the pre-processed inputs\n\nReturns\n\nouts::Vector{NamedTuple} : Named Tuple of various analysis outputs (see docstring for postprocess for details), note, if linear system decomposition fails, no solve is performed and an empty vector is returned.\nins::NamedTuple : Named Tuple of various pre-processed inputs (e.g. panels and body linear system), will only be returned if return_inputs=true. Note that some inputs will be overwritten (e.g. the linear system RHS components related to the freestream) and only those associated with the final operating point will be returned.\nconvergence_flag : Flag for successful solve convergence\n\n\n\n\n\n","category":"function"},{"location":"DuctAPE/api/public_api/#Miscellaneous","page":"Public API Reference","title":"Miscellaneous","text":"","category":"section"},{"location":"DuctAPE/api/public_api/#Airfoil/Geometry-Manipulation","page":"Public API Reference","title":"Airfoil/Geometry Manipulation","text":"","category":"section"},{"location":"DuctAPE/api/public_api/#NACA-6-Series-Cascade-Geometry-Generation","page":"Public API Reference","title":"NACA 6-Series Cascade Geometry Generation","text":"","category":"section"},{"location":"DuctAPE/api/private_utilities/#Utility-Functions","page":"Utilities","title":"Utility Functions","text":"","category":"section"},{"location":"DuctAPE/api/private_utilities/","page":"Utilities","title":"Utilities","text":"DuctAPE.promote_propulsor_type\nDuctAPE.update_operating_point!\nDuctAPE.isscalar\nDuctAPE.dot\nDuctAPE.norm\nDuctAPE.cross2mag\nDuctAPE.linear_transform\nDuctAPE.extract_primals!\nDuctAPE.lfs\nDuctAPE.reset_containers!\nDuctAPE.cache_dims!\nDuctAPE.write_data","category":"page"},{"location":"DuctAPE/api/private_utilities/#DuctAPE.promote_propulsor_type","page":"Utilities","title":"DuctAPE.promote_propulsor_type","text":"promote_propulsor_type(propulsor)\n\nConvenience function for promoting types based on any potential elements of the propulsor object dependent on optimization design variables.\n\nArguments\n\npropulsor::Propulsor : the propulsor input\n\nReturns\n\nTP::Type : the promoted type\n\n\n\n\n\n","category":"function"},{"location":"DuctAPE/api/private_utilities/#DuctAPE.update_operating_point!","page":"Utilities","title":"DuctAPE.update_operating_point!","text":"update_operating_point!(op_old, op_new)\n\nOverwrites all the values of an OperatingPoint object with another OperatingPoint object's values (or NamedTuple with the same field names).\n\nArguments\n\nop_old::OperatingPoint : the OperatingPoint to be overwritten (can also be a NamedTuple with the same field names as an OperatingPoint).\nop_new::OperatingPoint : the OperatingPoint values to be used (can also be a NamedTuple with the same field names as an OperatingPoint).\n\n\n\n\n\n","category":"function"},{"location":"DuctAPE/api/private_utilities/#DuctAPE.isscalar","page":"Utilities","title":"DuctAPE.isscalar","text":"isscalar(x::T) where {T} = isscalar(T)\nisscalar(::Type{T}) where {T} = BroadcastStyle(T) isa Broadcast.DefaultArrayStyle{0}\n\nDetermines if the input is a scalar. Note that Base.BroadcastStyle is imported.\n\n\n\n\n\n","category":"function"},{"location":"DuctAPE/api/private_utilities/#DuctAPE.dot","page":"Utilities","title":"DuctAPE.dot","text":"dot(A, B) = sum(a * b for (a, b) in zip(A, B))\n\nA faster dot product.\n\n\n\n\n\n","category":"function"},{"location":"DuctAPE/api/private_utilities/#DuctAPE.norm","page":"Utilities","title":"DuctAPE.norm","text":"norm(A) = sqrt(mapreduce(x -> x^2, +, A))\n\nA faster 2-norm.\n\n\n\n\n\n","category":"function"},{"location":"DuctAPE/api/private_utilities/#DuctAPE.cross2mag","page":"Utilities","title":"DuctAPE.cross2mag","text":"cross2mag(A, B) = A[1] * B[2] - A[2] * B[1]\n\n2D \"cross product\" magnitude\n\n\n\n\n\n","category":"function"},{"location":"DuctAPE/api/private_utilities/#DuctAPE.linear_transform","page":"Utilities","title":"DuctAPE.linear_transform","text":"linear_transform(range1, range2, values)\n\nLinear transfrom of values from range (source_range[1], source_range[end]) to (target_range[1], target_range[end])\n\nArguments\n\nsource_range::Vector{Float} : range values come from (can also be a Tuple)\ntarget_range::Vector{Float} : range onto which we are transforming (can also be a Tuple)\nsource_values::Array{Float} : array of source values to transform\n\nReturns\n\ntarget_values::Array{Float} : array of transformed sourcevalues onto target range\n\n\n\n\n\n","category":"function"},{"location":"DuctAPE/api/private_utilities/#DuctAPE.extract_primals!","page":"Utilities","title":"DuctAPE.extract_primals!","text":"extract_primals!(Avalue, A::AbstractMatrix{T}) where {T}\n\nExtracts primals of A and places them in Avalue.\n\n\n\n\n\n","category":"function"},{"location":"DuctAPE/api/private_utilities/#DuctAPE.lfs","page":"Utilities","title":"DuctAPE.lfs","text":"lfs(shape)\n\nDetermines length from shape (output of size function).\n\n\n\n\n\n","category":"function"},{"location":"DuctAPE/api/private_utilities/#DuctAPE.reset_containers!","page":"Utilities","title":"DuctAPE.reset_containers!","text":"reset_containers!(containers; exception_keys=[])\n\nResets all fields (not incluing any contained in exception keys) of containers–-which must be arrays, structs of arrays, or tuples of arrays–-to zeros.\n\n\n\n\n\n","category":"function"},{"location":"DuctAPE/api/private_utilities/#DuctAPE.cache_dims!","page":"Utilities","title":"DuctAPE.cache_dims!","text":"cache_dims!(total_length, l, s)\n\nA function that returns a named tuple containing an index range and shape and increases total_length by l.\n\nThis function is used heavily in the cache allocation functions for setting up the dimension maps used to access the vectorized caches.\n\nArguments\n\ntotal_length::Vector{Int} : single element vector containing the current total length of the eventual cache vector. Modified in place.\nl::Int : total length of the object in question\ns::Int : size of the object in question\n\nReturns\n\ndims::NamedTuple : A named tuple containing index and shape fields\n\n\n\n\n\n","category":"function"},{"location":"DuctAPE/api/private_utilities/#DuctAPE.write_data","page":"Utilities","title":"DuctAPE.write_data","text":"write_data(outs, filename; checkoutfileexists=false)\n\nWrites NamedTuples, specifically for writing out the output of the post_procces() function.\n\nArguments:\n\nouts::NamedTuple : Named tuple to write to file.\nfilename::String : file name (including full desired path and file type) for file to write\n\nKeyword Arguments:\n\noutput_tuple_name::String : desired variable name of written NamedTuple\ncheckoutfileexists::Bool=false : boolean for whether to check if the outfile already exists and whether or not to overwrite it.\n\n\n\n\n\n","category":"function"},{"location":"DuctAPE/api/private_process/#Analysis","page":"Process","title":"Analysis","text":"","category":"section"},{"location":"DuctAPE/api/private_process/","page":"Process","title":"Process","text":"DuctAPE.analyze_multipoint","category":"page"},{"location":"DuctAPE/api/private_process/#DuctAPE.analyze_multipoint","page":"Process","title":"DuctAPE.analyze_multipoint","text":"analyze_multipoint(\n operating_point::OperatingPoint,\n propulsor::Propulsor,\n prepost_containers,\n solve_parameter_cache_vector,\n solve_parameter_cache_dims,\n airfoils,\n A_bb_LU,\n idmaps,\n problem_dimensions,\n options::Options;\n solve_container_caching=nothing,\n return_inputs=false,\n)\n\nIdentical to the single analyze function assuming setup_analysis has been called; except here we are running a single operating point for a multipoint analysis, and overwriting the operating point in the propulsor with the explicit operating point input.\n\n\n\n\n\n","category":"function"},{"location":"DuctAPE/api/private_process/#Process","page":"Process","title":"Process","text":"","category":"section"},{"location":"DuctAPE/api/private_process/","page":"Process","title":"Process","text":"DuctAPE.process\nDuctAPE.solve","category":"page"},{"location":"DuctAPE/api/private_process/#DuctAPE.process","page":"Process","title":"DuctAPE.process","text":"process(\n solver_options::SolverOptionsType,\n solve_parameter_cache_vector,\n solve_parameter_cache_dims,\n airfoils,\n A_bb_LU,\n solve_container_caching,\n idmaps,\n options,\n)\n\nProcess (the step between pre-process and post-process) the solution, in other words: call the solver(s).\n\nArguments\n\nsolver_options::SolverOptionsType : the solver options contained in the options object, used for dispatch.\nsolve_parameter_cache_vector::Vector{Float} : The vector cache for parameters used in the solve.\nsolve_parameter_cache_dims::NamedTuple : A named tuple containing the dimensions of the solve parameters.\nairfoils::NamedTuple : The airfoils to be interpolated that are associated with each blade element\nA_bb_LU::LinearAlgebra.LU : The LU decomposition of the panel method LHS matrix\nsolve_container_caching::NamedTuple : A named tuple containing the cache and dimensions for the intermediate solve values.\nidmaps::NamedTuple : The set of index maps used in various solve sub-functions\noptions::Options : User options\n\nReturns\n\nconverged_states::Vector{Float} : The output of a call to ImplicitAD.implicit\n\n\n\n\n\n","category":"function"},{"location":"DuctAPE/api/private_process/#DuctAPE.solve","page":"Process","title":"DuctAPE.solve","text":"solve(sensitivity_parameters, const_cache; initial_guess=nothing)\n\nA compact dispatch of solve that automatically dispatches based on the solveroptions contained in constcache.\n\n\n\n\n\nsolve(\n solver_options::SolverOptionsType,\n sensitivity_parameters,\n const_cache;\n initial_guess=nothing,\n)\n\nConverge the residual, solving for the state variables that do so.\n\nArguments\n\nsolver_options::SolverOptionsType : SolverOptionsType used for dispatch\nsensitivity_parameters::Vector{Float} : Sensitivity parameters for solve (parameters passed in through ImplicitAD)\nconst_cache::NamedTuple : A named tuple containing constants and caching helpers.\n\nKeyword Arguments\n\ninitial_guess=nothing::Vector{Float} : An optional manually provided initial guess (contained in the sensitivity parameters anyway).\n\nReturns\n\nconverged_states::Vector{Float} : the states for which the residual has converged.\n\n\n\n\n\n","category":"function"},{"location":"DuctAPE/api/private_process/#Residuals","page":"Process","title":"Residuals","text":"","category":"section"},{"location":"DuctAPE/api/private_process/#CSOR","page":"Process","title":"CSOR","text":"","category":"section"},{"location":"DuctAPE/api/private_process/","page":"Process","title":"Process","text":"DuctAPE.CSOR_residual!\nDuctAPE.compute_CSOR_residual!\nDuctAPE.relax_Gamr!\nDuctAPE.relax_gamw!\nDuctAPE.apply_relaxation_schedule\nDuctAPE.update_CSOR_residual_values!\nDuctAPE.check_CSOR_convergence!","category":"page"},{"location":"DuctAPE/api/private_process/#DuctAPE.CSOR_residual!","page":"Process","title":"DuctAPE.CSOR_residual!","text":"CSOR_residual!(resid, state_variables, sensitivity_parameters, constants)\n\nThe in-place residual used for the CSOR solve method.\n\nArguments\n\nresid::Vector{Float} : In-place residual.\nstate_variables::Vector{Float} : The state variables\nsensitivity_parameters::Vector{Float} : The parameters to which the solution is sensitive.\nconstants::NamedTuple : Various constants required in the solve\n\nReturns\n\nstate_variables::Vector{Float} : The state variables (modified in place)\n\n\n\n\n\n","category":"function"},{"location":"DuctAPE/api/private_process/#DuctAPE.compute_CSOR_residual!","page":"Process","title":"DuctAPE.compute_CSOR_residual!","text":"compute_CSOR_residual!(\n resid,\n solver_options,\n solve_containers,\n Gamr,\n sigr,\n gamw,\n operating_point,\n ivr,\n ivw,\n linsys,\n blade_elements,\n wakeK,\n idmaps;\n verbose=false,\n)\n\nDescription\n\nArguments\n\nresid::Vector{Float} : the residual vector\nsolver_options::SolverOptionsType : solver options (used for convergence criteria)\nsolve_containers::NamedTuple : cache for intermediate solve values\nGamr::type : Blade element circulation strengths\nsigr::type : Rotor source panel strengths\ngamw::type : Wake vortex panel strengths\noperating_point::NamedTuple : Named tuple containing operating_point information\nivr::NamedTuple : unit induced velocities on rotor(s)\nivw::NamedTuple : unit induced velocities on wake\nlinsys::NamedTuple : vectors and matricies comprising the panel method linear system\nblade_elements::NamedTuple : blade element geometry and airfoil polar information\nwakeK::Vector{Float} : geometric constants used in caculating wake strengths\nidmaps::NamedTuple : index maps used throughout solve\n\nKeyword Arguments\n\nverbose::Bool=false : Flag to print verbose statements\n\n\n\n\n\ncompute_CSOR_residual!(\n resid,\n solver_options,\n solve_containers,\n Gamr,\n sigr,\n gamw,\n operating_point,\n ivr,\n ivw,\n linsys,\n blade_elements,\n wakeK,\n idmaps;\n verbose=false,\n)\n\nDescription\n\nArguments\n\nresid::Vector{Float} : the residual vector\nsolver_options::SolverOptionsType : solver options (used for convergence criteria)\nsolve_containers::NamedTuple : cache for intermediate solve values\nGamr::type : Blade element circulation strengths\nsigr::type : Rotor source panel strengths\ngamw::type : Wake vortex panel strengths\noperating_point::NamedTuple : Named tuple containing operating_point information\nivr::NamedTuple : unit induced velocities on rotor(s)\nivw::NamedTuple : unit induced velocities on wake\nlinsys::NamedTuple : vectors and matricies comprising the panel method linear system\nblade_elements::NamedTuple : blade element geometry and airfoil polar information\nwakeK::Vector{Float} : geometric constants used in caculating wake strengths\nidmaps::NamedTuple : index maps used throughout solve\n\nKeyword Arguments\n\nverbose::Bool=false : Flag to print verbose statements\n\n\n\n\n\n","category":"function"},{"location":"DuctAPE/api/private_process/#DuctAPE.relax_Gamr!","page":"Process","title":"DuctAPE.relax_Gamr!","text":"relax_Gamr!(\n Gamr,\n delta_prev_mat,\n delta_mat,\n maxBGamr,\n maxdeltaBGamr,\n B;\n nrf=0.4,\n bt1=0.2,\n bt2=0.6,\n pf1=0.4,\n pf2=0.5,\n test=false,\n)\n\nApply relaxed step to Gamr.\n\nArguments\n\nGamr::Array{Float} : Array of rotor circulations (columns = rotors, rows = blade elements), updated in place\ndelta_prev_mat::Array{Float} : Array of previous iteration's differences in circulation values, updated in place\ndelta_mat::Array{Float} : Array of current iteration's differences in circulation values\nB::Vector{Float} : number of blades on each rotor\nnrf::Float=0.4 : nominal relaxation factor\nbt1::Float=0.2 : backtrack factor 1\nbt2::Float=0.6 : backtrack factor 2\npf1::Float=0.4 : press forward factor 1\npf2::Float=0.5 : press forward factor 2\n\n\n\n\n\nrelax_Gamr!(\n Gamr,\n delta_prev_mat,\n delta_mat,\n maxBGamr,\n B;\n nrf=0.4,\n bt1=0.2,\n bt2=0.6,\n pf1=0.4,\n pf2=0.5,\n test=false,\n)\n\nApply relaxed step to Gamr.\n\nArguments\n\nGamr::Array{Float} : Array of rotor circulations (columns = rotors, rows = blade elements), updated in place\ndelta_prev_mat::Array{Float} : Array of previous iteration's differences in circulation values, updated in place\ndelta_mat::Array{Float} : Array of current iteration's differences in circulation values\nB::Vector{Float} : number of blades on each rotor\nnrf::Float=0.4 : nominal relaxation factor\nbt1::Float=0.2 : backtrack factor 1\nbt2::Float=0.6 : backtrack factor 2\npf1::Float=0.4 : press forward factor 1\npf2::Float=0.5 : press forward factor 2\n\n\n\n\n\n","category":"function"},{"location":"DuctAPE/api/private_process/#DuctAPE.relax_gamw!","page":"Process","title":"DuctAPE.relax_gamw!","text":"relax_gamw!(\n gamw, delta_prev, delta, maxdeltagamw; nrf=0.4, btw=0.6, pfw=1.2, test=false\n)\n\nApply relaxed step to gamw.\n\nArguments\n\ngamw::Array{Float} : Array of rotor circulations (columns = rotors, rows = blade elements), updated in place\ndelta_prev_mat::Array{Float} : Array of previous iteration's differences in circulation values, updated in place\ndelta_mat::Array{Float} : Array of current iteration's differences in circulation values\nB::Vector{Float} : number of blades on each rotor\nnrf::Float=0.4 : nominal relaxation factor\nbt1::Float=0.2 : backtrack factor 1\nbt2::Float=0.6 : backtrack factor 2\npf1::Float=0.4 : press forward factor 1\npf2::Float=0.5 : press forward factor 2\n\n\n\n\n\nrelax_gamw!(\n gamw, delta_prev, delta; nrf=0.4, btw=0.6, pfw=1.2, test=false\n)\n\nApply relaxed step to gamw.\n\nArguments\n\ngamw::Array{Float} : Array of rotor circulations (columns = rotors, rows = blade elements), updated in place\ndelta_prev_mat::Array{Float} : Array of previous iteration's differences in circulation values, updated in place\ndelta_mat::Array{Float} : Array of current iteration's differences in circulation values\nB::Vector{Float} : number of blades on each rotor\nnrf::Float=0.4 : nominal relaxation factor\nbt1::Float=0.2 : backtrack factor 1\nbt2::Float=0.6 : backtrack factor 2\npf1::Float=0.4 : press forward factor 1\npf2::Float=0.5 : press forward factor 2\n\n\n\n\n\n","category":"function"},{"location":"DuctAPE/api/private_process/#DuctAPE.apply_relaxation_schedule","page":"Process","title":"DuctAPE.apply_relaxation_schedule","text":"apply_relaxation_schedule(\n resid::AbstractVector, solver_options::TS\n) where {TS<:SolverOptionsType}\n\nApply custom relaxation schedule to all relaxation factor inputs based on residual values.\n\nArguments\n\nresid::AbstractVector{Float} : current residual values\nsolver_options::SolverOptionsType : SolverOptions containing relaxation schedule\n\nReturns\n\nnrf::Float : nominal relaxation factor\nbt1::Float : backtrack factor 1\nbt2::Float : backtrack factor 2\npf1::Float : press forward factor 1\npf2::Float : press forward factor 2\n\n\n\n\n\napply_relaxation_schedule(resid, nominal, schedule)\n\nApply custom relaxation schedule to a single relaxation factor input.\n\nArguments\n\nresid::Float : residual value\nnominal::Float : nominal relaxation value\nschedule::AbstractVector{AbstractVector{Float}} : values between which to interpolate to scale the nominal relaxation value.\n\nReturns\n\nrf::Float : the updated relaxation factor\n\n\n\n\n\n","category":"function"},{"location":"DuctAPE/api/private_process/#DuctAPE.update_CSOR_residual_values!","page":"Process","title":"DuctAPE.update_CSOR_residual_values!","text":"update_CSOR_residual_values!(\n convergence_type::ConvergenceType, resid, maxBGamr, maxdeltaBGamr, maxdeltagamw, Vconv\n)\n\nUpdate CSOR residual values in place.\n\nArguments\n\nconvergence_type::ConvergenceType : used for dispatch of relative or absolute residual values.\nresid::Vector{Float} : residual values modified in place\nmaxBGamr::Float : Maximum value of B*Gamr among all blade elements\nmaxdeltaBGamr::Float : Maximum change in B*Gamr between iterations among all blade elements\nmaxdeltagamw::Vector{Float} : Maximum change in gamw among all wake nodes (one element)\nVconv::Float : Reference velocity upon which the relative convergence criteria is based (one element)\n\n\n\n\n\n","category":"function"},{"location":"DuctAPE/api/private_process/#DuctAPE.check_CSOR_convergence!","page":"Process","title":"DuctAPE.check_CSOR_convergence!","text":"check_CSOR_convergence!(\n conv, resid; f_circ=1e-3, f_dgamw=2e-4, convergence_type=Relative(), verbose=false\n)\n\nDescription\n\nArguments\n\nconv::Vector{Float} : container holding convergence flag\nresid::Vector{Float} : residual vector\n\nKeyword Arguments\n\nf_circ::Float=1e-3 : convergence criteria for circulation residual\nf_dgamw::Float=2e-4 : convergence criteria for wake strength residual\nconvergence_type::ConvergenceType=Relative() : convergence type (absolute or relative) for print statements\nverbose::Bool=false : flag for verbose print statements\n\n\n\n\n\n","category":"function"},{"location":"DuctAPE/api/private_process/#External-Solvers","page":"Process","title":"External Solvers","text":"","category":"section"},{"location":"DuctAPE/api/private_process/","page":"Process","title":"Process","text":"DuctAPE.system_residual\nDuctAPE.system_residual!\nDuctAPE.update_system_residual!\nDuctAPE.estimate_states!","category":"page"},{"location":"DuctAPE/api/private_process/#DuctAPE.system_residual","page":"Process","title":"DuctAPE.system_residual","text":"system_residual(state_variables, sensitivity_parameters, constants)\n\nThe residual function for external solvers.\n\nArguments\n\nstate_variables::Vector{Float} : the state variables\nsensitivity_parameters::Vector{Float} : parameters to which the solution derivatives are sensitive\nconstants::NamedTuple : parameters to which the solution derivatives are constant\n\nReturs\n\nresid::Vector{Float} : residual vector\n\n\n\n\n\n","category":"function"},{"location":"DuctAPE/api/private_process/#DuctAPE.system_residual!","page":"Process","title":"DuctAPE.system_residual!","text":"system_residual!(resid, state_variables, sensitivity_parameters, constants)\n\nIn-place version of system_residual.\n\n\n\n\n\n","category":"function"},{"location":"DuctAPE/api/private_process/#DuctAPE.update_system_residual!","page":"Process","title":"DuctAPE.update_system_residual!","text":"update_system_residual!(\n solver_options::SolverOptionsType\n resid,\n vz_est,\n vz_rotor,\n vtheta_est,\n vtheta_rotor,\n Cm_est,\n Cm_wake,\n solve_parameter_cache_dims,\n)\n\nUpdate the residual for external solvers.\n\nArguments\n\n`solver_options::SolverOptionsType\nresid::Vector{Float} : residual vector\nvz_est::Vector{Float} : axial induced rotor velocity estimate container\nvz_rotor::Vector{Float} : axial induced rotor velocity state container\nvtheta_est::Vector{Float} : tangential induced rotor velocity estimate container\nvtheta_rotor::Vector{Float} : tangential induced rotor velocity state container\nCm_est::Vector{Float} : absolute meridional wake control point velocity estimate container\nCm_wake::Vector{Float} : absolute meridional wake control point velocity state container\nsolve_parameter_cache_dims::Vector{Float} : dimensions of state vectors to use in accessing the residual vector\n\n\n\n\n\n","category":"function"},{"location":"DuctAPE/api/private_process/#DuctAPE.estimate_states!","page":"Process","title":"DuctAPE.estimate_states!","text":"estimate_states!(\n solve_containers,\n vz_rotor,\n vtheta_rotor,\n Cm_wake,\n operating_point,\n ivr,\n ivw,\n linsys,\n blade_elements,\n wakeK,\n idmaps;\n verbose=false,\n)\n\nEstimate velocity states.\n\nArguments\n\nsolve_containers::NamedTuple : cache for intermediate values in solve\nvz_rotor::Vector{Float} : axial induced rotor velocity state container\nvtheta_rotor::Vector{Float} : tangential induced rotor velocity state container\nCm_wake::Vector{Float} : absolute meridional wake control point velocity state container\noperating_point::NamedTuple : Named tuple containing operating_point information\nivr::NamedTuple : unit induced velocities on rotor(s)\nivw::NamedTuple : unit induced velocities on wake\nlinsys::NamedTuple : vectors and matricies comprising the panel method linear system\nblade_elements::NamedTuple : blade element geometry and airfoil polar information\nwakeK::Vector{Float} : geometric constants used in caculating wake strengths\nidmaps::NamedTuple : index maps used throughout solve\n\nKeyword Arguments\n\nverbose::Bool=false : flag for verbose print statements\n\n\n\n\n\n","category":"function"},{"location":"DuctAPE/api/private_process/#Solve-Utilities","page":"Process","title":"Solve Utilities","text":"","category":"section"},{"location":"DuctAPE/api/private_process/","page":"Process","title":"Process","text":"DuctAPE.extract_initial_guess\nDuctAPE.extract_state_variables","category":"page"},{"location":"DuctAPE/api/private_process/#DuctAPE.extract_initial_guess","page":"Process","title":"DuctAPE.extract_initial_guess","text":"extract_initial_guess(\n solver_options::SolverOptionsType, sensitivity_parameters, state_dims\n)\n\nExtract initial guess from the solve parameters cache vector.\n\nArguments\n\nsolver_options::SolverOptionsType : used for dispatch\nsensitivity_parameters::Vector{Float} : vector form of solve parameter cache passed into the solver.\nstate_dims::NamedTuple : dimensions and indices of state variables within the solve parameter cache vector\n\nReturns\n\ninitial_guess::Vector{Float}` : a vector of the solver initial guess\n\n\n\n\n\n","category":"function"},{"location":"DuctAPE/api/private_process/#DuctAPE.extract_state_variables","page":"Process","title":"DuctAPE.extract_state_variables","text":"extract_state_variables(solver_options::SolverOptionsType, vars, dims)\n\nReshape the state variables from a single vector, to multiple arrays.\n\nArguments\n\nReturns if solver_options <: CSORSolverOptions\n\nGamr::type : Blade element circulation strengths\nsigr::type : Rotor source panel strengths\ngamw::type : Wake vortex panel strengths\n\nReturns if solver_options <: Union{ExternalSolverOptions, PolyAlgorithmOptions}\n\nvz_rotor::Vector{Float} : axial induced rotor velocity state container\nvtheta_rotor::Vector{Float} : tangential induced rotor velocity state container\nCm_wake::Vector{Float} : absolute meridional wake control point velocity state container\n\n\n\n\n\n","category":"function"},{"location":"C4Blade/api/#Index","page":"API Reference","title":"Index","text":"","category":"section"},{"location":"C4Blade/api/","page":"API Reference","title":"API Reference","text":"Pages = [\"C4Blade/api.md\"]\nDepth = 5","category":"page"},{"location":"C4Blade/api/","page":"API Reference","title":"API Reference","text":"Modules=[DuctAPE.C4Blade]","category":"page"},{"location":"DuctAPE/api/private_preprocess/#General","page":"Preprocess","title":"General","text":"","category":"section"},{"location":"DuctAPE/api/private_preprocess/","page":"Preprocess","title":"Preprocess","text":"DuctAPE.set_index_maps\nDuctAPE.precompute_parameters\nDuctAPE.precompute_parameters!","category":"page"},{"location":"DuctAPE/api/private_preprocess/#DuctAPE.set_index_maps","page":"Preprocess","title":"DuctAPE.set_index_maps","text":"set_index_maps(\n npanels,\n ncenterbody_inlet,\n nwake_sheets,\n dte_minus_cbte,\n wnm,\n wenids,\n nwp,\n nwsp,\n nbn,\n ndp,\n riiw,\n nrotor,\n)\n\nSet values for index map to be used throughout solve and post-process.\n\nArguments\n\nnpanels : paneling_constants.npanels\nncenterbody_inlet : paneling_constants.ncenterbody_inlet\nnwake_sheets : paneling_constants.nwake_sheets\ndte_minus_cbte : paneling_constants.dte_minus_cbte\nwnm : wake_vortex_panels.nodemap\nwenids : wake_vortex_panels.endnodeidxs\nnwp : problem_dimensions.nwp\nnwsp : problem_dimensions.nwsp\nnbn : problem_dimensions.nbn\nndp : body_vortex_panels.npanel[1]\nriiw : rotor_indices_in_wake\nnrotor : problem_dimensions.nrotor\n\nReturns\n\nidmaps::NamedTuple : A named tuple containing index mapping used in bookkeeping throughout solve and post-process\n\n\n\n\n\n","category":"function"},{"location":"DuctAPE/api/private_preprocess/#DuctAPE.precompute_parameters","page":"Preprocess","title":"DuctAPE.precompute_parameters","text":"precompute_parameters(\n propulsor;\n grid_solver_options=GridSolverOptions(),\n integration_options=IntegrationOptions(),\n autoshiftduct=true,\n itcpshift=0.05,\n axistol=1e-15,\n tegaptol=1e1 * eps(),\n finterp=(x,y,xp)->FLOWMath.akima(x,y,xp,2.0*eps(),eps()),\n silence_warnings=true,\n verbose=false,\n)\n\nOut of place main pre-processing function that computes all the required parameters for the solve.\n\nArguments\n\npropulsor::Propulsor : A Propuslor object\n\nKeyword Arguments\n\ngrid_solver_options::GridSolverOptionsType=GridSolverOptions() : A GridSolverOptionsType object\nintegration_options::IntegrationMethod=IntegrationOptions() : An IntegrationMethod object\nautoshiftduct::Bool=true : flag to shift duct geometry based on rotor tip radius\nitcpshift::Float=0.05 : value used in positioning the internal pseudo control point in the solid bodies. Default is DFDC hard-coded value.\naxistol::Float=1e-15 : tolerance for how close to the axis of rotation to be considered on the axis.\ntegaptol::Float=1e1 * eps() : tolerance for how large of a trailing edge gap is considered a gap.\nfinterp::Function=FLOWMath.akima : interpolation method for re-interpolating body coordinates\nsilence_warnings::Bool=true : flag to silence warnings\nverbose::Bool=false : flag to print verbose statements\n\nReturns\n\nivr::NamedTuple : A named tuple containing arrays of induced velocities on the rotors\nivw::NamedTuple : A named tuple containing arrays of induced velocities on the wake\nivb::NamedTuple : A named tuple containing arrays of induced velocities on the bodies\nlinsys::NamedTuple : A named tuple containing cacheable data for the linear system, including:\nA_bb::Array{Float} : AIC (LHS) matrix for the panel method system\nb_bf::Array{Float} : Initial system RHS vector based on freestrem magnitude\nA_br::Array{Float} : Unit normal velocity from rotors onto body panels\nA_pr::Array{Float} : Unit normal velocity from rotors onto body internal psuedo control points\nA_bw::Array{Float} : Unit normal velocity from wake onto body panels\nA_pw::Array{Float} : Unit normal velocity from wake onto body internal psuedo control points\nA_bb_LU::LinearAlgebra.LU : LinearAlgebra LU factorization of the LHS matrix\nlu_decomp_flag::Vector{Bool} : flag for whether factorization was successful\nblade_elements::NamedTuple : A named tuple containing cacheable blade element information (see docs for interpolate_blade_elements)\nairfoils::Vector{AFType} : A matrix of airfoil types associated with each of the blade elements\nwakeK::Matrix{Float} : A matrix of precomputed geometric constants used in the calculation of the wake vortex strengths\nidmaps::NamedTuple : A named tuple containing index mapping used in bookkeeping throughout solve and post-process\npanels::NamedTuple : A named tuple of panel objects including:\nbody_vortex_panels::NamedTuple : the named tuple containing the body vortex panel information\nrotor_source_panels::NamedTuple : the named tuple containing the rotor source panel information\nwake_vortex_panels::NamedTuple : the named tuple containing the wake vortex panel information\nproblem_dimensions::ProblemDimensions : A ProblemDimensions object\n\n\n\n\n\nprecompute_parameters(\n rp_duct_coordinates,\n rp_centerbody_coordinates,\n wake_grid,\n rotor_indices_in_wake,\n Rtips,\n Rhubs,\n rotorstator_parameters,\n paneling_constants,\n operating_point,\n integration_options,\n problem_dimensions=nothing;\n itcpshift=0.05,\n axistol=1e-15,\n tegaptol=1e1 * eps(),\n silence_warnings=true,\n verbose=false,\n)\n\nAn alternate version of precompute_parameters allowing for user defined geometry that does not go through a re-panling step (use with caution).\n\nThe first inputs are the outputs of the reinterpolate_geometry and get_blade_ends_from_body_geometry functions.\n\n\n\n\n\n","category":"function"},{"location":"DuctAPE/api/private_preprocess/#DuctAPE.precompute_parameters!","page":"Preprocess","title":"DuctAPE.precompute_parameters!","text":"precompute_parameters!(\n ivr,\n ivw,\n blade_element_cache,\n linsys,\n wakeK,\n propulsor,\n prepost_containers,\n problem_dimensions;\n grid_solver_options=GridSolverOptions(),\n integration_options=IntegrationOptions(),\n autoshiftduct=true,\n itcpshift=0.05,\n axistol=1e-15,\n tegaptol=1e1 * eps(),\n finterp=(x,y,xp)->FLOWMath.akima(x,y,xp,2.0*eps(),eps()),\n silence_warnings=true,\n verbose=false,\n)\n\nIn-place version of precompute_parameters.\n\n\n\n\n\nprecompute_parameters!(\n ivr,\n ivw,\n blade_element_cache,\n linsys,\n wakeK,\n wake_grid,\n rp_duct_coordinates,\n rp_centerbody_coordinates,\n rotor_indices_in_wake,\n rotorstator_parameters,\n paneling_constants,\n operating_point,\n prepost_containers,\n problem_dimensions=nothing;\n integration_options=IntegrationOptions(),\n itcpshift=0.05,\n axistol=1e-15,\n tegaptol=1e1 * eps(),\n finterp=(x,y,xp)->FLOWMath.akima(x,y,xp,2.0*eps(),eps()),\n silence_warnings=true,\n verbose=false,\n)\n\nIn-place version of the precompute_parameters function by-passing the geometry reinterpolateion. (Use with caution)\n\n\n\n\n\n","category":"function"},{"location":"DuctAPE/api/private_preprocess/#Geometry","page":"Preprocess","title":"Geometry","text":"","category":"section"},{"location":"DuctAPE/api/private_preprocess/","page":"Preprocess","title":"Preprocess","text":"DuctAPE.reinterpolate_geometry\nDuctAPE.reinterpolate_geometry!\nDuctAPE.generate_all_panels\nDuctAPE.generate_all_panels!","category":"page"},{"location":"DuctAPE/api/private_preprocess/#DuctAPE.reinterpolate_geometry","page":"Preprocess","title":"DuctAPE.reinterpolate_geometry","text":"reinterpolate_geometry(\n problem_dimensions,\n duct_coordinates,\n centerbody_coordinates,\n rotorstator_parameters,\n paneling_constants;\n autoshiftduct=true,\n grid_solver_options=GridSolverOptions(),\n finterp=(x,y,xp)->FLOWMath.akima(x,y,xp,2.0*eps(),eps()),\n verbose=false,\n silence_warnings=true,\n)\n\nRe-interpolate the body geometry and return compatible body and way geometry.\n\nArguments\n\nproblem_dimensions::ProblemDimensions : A ProblemDimensions object\nduct_coordinates::Matrix{Float} : [z,r] coordinates of duct geometry\ncenterbody_coordinates::Matrix{Float} : [z,r] coordinates of centerbody geometry\nrotorstator_parameters::RotorStatorParameters : A RotorStatorParameters object\npaneling_constants::PanelingConstants : A PanelingConstants object\n\nKeyword Arguments\n\nautoshiftduct::Bool=true : flag to shift duct geometry based on rotor tip radius\ngrid_solver_options::SolverOptionsType=GridSolverOptions() : options for the wake grid position solver\nfinterp::Function=FLOWMath.akima : interpolation method for re-interpolating body coordinates\nverbose::Bool=false : flag to print verbose statements\nsilence_warnings::Bool=true : flag to silence warnings\n\nReturns\n\nwake_grid::Array{Float} : array containig the z and r elliptic grid points defning the wake geometry.\nrp_duct_coordinates::Matrix{Float} : matrix containing the re-paneled duct coordinates\nrp_centerbody_coordinates::Matrix{Float} : matrix containing the re-paneled centerbody coordinates\nrotor_indices_in_wake::Vector{Int} : vector containing the indices of where in the wake the rotors reside (used later to define the rotor panel edges).\n\n\n\n\n\n","category":"function"},{"location":"DuctAPE/api/private_preprocess/#DuctAPE.reinterpolate_geometry!","page":"Preprocess","title":"DuctAPE.reinterpolate_geometry!","text":"reinterpolate_geometry!(\n wake_grid,\n rp_duct_coordinates,\n rp_centerbody_coordinates,\n rotor_indices_in_wake,\n duct_coordinates,\n centerbody_coordinates,\n rotorstator_parameters,\n blade_element_cache,\n paneling_constants;\n autoshiftduct=true,\n grid_solver_options=GridSolverOptions(),\n finterp=(x,y,xp)->FLOWMath.akima(x,y,xp,2.0*eps(),eps()),\n verbose=false,\n silence_warnings=true,\n)\n\nIn-place version of reinterpolate_geometry.\n\n\n\n\n\n","category":"function"},{"location":"DuctAPE/api/private_preprocess/#DuctAPE.generate_all_panels","page":"Preprocess","title":"DuctAPE.generate_all_panels","text":"generate_all_panels(\n rp_duct_coordinates,\n rp_centerbody_coordinates,\n nwake_sheets,\n rotor_indices_in_wake,\n rotorzloc,\n wake_grid;\n itcpshift=0.05,\n axistol=1e-15,\n tegaptol=1e1 * eps(),\n silence_warnings=true,\n)\n\nFunction that calls all of the various panel generation functions are returns a named tuple containing all the panels\n\nArguments\n\nrp_duct_coordinates::Matrix{Float} : matrix containing the re-paneled duct coordinates\nrp_centerbody_coordinates::Matrix{Float} : matrix containing the re-paneled centerbody coordinates\nnwake_sheets::Int : number of wake sheets\nrotor_indices_in_wake::Vector{Int} : vector containing the indices of where in the wake the rotors reside (used later to define the rotor panel edges).\nrotorzloc:Vector{Float} : axial locations of rotor lifting lines (contained in RotorStatorParameters)\nwake_grid::Array{Float} : array containig the z and r elliptic grid points defning the wake geometry.\n\nKeyword Arguments\n\nitcpshift::Float=0.05 : value used in positioning the internal pseudo control point in the solid bodies. Default is DFDC hard-coded value.\naxistol::Float=1e-15 : tolerance for how close to the axis of rotation to be considered on the axis.\ntegaptol::Float=1e1 * eps() : tolerance for how large of a trailing edge gap is considered a gap.\nsilence_warnings::Bool=true : flag to silence warnings\n\nReturns\n\npanels::NamedTuple : A named tuple of named tuples containing paneling information, including:\nbody_vortex_panels::NamedTuple\nrotor_source_panels::NamedTuple\nwake_vortex_panels::NamedTuple\n\n\n\n\n\n","category":"function"},{"location":"DuctAPE/api/private_preprocess/#DuctAPE.generate_all_panels!","page":"Preprocess","title":"DuctAPE.generate_all_panels!","text":"generate_all_panels!(\n panels,\n wake_grid,\n rp_duct_coordinates,\n rp_centerbody_coordinates,\n rotor_indices_in_wake,\n rotorzloc,\n nwake_sheets;\n itcpshift=0.05,\n axistol=1e-15,\n tegaptol=1e1 * eps(),\n silence_warnings=true,\n)\n\nIn-place version of generate_all_panels.\n\n\n\n\n\n","category":"function"},{"location":"DuctAPE/api/private_preprocess/#Wake","page":"Preprocess","title":"Wake","text":"","category":"section"},{"location":"DuctAPE/api/private_preprocess/","page":"Preprocess","title":"Preprocess","text":"DuctAPE.discretize_wake\nDuctAPE.generate_wake_grid\nDuctAPE.generate_wake_grid!\nDuctAPE.initialize_wake_grid\nDuctAPE.initialize_wake_grid!\nDuctAPE.relax_grid!\nDuctAPE.generate_wake_panels\nDuctAPE.generate_wake_panels!\nDuctAPE.get_wake_k\nDuctAPE.get_wake_k!","category":"page"},{"location":"DuctAPE/api/private_preprocess/#DuctAPE.discretize_wake","page":"Preprocess","title":"DuctAPE.discretize_wake","text":"discretize_wake(\n duct_coordinates,\n centerbody_coordinates,\n rotorzloc, # rotor axial locations\n wake_length,\n npanels,\n dte_minus_cbte;\n)\n\nCalculate wake sheet panel node z-coordinates.\n\nArguments\n\nduct_coordinates::Matrix{Float} : Array of input duct coordinates\ncenterbody_coordinates::Matrix{Float} : Array of input centerbody_coordinates coordinates\nrotorzloc ::Vector{Float} : rotor axial locations\nwake_length::Float : non-dimensional length of wake to extend beyond aft-most body trailing edge.\nnpanels::Vector{Int} : A vector of the number of panels between each discrete point. For example: [number of panels between the rotors; number of panels between the stator and the first trailing edge; number of panels between the trailing edges; number of panels between the last trailing edge and the end of the wake]\ndte_minus_cbte::Float : indicator as to whether the duct trailing edge minus the centerbody trailing edge is positive, zero, or negative.\n\n\n\n\n\n","category":"function"},{"location":"DuctAPE/api/private_preprocess/#DuctAPE.generate_wake_grid","page":"Preprocess","title":"DuctAPE.generate_wake_grid","text":"generate_wake_grid(\n problem_dimensions,\n rp_duct_coordinates,\n rp_centerbody_coordinates,\n Rhub1,\n Rtip1,\n tip_gap1,\n zwake;\n grid_solver_options=GridSolverOptions(),\n verbose=false,\n silence_warnings=true,\n)\n\nInitialize and solve for elliptic grid on which wake sheets are defined.\n\nArguments\n\nproblem_dimensions:: : A ProblemDimensions object\nrp_duct_coordinates:: : repaneled duct coordinates\nrp_centerbody_coordinates:: : repaneled centerbody coordinates\nRhub1:: : Hub radius of first rotor\nRtip1:: : Tip radius of first rotor\ntip_gap1:: : Tip gap of first rotor (MUST BE ZERO for now)\nzwake:: : axial positions of wake sheet panel nodes\n\nKeyword Arguments\n\ngrid_solver_options::GridSolverOptionsType=GridSolverOptions() : options for solving the elliptic grid.\nverbose::Bool=false : flag to print verbose statements\nsilence_warnings::Bool=true : flag to supress warnings\n\nReturns\n\nwake_grid::Array{Float,3} : 3D Array of axial and radial wake_grid points after solution of elliptic system.\n\n\n\n\n\n","category":"function"},{"location":"DuctAPE/api/private_preprocess/#DuctAPE.generate_wake_grid!","page":"Preprocess","title":"DuctAPE.generate_wake_grid!","text":"generate_wake_grid!(\n wake_grid,\n rp_duct_coordinates,\n rp_centerbody_coordinates,\n Rhub1,\n Rtip1,\n tip_gap1,\n zwake;\n grid_solver_options=grid_solver_options,\n verbose=false,\n silence_warnings=true,\n)\n\nIn-place version of generate_wake_grid.\n\n\n\n\n\n","category":"function"},{"location":"DuctAPE/api/private_preprocess/#DuctAPE.initialize_wake_grid","page":"Preprocess","title":"DuctAPE.initialize_wake_grid","text":"initialize_wake_grid(rp_duct_coordinates, rp_centerbody_coordinates, zwake, rwake)\n\nInitialize the wake grid.\n\nArguments:\n\nrp_duct_coordinates::Matrix{Float} : The re-paneled duct coordinates\nrp_centerbody_coordinates::Matrix{Float} : The re-paneled centerbody coordinates\nzwake::Vector{Float} : The axial positions of the wake sheet panel nodes\nrwake::Vector{Float} : The radial positions of the blade elements for the foremost rotor\n\nReturns:\n\nwake_grid::Array{Float,3} : 3D Array of axial and radial wake_grid points\n\n\n\n\n\n","category":"function"},{"location":"DuctAPE/api/private_preprocess/#DuctAPE.initialize_wake_grid!","page":"Preprocess","title":"DuctAPE.initialize_wake_grid!","text":"initialize_wake_grid!(\n wake_grid, rp_duct_coordinates, rp_centerbody_coordinates, zwake, rwake\n)\n\nIn-place version of initialize_wake_grid.\n\n\n\n\n\n","category":"function"},{"location":"DuctAPE/api/private_preprocess/#DuctAPE.relax_grid!","page":"Preprocess","title":"DuctAPE.relax_grid!","text":"relax_grid!(\n grid_solver_options::GridSolverOptionsType,\n wake_grid;\n verbose=false,\n silence_warnings=true,\n tabchar=\" \",\n ntab=1,\n)\n\nRelax/Solve initial wake grid according to elliptic system of equations.\n\nArguments\n\n`gridsolveroptions::GridSolverOptionsType' : options for elliptic grid solver\nwake_grid::Array{Float,3} : Initialized wake grid\n\nKeyword Arguments\n\n`verbose=false::' : flag for printing verbose statements\n`silence_warnings=true::' : flag for supressing warnings\n`tabchar::String=\" \"::' : string to use for tabbing over verbose statements.\n`ntab::Int=1' : number of tabs for printing verbose statements\n\n\n\n\n\nrelax_grid!(xg, rg, nxi, neta; iteration_limit, atol)\n\nRelax wakegrid using elliptic wakegrid solver.\n\nArguments:\n\nKeyword Arguments:\n\niteration_limit::Int : maximum number of iterations to run, default=100\natol::Float : convergence tolerance, default = 1e-9\n\nReturns:\n\n\n\n\n\n","category":"function"},{"location":"DuctAPE/api/private_preprocess/#DuctAPE.generate_wake_panels","page":"Preprocess","title":"DuctAPE.generate_wake_panels","text":"generate_wake_panels(wake_grid)\n\nGenerate paneling for each wake sheet emanating from the rotor blade elements.\n\nArguments:\n\nwake_grid::Array{Float,3} : axial and radial locations of each wake_grid point (after relaxation/solution)\n\nReturns:\n\nwake_vortex_panels::NamedTuple : A named tuple of panel values describing the wake vortex panels\n\n\n\n\n\n","category":"function"},{"location":"DuctAPE/api/private_preprocess/#DuctAPE.generate_wake_panels!","page":"Preprocess","title":"DuctAPE.generate_wake_panels!","text":"generate_wake_panels!(wake_panels, wake_grid)\n\nIn-place version of generate_wake_panels.\n\n\n\n\n\n","category":"function"},{"location":"DuctAPE/api/private_preprocess/#DuctAPE.get_wake_k","page":"Preprocess","title":"DuctAPE.get_wake_k","text":"get_wake_k(r, nwn)\n\nCalculate geometric constant for use in later calculation of wake panel node strengths.\n\nArguments\n\nr::Vector{Float} : Vector of wake panel node radial positions\n\nReturns\n\nK::Vector{Float} : Vector of geometric constants used in calculation of panel node strengths.\n\n\n\n\n\n","category":"function"},{"location":"DuctAPE/api/private_preprocess/#DuctAPE.get_wake_k!","page":"Preprocess","title":"DuctAPE.get_wake_k!","text":"get_wake_k!(K, r)\n\nIn-place version of get_wake_k.\n\n\n\n\n\n","category":"function"},{"location":"DuctAPE/api/private_preprocess/#Bodies","page":"Preprocess","title":"Bodies","text":"","category":"section"},{"location":"DuctAPE/api/private_preprocess/","page":"Preprocess","title":"Preprocess","text":"DuctAPE.reinterpolate_bodies!\nDuctAPE.place_duct!","category":"page"},{"location":"DuctAPE/api/private_preprocess/#DuctAPE.reinterpolate_bodies!","page":"Preprocess","title":"DuctAPE.reinterpolate_bodies!","text":"reinterpolate_bodies!(\n rp_duct_coordinates,\n rp_centerbody_coordinates,\n duct_coordinates,\n centerbody_coordinates,\n zwake,\n ncenterbody_inlet,\n nduct_inlet;\n finterp=FLOWMath.akima,\n)\n\nReinterpolate duct and centerbody coordinates in order to make them compatible with the calculated wake sheet panel axial positions.\n\nArguments\n\nrp_duct_coordinates::Matrix{Float} : the re-paneled duct coordinates\nrp_centerbody_coordinates::Matrix{Float} : the re-paneled centerbody coordinates\nduct_coordinates::Matrix{Float} : the input duct coordinates\ncenterbody_coordinates::Matrix{Float} : the input centerbody coordinates\nzwake::Matrix{Float} : the wake sheet panel node axial positions\nncenterbody_inlet::Matrix{Float} : the number of panels to use for the centerbody inlet\nnduct_inlet::Matrix{Float} : the number of panels to use for the duct inlet\n\nKeyword Arguments\n\nfinterp::Function=FLOWMath.akima : interpolation method\n\n\n\n\n\n","category":"function"},{"location":"DuctAPE/api/private_preprocess/#DuctAPE.place_duct!","page":"Preprocess","title":"DuctAPE.place_duct!","text":"place_duct!(rp_duct_coordinates, Rtip, rotorzloc, tip_gap)\n\nTransform the duct radial coordinates such that the leading rotor radius touches the duct wall.\n\nNote that this function is called AFTER the repanling function is called, such that the rotorzloc locations should line up directly with the duct and centerbody coordinates.\n\nArguments\n\nrp_duct_coordinates::Matrix{Float} : the re-paneled duct coordinates\nRtip::Vector{Float} : Tip radii for the rotor(s)\nrotorzloc::Vector{Float} : axial position(s) of the rotor(s)\ntip_gap::Vector{Float} : tip gap for the fore-most rotor (MUST BE ZERO for now)\n\n\n\n\n\n","category":"function"},{"location":"DuctAPE/api/private_preprocess/#Rotors","page":"Preprocess","title":"Rotors","text":"","category":"section"},{"location":"DuctAPE/api/private_preprocess/","page":"Preprocess","title":"Preprocess","text":"DuctAPE.interpolate_blade_elements\nDuctAPE.interpolate_blade_elements!\nDuctAPE.get_blade_ends_from_body_geometry\nDuctAPE.get_blade_ends_from_body_geometry!\nDuctAPE.get_local_solidity\nDuctAPE.get_stagger\nDuctAPE.generate_rotor_panels\nDuctAPE.generate_rotor_panels!","category":"page"},{"location":"DuctAPE/api/private_preprocess/#DuctAPE.interpolate_blade_elements","page":"Preprocess","title":"DuctAPE.interpolate_blade_elements","text":"interpolate_blade_elements(\n rsp, Rtips, Rhubs, rotor_panel_centers, nbe; finterp=FLOWMath.linear\n)\n\nInterpolate blade elements based on RotorStatorParameters inputs and number of desired blade elements (from number of wake sheet in PanelingConstants input)\n\nArguments\n\nrsp::RotorStatorParameters : A RotorStatorParameters object\n`Rtips::Vector{Float}' : Vector of rotor tip radii\n`Rhubs::Vector{Float}' : Vector of rotor hub radii\n`rotorpanelcenters::Vector{Float}' : Vector of rotor panel centers\nnbe::Int : number of blade elements per rotor\n\nKeyword Arguments\n\nfinterp::Function=FLOWMath.linear : interpolation method (note, using Akima splines as is done for the body geometry can lead to negative chord in some cases)\n\nReturns\n\nblade_element_cache::NamedTuple : A named tuple containing the cacheable blade element information excluding the airfoil data.\nairfoils::NamedTuple : A named tuple containing vectors of inner and outer airfoil polar data for each blade element, used in interpolating the input data at blade element locations.\n\n\n\n\n\n","category":"function"},{"location":"DuctAPE/api/private_preprocess/#DuctAPE.interpolate_blade_elements!","page":"Preprocess","title":"DuctAPE.interpolate_blade_elements!","text":"interpolate_blade_elements!(\n blade_element_cache, rsp, rotor_panel_centers, nbe; finterp=FLOWMath.linear\n)\n\nIn-place version of interpolate_blade_elements.\n\nReturns\n\nairfoils::NamedTuple : A named tuple containing vectors of inner and outer airfoil polar data for each blade element, used in interpolating the input data at blade element locations.\n\n\n\n\n\n","category":"function"},{"location":"DuctAPE/api/private_preprocess/#DuctAPE.get_blade_ends_from_body_geometry","page":"Preprocess","title":"DuctAPE.get_blade_ends_from_body_geometry","text":"get_blade_ends_from_body_geometry(\n rp_duct_coordinates, rp_centerbody_coordinates, tip_gaps, rotorzloc\n)\n\nObtain rotor hub and tip radii based on duct and centerbody geometry.\n\nArguments\n\nvar::type :\nrp_duct_coordinates::Matrix{Float} : re-paneled duct coordinates\nrp_centerbody_coordinates::Matrix{Float} : re-paneled centerbody coordinates\ntip_gaps::Vector{Float} : gaps between blade tips and duct surface (MUST BE ZEROS for now)\nrotorzloc::Vector{Float} : rotor lifting line axial positions.\n\nReturns\n\nRtips::Vector{Float} : rotor tip radii\nRhubs::Vector{Float} : rotor hub radii\n\n\n\n\n\n","category":"function"},{"location":"DuctAPE/api/private_preprocess/#DuctAPE.get_blade_ends_from_body_geometry!","page":"Preprocess","title":"DuctAPE.get_blade_ends_from_body_geometry!","text":"get_blade_ends_from_body_geometry!(\n Rtip,\n Rhub,\n rp_duct_coordinates,\n rp_centerbody_coordinates,\n tip_gaps,\n rotorzloc;\n silence_warnings=true,\n)\n\nIn-place version of get_blade_ends_from_body_geometry.\n\n\n\n\n\n","category":"function"},{"location":"DuctAPE/api/private_preprocess/#DuctAPE.get_local_solidity","page":"Preprocess","title":"DuctAPE.get_local_solidity","text":"get_local_solidity(B, chord, r)\n\nCalculate local solidity from local chord, radial position, and number of blades.\n\nArguments\n\nB::Float : number of blades on rotor (usually an integer, but not necessarily).\nchord::Vector{Float} : chord lengths at each radial station.\nr::Vector{Float} : dimensional radial positions.\n\nReturns\n\nsolidity::Vector{Float} : local solidity at each radial station\n\n\n\n\n\n","category":"function"},{"location":"DuctAPE/api/private_preprocess/#DuctAPE.get_stagger","page":"Preprocess","title":"DuctAPE.get_stagger","text":"get_stagger(twists)\n\nConvert twist angle to stagger angle\n\n\n\n\n\n","category":"function"},{"location":"DuctAPE/api/private_preprocess/#DuctAPE.generate_rotor_panels","page":"Preprocess","title":"DuctAPE.generate_rotor_panels","text":"generate_rotor_panels(rotorzloc, wake_grid, rotor_indices_in_wake, nwake_sheets)\n\nGenerate rotor panel objects.\n\nArguments\n\nrotorzloc::Vector{Float} : rotor lifting line axial position\nwake_grid::Array{Float,3} : wake elliptic grid axial and radial locations\nrotor_indices_in_wake::Vector{Int} : indices of where along wake the rotors are placed\nnwake_sheets::Int : number of wake sheets\n\nReturns\n\nrotor_source_panels::NamedTuple : A named tuple containing the rotor source panel variables.\n\n\n\n\n\n","category":"function"},{"location":"DuctAPE/api/private_preprocess/#DuctAPE.generate_rotor_panels!","page":"Preprocess","title":"DuctAPE.generate_rotor_panels!","text":"generate_rotor_panels!(\n rotor_source_panels, rotorzloc, wake_grid, rotor_indices_in_wake, nwake_sheets\n)\n\nIn-place version of generate_rotor_panels.\n\n\n\n\n\n","category":"function"},{"location":"DuctAPE/api/private_preprocess/#Induced-Velocities","page":"Preprocess","title":"Induced Velocities","text":"","category":"section"},{"location":"DuctAPE/api/private_preprocess/","page":"Preprocess","title":"Preprocess","text":"DuctAPE.calculate_unit_induced_velocities\nDuctAPE.calculate_unit_induced_velocities!\nDuctAPE.initialize_linear_system\nDuctAPE.initialize_linear_system!","category":"page"},{"location":"DuctAPE/api/private_preprocess/#DuctAPE.calculate_unit_induced_velocities","page":"Preprocess","title":"DuctAPE.calculate_unit_induced_velocities","text":"calculate_unit_induced_velocities(problem_dimensions, panels, integration_options)\n\nCalculate all the unit-induced velocties of all panels on all control points\n\nArguments\n\nproblem_dimensions::ProblemDimensions : A ProblemDimensions object\npanels::NamedTuple : A named tuple containing all the paneling information\nintegration_options::IntegrationOptions : Options used for integration of velocity kernals across panels\n\nReturns\n\nivr::NamedTuple : A named tuple containing arrays of induced velocities on the rotors\nivw::NamedTuple : A named tuple containing arrays of induced velocities on the wake\nivb::NamedTuple : A named tuple containing arrays of induced velocities on the bodies\n\n\n\n\n\n","category":"function"},{"location":"DuctAPE/api/private_preprocess/#DuctAPE.calculate_unit_induced_velocities!","page":"Preprocess","title":"DuctAPE.calculate_unit_induced_velocities!","text":"calculate_unit_induced_velocities!(ivr, ivw, ivb, panels, integration_options)\n\nIn-place version of calculate_unit_induced_velocities.\n\n\n\n\n\n","category":"function"},{"location":"DuctAPE/api/private_preprocess/#DuctAPE.initialize_linear_system","page":"Preprocess","title":"DuctAPE.initialize_linear_system","text":"initialize_linear_system(\n ivb,\n body_vortex_panels,\n rotor_source_panels,\n wake_vortex_panels,\n Vinf,\n integration_options,\n)\n\nSet up the linear system used in the panel method solve.\n\nArguments\n\nivb::NamedTuple : the named tuple containing all the unit induced velocities on the bodies\nbody_vortex_panels::NamedTuple : the named tuple containing the body vortex panel information\nrotor_source_panels::NamedTuple : the named tuple containing the rotor source panel information\nwake_vortex_panels::NamedTuple : the named tuple containing the wake vortex panel information\nVinf::Vector{Float} : the one-element vector containing the Freestream velocity magnitude\nintegration_options::IntegrationOptions : the integration options used in integrating the panel induced velocities\n\nReturns\n\nlinsys::NamedTuple : A named tuple containing cacheable data for the linear system, including:\nA_bb::Array{Float} : AIC (LHS) matrix for the panel method system\nb_bf::Array{Float} : Initial system RHS vector based on freestrem magnitude\nA_br::Array{Float} : Unit normal velocity from rotors onto body panels\nA_pr::Array{Float} : Unit normal velocity from rotors onto body internal psuedo control points\nA_bw::Array{Float} : Unit normal velocity from wake onto body panels\nA_pw::Array{Float} : Unit normal velocity from wake onto body internal psuedo control points\nA_bb_LU::LinearAlgebra.LU : LinearAlgebra LU factorization of the LHS matrix\nlu_decomp_flag::Vector{Bool} : flag for whether factorization was successful\n\n\n\n\n\n","category":"function"},{"location":"DuctAPE/api/private_preprocess/#DuctAPE.initialize_linear_system!","page":"Preprocess","title":"DuctAPE.initialize_linear_system!","text":"initialize_linear_system!(\n linsys,\n ivb,\n body_vortex_panels,\n rotor_source_panels,\n wake_vortex_panels,\n Vinf,\n intermediate_containers,\n integration_options,\n)\n\nIn-place version of initialize_linear_system.\n\n\n\n\n\n","category":"function"},{"location":"DuctAPE/api/private_preprocess/#Unit-Induced-Velocities","page":"Preprocess","title":"Unit Induced Velocities","text":"","category":"section"},{"location":"DuctAPE/api/private_preprocess/","page":"Preprocess","title":"Preprocess","text":"DuctAPE.calculate_xrm\nDuctAPE.calculate_xrm!\nDuctAPE.get_elliptics\nDuctAPE.vortex_ring_vz\nDuctAPE.vortex_ring_vz!\nDuctAPE.smoke_ring_vz\nDuctAPE.vortex_ring_vr\nDuctAPE.vortex_ring_vr!\nDuctAPE.source_ring_vz\nDuctAPE.source_ring_vz!\nDuctAPE.source_ring_vr\nDuctAPE.source_ring_vr!","category":"page"},{"location":"DuctAPE/api/private_preprocess/#DuctAPE.calculate_xrm","page":"Preprocess","title":"DuctAPE.calculate_xrm","text":"calculate_xrm(controlpoint, node)\n\nCalculate xi, rho, and m for vortex and/or source ring induced velocity calculation.\n\nReturns zeros if ring is on (or approximately on) the axis of rotation (zero radius).\n\nArguments\n\ncontrolpoint::Vector{Float} [z r] coordinates of point being influenced\nnode::Vector{Float} : [z r] coordinates of singularity ring\n\nReturns\n\nxi::Float : normalized relative axial position\nrho::Float : normalized relative radial position\nm::Float : Elliptic integral input\nrj::Float : radial position of the ring\n\n\n\n\n\n","category":"function"},{"location":"DuctAPE/api/private_preprocess/#DuctAPE.calculate_xrm!","page":"Preprocess","title":"DuctAPE.calculate_xrm!","text":"calculate_xrm!(cache_vec, controlpoint, node)\n\nIn-place version of calculate_xrm.\n\nCache_vec is a vector used to hold intermediate values as well as the outputs.\n\n\n\n\n\n","category":"function"},{"location":"DuctAPE/api/private_preprocess/#DuctAPE.get_elliptics","page":"Preprocess","title":"DuctAPE.get_elliptics","text":"get_elliptics(m)\n\nCalculate value of elliptic functions for the given geometry parameter.\n\nArguments\n\nm::Float : Elliptic Function parameter\n\nReturns\n\nK::Float : K(m), value of elliptic function of the first kind at m.\nE::Float : E(m), value of eeliptic function of the second kind at m.\n\n\n\n\n\n","category":"function"},{"location":"DuctAPE/api/private_preprocess/#DuctAPE.vortex_ring_vz","page":"Preprocess","title":"DuctAPE.vortex_ring_vz","text":"vortex_ring_vz(xi, rho, m, r_influence, influence_length)\n\nAxial velocity induced by axisymmetric vortex ring.\n\nUses equivalent smoke ring induced velocity for self-induction, and returns zero if vortex ring is on axis of rotation (zero radius).\n\nArguments\n\nxi::Float : normalized z-coordinate, (z-zo)/ro\nrho::Float : normalized r-coordinate, r/ro\nm::Float : Elliptic Integral parameter, 4rho/sqrt(xi^2+(rho+1)^2)\nr_influence::Float : radial location of vortex ring, ro\ninfluence_length::Float : length of panel used in calculating self-induction\n\nReturns\n\nvz::Float : axially induced velocity of vortex ring\n\n\n\n\n\n","category":"function"},{"location":"DuctAPE/api/private_preprocess/#DuctAPE.vortex_ring_vz!","page":"Preprocess","title":"DuctAPE.vortex_ring_vz!","text":"vortex_ring_vz!(xi, rho, m, r_influence, influence_length, cache_vec)\n\nSame as vortexringvz, but uses the cache_vec to store intermediate calculations.\n\n\n\n\n\n","category":"function"},{"location":"DuctAPE/api/private_preprocess/#DuctAPE.smoke_ring_vz","page":"Preprocess","title":"DuctAPE.smoke_ring_vz","text":"smoke_ring_vz(r_influence, influence_length)\n\nEquivalent \"smoke\" ring self-induced velocity.\n\nArguments\n\nr_influence::Float : radial position of ring (i.e. the ring raidus)\ninfluence_length::Float : length of influencing panel\n\nReturs\n\nvz::Float : axially induced velocity of vortex ring\n\n\n\n\n\n","category":"function"},{"location":"DuctAPE/api/private_preprocess/#DuctAPE.vortex_ring_vr","page":"Preprocess","title":"DuctAPE.vortex_ring_vr","text":"vortex_ring_vr(xi, rho, m, r_influence)\n\nRadial velocity induced by axisymmetric vortex ring.\n\nReturns zero if vortex ring is on axis of rotation (zero radius), the point of influence is on the axis, or if self-inducing velocity.\n\nArguments\n\nxi::Float : normalized z-coordinate, (z-zo)/ro\nrho::Float : normalized r-coordinate, r/ro\nm::Float : Elliptic Integral parameter, 4rho/sqrt(xi^2+(rho+1)^2)\nr_influence::Float : radial location of vortex ring, ro\n\nReturns\n\nvr::Float : radially induced velocity of vortex ring\n\n\n\n\n\n","category":"function"},{"location":"DuctAPE/api/private_preprocess/#DuctAPE.vortex_ring_vr!","page":"Preprocess","title":"DuctAPE.vortex_ring_vr!","text":"vortex_ring_vr!(xi, rho, m, r_influence, cache_vec)\n\nSame as vortexringvr, but uses the cache_vec to store intermediate calculations.\n\n\n\n\n\n","category":"function"},{"location":"DuctAPE/api/private_preprocess/#DuctAPE.source_ring_vz","page":"Preprocess","title":"DuctAPE.source_ring_vz","text":"source_ring_vz(xi, rho, m, r_influence)\n\nAxial velocity induced by axisymmetric source ring.\n\nReturns zero if source ring is on axis of rotation (zero radius), the point of influence is on the axis, or if self-inducing velocity.\n\nArguments:\n\nxi::Float : normalized z-coordinate, (z-zo)/ro\nrho::Float : normalized r-coordinate, r/ro\nm::Float : Elliptic Integral parameter, 4rho/sqrt(xi^2+(rho+1)^2)\nr_influence::Float : radial location of vortex ring, ro\n\nReturns:\n\nvz::Float : axially induced velocity of source ring\n\n\n\n\n\n","category":"function"},{"location":"DuctAPE/api/private_preprocess/#DuctAPE.source_ring_vz!","page":"Preprocess","title":"DuctAPE.source_ring_vz!","text":"source_ring_vz!(xi, rho, m, r_influence, cache_vec)\n\nSame as sourceringvz, but uses cache_vec to store intermediate values.\n\n\n\n\n\n","category":"function"},{"location":"DuctAPE/api/private_preprocess/#DuctAPE.source_ring_vr","page":"Preprocess","title":"DuctAPE.source_ring_vr","text":"source_ring_vr(xi, rho, m, r_influence)\n\nRadial velocity induced by axisymmetric source ring.\n\nReturns zero if source ring is on axis of rotation (zero radius), the point of influence is on the axis, or if self-inducing velocity.\n\nArguments:\n\nxi::Float : normalized z-coordinate, (z-zo)/ro\nrho::Float : normalized r-coordinate, r/ro\nm::Float : Elliptic Integral parameter, 4rho/sqrt(xi^2+(rho+1)^2)\nr_influence::Float : radial location of vortex ring, ro\n\nReturns:\n\nvr::Float : radially induced velocity of source ring\n\n\n\n\n\n","category":"function"},{"location":"DuctAPE/api/private_preprocess/#DuctAPE.source_ring_vr!","page":"Preprocess","title":"DuctAPE.source_ring_vr!","text":"source_ring_vr!(xi, rho, m, r_influence, cache_vec)\n\nSame as sourceringvr, but uses cache_vec to store intermediate values.\n\n\n\n\n\n","category":"function"},{"location":"DuctAPE/api/private_preprocess/#Unit-Induced-Velocity-Matrices","page":"Preprocess","title":"Unit Induced Velocity Matrices","text":"","category":"section"},{"location":"DuctAPE/api/private_preprocess/","page":"Preprocess","title":"Preprocess","text":"DuctAPE.induced_velocities_from_vortex_panels_on_points\nDuctAPE.induced_velocities_from_vortex_panels_on_points!\nDuctAPE.induced_velocities_from_source_panels_on_points\nDuctAPE.induced_velocities_from_source_panels_on_points!\nDuctAPE.induced_velocities_from_trailing_edge_gap_panel!","category":"page"},{"location":"DuctAPE/api/private_preprocess/#DuctAPE.induced_velocities_from_vortex_panels_on_points","page":"Preprocess","title":"DuctAPE.induced_velocities_from_vortex_panels_on_points","text":"induced_velocities_from_vortex_panels_on_points(\n controlpoints,\n nodes,\n nodemap,\n influence_lengths,\n integration_options;\n integration_caches=nothing,\n)\n\nCalculate axial and radial components of induced velocity for a set of control points due to a set of axisymmetric vortex panels (bands).\n\nUsed for getting the unit induced velocities due to the body panels on the rotor/wake as well as the unit induced velocity due to the wake on the body/rotor.\n\nArguments\n\ncontrolpoints::Matrix{Float} [z r] coordinates of points being influenced\nnodes::Matrix{Float} : [z r] coordinates of vortex rings\nnodemap::Matrix{Int} : mapping from panel index to associated node indices\ninfluence_lengths::Vector{Float} : lengths over which vortex ring influence is applied on the surface.\nintegration_options::IntegrationOptions : integration options\n\nKeyword Arguments\n\nintegration_caches::NamedTuple=nothing : cache used in in-place quadrature functions.\n\nReturns\n\nVEL::Array{Float} : N-controlpoint x N-node x [vz, vr] array of induced velocity components\n\n\n\n\n\n","category":"function"},{"location":"DuctAPE/api/private_preprocess/#DuctAPE.induced_velocities_from_vortex_panels_on_points!","page":"Preprocess","title":"DuctAPE.induced_velocities_from_vortex_panels_on_points!","text":"induced_velocities_from_vortex_panels_on_points!(\n VEL,\n controlpoint,\n node,\n nodemap,\n influence_length,\n integration_options;\n integration_caches=nothing,\n)\n\nIn-place version of induced_velocities_from_vortex_panels_on_points.\n\n\n\n\n\n","category":"function"},{"location":"DuctAPE/api/private_preprocess/#DuctAPE.induced_velocities_from_source_panels_on_points","page":"Preprocess","title":"DuctAPE.induced_velocities_from_source_panels_on_points","text":"induced_velocities_from_source_panels_on_points(\n controlpoints,\n nodes,\n nodemap,\n influence_lengths,\n integration_options;\n integration_caches=nothing,\n)\n\nCalculate axial and radial components of induced velocity for a set of control points due to a set of axisymmetric source panels (bands)\n\nUsed for getting the unit induced velocities due to the body panels on the rotor/wake as well as the unit induced velocity due to the wake on the body/rotor.\n\nArguments\n\ncontrolpoints::Matrix{Float} [z r] coordinates of points being influenced\nnodes::Matrix{Float} : [z r] coordinates of vortex rings\nnodemap::Matrix{Int} : mapping from panel index to associated node indices\ninfluence_lengths::Vector{Float} : lengths over which vortex ring influence is applied on the surface.\nintegration_options::IntegrationOptions : integration options\n\nReturns:\n\nVEL::Array{Float} : N-controlpoint x N-node x [vz, vr] array of induced velocity components\n\n\n\n\n\n","category":"function"},{"location":"DuctAPE/api/private_preprocess/#DuctAPE.induced_velocities_from_source_panels_on_points!","page":"Preprocess","title":"DuctAPE.induced_velocities_from_source_panels_on_points!","text":"induced_velocities_from_source_panels_on_points!(\n VEL,\n controlpoint,\n node,\n nodemap,\n influence_length,\n integration_options;\n integration_caches=nothing,\n)\n\nIn-place version of induced_velocities_from_source_panels_on_points.\n\n\n\n\n\n","category":"function"},{"location":"DuctAPE/api/private_preprocess/#DuctAPE.induced_velocities_from_trailing_edge_gap_panel!","page":"Preprocess","title":"DuctAPE.induced_velocities_from_trailing_edge_gap_panel!","text":"induced_velocities_from_trailing_edge_gap_panel!(\n VEL,\n controlpoint,\n tenode,\n teinfluence_length,\n tendotn,\n tencrossn,\n teadjnodeidxs,\n integration_options;\n wake=false,\n integration_caches=nothing,\n)\n\nCalculate axial and radial components of induced velocity for a set of control points due to any trailing edge gap panels.\n\nUsed for getting the unit induced velocities due to the body body trailing edge gap panels on the body/rotor/wake.\n\nNote, this function is also used to calculate the influence of the wake ends rather than modeling a semi-infinite fortex sheet.\n\nArguments\n\nVEL::Array{Float} : N-controlpoint x N-node x [vz, vr] array of induced velocity components (modified in place)\ncontrolpoints::Matrix{Float} [z r] coordinates of points being influenced\nnodes::Matrix{Float} : [z r] coordinates of vortex rings\nnodemap::Matrix{Int} : mapping from panel index to associated node indices\ninfluence_lengths::Vector{Float} : lengths over which vortex ring influence is applied on the surface.\nstrengths::Matrix{Float} : vortex constant circulation values\nintegration_options::IntegrationOptions : integration options\n\nKeyword Arguments\n\nwake::Bool=false : flag to indicate if this is being used for a wake sheet.\nintegration_caches::NamedTuple=nothing : cache used in in-place quadrature functions.\n\n\n\n\n\n","category":"function"},{"location":"DuctAPE/api/private_preprocess/#Panel-Method-Velocity-Functions","page":"Preprocess","title":"Panel Method Velocity Functions","text":"","category":"section"},{"location":"DuctAPE/api/private_preprocess/","page":"Preprocess","title":"Preprocess","text":"DuctAPE.vortex_aic_boundary_on_boundary\nDuctAPE.vortex_aic_boundary_on_boundary!\nDuctAPE.vortex_aic_boundary_on_field\nDuctAPE.vortex_aic_boundary_on_field!\nDuctAPE.add_kutta!\nDuctAPE.add_te_gap_aic!\nDuctAPE.source_aic\nDuctAPE.source_aic!\nDuctAPE.freestream_influence_vector\nDuctAPE.freestream_influence_vector!\nDuctAPE.assemble_lhs_matrix\nDuctAPE.assemble_lhs_matrix!\nDuctAPE.factorize_LHS\nDuctAPE.factorize_LHS!\nDuctAPE.assemble_rhs_matrix\nDuctAPE.assemble_rhs_matrix!\nDuctAPE.calculate_normal_velocity\nDuctAPE.calculate_normal_velocity!","category":"page"},{"location":"DuctAPE/api/private_preprocess/#DuctAPE.vortex_aic_boundary_on_boundary","page":"Preprocess","title":"DuctAPE.vortex_aic_boundary_on_boundary","text":"vortex_aic_boundary_on_boundary(\n controlpoint, normal, node, nodemap, influence_length, integration_options\n)\n\nCalculate panel method influence coefficients (V dot nhat) for a set of control points (on panels) due to a set of axisymmetric vortex rings (also on body surface)\n\nCan be used for constructing the LHS influence Matrix for the panel method system.\n\nArguments\n\ncontrolpoint::Matrix{Float} [z r] coordinates of points being influenced\nnormal::Matrix{Float} : unit normal vectors of the panels on which the control points are situated.\nnode::Matrix{Float} : [z r] coordinates of panel nodes (edges)\nnodemap::Matrix{Int} : [1 2] node indices for each panel\ninfluence_length::Vector{Float} : lengths of influencing panels\nintegration_options::IntegrationOptions : integration options\n\nReturns\n\nAICn::Matrix{Float} : N controlpoint x N+1 node array of V dot nhat values\n\n\n\n\n\n","category":"function"},{"location":"DuctAPE/api/private_preprocess/#DuctAPE.vortex_aic_boundary_on_boundary!","page":"Preprocess","title":"DuctAPE.vortex_aic_boundary_on_boundary!","text":"vortex_aic_boundary_on_boundary!(\n AICn,\n controlpoint,\n normal,\n node,\n nodemap,\n influence_length,\n integration_options;\n integration_caches=nothing,\n)\n\nIn-place verion of vortex_aic_boundary_on_boundary.\n\nintegration_caches is a named tuple containing caching for intermediate calculation values.\n\n\n\n\n\n","category":"function"},{"location":"DuctAPE/api/private_preprocess/#DuctAPE.vortex_aic_boundary_on_field","page":"Preprocess","title":"DuctAPE.vortex_aic_boundary_on_field","text":"vortex_aic_boundary_on_field(\n controlpoint,\n normal,\n node,\n nodemap,\n influence_length,\n integration_options;\n integration_caches=nothing,\n)\n\nCalculate panel method influence coefficients (V dot nhat) for a set of control points (NOT on panels) due to a set of axisymmetric vortex rings (on body surface)\n\nUsed for constructing portions of the panel method LHS matrix related to the pseudo control points in the bodies.\n\nArguments:\n\ncontrolpoint::Matrix{Float} [z r] coordinates of points being influenced\nnormal::Matrix{Float} : unit normal vectors of the panels on which the control points are situated.\nnode::Matrix{Float} : [z r] coordinates of panel nodes (edges)\nnodemap::Matrix{Int} : [1 2] node indices for each panel\ninfluence_length::Vector{Float} : lengths of influencing panels\nintegration_options::IntegrationOptions : integration options\n\nKeyword Arguments\n\nintegration_caches::NamedTuple=nothing : caches for intermediate values in integration.\n\nReturns:\n\nAICn::Matrix{Float} : N controlpoint x N+1 node array of V dot nhat values\n\n\n\n\n\n","category":"function"},{"location":"DuctAPE/api/private_preprocess/#DuctAPE.vortex_aic_boundary_on_field!","page":"Preprocess","title":"DuctAPE.vortex_aic_boundary_on_field!","text":"vortex_aic_boundary_on_field!(\n AICn,\n controlpoint,\n normal,\n node,\n nodemap,\n influence_length,\n integration_options;\n integration_caches=nothing,\n)\n\nIn-place version of vortex_aic_boundary_on_field.\n\n\n\n\n\n","category":"function"},{"location":"DuctAPE/api/private_preprocess/#DuctAPE.add_kutta!","page":"Preprocess","title":"DuctAPE.add_kutta!","text":"add_kutta!(LHS, AICn, kids)\n\nAdd Kutta condition (γ1 + γN = 0) to LHS matrix.\n\nLHS::Matrix{Float} : a pre-allocated (zeros) full size left-hand side matrix\nAICn::Matrix{Float} : influence coefficients for panels/nodes\nkids::Vector{Int} : [1 2] indices of where to put 1's for kutta condition\n\n\n\n\n\n","category":"function"},{"location":"DuctAPE/api/private_preprocess/#DuctAPE.add_te_gap_aic!","page":"Preprocess","title":"DuctAPE.add_te_gap_aic!","text":"add_te_gap_aic!(\n AICn,\n controlpoint,\n normal,\n tenode,\n teinfluence_length,\n tendotn,\n tencrossn,\n teadjnodeidxs,\n integration_options;\n wake=false,\n integration_caches=nothing,\n)\n\nAdd trailing edge gap aerodynmic influence coefficient contributions to the AIC matrix.\n\nArguments\n\nAICn::Matrix{Float} : N controlpoint x N+1 node array of V dot nhat values\ncontrolpoint::Matrix{Float} [z r] coordinates of points being influenced\nnormal::Matrix{Float} : unit normal vectors of the panels on which the control points are situated.\ntenode::Matrix{Float} : [z r] coordinates of trailing edge panel nodes (edges)\nteinfluence_length::Vector{Float} : lengths of influencing trailing edge panels\ntendotn::Matrix{Float} : nhat of trailing edge panel dotted with nhat of adjacent panels\ntencrossn::Matrix{Float} : nhat of trailing edge panel crossed with nhat of adjacent panels\nteadjnodeidxs::Matrix{Float} : indices of nodes adjacent to trailing edge panel\nintegration_options::IntegrationOptions : integration options\n\nKeyword Arguments\n\nwake::Bool=false : flag as to whether this function is being applied to a wake sheet.\nintegration_caches::NamedTuple=nothing : caches for intermediate values in integration.\n\n\n\n\n\n","category":"function"},{"location":"DuctAPE/api/private_preprocess/#DuctAPE.source_aic","page":"Preprocess","title":"DuctAPE.source_aic","text":"source_aic(\n controlpoint,\n normal,\n node,\n nodemap,\n influence_length,\n integration_options;\n integration_caches=nothing,\n)\n\nCalculate panel method influence coefficients (V dot nhat) for a set of control points (on panels) due to a set of axisymmetric source rings not on body surface.\n\nCan be used for constructing the RHS boundary conditions due to rotor source panels.\n\nArguments\n\ncontrolpoint::Matrix{Float} [z r] coordinates of points being influenced\nnormal::Matrix{Float} : unit normal vectors of the panels on which the control points are situated.\nnode::Matrix{Float} : [z r] coordinates of panel nodes (edges)\nnodemap::Matrix{Int} : [1 2] node indices for each panel\ninfluence_length::Vector{Float} : lengths of influencing panels\nintegration_options::IntegrationOptions : integration options\n\nKeyword Arguments\n\nintegration_caches::NamedTuple=nothing : caches for intermediate values in integration.\n\nReturns\n\nAICn::Matrix{Float} : N controlpoint x N+1 node array of V dot nhat values\n\n\n\n\n\n","category":"function"},{"location":"DuctAPE/api/private_preprocess/#DuctAPE.source_aic!","page":"Preprocess","title":"DuctAPE.source_aic!","text":"source_aic!(\n AICn,\n controlpoint,\n normal,\n node,\n nodemap,\n influence_length,\n integration_options;\n integration_caches=nothing,\n)\n\nIn-place version of source_aic.\n\n\n\n\n\n","category":"function"},{"location":"DuctAPE/api/private_preprocess/#DuctAPE.freestream_influence_vector","page":"Preprocess","title":"DuctAPE.freestream_influence_vector","text":"freestream_influence_vector(normals, Vinfmat)\n\nCalculate RHS contributions due to freestream.\n\nNote that the freestream is assumed to have zero radial component in the underlying theory, but here we allow an arbitrary 2D vector for velocity for taking the dot product easier.\n\nArguments\n\nnormals::Matrix{Float} : unit normal vectors of the panels on which the control points are situated.\nVinfmat::Matrix{Float} : [z r] components of freestream velocity (r's should be zero)\n\nReturns\n\nRHS::Vector{Float} : vector of normal components of freestream velocity on input panels\n\n\n\n\n\n","category":"function"},{"location":"DuctAPE/api/private_preprocess/#DuctAPE.freestream_influence_vector!","page":"Preprocess","title":"DuctAPE.freestream_influence_vector!","text":"freestream_influence_vector!(RHS, normals, Vinfmat)\n\nIn-place version of freestream_influence_vector.\n\n\n\n\n\n","category":"function"},{"location":"DuctAPE/api/private_preprocess/#DuctAPE.assemble_lhs_matrix","page":"Preprocess","title":"DuctAPE.assemble_lhs_matrix","text":"assemble_lhs_matrix(\n AICn, AICpcp, npanel, nnode, totpanel, totnode, prescribednodeidxs; dummyval=1.0\n)\n\nAssemble the LHS matrix of the panel method.\n\nArguments\n\nAICn::Matrix{Float} : N controlpoint x N+1 node array of V dot nhat values\nAICpcp::Matrix{Float} : Nbodies controlpoint x N+1 node array of V dot nhat values (influence on psuedo control points)\nnpanel::Vector{Int} : number of panels comprising each body\nnnode::Vector{Int} : number of nodes comprising each body\ntotpanel::Int : total number of panels\ntotnode::Int : total number of nodes\nprescribednodeidxs::Vector{Int} : indices of nodes with prescribed strengths (those on the axis of rotation).\n\nKeyword Arguments\n\ndummyval::Float=1.0 : value for dummy input for prescribed and internal control points in the system. Do not change except for debugging purposes.\n\nReturns\n\nLHS::Matrix{Float} : The full LHS matrix for the panel method.\n\n\n\n\n\n","category":"function"},{"location":"DuctAPE/api/private_preprocess/#DuctAPE.assemble_lhs_matrix!","page":"Preprocess","title":"DuctAPE.assemble_lhs_matrix!","text":"assemble_lhs_matrix!(\n LHS, AICn, AICpcp, npanel, nnode, totpanel, totnode, prescribednodeidxs; dummyval=1.0\n)\n\nIn-place version of assemble_lhs_matrix.\n\n\n\n\n\n","category":"function"},{"location":"DuctAPE/api/private_preprocess/#DuctAPE.factorize_LHS","page":"Preprocess","title":"DuctAPE.factorize_LHS","text":"factorize_LHS(A::AbstractMatrix)\n\nReturns the LU decomposition of A.\n\n\n\n\n\n","category":"function"},{"location":"DuctAPE/api/private_preprocess/#DuctAPE.factorize_LHS!","page":"Preprocess","title":"DuctAPE.factorize_LHS!","text":"factorize_LHS!(Apivot::AbstractMatrix, A::AbstractMatrix)\n\nReturns the LU decomposition of A using Apivot as storage memory to pivot leaving A unchanged.\n\n\n\n\n\n","category":"function"},{"location":"DuctAPE/api/private_preprocess/#DuctAPE.assemble_rhs_matrix","page":"Preprocess","title":"DuctAPE.assemble_rhs_matrix","text":"assemble_rhs_matrix(\n vdnb, vdnpcp, npanel, nnode, totpanel, totnode, prescribednodeidxs\n)\n\nArguments\n\nvdnb::Vector{Float} : V dot nhat for body panels\nvdnpcp::Vector{Float} : V dot nhat for pseudo control points\nnpanel::Vector{Int} : number of panels comprising each body\nnnode::Vector{Int} : number of nodes comprising each body\ntotpanel::Int : total number of body panels\ntotnode::Int : total number of body nodes\nprescribednodeidxs::Vector{Int} : indices of nodes with prescribed strengths (those on the axis of rotation)\n\nReturns\n\nRHS::Vector{Float} : the RHS vector of the panel method.\n\n\n\n\n\n","category":"function"},{"location":"DuctAPE/api/private_preprocess/#DuctAPE.assemble_rhs_matrix!","page":"Preprocess","title":"DuctAPE.assemble_rhs_matrix!","text":"assemble_rhs_matrix!(\n RHS, vdnb, vdnpcp, npanel, nnode, totpanel, totnode, prescribednodeidxs\n)\n\nIn-place version of assemble_rhs_matrix.\n\n\n\n\n\n","category":"function"},{"location":"DuctAPE/api/private_preprocess/#DuctAPE.calculate_normal_velocity","page":"Preprocess","title":"DuctAPE.calculate_normal_velocity","text":"calculate_normal_velocity(velocity_vector, normal)\n\nCalculate normal velocity_vector (V dot nhat).\n\nArguments\n\nvelocity_vector::Matrix{Float} : velocity vector [z r] on each panel\nnormal::Matrix{Float} : the panel unit normals\n\nReturns\n\nAIC::Matrix{Float} : V dot n on each panel\n\n\n\n\n\n","category":"function"},{"location":"DuctAPE/api/private_preprocess/#DuctAPE.calculate_normal_velocity!","page":"Preprocess","title":"DuctAPE.calculate_normal_velocity!","text":"calculate_normal_velocity!(AIC, velocity_vector, normal)\n\nIn-place version of calculate_normal_velocity.\n\n\n\n\n\n","category":"function"},{"location":"DuctAPE/api/private_preprocess/#Quadrature","page":"Preprocess","title":"Quadrature","text":"","category":"section"},{"location":"DuctAPE/api/private_preprocess/#Integrands","page":"Preprocess","title":"Integrands","text":"","category":"section"},{"location":"DuctAPE/api/private_preprocess/","page":"Preprocess","title":"Preprocess","text":"DuctAPE.nominal_vortex_induced_velocity_sample\nDuctAPE.nominal_vortex_induced_velocity_sample!\nDuctAPE.subtracted_singular_vortex_influence\nDuctAPE.subtracted_singular_vortex_influence!\nDuctAPE.analytically_integrated_vortex_influence\nDuctAPE.analytically_integrated_vortex_influence!\nDuctAPE.self_vortex_induced_velocity_sample\nDuctAPE.self_vortex_induced_velocity_sample!\nDuctAPE.nominal_source_induced_velocity_sample\nDuctAPE.nominal_source_induced_velocity_sample!\nDuctAPE.subtracted_singular_source_influence\nDuctAPE.subtracted_singular_source_influence!\nDuctAPE.analytically_integrated_source_influence\nDuctAPE.analytically_integrated_source_influence!\nDuctAPE.self_source_induced_velocity_sample\nDuctAPE.self_source_induced_velocity_sample!","category":"page"},{"location":"DuctAPE/api/private_preprocess/#DuctAPE.nominal_vortex_induced_velocity_sample","page":"Preprocess","title":"DuctAPE.nominal_vortex_induced_velocity_sample","text":"nominal_vortex_induced_velocity_sample(\n t, node1, node2, influence_length, controlpoint, cache_vec; nondimrange=(0.0, 1.0)\n)\n\nCalculate the velocity induced by a linear vortex panel on a point.\n\nArguments\n\nt::Float : sample point in range (0,1) selected by quadrature method.\nnode1::Vector{Float} : first panel node (edge) position.\nnode2::Vector{Float} : second panel node (edge) position.\ninfluence_length::Float : dimensional length of panel.\ncontrolpoint::Vector{Float} : controlpoint position\ncache_vec::Vector{Float} : cache for intermediate calculations\n\nKeyword Arguments\n\nnondimrange::Tuple=(0.0,1.0) : Non-dimensional range describing the panel length. Do not change excpet for debugging purposes. Note, can also be a vector.\n\nReturns\n\nV::Matrix{Float} : 2x2 matrix of axial and radial induced velocities from each of the nodes.\n\n\n\n\n\n","category":"function"},{"location":"DuctAPE/api/private_preprocess/#DuctAPE.nominal_vortex_induced_velocity_sample!","page":"Preprocess","title":"DuctAPE.nominal_vortex_induced_velocity_sample!","text":"nominal_vortex_induced_velocity_sample!(\n V, t, node1, node2, influence_length, controlpoint, cache_vec; nondimrange=(0.0, 1.0)\n)\n\nIn-place version of nominal_vortex_induced_velocity_sample.\n\n\n\n\n\n","category":"function"},{"location":"DuctAPE/api/private_preprocess/#DuctAPE.subtracted_singular_vortex_influence","page":"Preprocess","title":"DuctAPE.subtracted_singular_vortex_influence","text":"subtracted_singular_vortex_influence(node, controlpoint)\n\nCalculate the singular portions of the self-induced vortex panel influence to subtract off the integral in the separation of singularity method.\n\nArguments\n\nnode::Vector{Float} : node position\ncontrolpoint::Vector{Float} : controlpoint position\n\nReturns\n\naxial::Float : axial direction influence\nradial::Float : radial direction influence\n\n\n\n\n\n","category":"function"},{"location":"DuctAPE/api/private_preprocess/#DuctAPE.subtracted_singular_vortex_influence!","page":"Preprocess","title":"DuctAPE.subtracted_singular_vortex_influence!","text":"subtracted_singular_vortex_influence!(node, controlpoint, cache_vec)\n\nSomewhat in-place version of subtracted_singular_vortex_influence.\n\nArguments\n\nnode::Vector{Float} : node position\ncontrolpoint::Vector{Float} : controlpoint position\ncache_vec::Vector{Float} : used to store intermediate values.\n\nReturns\n\naxial::Float : axial direction influence\nradial::Float : radial direction influence\n\n\n\n\n\n","category":"function"},{"location":"DuctAPE/api/private_preprocess/#DuctAPE.analytically_integrated_vortex_influence","page":"Preprocess","title":"DuctAPE.analytically_integrated_vortex_influence","text":"analytically_integrated_vortex_influence(r, influence_length)\n\nAnalytical approximation of the singular portions of the self-induced vortex panel velocities to be added back in as part of the separation of singularity method.\n\nArguments\n\nr::Float : radial position of self-induced control point\ninfluence_length::Float : dimensional length of the panel\n\nReturns\n\nV::Vector{Float} : axial and radial induced velocities\n\n\n\n\n\n","category":"function"},{"location":"DuctAPE/api/private_preprocess/#DuctAPE.analytically_integrated_vortex_influence!","page":"Preprocess","title":"DuctAPE.analytically_integrated_vortex_influence!","text":"analytically_integrated_vortex_influence!(V, r, influence_length)\n\nIn-place version of analytically_integrated_vortex_influence.\n\n\n\n\n\n","category":"function"},{"location":"DuctAPE/api/private_preprocess/#DuctAPE.self_vortex_induced_velocity_sample","page":"Preprocess","title":"DuctAPE.self_vortex_induced_velocity_sample","text":"self_vortex_induced_velocity_sample(\n t, node1, node2, influence_length, controlpoint, cache_vec; nondimrange=(0.0, 1.0)\n)\n\nCalculate the velocity induced by a linear vortex panel on a point at the midpoint between the panel edges.\n\nArguments\n\nt::Float : sample point in range (0,1) selected by quadrature method.\nnode1::Vector{Float} : first panel node (edge) position.\nnode2::Vector{Float} : second panel node (edge) position.\ninfluence_length::Float : dimensional length of panel.\ncontrolpoint::Vector{Float} : controlpoint position\ncache_vec::Vector{Float} : cache for intermediate calculations\n\nKeyword Arguments\n\nnondimrange::Tuple=(0.0,1.0) : Non-dimensional range describing the panel length. Do not change excpet for debugging purposes. Note, can also be a vector.\n\nReturns\n\nV::Matrix{Float} : 2x2 matrix of axial and radial induced velocities from each of the nodes.\n\n\n\n\n\n","category":"function"},{"location":"DuctAPE/api/private_preprocess/#DuctAPE.self_vortex_induced_velocity_sample!","page":"Preprocess","title":"DuctAPE.self_vortex_induced_velocity_sample!","text":"self_vortex_induced_velocity_sample!(\n V, t, node1, node2, influence_length, controlpoint, cache_vec; nondimrange=(0.0, 1.0)\n)\n\nIn-place version of self_vortex_induced_velocity_sample.\n\n\n\n\n\n","category":"function"},{"location":"DuctAPE/api/private_preprocess/#DuctAPE.nominal_source_induced_velocity_sample","page":"Preprocess","title":"DuctAPE.nominal_source_induced_velocity_sample","text":"nominal_source_induced_velocity_sample(\n t, node1, node2, influence_length, controlpoint, cache_vec; nondimrange=(0.0, 1.0)\n)\n\nCalculate the velocity induced by a source panel on a point.\n\nArguments\n\nt::Float : sample point in range (0,1) selected by quadrature method.\nnode1::Vector{Float} : first panel node (edge) position.\nnode2::Vector{Float} : second panel node (edge) position.\ninfluence_length::Float : dimensional length of panel.\ncontrolpoint::Vector{Float} : controlpoint position\ncache_vec::Vector{Float} : cache for intermediate calculations\n\nKeyword Arguments\n\nnondimrange::Tuple=(0.0,1.0) : Non-dimensional range describing the panel length. Do not change excpet for debugging purposes. Note, can also be a vector.\n\nReturns\n\nV::Matrix{Float} : 2x2 matrix of axial and radial induced velocities from each of the nodes.\n\n\n\n\n\n","category":"function"},{"location":"DuctAPE/api/private_preprocess/#DuctAPE.nominal_source_induced_velocity_sample!","page":"Preprocess","title":"DuctAPE.nominal_source_induced_velocity_sample!","text":"nominal_source_induced_velocity_sample!(\n V, t, node1, node2, influence_length, controlpoint, cache_vec; nondimrange=(0.0,1.0)\n)\n\nIn-place version of nominal_source_induced_velocity_sample.\n\n\n\n\n\n","category":"function"},{"location":"DuctAPE/api/private_preprocess/#DuctAPE.subtracted_singular_source_influence","page":"Preprocess","title":"DuctAPE.subtracted_singular_source_influence","text":"subtracted_singular_source_influence(node, controlpoint)\n\nCalculate the singular portions of the self-induced source panel influence to subtract off the integral in the separation of singularity method.\n\nArguments\n\nnode::Vector{Float} : node position\ncontrolpoint::Vector{Float} : controlpoint position\n\nReturns\n\naxial::Float : axial direction influence\nradial::Float : radial direction influence\n\n\n\n\n\n","category":"function"},{"location":"DuctAPE/api/private_preprocess/#DuctAPE.subtracted_singular_source_influence!","page":"Preprocess","title":"DuctAPE.subtracted_singular_source_influence!","text":"subtracted_singular_source_influence!(node, controlpoint, cache_vec)\n\nIn-place version of subtracted_singular_source_influence.\n\n\n\n\n\n","category":"function"},{"location":"DuctAPE/api/private_preprocess/#DuctAPE.analytically_integrated_source_influence","page":"Preprocess","title":"DuctAPE.analytically_integrated_source_influence","text":"analytically_integrated_source_influence(r, influence_length)\n\nIn-place version of analytically_integrated_source_influence.\n\n\n\n\n\n","category":"function"},{"location":"DuctAPE/api/private_preprocess/#DuctAPE.analytically_integrated_source_influence!","page":"Preprocess","title":"DuctAPE.analytically_integrated_source_influence!","text":"analytically_integrated_source_influence(r, influence_length)\n\nAnalytical approximation of the singular portions of the self-induced source panel velocities to be added back in as part of the separation of singularity method.\n\nArguments\n\nr::Float : radial position of self-induced control point\ninfluence_length::Float : dimensional length of the panel\n\nReturns\n\nV::Vector{Float} : axial and radial induced velocities\n\n\n\n\n\n","category":"function"},{"location":"DuctAPE/api/private_preprocess/#DuctAPE.self_source_induced_velocity_sample","page":"Preprocess","title":"DuctAPE.self_source_induced_velocity_sample","text":"self_source_induced_velocity_sample(\n t, node1, node2, influence_length, controlpoint, cache_vec; nondimrange=(0.0, 1.0)\n)\n\nCalculate the velocity induced by a linear source panel on a point at the midpoint between the panel edges.\n\nArguments\n\nt::Float : sample point in range (0,1) selected by quadrature method.\nnode1::Vector{Float} : first panel node (edge) position.\nnode2::Vector{Float} : second panel node (edge) position.\ninfluence_length::Float : dimensional length of panel.\ncontrolpoint::Vector{Float} : controlpoint position\ncache_vec::Vector{Float} : cache for intermediate calculations\n\nKeyword Arguments\n\nnondimrange::Tuple=(0.0,1.0) : Non-dimensional range describing the panel length. Do not change excpet for debugging purposes. Note, can also be a vector.\n\nReturns\n\nV::Matrix{Float} : 2x2 matrix of axial and radial induced velocities from each of the nodes.\n\n\n\n\n\n","category":"function"},{"location":"DuctAPE/api/private_preprocess/#DuctAPE.self_source_induced_velocity_sample!","page":"Preprocess","title":"DuctAPE.self_source_induced_velocity_sample!","text":"self_source_induced_velocity_sample!(\n V, t, node1, node2, influence_length, controlpoint, cache_vec; nondimrange=(0.0, 1.0)\n)\n\nIn-place version of self_source_induced_velocity_sample.\n\n\n\n\n\n","category":"function"},{"location":"DuctAPE/api/private_preprocess/#Integrals","page":"Preprocess","title":"Integrals","text":"","category":"section"},{"location":"DuctAPE/api/private_preprocess/","page":"Preprocess","title":"Preprocess","text":"DuctAPE.nominal_vortex_panel_integration\nDuctAPE.nominal_vortex_panel_integration!\nDuctAPE.self_vortex_panel_integration\nDuctAPE.self_vortex_panel_integration!\nDuctAPE.nominal_source_panel_integration\nDuctAPE.nominal_source_panel_integration!\nDuctAPE.self_source_panel_integration\nDuctAPE.self_source_panel_integration!\nDuctAPE.extrapolate!","category":"page"},{"location":"DuctAPE/api/private_preprocess/#DuctAPE.nominal_vortex_panel_integration","page":"Preprocess","title":"DuctAPE.nominal_vortex_panel_integration","text":"nominal_vortex_panel_integration(\n integration_options,\n node1,\n node2,\n influence_length,\n controlpoint,\n containers;\n debug=false,\n)\n\nIntegration of vortex panel induced velocity on a point far away.\n\nArguments\n\nintegration_options::IntegrationMethod : options for itegration methods\nnode1::Vector{Float} : first panel node (edge) position.\nnode2::Vector{Float} : second panel node (edge) position.\ninfluence_length::Float : dimensional length of panel.\ncontrolpoint::Vector{Float} : controlpoint position\ncontainers::NamedTuple : cache for intermediate calculations\n\nKeyword Arguments\n\ndebug::Bool=false : if true, some methods will return the estimation error.\n\nReturns\n\nV::Matrix{Float} : velocity components due to the jth and j+1th nodes in the format: [vz_j vr_j; vz_{j+1} vr_{j+1}]\n\n\n\n\n\n","category":"function"},{"location":"DuctAPE/api/private_preprocess/#DuctAPE.nominal_vortex_panel_integration!","page":"Preprocess","title":"DuctAPE.nominal_vortex_panel_integration!","text":"nominal_vortex_panel_integration!(\n integration_options,\n V,\n node1,\n node2,\n influence_length,\n controlpoint,\n containers;\n debug=false,\n)\n\nIn-place version of nominal_vortex_panel_integration.\n\n\n\n\n\n","category":"function"},{"location":"DuctAPE/api/private_preprocess/#DuctAPE.self_vortex_panel_integration","page":"Preprocess","title":"DuctAPE.self_vortex_panel_integration","text":"self_vortex_panel_integration(\n integration_options,\n node1,\n node2,\n influence_length,\n controlpoint,\n containers;\n debug=false,\n)\n\nIntegration of linear vortex panel self-induced velocity.\n\nArguments\n\nintegration_options::IntegrationMethod : options for itegration methods\nnode1::Vector{Float} : first panel node (edge) position.\nnode2::Vector{Float} : second panel node (edge) position.\ninfluence_length::Float : dimensional length of panel.\ncontrolpoint::Vector{Float} : controlpoint position\ncontainers::NamedTuple : cache for intermediate calculations\n\nKeyword Arguments\n\ndebug::Bool=false : if true, some methods will return the estimation error.\n\nReturns\n\nV::Matrix{Float} : velocity components due to the jth and j+1th nodes in the format: [vz_j vr_j; vz_{j+1} vr_{j+1}]\n\n\n\n\n\n","category":"function"},{"location":"DuctAPE/api/private_preprocess/#DuctAPE.self_vortex_panel_integration!","page":"Preprocess","title":"DuctAPE.self_vortex_panel_integration!","text":"self_vortex_panel_integration!(\n integration_options,\n V,\n node1,\n node2,\n influence_length,\n controlpoint,\n containers;\n debug=false,\n)\n\nIn-place version of self_vortex_panel_integration.\n\n\n\n\n\n","category":"function"},{"location":"DuctAPE/api/private_preprocess/#DuctAPE.nominal_source_panel_integration","page":"Preprocess","title":"DuctAPE.nominal_source_panel_integration","text":"nominal_source_panel_integration(\n integration_options,\n node1,\n node2,\n influence_length,\n controlpoint,\n containers;\n debug=false,\n)\n\nIntegration of source panel induced velocity on a point far away.\n\nArguments\n\nintegration_options::IntegrationMethod : options for itegration methods\nnode1::Vector{Float} : first panel node (edge) position.\nnode2::Vector{Float} : second panel node (edge) position.\ninfluence_length::Float : dimensional length of panel.\ncontrolpoint::Vector{Float} : controlpoint position\ncontainers::NamedTuple : cache for intermediate calculations\n\nKeyword Arguments\n\ndebug::Bool=false : if true, some methods will return the estimation error.\n\nReturns\n\nV::Matrix{Float} : velocity components due to the jth and j+1th nodes in the format: [vz_j vr_j; vz_{j+1} vr_{j+1}]\n\n\n\n\n\n","category":"function"},{"location":"DuctAPE/api/private_preprocess/#DuctAPE.nominal_source_panel_integration!","page":"Preprocess","title":"DuctAPE.nominal_source_panel_integration!","text":"nominal_source_panel_integration!(\n integration_options,\n V,\n node1,\n node2,\n influence_length,\n controlpoint,\n containers;\n debug=false,\n)\n\nIn-place version of nominal_source_panel_integration.\n\n\n\n\n\n","category":"function"},{"location":"DuctAPE/api/private_preprocess/#DuctAPE.self_source_panel_integration","page":"Preprocess","title":"DuctAPE.self_source_panel_integration","text":"self_source_panel_integration(\n integration_options,\n node1,\n node2,\n influence_length,\n controlpoint,\n containers;\n debug=false,\n)\n\nIntegration of linear source panel self-induced velocity.\n\nArguments\n\nintegration_options::IntegrationMethod : options for itegration methods\nnode1::Vector{Float} : first panel node (edge) position.\nnode2::Vector{Float} : second panel node (edge) position.\ninfluence_length::Float : dimensional length of panel.\ncontrolpoint::Vector{Float} : controlpoint position\ncontainers::NamedTuple : cache for intermediate calculations\n\nKeyword Arguments\n\ndebug::Bool=false : if true, some methods will return the estimation error.\n\nReturns\n\nV::Matrix{Float} : velocity components due to the jth and j+1th nodes in the format: [vz_j vr_j; vz_{j+1} vr_{j+1}]\n\n\n\n\n\n","category":"function"},{"location":"DuctAPE/api/private_preprocess/#DuctAPE.self_source_panel_integration!","page":"Preprocess","title":"DuctAPE.self_source_panel_integration!","text":"self_source_panel_integration!(\n integration_options,\n V,\n node1,\n node2,\n influence_length,\n controlpoint,\n containers;\n debug=false,\n)\n\nIn-place version of self_source_panel_integration.\n\n\n\n\n\n","category":"function"},{"location":"DuctAPE/api/private_preprocess/#DuctAPE.extrapolate!","page":"Preprocess","title":"DuctAPE.extrapolate!","text":"extrapolate!(V, err, fh; power=2, atol=1e-6)\n\nPerforms Richardson extrapolation on an array fh for use in Romberg integration.\n\nArguments\n\nV::Matrix{Float} : velocity components due to the jth and j+1th nodes in the format: [vz_j vr_j; vz_{j+1} vr_{j+1}]\nerr::Vector{Float} : estimated errors in velocity approximation\nfh::Tuple : (f(h), h) tuples (in order of decreasing |h|)\n\n\n\n\n\n","category":"function"},{"location":"DuctAPE/api/private_preprocess/#State-Initialization","page":"Preprocess","title":"State Initialization","text":"","category":"section"},{"location":"DuctAPE/api/private_preprocess/","page":"Preprocess","title":"Preprocess","text":"DuctAPE.initialize_velocities\nDuctAPE.initialize_velocities!\nDuctAPE.initialize_strengths!","category":"page"},{"location":"DuctAPE/api/private_preprocess/#DuctAPE.initialize_velocities","page":"Preprocess","title":"DuctAPE.initialize_velocities","text":"initialize_velocities(\n solver_options::SolverOptionsType,\n operating_point,\n blade_elements,\n linsys,\n ivr,\n ivw,\n body_totnodes,\n wake_panel_sheet_be_map,\n)\n\nInitialize velocity state variables.\n\nArguments\n\nsolver_options::SolverOptionsType : solver options type for dispatch\noperating_point::OperatingPoint : an OperatingPoint object\nblade_elements::NamedTuple : A named tuple containing the blade element geometry and airfoil information.\nlinsys::NamedTuple : A named tuple containing the panel method linear system information.\nivr::NamedTuple : A named tuple containing the unit induced velocities on the rotors\nivw::NamedTuple : A named tuple containing the unit induced velocities on the wake\nbody_totnodes::Int : the total number of panel nodes comprising the duct and centerbody geometry\nwake_panel_sheet_be_map::Matrix{Int} : An index map from the wake panels to the nearest ahead rotor blade element along the wake sheets\n\nReturns\n\nvz_rotor::Vector{Float} : a vector of the velocity state variables associated with the rotor axially induced velocity\nvtheta_rotor::Vector{Float} : a vector of the velocity state variables associated with the rotor tangentially induced velocity\nCm_wake::Vector{Float} : a vector of the velocity state variables associated with the wake control point meridional velocity\n\n\n\n\n\n","category":"function"},{"location":"DuctAPE/api/private_preprocess/#DuctAPE.initialize_velocities!","page":"Preprocess","title":"DuctAPE.initialize_velocities!","text":"function initializevelocities!( solveroptions::SolverOptionsType, vzrotor, vthetarotor, Cmwake, operatingpoint, bladeelements, linsys, ivr, ivw, bodytotnodes, wakepanelsheetbemap, )\n\nIn-place version of initialize_velocities.\n\n\n\n\n\n","category":"function"},{"location":"DuctAPE/api/private_preprocess/#DuctAPE.initialize_strengths!","page":"Preprocess","title":"DuctAPE.initialize_strengths!","text":"initialize_strengths!(\n solver_options::SolverOptionsType,\n Gamr,\n sigr,\n gamw,\n operating_point,\n blade_elements,\n linsys,\n ivr,\n ivw,\n wakeK,\n body_totnodes,\n wake_nodemap,\n wake_endnodeidxs,\n wake_panel_sheet_be_map,\n wake_node_sheet_be_map,\n wake_node_ids_along_casing_wake_interface,\n wake_node_ids_along_centerbody_wake_interface,\n)\n\nInitialize strength state variables.\n\nArguments\n\nsolver_options::SolverOptionsType : solver options type for dispatch\nGamr::Vector{Float} : Rotor circulation state variables (modified in place)\nsigr::Vector{Float} : Rotor panel strength state variables (modified in place)\ngamw::Vector{Float} : Wake panel strength state variables (modified in place)\noperating_point::OperatingPoint : an OperatingPoint object\nblade_elements::NamedTuple : A named tuple containing the blade element geometry and airfoil information.\nlinsys::NamedTuple : A named tuple containing the panel method linear system information.\nivr::NamedTuple : A named tuple containing the unit induced velocities on the rotors\nivw::NamedTuple : A named tuple containing the unit induced velocities on the wake\nwakeK::Vector{Float} : geometric constants of wake nodes used in calculating wake strengths\nbody_totnodes::Int : the total number of panel nodes comprising the duct and centerbody geometry\nwake_nodemap::Matrix{Int} : an index map of wake panel to the associated node indices\nwake_endnodeidxs::Matrix{Int} : the node indices of the start and end of the wake sheets.\nwake_panel_sheet_be_map::Matrix{Int} : An index map from the wake panels to the nearest ahead rotor blade element along the wake sheets\nwake_node_sheet_be_map::Matrix{Int} : An index map from the wake nodes to the nearest ahead rotor blade element along the wake sheets\nwake_node_ids_along_casing_wake_interface::type : An index map indicating which wake nodes interface with the duct wall\nwake_node_ids_along_centerbody_wake_interface::type : An index map indicating which wake nodes interface with the centerbody wall\n\n\n\n\n\nfunction initialize_strengths!(\n solver_options::CSORSolverOptions,\n Gamr,\n sigr,\n gamw,\n solve_containers,\n operating_point,\n blade_elements,\n wakeK,\n wake_nodemap,\n wake_endnodeidxs,\n wake_panel_sheet_be_map,\n wake_node_sheet_be_map,\n wake_node_ids_along_casing_wake_interface,\n wake_node_ids_along_centerbody_wake_interface;\n niter=10,\n rlx=0.5,\n)\n\nRefactored from DFDC SUBROUTINE ROTINITBLD\n\nFrom the subroutine notes: Sets reasonable initial circulation using current rotor blade geometry (chord, beta). Initial circulations are set w/o induced effects An iteration is done using the self-induced velocity from momentum theory to converge an approximate induced axial velocity\n\nArguments\n\nsolver_options::SolverOptionsType : solver options type for dispatch\nGamr::Vector{Float} : Rotor circulation state variables (modified in place)\nsigr::Vector{Float} : Rotor panel strength state variables (modified in place)\ngamw::Vector{Float} : Wake panel strength state variables (modified in place)\noperating_point::OperatingPoint : an OperatingPoint object\nblade_elements::NamedTuple : A named tuple containing the blade element geometry and airfoil information.\nwakeK::Vector{Float} : geometric constants of wake nodes used in calculating wake strengths\nwake_nodemap::Matrix{Int} : an index map of wake panel to the associated node indices\nwake_endnodeidxs::Matrix{Int} : the node indices of the start and end of the wake sheets.\nwake_panel_sheet_be_map::Matrix{Int} : An index map from the wake panels to the nearest ahead rotor blade element along the wake sheets\nwake_node_sheet_be_map::Matrix{Int} : An index map from the wake nodes to the nearest ahead rotor blade element along the wake sheets\nwake_node_ids_along_casing_wake_interface::type : An index map indicating which wake nodes interface with the duct wall\nwake_node_ids_along_centerbody_wake_interface::type : An index map indicating which wake nodes interface with the centerbody wall\n\nKeyword Arguments\n\nrlx::Float=0.5 : factor for under-relaxation to reduce transients in CL\n\nReturns\n\n\n\n\n\n","category":"function"},{"location":"C4Blade/airfoil_types/CCBlade/#CCBlade-Airfoil-Types","page":"CCBlade Airfoil Types","title":"CCBlade Airfoil Types","text":"","category":"section"},{"location":"C4Blade/airfoil_types/CCBlade/","page":"CCBlade Airfoil Types","title":"CCBlade Airfoil Types","text":"DuctAPE includes all the airfoil types and methods available in CCBlade. We repeat them here for convenience, but refer the user to the CCBlade documentation for more context if advanced usage is desired.","category":"page"},{"location":"C4Blade/airfoil_types/CCBlade/","page":"CCBlade Airfoil Types","title":"CCBlade Airfoil Types","text":"Modules = [DuctAPE.C4Blade]\nPages = [\"C4Blade/airfoils.jl\"]","category":"page"},{"location":"C4Blade/airfoil_types/CCBlade/#DuctAPE.C4Blade.AlphaAF","page":"CCBlade Airfoil Types","title":"DuctAPE.C4Blade.AlphaAF","text":"AlphaAF(alpha, cl, cd, info, Re, Mach)\nAlphaAF(alpha, cl, cd, info, Re=0.0, Mach=0.0)\nAlphaAF(alpha, cl, cd, info=\"CCBlade generated airfoil\", Re=0.0, Mach=0.0)\nAlphaAF(filename::String; radians=true)\n\nAirfoil data that varies with angle of attack. Data is fit with an Akima spline.\n\nArguments:\n\nalpha::Vector{Float64}: angles of attack\ncl::Vector{Float64}: corresponding lift coefficients\ncd::Vector{Float64}: corresponding drag coefficients\ninfo::String: a description of this airfoil data (just informational)\nRe::Float64: Reynolds number data was taken at (just informational)\nMach::Float64: Mach number data was taken at (just informational)\n\nor\n\na file\n\nArguments:\n\nfilename::String: name/path of file to read in\nradians::Bool: true if angle of attack in file is given in radians\n\n\n\n\n\n","category":"type"},{"location":"C4Blade/airfoil_types/CCBlade/#DuctAPE.C4Blade.AlphaMachAF","page":"CCBlade Airfoil Types","title":"DuctAPE.C4Blade.AlphaMachAF","text":"AlphaMachAF(alpha, Mach, cl, cd, info, Re)\nAlphaMachAF(alpha, Mach, cl, cd, info)\nAlphaMachAF(alpha, Mach, cl, cd)\nAlphaMachAF(filenames::Vector{String}; radians=true)\n\nAirfoil data that varies with angle of attack and Mach number. Data is fit with a recursive Akima spline.\n\nArguments:\n\nalpha::Vector{Float64}: angles of attack\nMach::Vector{Float64}: Mach numbers\ncl::Matrix{Float64}: lift coefficients where cl[i, j] corresponds to alpha[i], Mach[j]\ncd::Matrix{Float64}: drag coefficients where cd[i, j] corresponds to alpha[i], Mach[j]\ninfo::String: a description of this airfoil data (just informational)\nRe::Float64: Reynolds number data was taken at (just informational)\n\nor\n\nfilenames with one file per Mach number.\n\nArguments:\n\nfilenames::Vector{String}: name/path of files to read in, each at a different Mach number in ascending order\nradians::Bool: true if angle of attack in file is given in radians\n\n\n\n\n\n","category":"type"},{"location":"C4Blade/airfoil_types/CCBlade/#DuctAPE.C4Blade.AlphaReAF","page":"CCBlade Airfoil Types","title":"DuctAPE.C4Blade.AlphaReAF","text":"AlphaReAF(alpha, Re, cl, cd, info, Mach)\nAlphaReAF(alpha, Re, cl, cd, info)\nAlphaReAF(alpha, Re, cl, cd)\nread_AlphaReAF(filenames::Vector{String}; radians=true)\n\nAirfoil data that varies with angle of attack and Reynolds number. Data is fit with a recursive Akima spline.\n\nArguments:\n\nalpha::Vector{Float64}: angles of attack\nRe::Vector{Float64}: Reynolds numbers\ncl::Matrix{Float64}: lift coefficients where cl[i, j] corresponds to alpha[i], Re[j]\ncd::Matrix{Float64}: drag coefficients where cd[i, j] corresponds to alpha[i], Re[j]\ninfo::String: a description of this airfoil data (just informational)\nMach::Float64: Mach number data was taken at (just informational)\n\nor\n\nfilenames with one file per Reynolds number.\n\nArguments:\n\nfilenames::Vector{String}: name/path of files to read in, each at a different Reynolds number in ascending order\nradians::Bool: true if angle of attack in file is given in radians\n\n\n\n\n\n","category":"type"},{"location":"C4Blade/airfoil_types/CCBlade/#DuctAPE.C4Blade.AlphaReMachAF","page":"CCBlade Airfoil Types","title":"DuctAPE.C4Blade.AlphaReMachAF","text":"AlphaReMachAF(alpha, Re, Mach, cl, cd, info)\nAlphaReMachAF(alpha, Re, Mach, cl, cd)\nAlphaReMachAF(filenames::Matrix{String}; radians=true)\n\nAirfoil data that varies with angle of attack, Reynolds number, and Mach number. Data is fit with a recursive Akima spline.\n\nArguments:\n\nalpha::Vector{Float64}: angles of attack\nRe::Vector{Float64}: Reynolds numbers\nMach::Vector{Float64}: Mach numbers\ncl::Array{Float64}: lift coefficients where cl[i, j, k] corresponds to alpha[i], Re[j], Mach[k]\ncd::Array{Float64}: drag coefficients where cd[i, j, k] corresponds to alpha[i], Re[j], Mach[k]\ninfo::String: a description of this airfoil data (just informational)\n\nor files with one per Re/Mach combination\n\nArguments:\n\nfilenames::Matrix{String}: name/path of files to read in. filenames[i, j] corresponds to Re[i] Mach[j] with Reynolds number and Mach number in ascending order.\nradians::Bool: true if angle of attack in file is given in radians\n\n\n\n\n\n","category":"type"},{"location":"C4Blade/airfoil_types/CCBlade/#DuctAPE.C4Blade.DuSeligEggers","page":"CCBlade Airfoil Types","title":"DuctAPE.C4Blade.DuSeligEggers","text":"DuSeligEggers(a, b, d, m, alpha0)\nDuSeligEggers(a=1.0, b=1.0, d=1.0, m=2*pi, alpha0=0.0) # uses defaults\n\nDuSelig correction for lift an Eggers correction for drag.\n\nArguments:\n\na, b, d::Float64: parameters in Du-Selig paper. Normally just 1.0 for each.\nm::Float64: lift curve slope. Defaults to 2 pi for zero argument version.\nalpha0::Float64: zero-lift angle of attack. Defaults to 0 for zero argument version.\n\n\n\n\n\n","category":"type"},{"location":"C4Blade/airfoil_types/CCBlade/#DuctAPE.C4Blade.PrandtlTip","page":"CCBlade Airfoil Types","title":"DuctAPE.C4Blade.PrandtlTip","text":"PrandtlTip()\n\nStandard Prandtl tip loss correction.\n\n\n\n\n\n","category":"type"},{"location":"C4Blade/airfoil_types/CCBlade/#DuctAPE.C4Blade.PrandtlTipHub","page":"CCBlade Airfoil Types","title":"DuctAPE.C4Blade.PrandtlTipHub","text":"PrandtlTipHub()\n\nStandard Prandtl tip loss correction plus hub loss correction of same form.\n\n\n\n\n\n","category":"type"},{"location":"C4Blade/airfoil_types/CCBlade/#DuctAPE.C4Blade.SimpleAF","page":"CCBlade Airfoil Types","title":"DuctAPE.C4Blade.SimpleAF","text":"SimpleAF(m, alpha0, clmax, clmin, cd0, cd2)\n\nA simple parameterized lift and drag curve.\n\ncl = m (alpha - alpha0) (capped by clmax/clmin)\ncd = cd0 + cd2 * cl^2\n\nArguments:\n\nm::Float64: lift curve slope\nalpha0::Float64: zero-lift angle of attack\nclmax::Float64: maximum lift coefficient\nclmin::Float64: minimum lift coefficient\ncd0::Float64: zero lift drag\ncd2::Float64: quadratic drag term\n\n\n\n\n\n","category":"type"},{"location":"C4Blade/airfoil_types/CCBlade/#DuctAPE.C4Blade.SkinFriction","page":"CCBlade Airfoil Types","title":"DuctAPE.C4Blade.SkinFriction","text":"SkinFriction(Re0, p)\n\nSkin friction model for a flat plate. cd *= (Re0 / Re)^p\n\nArguments:\n\nRe0::Float64: reference Reynolds number (i.e., no corrections at this number)\np::Float64: exponent in flat plate model. 0.5 for laminar (Blasius solution), ~0.2 for fully turbulent (Schlichting empirical fit)\n\n\n\n\n\n","category":"type"},{"location":"C4Blade/airfoil_types/CCBlade/#DuctAPE.C4Blade.afeval-Tuple{DuctAPE.C4Blade.AFType, Any, Any, Any}","page":"CCBlade Airfoil Types","title":"DuctAPE.C4Blade.afeval","text":"afeval(af::AFType, alpha, Re, Mach)\n\nEvaluate airfoil aerodynamic performance\n\nArguments:\n\naf::AFType or Function: dispatch on AFType or if function call: cl, cd = af(alpha, Re, Mach)\nalpha::Float64: angle of attack in radians\nRe::Float64: Reynolds number\nMach::Float64: Mach number\n\nReturns:\n\ncl::Float64: lift coefficient\ncd::Float64: drag coefficient\n\n\n\n\n\n","category":"method"},{"location":"C4Blade/airfoil_types/CCBlade/#DuctAPE.C4Blade.mach_correction-Tuple{DuctAPE.C4Blade.MachCorrection, Any, Any, Any}","page":"CCBlade Airfoil Types","title":"DuctAPE.C4Blade.mach_correction","text":"mach_correction(::MachCorrection, cl, cd, Mach)\n\nMach number correction for lift/drag coefficient\n\nArguments:\n\nmc::MachCorrection: used for dispatch\ncl::Float64: lift coefficient before correction\ncd::Float64: drag coefficient before correction\nMach::Float64: Mach number\n\nReturns:\n\ncl::Float64: lift coefficient after correction\ncd::Float64: drag coefficient after correction\n\n\n\n\n\n","category":"method"},{"location":"C4Blade/airfoil_types/CCBlade/#DuctAPE.C4Blade.mach_correction-Tuple{DuctAPE.C4Blade.PrandtlGlauert, Any, Any, Any}","page":"CCBlade Airfoil Types","title":"DuctAPE.C4Blade.mach_correction","text":"mach_correction(::PrandtlGlauert, cl, cd, Mach)\n\nPrandtl/Glauert Mach number correction for lift coefficient\n\n\n\n\n\n","category":"method"},{"location":"C4Blade/airfoil_types/CCBlade/#DuctAPE.C4Blade.parsefile-Tuple{Any, Any}","page":"CCBlade Airfoil Types","title":"DuctAPE.C4Blade.parsefile","text":"A basic airfoil file format. nheader is the number of header lines, which will be skipped. For one Reynolds/Mach number. Additional data like cm is optional but will be ignored.\n\nformat:\n\ninformational header\n\nRe\n\nMach\n\nalpha1 cl1 cd1 ...\n\nalpha2 cl2 cd2\n\nalpha3 cl3 cd3\n\n...\n\n\n\n\n\n","category":"method"},{"location":"C4Blade/airfoil_types/CCBlade/#DuctAPE.C4Blade.re_correction-Tuple{DuctAPE.C4Blade.ReCorrection, Any, Any, Any}","page":"CCBlade Airfoil Types","title":"DuctAPE.C4Blade.re_correction","text":"re_correction(re::ReCorrection, cl, cd, Re)\n\nReynolds number correction for lift/drag coefficient\n\nArguments:\n\nre::ReCorrection: used for dispatch\ncl::Float64: lift coefficient before correction\ncd::Float64: drag coefficient before correction\nRe::Float64: Reynolds number\n\nReturns:\n\ncl::Float64: lift coefficient after correction\ncd::Float64: drag coefficient after correction\n\n\n\n\n\n","category":"method"},{"location":"C4Blade/airfoil_types/CCBlade/#DuctAPE.C4Blade.re_correction-Tuple{DuctAPE.C4Blade.SkinFriction, Any, Any, Any}","page":"CCBlade Airfoil Types","title":"DuctAPE.C4Blade.re_correction","text":"re_correction(sf::SkinFriction, cl, cd, Re)\n\nSkin friction coefficient correction based on flat plat drag increases with Reynolds number.\n\n\n\n\n\n","category":"method"},{"location":"C4Blade/airfoil_types/CCBlade/#DuctAPE.C4Blade.rotation_correction","page":"CCBlade Airfoil Types","title":"DuctAPE.C4Blade.rotation_correction","text":"rotation_correction(rc::RotationCorrection, cl, cd, cr, rR, tsr, alpha, phi=alpha, alpha_max_corr=30*pi/180)\n\nRotation correction (3D stall delay).\n\nArguments:\n\nrc::RotationCorrection: used for dispatch\ncl::Float64: lift coefficient before correction\ncd::Float64: drag coefficient before correction\ncr::Float64: local chord / local radius\nrR::Float64: local radius / tip radius\ntsr::Float64: local tip speed ratio (Omega r / Vinf)\nalpha::Float64: local angle of attack\nphi::Float64: local inflow angles (defaults to angle of attack is precomputing since it is only known for on-the-fly computations)\nalpha_max_corr::Float64: angle of attack for maximum correction (tapers off to zero by 90 degrees)\n\nReturns:\n\ncl::Float64: lift coefficient after correction\ncd::Float64: drag coefficient after correction\n\n\n\n\n\n","category":"function"},{"location":"C4Blade/airfoil_types/CCBlade/#DuctAPE.C4Blade.tip_correction-Tuple{DuctAPE.C4Blade.TipCorrection, Vararg{Any, 5}}","page":"CCBlade Airfoil Types","title":"DuctAPE.C4Blade.tip_correction","text":"tip_correction(::TipCorrection, r, Rhub, Rtip, phi, B)\n\nTip corrections for 3D flow.\n\nArguments:\n\ntc::TipCorrection: used for dispatch\nr::Float64: local radius\nRhub::Float64: hub radius\nRtip::Float64: tip radius\nphi::Float64: inflow angle\nB::Integer: number of blades\n\nReturns:\n\nF::Float64: tip loss factor to multiple against loads.\n\n\n\n\n\n","category":"method"},{"location":"C4Blade/airfoil_types/CCBlade/#DuctAPE.C4Blade.viterna","page":"CCBlade Airfoil Types","title":"DuctAPE.C4Blade.viterna","text":"viterna(alpha, cl, cd, cr75, nalpha=50)\n\nViterna extrapolation. Follows Viterna paper and somewhat follows NREL version of AirfoilPrep, but with some modifications for better robustness and smoothness.\n\nArguments:\n\nalpha::Vector{Float64}: angles of attack\ncl::Vector{Float64}: correspnding lift coefficients\ncd::Vector{Float64}: correspnding drag coefficients\ncr75::Float64: chord/Rtip at 75% Rtip\nnalpha::Int64: number of discrete points (angles of attack) to include in extrapolation\n\nReturns:\n\nalpha::Vector{Float64}: angle of attack from -pi to pi\ncl::Vector{Float64}: correspnding extrapolated lift coefficients\ncd::Vector{Float64}: correspnding extrapolated drag coefficients\n\n\n\n\n\n","category":"function"},{"location":"C4Blade/airfoil_types/CCBlade/#DuctAPE.C4Blade.write_af-Tuple{Any, DuctAPE.C4Blade.AlphaAF}","page":"CCBlade Airfoil Types","title":"DuctAPE.C4Blade.write_af","text":"write_af(filename(s), af::AFType; radians=true)\n\nWrite airfoil data to file\n\nArguments:\n\nfilename(s)::String or Vector{String} or Matrix{String}: name/path of file to write to\naf::AFType: writing is dispatched based on type (AlphaAF, AlphaReAF, etc.)\nradians::Bool: true if you want angle of attack to be written in radians\n\n\n\n\n\n","category":"method"},{"location":"DuctAPE/api/private_prelims/#Option-Types","page":"Prelims","title":"Option Types","text":"","category":"section"},{"location":"DuctAPE/api/private_prelims/","page":"Prelims","title":"Prelims","text":"DuctAPE.DFDC_options\nDuctAPE.ConvergenceType\nDuctAPE.Relative\nDuctAPE.Absolute\nDuctAPE.SolverOptionsType\nDuctAPE.ExternalSolverOptions\nDuctAPE.PolyAlgorithmOptions\nDuctAPE.GridSolverOptionsType\nDuctAPE.IntegrationMethod","category":"page"},{"location":"DuctAPE/api/private_prelims/#DuctAPE.DFDC_options","page":"Prelims","title":"DuctAPE.DFDC_options","text":"function DFDC_options(;\n grid_solver_options=SLORGridSolverOptions(),\n solver_options=CSORSolverOptions(),\n kwargs...,\n)\n\nConvenience function to select options used in DFDC.\n\n\n\n\n\nfunction DFDC_options(\n multipoint;\n grid_solver_options=SLORGridSolverOptions(),\n solver_options=CSORSolverOptions(),\n kwargs...,\n)\n\nConvenience function to select options used in DFDC and run multipoint analysis.\n\nArguments\n\nmultipoint::Vector : doesn't need to be anything but a vector of the length of multipoints.\n\n\n\n\n\n","category":"function"},{"location":"DuctAPE/api/private_prelims/#DuctAPE.ConvergenceType","page":"Prelims","title":"DuctAPE.ConvergenceType","text":"abstract type ConvergenceType\n\nUsed in dispatching the CSOR (controlled successive over relaxation) residual as relative or absolute.\n\n\n\n\n\n","category":"type"},{"location":"DuctAPE/api/private_prelims/#DuctAPE.Relative","page":"Prelims","title":"DuctAPE.Relative","text":"struct Relative <: ConvergenceType\n\nUsed to dispatch the relative residual for CSOR (controlled successive over relaxation) method\n\n\n\n\n\n","category":"type"},{"location":"DuctAPE/api/private_prelims/#DuctAPE.Absolute","page":"Prelims","title":"DuctAPE.Absolute","text":"struct Absolute <: ConvergenceType\n\nUsed to dispatch the absolute residual for CSOR (controlled successive over relaxation) method\n\n\n\n\n\n","category":"type"},{"location":"DuctAPE/api/private_prelims/#DuctAPE.SolverOptionsType","page":"Prelims","title":"DuctAPE.SolverOptionsType","text":"abstract type SolverOptionsType\n\nUsed for solver dispatch.\n\n\n\n\n\n","category":"type"},{"location":"DuctAPE/api/private_prelims/#DuctAPE.ExternalSolverOptions","page":"Prelims","title":"DuctAPE.ExternalSolverOptions","text":"abstract type ExternalSolverOptions <: SolverOptionsType\n\nUsed for solver dispatch.\n\n\n\n\n\n","category":"type"},{"location":"DuctAPE/api/private_prelims/#DuctAPE.PolyAlgorithmOptions","page":"Prelims","title":"DuctAPE.PolyAlgorithmOptions","text":"abstract type PolyAlgorithmOptions <: SolverOptionsType\n\nUsed for solver dispatch.\n\n\n\n\n\n","category":"type"},{"location":"DuctAPE/api/private_prelims/#DuctAPE.GridSolverOptionsType","page":"Prelims","title":"DuctAPE.GridSolverOptionsType","text":"abstract type GridSolverOptionsType\n\nUsed for elliptic grid solver dispatch\n\n\n\n\n\n","category":"type"},{"location":"DuctAPE/api/private_prelims/#DuctAPE.IntegrationMethod","page":"Prelims","title":"DuctAPE.IntegrationMethod","text":"abstract type IntegrationMethod\n\nUsed in integration method dispatch\n\n\n\n\n\n","category":"type"},{"location":"DuctAPE/api/private_prelims/#Bookkeeping","page":"Prelims","title":"Bookkeeping","text":"","category":"section"},{"location":"DuctAPE/api/private_prelims/","page":"Prelims","title":"Prelims","text":"DuctAPE.get_problem_dimensions","category":"page"},{"location":"DuctAPE/api/private_prelims/#DuctAPE.get_problem_dimensions","page":"Prelims","title":"DuctAPE.get_problem_dimensions","text":"get_problem_dimensions(paneling_constants::PanelingConstants)\nget_problem_dimensions(body_vortex_panels, rotor_source_panels, wake_vortex_panels)\n\nDetermine all relevant dimensions to the problem based either on the paneling_constants or the panels themselves.\n\nArguments\n\npaneling_constants::PanelingConstants : Rotor (and possibly stator) geometric paramters.\n\nReturns\n\nproblem_dimensions::ProblemDimensions : ProblemDimensions object.\n\n\n\n\n\n\n\n\n\n","category":"function"},{"location":"DuctAPE/api/private_prelims/#Caching","page":"Prelims","title":"Caching","text":"","category":"section"},{"location":"DuctAPE/api/private_prelims/#Allocation","page":"Prelims","title":"Allocation","text":"","category":"section"},{"location":"DuctAPE/api/private_prelims/","page":"Prelims","title":"Prelims","text":"The following are various helper functions used in preallocating the various caches.","category":"page"},{"location":"DuctAPE/api/private_prelims/","page":"Prelims","title":"Prelims","text":"DuctAPE.initialize_all_caches\nDuctAPE.allocate_wake_panel_container!\nDuctAPE.allocate_panel_containers!\nDuctAPE.allocate_panel_container!\nDuctAPE.allocate_body_panel_container!\nDuctAPE.allocate_rotor_panel_container!\nDuctAPE.allocate_solve_parameter_extras!\nDuctAPE.allocate_grid_parameter_cache\nDuctAPE.allocate_integration_containers","category":"page"},{"location":"DuctAPE/api/private_prelims/#DuctAPE.initialize_all_caches","page":"Prelims","title":"DuctAPE.initialize_all_caches","text":"initialize_all_caches(solver_options, paneling_constants)\n\nConvenience function to initialize all caches before calling analysis.\n\nArguments\n\nsolver_options::SolverOptionsType : solver options used for cache allocation dispatch\npaneling_constants::PanelingConstants : PanelingConstants object upon which all cache sizing depends\n\nKeyword Arguments\n\nfd_chunk_size::Int=12 : chunk size to use for PreallocationTools caches. Note that the automated chuck size for DuctAPE will always be the ForwardDiff threshold of 12 due to the size of the system, so it will be best to leave this at the default unless further development allows for chunk size selection for individual solvers.\nlevels::Int=1 : levels for nested duals. Note that since ImplicitAD is being used for all solves, there should be no need for more than 1 level.\n\nReturns\n\nprepost_container_caching::NamedTuple : A named tuple containing the PreallocationTools DiffCache and a named tuple with relevant dimensions for accessing the cache.\nsolve_parameter_caching::NamedTuple : A named tuple containing the PreallocationTools DiffCache and a named tuple with relevant dimensions for accessing the cache.\nsolve_container_caching::NamedTuple : A named tuple containing the PreallocationTools DiffCache and a named tuple with relevant dimensions for accessing the cache.\n\n\n\n\n\n","category":"function"},{"location":"DuctAPE/api/private_prelims/#DuctAPE.allocate_wake_panel_container!","page":"Prelims","title":"DuctAPE.allocate_wake_panel_container!","text":"allocate_wake_panel_containers!(total_length, problem_dimensions::ProblemDimensions)\n\nA helper function is assembling the prepostcontainercache.\n\nArguments\n\ntotal_length::Vector{Int} : a one-element vector used to store the total length in order to know how large of a cache to allocate. Is updated in place.\nproblem_dimensions::ProblemDimensions : a ProblemDimensions object\n\nReturns\n\nwake_vortex_panels::NamedTuple : A named containing the dimensions needed to reshape the cache with regards to the wake vortex panel object\n\n\n\n\n\n","category":"function"},{"location":"DuctAPE/api/private_prelims/#DuctAPE.allocate_panel_containers!","page":"Prelims","title":"DuctAPE.allocate_panel_containers!","text":"allocate_panel_containers!(total_length, problem_dimensions::ProblemDimensions)\n\nA helper function is assembling the prepostcontainercache.\n\nArguments\n\ntotal_length::Vector{Int} : a one-element vector used to store the total length in order to know how large of a cache to allocate. Is updated in place.\nproblem_dimensions::ProblemDimensions : a ProblemDimensions object\n\nReturns\n\npanels::NamedTuple : A named tuple of named tuples containing the dimensions needed to reshape the cache with regards to the panel objects\n\n\n\n\n\n","category":"function"},{"location":"DuctAPE/api/private_prelims/#DuctAPE.allocate_panel_container!","page":"Prelims","title":"DuctAPE.allocate_panel_container!","text":"allocate_panel_container!(total_length, nn, np, tn, tp, nb)\n\nA helper function is assembling the prepostcontainercache.\n\nArguments\n\ntotal_length::Vector{Int} : a one-element vector used to store the total length in order to know how large of a cache to allocate. Is updated in place.\nnn::Int : number of nodes in each body, rotor, or wake sheet\nnp::Int : number of panels in each body, rotor, or wake sheet\ntn::Int : number of total nodes among the bodies, rotors, or wake sheets\ntp::Int : number of total panels among the bodies, rotors, or wake sheets\nnb::Int : number of bodies, rotors, or wake sheets\n\nReturns\n\npanel::NamedTuple : A named containing the dimensions needed to reshape the cache with regards to an arbitrary panel set\n\n\n\n\n\n","category":"function"},{"location":"DuctAPE/api/private_prelims/#DuctAPE.allocate_body_panel_container!","page":"Prelims","title":"DuctAPE.allocate_body_panel_container!","text":"allocate_body_panel_containers!(total_length, problem_dimensions::ProblemDimensions)\n\nA helper function is assembling the prepostcontainercache.\n\nArguments\n\ntotal_length::Vector{Int} : a one-element vector used to store the total length in order to know how large of a cache to allocate. Is updated in place.\nproblem_dimensions::ProblemDimensions : a ProblemDimensions object\n\nReturns\n\nbody_vortex_panels::NamedTuple : A named tuple containing the dimensions needed to reshape the cache with regards to the body vortex panel object\n\n\n\n\n\n","category":"function"},{"location":"DuctAPE/api/private_prelims/#DuctAPE.allocate_rotor_panel_container!","page":"Prelims","title":"DuctAPE.allocate_rotor_panel_container!","text":"allocate_rotor_panel_containers!(total_length, problem_dimensions::ProblemDimensions)\n\nA helper function is assembling the prepostcontainercache.\n\nArguments\n\ntotal_length::Vector{Int} : a one-element vector used to store the total length in order to know how large of a cache to allocate. Is updated in place.\nproblem_dimensions::ProblemDimensions : a ProblemDimensions object\n\nReturns\n\nrotor_source_panels::NamedTuple : A named containing the dimensions needed to reshape the cache with regards to the rotor source panel object\n\n\n\n\n\n","category":"function"},{"location":"DuctAPE/api/private_prelims/#DuctAPE.allocate_solve_parameter_extras!","page":"Prelims","title":"DuctAPE.allocate_solve_parameter_extras!","text":"allocate_solve_parameter_extras!(\n solver_options::SolverOptionsType, input_length, total_length\n)\n\nIncludes additional caching for various solvers. Currently only does anything for SIAMFANLEOptions types.\n\nArguments\n\ninput_length::Int : the number of state variables in the solver\ntotal_length::Vector{Int} : a one-element vector used to store the total length in order to know how large of a cache to allocate. Is updated in place.\n\nReturns\n\nsolve_parameter_extras::NamedTuple : A named tuple containing dimensions related to extra caching parameters used in various solvers.\n\n\n\n\n\n","category":"function"},{"location":"DuctAPE/api/private_prelims/#DuctAPE.allocate_grid_parameter_cache","page":"Prelims","title":"DuctAPE.allocate_grid_parameter_cache","text":"allocate_grid_parameter_cache(pg, x, n)\n\nAllocate a cache used inside the elliptic grid solve.\n\nArguments\n\npg::AbstractArray{Float,3} : the proposed grid array\nx::AbstractVector{Float} : the array of ξ values used in the solve\nn::AbstractVector{Float} : the array of η values used in the solve\n\nReturns\n\ngrid_parameter_cache::NamedTuple : A named tuple containing the PreallocationTools DiffCache and dimensions for accessing it.\n\n\n\n\n\n","category":"function"},{"location":"DuctAPE/api/private_prelims/#DuctAPE.allocate_integration_containers","page":"Prelims","title":"DuctAPE.allocate_integration_containers","text":"allocate_integration_containers(\n integration_options::IntegrationMethod, dispatch_type; cache_size=20\n)\n\nDescription\n\nArguments\n\nintegration_options::IntegrationMethod : options for integration used for dispatch and to size cache\ndispatch_type:: : an object with eltype(dispatch_type) with which to define the type for cache initialization.\n\nKeyword Arguments\n\ncache_size::Int=20 : size needed for intermediate calculations for integration.\n\nReturns\n\nintegration_containers::NamedTuple : A named tuple containing the cache(s) needed for integration.\n\n\n\n\n\n","category":"function"},{"location":"DuctAPE/api/private_prelims/#Reshaping","page":"Prelims","title":"Reshaping","text":"","category":"section"},{"location":"DuctAPE/api/private_prelims/","page":"Prelims","title":"Prelims","text":"The following are used internally to reshape the cache vectors into more usable formats.","category":"page"},{"location":"DuctAPE/api/private_prelims/","page":"Prelims","title":"Prelims","text":"DuctAPE.withdraw_prepost_container_cache\nDuctAPE.withdraw_solve_parameter_cache\nDuctAPE.withdraw_solve_container_cache\nDuctAPE.withdraw_grid_parameter_cache","category":"page"},{"location":"DuctAPE/api/private_prelims/#DuctAPE.withdraw_prepost_container_cache","page":"Prelims","title":"DuctAPE.withdraw_prepost_container_cache","text":"withdraw_prepost_container_cache(vec, dims)\n\nReshape the prepost cache vector using the saved dimensions tuple.\n\nArguments\n\nvec::Vector{Float} : vector cache of pre- and post-processing intermediate containers.\ndims::NamedTuple : Named tuple containing the indices and shape of the various items stored in the cache vector.\n\nReturns\n\nprepost_container_caching::NamedTuple : Named tuple containing reshaped views of sections of the cache vector.\n\n\n\n\n\n","category":"function"},{"location":"DuctAPE/api/private_prelims/#DuctAPE.withdraw_solve_parameter_cache","page":"Prelims","title":"DuctAPE.withdraw_solve_parameter_cache","text":"withdraw_solve_parameter_cache(solver_options::SolverOptionsType, vec, dims)\n\nReshape the solve parameter cache vector using the saved dimensions tuple.\n\nArguments\n\nsolver_options::SolverOptionsType : Solver options type for dispatch.\nvec::Vector{Float} : vector cache of pre- and post-processing intermediate containers.\ndims::NamedTuple : Named tuple containing the indices and shape of the various items stored in the cache vector.\n\nReturns\n\nsolve_parameter_caching::NamedTuple : Named tuple containing reshaped views of sections of the cache vector.\n\n\n\n\n\n","category":"function"},{"location":"DuctAPE/api/private_prelims/#DuctAPE.withdraw_solve_container_cache","page":"Prelims","title":"DuctAPE.withdraw_solve_container_cache","text":"withdraw_solve_container_cache(solver_options::SolverOptionsType, vec, dims)\n\nReshape the intermediate solve container cache vector using the saved dimensions tuple.\n\nArguments\n\nsolver_options::SolverOptionsType : Solver options type for dispatch.\nvec::Vector{Float} : vector cache of pre- and post-processing intermediate containers.\ndims::NamedTuple : Named tuple containing the indices and shape of the various items stored in the cache vector.\n\nReturns\n\nsolve_container_caching::NamedTuple : Named tuple containing reshaped views of sections of the cache vector.\n\n\n\n\n\n","category":"function"},{"location":"DuctAPE/api/private_prelims/#DuctAPE.withdraw_grid_parameter_cache","page":"Prelims","title":"DuctAPE.withdraw_grid_parameter_cache","text":"withdraw_grid_parameter_cache(vec, dims)\n\nReshape the cache used inside the elliptic grid solve.\n\nArguments\n\nvec::Vector{Float} : the cache vector\ndims::NamedTuple : the named tuple of dimensions used to reshape the cache vector\n\nReturns\n\nproposed_grid::AbstractArray{Float,3} : the proposed grid array\nxi::AbstractVector{Float} : the array of ξ values used in the solve\neta::AbstractVector{Float} : the array of η values used in the solve\n\n\n\n\n\n","category":"function"},{"location":"C4Blade/airfoil_types/DFDC/#DFDC-Airfoil-Type","page":"DFDC Airfoil Type","title":"DFDC Airfoil Type","text":"","category":"section"},{"location":"C4Blade/airfoil_types/DFDC/","page":"DFDC Airfoil Type","title":"DFDC Airfoil Type","text":"The DFDC Airfoil type is very similar to the XROTOR airfoil type, but includes additions for cascade corrections based on stagger and solidity. The cascade corrections aren't particularly accurate, but they do apply ballpark effects resulting from high solidity blade sections. The main benefit to this airfoil type is its simplicity and that the post-stall behavior is already in a format allowing more robust convergence of the DuctAPE solvers.","category":"page"},{"location":"C4Blade/airfoil_types/DFDC/","page":"DFDC Airfoil Type","title":"DFDC Airfoil Type","text":"DuctAPE.C4Blade.DFDCairfoil","category":"page"},{"location":"C4Blade/airfoil_types/DFDC/#DuctAPE.C4Blade.DFDCairfoil","page":"DFDC Airfoil Type","title":"DuctAPE.C4Blade.DFDCairfoil","text":"Fields:\n\nalpha0::Float : zero lift angle of attack\nclmax::Float : maximum cl\nclmin::Float : minimum cl\ndclda::Float : lift curve slope (1/radians)\ndclda_stall::Float : lift curve slope post-stall (1/radians)\ndcl_stall::Float : cl increment from initial to total stall.\ncdmin::Float : minimum cd\ncldmin::Float : cl at cdmin\ndcddcl2::Float : quadratic curve factor for cl vs cd curve left(fracd(c_d)d(c_l^2)right)\ncmcon::Float : pitching moment constant (unused right now)\nRe_ref::Float : reference Reynolds number at which cd values apply\nRe_exp::Float : Reynolds number exponent scaling left( c_d = c_d(ReRe_ref)^Re_expright) should be 0.2 for fully laminar and 0.5 for fully turbulent\nmcrit::Float : critical Mach number\n\n\n\n\n\n","category":"type"},{"location":"C4Blade/airfoil_types/actuator_disk/#Actuator-Disk-Type","page":"Actuator Disk Type","title":"Actuator Disk Type","text":"","category":"section"},{"location":"C4Blade/airfoil_types/actuator_disk/","page":"Actuator Disk Type","title":"Actuator Disk Type","text":"warning: Warning\nActuator disk types are currently in development and not ready for general use.","category":"page"},{"location":"C4Blade/airfoil_types/actuator_disk/","page":"Actuator Disk Type","title":"Actuator Disk Type","text":"DuctAPE currently implements an actuator disk type that can be used to directly define the rotor blade circulation.","category":"page"},{"location":"C4Blade/airfoil_types/actuator_disk/","page":"Actuator Disk Type","title":"Actuator Disk Type","text":"DuctAPE.C4Blade.ADM","category":"page"},{"location":"C4Blade/airfoil_types/actuator_disk/#DuctAPE.C4Blade.ADM","page":"Actuator Disk Type","title":"DuctAPE.C4Blade.ADM","text":"Fields:\n\nprescribed_circulation::Float=0.0 : Prescribed circulation strength\nprescribed_source_strength::Float=0.0 : Prescribed source panel strength\n\n\n\n\n\n","category":"type"},{"location":"DuctAPE/api/private_api/#Private-API","page":"Private API","title":"Private API","text":"","category":"section"},{"location":"DuctAPE/api/private_api/","page":"Private API","title":"Private API","text":"Pages = [\"private_api.md\",\n\"private_prelims.md\",\n\"private_preprocess.md\",\n\"private_process.md\",\n\"private_postprocess.md\",\n\"private_utlities.md\"]\nDepth = 5","category":"page"},{"location":"DuctAPE/advanced_usage/option/#Advanced-Option-Selection","page":"Options","title":"Advanced Option Selection","text":"","category":"section"},{"location":"DuctAPE/advanced_usage/option/","page":"Options","title":"Options","text":"DuctAPE has been written in an attempt to make as many of the available options exposed to the user as possible. This means that there are quite a few options to select from if not using the option convenience functions. To help the user, the majority of overarching option types are defined using the @kwdef macro and have default values that should be reasonable in most cases. We will introduce some of the available options here that may be of common interest.","category":"page"},{"location":"DuctAPE/advanced_usage/option/#General-Option-Selection","page":"Options","title":"General Option Selection","text":"","category":"section"},{"location":"DuctAPE/advanced_usage/option/","page":"Options","title":"Options","text":"In general, options are all accessed through the options argument of the analysis function being called. Said options are passed via an Options struct.","category":"page"},{"location":"DuctAPE/advanced_usage/option/","page":"Options","title":"Options","text":"DuctAPE.Options","category":"page"},{"location":"DuctAPE/advanced_usage/option/#DuctAPE.Options-DuctAPE-advanced_usage-option","page":"Options","title":"DuctAPE.Options","text":"struct Options{\n TB,\n TBwo,\n TF,\n TI,\n TSf,\n TSt,\n Tin,\n TIo<:IntegrationOptions,\n TSo<:SolverOptionsType,\n WS<:GridSolverOptionsType,\n}\n\nType containing (nearly) all the available user options.\n\nFields\n\nGeneral Options\n\nverbose::TB = false : flag to print verbose statements\nsilence_warnings::TB = true : flag to silence warnings\nmultipoint_index::TI = [1] : holds current index of multi-point solver (no need for user to change this usually)\n\nPre-processing Options\n\nGeometry ee-interpolation and generation options :\n\nfinterp::Tin = FLOWMath.akima : interpolation method used for re-paneling bodies\nautoshiftduct::TB = true : flag as to whether duct geometry should be shifted based on rotor tip location\nlu_decomp_flag::TB = false : flag indicating if panel method LHS matrix factorization was successful\n\npaneling options\n\nitcpshift::TF = 0.05 : factor for internal trailing edge psuedo-panel placement (default is DFDC hard-coded value)\naxistol::TF = 1e-15 : tolerance for how close the the axis of rotation should be considered on the axis\ntegaptol::TF = 1e1 * eps() : tolerance for how large of a trailing edge gap should be considered a gap\n\nIntegration Options\n\nintegration_options::TIo = IntegrationOptions() : integration options\n\nPost-processing Options\n\nwrite_outputs::TBwo = [false] : Bool for whether to write the outputs of the analysis to an external file (slow)\noutfile::TSf = [\"outputs.jl\"] : External output file name (including path information) for files to write\ncheckoutfileexists::TB = false : Flag for whether to check if file exists before overwriting\noutput_tuple_name::TSt = [\"outs\"] : variable name for named tuple written to out file\n\nSolving Options\n\ngrid_solver_options::WS = GridSolverOptions() : elliptic grid solver options\nsolver_options::TSo = ChainSolverOptions() : solver options\n\n\n\n\n\n","category":"type"},{"location":"DuctAPE/advanced_usage/option/","page":"Options","title":"Options","text":"Options are selected through the set_options function","category":"page"},{"location":"DuctAPE/advanced_usage/option/","page":"Options","title":"Options","text":"DuctAPE.set_options","category":"page"},{"location":"DuctAPE/advanced_usage/option/#DuctAPE.set_options-DuctAPE-advanced_usage-option","page":"Options","title":"DuctAPE.set_options","text":"set_options(; kwargs...)\nset_options(multipoint; kwargs...)\n\nSet the options for DuctAPE to use.\n\nNote that the vast majority of the available options are defined through keyword arguments. See the documentation for the various option types for more information.\n\nArguments\n\nmultipoint::AbstractArray{OperatingPoint} : a vector of operating points to use if running a multi-point analysis.\n\n\n\n\n\n","category":"function"},{"location":"DuctAPE/advanced_usage/option/","page":"Options","title":"Options","text":"There are three main sub-option objects for quadrature, wake geometry solver, and aerodyanmic solver; these are explained in more detail below. In addition, there are various options for pre- and post-processing as well as miscellaneous options for things such as supressing warnings and printing verbose statements throughout the analysis, which can be seen in the docstring above.","category":"page"},{"location":"DuctAPE/advanced_usage/option/#Quadrature","page":"Options","title":"Quadrature","text":"","category":"section"},{"location":"DuctAPE/advanced_usage/option/","page":"Options","title":"Options","text":"There are several implementations for different quadrature approaches depending on user desires; they include:","category":"page"},{"location":"DuctAPE/advanced_usage/option/","page":"Options","title":"Options","text":"Gauss-Legendre quadature (default),\nGauss-Kronrod Quadrature, and\nRomberg Quadrature methods.","category":"page"},{"location":"DuctAPE/advanced_usage/option/","page":"Options","title":"Options","text":"The default method is Gauss-Legendre quadrature using 8 sample points for both the nominal and singular integrals. To modify the quadrature methods and settings, an IntegrationOptions struct needs to be passed to the set_options method.","category":"page"},{"location":"DuctAPE/advanced_usage/option/","page":"Options","title":"Options","text":"DuctAPE.IntegrationOptions","category":"page"},{"location":"DuctAPE/advanced_usage/option/#DuctAPE.IntegrationOptions-DuctAPE-advanced_usage-option","page":"Options","title":"DuctAPE.IntegrationOptions","text":"struct IntegrationOptions{TN<:IntegrationMethod,TS<:IntegrationMethod}\n\nA struct used to hold the integration options for both the nominal and singular cases.\n\nFields\n\nnominal::IntegrationMethod=GaussLegendre(8) : the integration options to use for the nominal case.\nsingular::IntegrationMethod=GaussLegendre(8) : the integration options to use for the self-induced case.\n\n\n\n\n\n","category":"type"},{"location":"DuctAPE/advanced_usage/option/","page":"Options","title":"Options","text":"The IntegraionOptions type takes in two objects of type IntegrationMethod, one for the nominal integrals, and one for the singular integrals. These methods can be mixed and matched between quadrature methods as well as settings.","category":"page"},{"location":"DuctAPE/advanced_usage/option/","page":"Options","title":"Options","text":"For example, if one wanted to use a 10-point Gauss-Legendre method for the nominal integrals, and a order 7 Gauss-Kronrod method with an absolute tolerance of 2e-16 the following would need to be included in the set_options call:","category":"page"},{"location":"DuctAPE/advanced_usage/option/","page":"Options","title":"Options","text":"# set nominal options using a GaussLegendre object (which is an InterationMethod type)\n# note that a convenience method is used here that takes in the number of points and\n#calculates the appropriate sample locations and weights.\nnominal_integration_method = DuctAPE.GaussLegendre(10)\n\n# set singular options using a GaussKronrod object (which is an InterationMethod type)\n# note that like most option structs, these are defined using @kwdef allowing the fields\n#to be treated as keyword arguments.\n# also note that we haven't changed the evaluation limit (default 10^7)\nsingular_integration_method = DuctAPE.GaussKronrod(; order=7, atol=2e-16)\n\n# put the quadrature options together\nintegration_options = DuctAPE.IntegrationOptions(;\n nominal=nominal_integration_method, singular=singular_integration_method\n)\n\n# example of calling the set_options function\noptions = DuctAPE.set_options(; integration_options=integration_options)","category":"page"},{"location":"DuctAPE/advanced_usage/option/#Elliptic-Grid-Solvers","page":"Options","title":"Elliptic Grid Solvers","text":"","category":"section"},{"location":"DuctAPE/advanced_usage/option/","page":"Options","title":"Options","text":"As part of the pre-process, an elliptic grid defining the wake geometry is solved with a system of Poisson equations. For this solve there currently two options:","category":"page"},{"location":"DuctAPE/advanced_usage/option/","page":"Options","title":"Options","text":"SLOR: DFDC grid solver\nSLOR+Newton","category":"page"},{"location":"DuctAPE/advanced_usage/option/","page":"Options","title":"Options","text":"The SLOR (successive line over relaxation) is the method employed by DFDC, and can be used by itself, or as a preconditioner to a Newton solve (using NLsolve.jl).","category":"page"},{"location":"DuctAPE/advanced_usage/option/","page":"Options","title":"Options","text":"Selection of solver and solver settings follows the same pattern as with the quadrature settings, in that the user must pass the appropriate GridSolverOptionsType into the set_options call.","category":"page"},{"location":"DuctAPE/advanced_usage/option/","page":"Options","title":"Options","text":"For the SLOR method alone, the type is","category":"page"},{"location":"DuctAPE/advanced_usage/option/","page":"Options","title":"Options","text":"DuctAPE.SLORGridSolverOptions","category":"page"},{"location":"DuctAPE/advanced_usage/option/#DuctAPE.SLORGridSolverOptions-DuctAPE-advanced_usage-option","page":"Options","title":"DuctAPE.SLORGridSolverOptions","text":"struct SLORGridSolverOptions{TB,TF,TI} <: GridSolverOptionsType\n\nOptions for SLOR (successive line over relaxation) elliptic grid solver.\n\nFields\n\niteration_limit::TI = 100 : maximum number of iterations\natol::TF = 1e-9 : absolute convergence tolerance\n`converged::AbstractArray{TB} = [false]\n\n\n\n\n\n","category":"type"},{"location":"DuctAPE/advanced_usage/option/","page":"Options","title":"Options","text":"And for the SLOR+Newton method, the type is","category":"page"},{"location":"DuctAPE/advanced_usage/option/","page":"Options","title":"Options","text":"DuctAPE.GridSolverOptions","category":"page"},{"location":"DuctAPE/advanced_usage/option/#DuctAPE.GridSolverOptions-DuctAPE-advanced_usage-option","page":"Options","title":"DuctAPE.GridSolverOptions","text":"struct GridSolverOptions{TB,TF,TI,TSym} <: GridSolverOptionsType\n\nOptions for SLOR + Newton elliptic grid solver.\n\nFields\n\niteration_limit::TI = 10 : maximum number of iterations\natol::TF = 1e-14 : absolute convergence tolerance\nalgorithm::TSym = :newton : algorithm to use in NLsolve.jl\nautodiff::TSym = :forward : differentiation method to use in NLsolve.jl\nconverged::AbstractArray{TB} = [false]\n\n\n\n\n\n","category":"type"},{"location":"DuctAPE/advanced_usage/option/","page":"Options","title":"Options","text":"As an example, this is the input that would be required to use the SLOR+Newton method with an absolute convergence tolerance of 1e-12, and also including the quadrature settings from above:","category":"page"},{"location":"DuctAPE/advanced_usage/option/","page":"Options","title":"Options","text":"# define wake grid solver settings\nwake_solve_options = DuctAPE.GridSolverOptions(; atol=1e-12)\n\n# set all options\noptions = DuctAPE.set_options(;\n integration_options=integration_options, grid_solver_options=wake_solve_options\n)","category":"page"},{"location":"DuctAPE/advanced_usage/option/","page":"Options","title":"Options","text":"note: Convergence Flags\nThe convergence flags default to false, and in general should be left alone as they are modified in-place in the various solves by the analysis.","category":"page"},{"location":"DuctAPE/advanced_usage/option/#Aerodynamics-Solvers","page":"Options","title":"Aerodynamics Solvers","text":"","category":"section"},{"location":"DuctAPE/advanced_usage/option/","page":"Options","title":"Options","text":"There are two general types of solvers available in DuctAPE, the first is very similar to the solver in DFDC and converges a residual very similar to DFDC's. The other type is for external solvers that converge an alternate residual that is default in DuctAPE. The various solver options include:","category":"page"},{"location":"DuctAPE/advanced_usage/option/","page":"Options","title":"Options","text":"CSOR: the DFDC solver\nFixedPoint.jl\nSpeedMapping.jl\nMINPACK.jl\nSIAMFANLEquations.jl\nNLsolve.jl\nSimpleNonlinearSolve.jl","category":"page"},{"location":"DuctAPE/advanced_usage/option/","page":"Options","title":"Options","text":"Note that the CSOR, FixedPoint.jl, and SpeedMapping.jl are all different fixed-point iteration solvers, MINPACK.jl and SIAMFANLEquations.jl are primarily quasi-newton solvers, and NLsolve.jl and SimpleNonlinearSolve.jl have various solver options.","category":"page"},{"location":"DuctAPE/advanced_usage/option/","page":"Options","title":"Options","text":"DuctAPE also has some poly-algorithm solvers that employ more than one solver. The Chain Solver option is the default which starts with a fixed-point iteration, and if it doesn't converge, moves on to a quasi-, then full Newton solver until either convergence is reached, or no convergence is found. The other poly-algorithm that is available, but is less robust is the Composite Solver which partially converges with one solver, and finishes with another.","category":"page"},{"location":"DuctAPE/advanced_usage/option/","page":"Options","title":"Options","text":"Each of the solve methods have a variety of different settings associated with them, detailed in their respective docstrings. The following example should contain all the principles required to be able to adapt to the most complex use cases.","category":"page"},{"location":"DuctAPE/advanced_usage/option/","page":"Options","title":"Options","text":"# Define settings for NLsolve's newton method\naero_solver_options = DuctAPE.NLsolveOptions(;\n algorithm=:newton,\n atol=1e-10,\n iteration_limite=30,\n linesearch_method=LineSearches.BackTracking, #don't include parentheses on method handle\n linesearch_kwargs=(; order=3, maxstep=1e6),\n additional_kwargs=(; autoscale=false),\n)\n\n# set all the options\nDuctAPE.set_options(;\n integration_options=integration_options,\n grid_solver_options=wake_solve_options,\n solver_options=aero_solver_options,\n)","category":"page"},{"location":"DuctAPE/advanced_usage/option/","page":"Options","title":"Options","text":"note: Iteration Counters\nThe iterations field (not to be confused with the iterations_limit field) in the solver options should generally not be changed. They automatically save (in-place) the number of iterations the solver performs and can be accessed after the analysis is run.","category":"page"},{"location":"DuctAPE/advanced_usage/option/#Advanced-Options-for-Multi-point-analyses","page":"Options","title":"Advanced Options for Multi-point analyses","text":"","category":"section"},{"location":"DuctAPE/advanced_usage/option/","page":"Options","title":"Options","text":"For using advanced options in multi-point analyses, there are various changes that need to be made to avoid run-time errors. Here is an example for setting options with the CSOR solver.","category":"page"},{"location":"DuctAPE/advanced_usage/option/","page":"Options","title":"Options","text":"# number of operating points to analyze\nnop = 3\n\noptions = DuctAPE.set_options(;\n solver_options=DuctAPE.CSORSolverOptions(;\n converged=fill(false, (1, nop)), # need a convergence flag for each operating point\n iterations=zeros(Int, (1, nop)), # need a iteration count for each operating point\n Vconv=ones(nop), # in this case, we need a reference velocity for each operating point\n ),\n write_outputs=fill(false, nop), # we need to know which of the operating point outputs to write\n outfile=fill(\"\", nop), # we need to include names, even if they won't be used.\n output_tuple_name=fill(\"outs\", nop), # we need to include names, even if they won't be used.\n)","category":"page"},{"location":"DuctAPE/advanced_usage/option/","page":"Options","title":"Options","text":"If using a poly-algorithm with a multi-point solve, then each of the solvers needs to have the multiple converged and iterations fields for each operating point, and the overall solve type needs to have a converged and iterations field for each solver and each operating point.","category":"page"},{"location":"DuctAPE/advanced_usage/option/","page":"Options","title":"Options","text":"options = DuctAPE.set_options(;\n solver_options=DuctAPE.ChainSolverOptions(;\n solvers=[ # vector of solvers to use in poly-algorithm\n DuctAPE.NLsolveOptions(;\n algorithm=:anderson,\n atol=1e-12,\n iteration_limit=200,\n converged=fill(false, (1, nop)), # flags for each operating point\n iterations=zeros(Int, (1, nop)), # counters for each operating point\n ),\n DuctAPE.MinpackOptions(;\n atol=1e-12,\n iteration_limit=100,\n converged=fill(false, (1, nop)),\n iterations=zeros(Int, (1, nop)),\n ),\n ],\n converged=fill(false, (2, nop)), # flags for each solver and each operating point\n iterations=zeros(Int, (2, nop)), # counts for each solver and each operating point\n ),\n)","category":"page"},{"location":"C4Blade/airfoil_types/cascade/#Cascade-Types","page":"Cascade Types","title":"Cascade Types","text":"","category":"section"},{"location":"C4Blade/airfoil_types/cascade/","page":"Cascade Types","title":"Cascade Types","text":"warning: Warning\nCascade types are currently in development and not ready for general use.","category":"page"},{"location":"C4Blade/airfoil_types/cascade/","page":"Cascade Types","title":"Cascade Types","text":"Cascade types are defined analogous to CCBlade airfoil types. Instead of angle of attack, however, cascade types take in both inflow and stagger angles. In addition, cascade types are dependent on local solidity.","category":"page"},{"location":"C4Blade/airfoil_types/cascade/","page":"Cascade Types","title":"Cascade Types","text":"Modules = [DuctAPE.C4Blade]\nPages = [\"C4Blade/cascades.jl\"]","category":"page"},{"location":"C4Blade/airfoil_types/cascade/#DuctAPE.C4Blade.InReStSoMaCAS","page":"Cascade Types","title":"DuctAPE.C4Blade.InReStSoMaCAS","text":"InReStSoMaCAS(inflow, Re, stagger, solidity, Mach, cl, cd, info)\nInReStSoMaCAS(inflow, Re, stagger, solidity, Mach, cl, cd)\nInReStSoMaCAS(filenames::Matrix{String}; radians=true)\n\nData is fit recursively with Akima splines.\n\nArguments:\n\ninflow::Vector{Float64}: inflow angles\nRe::Vector{Float64}: Reynolds numbers\nstagger::Vector{Float64}: stagger angles\nsolidity::Vector{Float64}: local solidity\nMach::Vector{Float64}: Mach numbers\ncl::Array{Float64}: lift coefficients where cl[i, j, k, ell] corresponds to stagger[i], Re[j], Mach[k], solidity[ell]\ncd::Array{Float64}: drag coefficients where cd[i, j, k, ell] corresponds to stagger[i], Re[j], Mach[k], solidity[ell]\ninfo::String: a description of this airfoil data (just informational)\n\nor files with one per Re/Stagger/Solidty/Mach combination\n\nArguments:\n\nfilenames::Matrix{String}: name/path of files to read in. filenames[i, j, k, ell] corresponds to Re[i] Stagger[j] Stagger[k] and Solidity[k] with each in ascending order.\nradians::Bool: true if angle of attack in file is given in radians\n\n\n\n\n\n","category":"type"},{"location":"C4Blade/airfoil_types/cascade/#DuctAPE.C4Blade.interp5d-NTuple{12, Any}","page":"Cascade Types","title":"DuctAPE.C4Blade.interp5d","text":" interp5d(interp1d, x1data, x2data, x3data, x4data, fdata, x1pt, x2pt, x3pt, x4pt)\n\nSame as FLOWMath.interp4d, ex1cept in five dimensions.\n\n\n\n\n\n","category":"method"},{"location":"C4Blade/airfoil_types/cascade/#DuctAPE.C4Blade.parsecascadefile-Tuple{Any, Any}","page":"Cascade Types","title":"DuctAPE.C4Blade.parsecascadefile","text":"parsefile(filename, radians, solidity)\n\nCascade version of parsefile function from CCBlade. Assumes stagger is given before reynolds and Mach number, and solidity is given after\n\n\n\n\n\n","category":"method"},{"location":"C4Blade/airfoil_types/cascade/#DuctAPE.C4Blade.writecascadefile-NTuple{10, Any}","page":"Cascade Types","title":"DuctAPE.C4Blade.writecascadefile","text":"writecascadefile(filename, info, Re, Mach, stagger, inflow, cl, cd, radians)\n\nCascade version of writecascadefile function from CCBlade. Writes solidity after Mach number\n\n\n\n\n\n","category":"method"},{"location":"C4Blade/corrections/#Airfoil-Polar-Corrections","page":"Polar Modification","title":"Airfoil Polar Corrections","text":"","category":"section"},{"location":"C4Blade/corrections/","page":"Polar Modification","title":"Polar Modification","text":"In some cases various airfoil polar corrections may be required. Of specific note are modifications to airfoil polars for post-stall behavior. Thus far, DuctAPE is much more robust if the post-stall behavior in the lift polars does not exhibit a decrease in lift at angles of attack beyond that of the maximum lift coefficient. Therefore a function is provided to help modify polars as needed:","category":"page"},{"location":"C4Blade/corrections/","page":"Polar Modification","title":"Polar Modification","text":"DuctAPE.C4Blade.stall_limiters","category":"page"},{"location":"C4Blade/corrections/#DuctAPE.C4Blade.stall_limiters","page":"Polar Modification","title":"DuctAPE.C4Blade.stall_limiters","text":"stall_limiters(\n aoa,\n cl,\n cd;\n clminid=nothing,\n clmaxid=nothing,\n cl_cutoff_slope=0.1,\n cd_cutoff_slope=0.9,\n N=20,\n blend_hardness=50\n)\n\nCuts off coefficient vs alpha curve at min and max coefficient and places rest of curve from -pi to min coeff and max coeff to pi according to user defined clcutoffslope (default 0.1)\n\nArguments:\n\naoa::AbstractVector{Float} : input angles of attack, in radians\ncl::AbstractVector{Float} : input lift coefficients\ncd::AbstractVector{Float} : input drag coefficients\n\nKeyword Arguments:\n\nclminid::Float=nothing : manually set index for minimum cl\nclmaxid::Float=nothing : manually set index for maximum cl\ncl_cutoff_slope::Float=0.1 : \"post-stall\" slope for cl\ncd_cutoff_slope::Float=0.1 : \"post-stall\" slope for cd\nblend_hardness::Float=50 : hardenss of blend between nominal polar and post-stall modifications.\n\nReturns:\n\naoa_ext::AbstractVector{Float} : angles of attack for modified polar, in radians\ncl_ext::AbstractVector{Float} : modified lift coefficients\ncd_ext::AbstractVector{Float} : modified drag coefficients\n\n\n\n\n\n","category":"function"},{"location":"C4Blade/corrections/","page":"Polar Modification","title":"Polar Modification","text":"Various other correction methods are available, including the cascade corrections inherent in the DuctAPE.C4Blade.DFDCairfoil type. The following methods are in addition to the various corrections available alongside the CCBlade Airfoil Types.","category":"page"},{"location":"C4Blade/corrections/","page":"Polar Modification","title":"Polar Modification","text":"Modules = [DuctAPE.C4Blade]\nPages = [\"C4Blade/airfoil_corrections.jl\"]","category":"page"},{"location":"C4Blade/corrections/#DuctAPE.C4Blade.corrected_clcd-Tuple{DuctAPE.C4Blade.AlphaReAF, Vararg{Any, 9}}","page":"Polar Modification","title":"DuctAPE.C4Blade.corrected_clcd","text":"corrected_clcd(af::AlphaReAF, alpha, Re, Mach, solidity, stagger; kwargs...)\n\nEvaluates and applies on-the-fly corrections for airfoil lift and drag. On-the-fly airfoil polar corrections include solidity/stagger corrections, Prandtl-Glauert compressibility corrections, and transonic lift limits and drag additions.\n\ncorrected_clcd!(cl, cd, af::AlphaReAF, Re, alpha, Mach, solidity, stagger; kwargs...)\n\nEvaluates and applies on-the-fly corrections for airfoil lift and drag in place.\n\ncorrected_clcd!(cl, cd, Mach, solidity, stagger; kwargs...)\n\nApplies on-the-fly corrections for airfoil lift and drag in place.\n\ncorrected_clcd!(cl, cd, af::AlphaAF, alpha, Re, Mach, solidity, stagger; kwargs...)\n\nEvaluates and applies on-the-fly corrections, including Reynolds corrections, for airfoil lift and drag in place\n\ncorrected_clcd(cas::InReStSoMaCAS, inflow, Re, Mach, solidity, stagger)\n\nEvaluates cascade lift and drag.\n\nArguments:\n\nCoefficients\n\ncl::Float : local lift coefficient\ncd::Float : local drag coefficient\n\nAirfoil Object\n\naf::AlphaReAF : airfoil object of CCBlade type dependent on angle of attack and Reynolds number\n\nor\n\naf::AlphaAF : airfoil object of CCBlade type dependent on angle of attack only\n\nor\n\ncas::InReStSoMaCAS : cascade object depentent on inflow angle, Reynolds number, stagger, solidity, and Mach number.\n\nFlow Angle\n\nalpha::Float : angle of attack, radians. Used with airfoil types\n\nor\n\ninflow::Float : inflow angle, radians. Used with cascade types\n\nFlow Conditions\n\nRe::Float : Reynolds number\nMach::Float : Mach number\n\nGeometry\n\nsolidity::Float : Local solidity\nstagger::Float : Stagger angle, radians\n\nKeyword Arguments:\n\nmcrit::Float=0.7 : Critical Mach number\n\nrotorzloc airfoil type parameters for post-stall behavior\n\ndcl_stall::Float=0.1 : change in cl from incipient to total stall, used in transonic lift limiter correction\ndclda_stall::Float=0.1 : Post-stall lift curve slope\n\nCorrection factors that were hard coded in rotorzloc and DFDC\n\ncdmfactor::Float=10.0 :\nclmfactor::Float=0.25 :\nmexp::Float=3.0 :\ncdmstall::Float=0.1 :\ncdmdd::Float=0.0020 :\n\nSmoothing Paramters\n\nssblend_hardness::Float=100.0 : sigmoid blending hardness for solidity/stagger corrections\ntransblendhardness::Float=75.0 : sigmoid blending hardness for transonic corrections\nabsdx::Float=0.0625 : smooth absolute value Δα (radians) for transonic drag addition\n\nMiscellaneous\n\nverbose::Bool=false : Boolean of whether to print warnings, etc.\n\n\n\n\n\n","category":"method"},{"location":"C4Blade/corrections/#DuctAPE.C4Blade.prandtl_glauert!-Tuple{Any, Any}","page":"Polar Modification","title":"DuctAPE.C4Blade.prandtl_glauert!","text":"prandtl_glauert!(cl, ma)\n\nIn place version of pradtl_glauert.\n\n\n\n\n\n","category":"method"},{"location":"C4Blade/corrections/#DuctAPE.C4Blade.prandtl_glauert-Tuple{Any, Any}","page":"Polar Modification","title":"DuctAPE.C4Blade.prandtl_glauert","text":"prandtl_glauert(cl, ma)\n\nApplies Prandtl-Glauert correction\n\nArguments:\n\ncl::Float : local lift coefficient\n\nReturns\n\ncl_corr::AbstractVector{Float} : corrected lift coefficients\n\n\n\n\n\n","category":"method"},{"location":"C4Blade/corrections/#DuctAPE.C4Blade.prandtl_glauert_factor-Tuple{Any}","page":"Polar Modification","title":"DuctAPE.C4Blade.prandtl_glauert_factor","text":"prandtl_glauert_factor(mach; verbose=false, blend_range=0.02)\n\nSmoothed Prandtl-Glauert Mach correction factor\n\nArguments:\n\nmach::Float : Mach number\n\nKeyword Arguments:\n\nblend_range::Float=0.02 : range for blending factor and max cutoff (allowing Mach >= 1.0 for continuity)\n\n\n\n\n\n","category":"method"},{"location":"C4Blade/corrections/#DuctAPE.C4Blade.quadspline-Tuple{Any, Any, Any}","page":"Polar Modification","title":"DuctAPE.C4Blade.quadspline","text":"quadspline(xdata, ydata, xpoint)\n\nSample data in quadratic spline at give point.\n\n\n\n\n\n","category":"method"},{"location":"C4Blade/corrections/#DuctAPE.C4Blade.re_drag!-Tuple{Any, Any, Any}","page":"Polar Modification","title":"DuctAPE.C4Blade.re_drag!","text":"re_drag!(cd, re, re_ref; re_exp=0.5)\n\nIn-place version of re_drag.\n\n\n\n\n\n","category":"method"},{"location":"C4Blade/corrections/#DuctAPE.C4Blade.re_drag-Tuple{Any, Any, Any}","page":"Polar Modification","title":"DuctAPE.C4Blade.re_drag","text":"re_drag(cd, re, re_ref; re_exp=0.5)\n\nArguments:\n\ncd::AbstractVector{Float} : input drag coefficients\nre::Float : Current Reynolds number\nre_ref::Float : Reference Reynolds number (at which the cd's were generated)\n\nKeyword Arguments:\n\nre_exp::Float=0.5 : should be 0.2 for laminar and 0.5 for turbulent flow\n\nReturns:\n\ncd_corr::AbstractVector{Float} : Reynolds corrected drag coefficients\n\n\n\n\n\n","category":"method"},{"location":"C4Blade/corrections/#DuctAPE.C4Blade.solidity_and_stagger!-Tuple{Any, Any, Any}","page":"Polar Modification","title":"DuctAPE.C4Blade.solidity_and_stagger!","text":"solidity_and_stagger!(cl, solidity, stagger; blend_hardness=100)\n\nIn-place version of solidity_and_stagger.\n\n\n\n\n\n","category":"method"},{"location":"C4Blade/corrections/#DuctAPE.C4Blade.solidity_and_stagger-Tuple{Any, Any, Any}","page":"Polar Modification","title":"DuctAPE.C4Blade.solidity_and_stagger","text":"solidity_and_stagger(cl, solidity, stagger; blend_hardness=100)\n\nApply smoothed Wallis' cascade correction (see solidity_and_stagger_factor_smooth) to local lift.\n\nArguments:\n\ncl::AbstractVector{Float} : input lift coefficients\nsolidity::Float : local solidity\nstagger::Float : local stagger (in radians)\n\nKeyword Arguments:\n\nblend_hardness::Float=100 : hardness of smoothing blends\n\nReturns:\n\ncl_corr::AbstractVector{Float} : corrected lift coefficients.\n\n\n\n\n\n","category":"method"},{"location":"C4Blade/corrections/#DuctAPE.C4Blade.solidity_and_stagger_factor-Tuple{Any, Any}","page":"Polar Modification","title":"DuctAPE.C4Blade.solidity_and_stagger_factor","text":"solidity_and_stagger_factor(solidity, stagger; blend_hardness=100)\n\nCorrection for airfoil data used in a high-solidity cascade application. Correction is used in DFDC airfoils nominally and come from quadratic fits to curves in fig 6-29 \"Axial Flow Fans and Ducts\" by Wallis (1983). Note that the corrections are really only meant for Wallis' custom airfoil design and specific conditions mentioned in the book.\n\nArguments:\n\nsolidity::Float : local solidity\nstagger::Float : local stagger (in radians)\n\nKeyword Arguments:\n\nblend_hardness::Float=100 : hardness for smoothing blends\n\n\n\n\n\n","category":"method"},{"location":"C4Blade/corrections/#DuctAPE.C4Blade.solidity_and_stagger_factor_smooth-Tuple{Any, Any}","page":"Polar Modification","title":"DuctAPE.C4Blade.solidity_and_stagger_factor_smooth","text":"solidity_and_stagger_factor_smooth(solidity, stagger; blend_hardness=100)\n\nA smoothed version of solidity_and_stagger_factor.\n\nArguments:\n\nsolidity::Float : local solidity\nstagger::Float : local stagger (in radians)\n\nKeyword Arguments:\n\nblend_hardness::Float=100 : hardness for smoothing blends\n\n\n\n\n\n","category":"method"},{"location":"C4Blade/corrections/#DuctAPE.C4Blade.stall_limiters-Tuple{Any, Any, Any}","page":"Polar Modification","title":"DuctAPE.C4Blade.stall_limiters","text":"stall_limiters(\n aoa,\n cl,\n cd;\n clminid=nothing,\n clmaxid=nothing,\n cl_cutoff_slope=0.1,\n cd_cutoff_slope=0.9,\n N=20,\n blend_hardness=50\n)\n\nCuts off coefficient vs alpha curve at min and max coefficient and places rest of curve from -pi to min coeff and max coeff to pi according to user defined clcutoffslope (default 0.1)\n\nArguments:\n\naoa::AbstractVector{Float} : input angles of attack, in radians\ncl::AbstractVector{Float} : input lift coefficients\ncd::AbstractVector{Float} : input drag coefficients\n\nKeyword Arguments:\n\nclminid::Float=nothing : manually set index for minimum cl\nclmaxid::Float=nothing : manually set index for maximum cl\ncl_cutoff_slope::Float=0.1 : \"post-stall\" slope for cl\ncd_cutoff_slope::Float=0.1 : \"post-stall\" slope for cd\nblend_hardness::Float=50 : hardenss of blend between nominal polar and post-stall modifications.\n\nReturns:\n\naoa_ext::AbstractVector{Float} : angles of attack for modified polar, in radians\ncl_ext::AbstractVector{Float} : modified lift coefficients\ncd_ext::AbstractVector{Float} : modified drag coefficients\n\n\n\n\n\n","category":"method"},{"location":"C4Blade/corrections/#DuctAPE.C4Blade.transonic_drag_addition!-NTuple{4, Any}","page":"Polar Modification","title":"DuctAPE.C4Blade.transonic_drag_addition!","text":"transonic_drag_addition!(\n cd,\n cl,\n clcdmin,\n mach;\n mcrit=0.7,\n cdmfactor=10.0,\n clmfactor=0.25,\n mexp=3.0,\n cdmdd=0.0020,\n cdmstall=0.1000,\n absdx=0.0625,\n blend_hardness=50,\n)\n\nSmoothed, vecotrized, in-place version of transonic_drag_addition.\n\nDifferent Arguments:\n\ncd::AbstractVector{Float} : vector of drag coefficients\ncl::AbstractVector{Float} : vector of lift coefficients\n\nAdditional Keyword Argument:\n\nblend_hardness::Float=50 : hardenss of smoothing blends\n\n\n\n\n\n","category":"method"},{"location":"C4Blade/corrections/#DuctAPE.C4Blade.transonic_drag_addition-NTuple{4, Any}","page":"Polar Modification","title":"DuctAPE.C4Blade.transonic_drag_addition","text":"transonic_drag_addition(\n cd,\n cl,\n clcdmin,\n mach;\n mcrit=0.7,\n cdmfactor=10.0,\n clmfactor=0.25,\n mexp=3.0,\n cdmdd=0.0020,\n cdmstall=0.1000,\n absdx=0.0625,\n)\n\nDrag augmentation due to transonic effects as found in XROTOR and DFDC. Note this is nominally applied to DFDC airfoil evaluation.\n\nArguments:\n\ncd::Float : input drag coefficient\ncl::Float : input lift coefficient\nclcdmin::Float : lift coefficient at minimum drag coefficient.\nmach::Float : Mach number\n\nKeyword Arguments\n\nmcrit::Float=0.7 : critical Mach number\ncdmfactor::Float=10.0 : factor hard coded in XROTOR and DFDC\nclmfactor::Float=0.25 : factor hard coded in XROTOR and DFDC\nmexp::Float=3.0 : factor hard coded in XROTOR and DFDC\ncdmstall::Float=0.1000 : factor hard coded in XROTOR and DFDC\nabsdx::Float=0.0625 : smoothing factor for smooth absolute value function\n\nReturns:\n\ncl_corr:Float : corrected lift coefficient\n\n\n\n\n\n","category":"method"},{"location":"C4Blade/corrections/#DuctAPE.C4Blade.transonic_lift_limiter-NTuple{6, Any}","page":"Polar Modification","title":"DuctAPE.C4Blade.transonic_lift_limiter","text":"transonic_lift_limiter(\n cl,\n mach,\n clcdmin,\n clmax,\n clmin,\n dclda;\n mcrit=0.7,\n dcl_stall=0.1,\n dclda_stall=0.1,\n cdmfactor=10.0,\n clmfactor=0.25,\n mexp=3.0,\n cdmstall=0.1000,\n)\n\nAirfoil polar corrections due to transonic effects as found in XROTOR and DFDC. Note that this correction is done nominally in the DFDC airfoil evaluation.\n\nArguments:\n\ncl::Float : input lift coefficient\nmach::Float : Mach number\nclcdmin::Float : lift coefficient at minimum drag coefficient.\nclmax::Float : maximum lift coefficient\nclmin::Float : minimum lift coefficient\ndclda::Float : lift-curve slope\nmcrit::Float=0.7 : critical Mach number\ndcl_stall::Float=0.1 : cl increment from initial to total stall\ndclda_stall::Float=0.1 : lift curve slope post-stall (1/radians)\ncdmfactor::Float=10.0 : factor hard coded in XROTOR and DFDC\nclmfactor::Float=0.25 : factor hard coded in XROTOR and DFDC\nmexp::Float=3.0 : factor hard coded in XROTOR and DFDC\ncdmstall::Float=0.1000 : factor hard coded in XROTOR and DFDC\n\nReturns:\n\ncl_corr:Float : corrected lift coefficient\n\n\n\n\n\n","category":"method"},{"location":"C4Blade/corrections/#DuctAPE.C4Blade.transonic_lift_limiter_smooth!-NTuple{6, Any}","page":"Polar Modification","title":"DuctAPE.C4Blade.transonic_lift_limiter_smooth!","text":"transonic_lift_limiter_smooth!(\n cl,\n mach,\n clcdmin,\n clmax,\n clmin,\n dclda;\n mcrit=0.7,\n dcl_stall=0.1,\n dclda_stall=0.1,\n cdmfactor=10.0,\n clmfactor=0.25,\n mexp=3.0,\n cdmstall=0.1000,\n blend_hardness=50,\n)\n\nSmoothed, vectorized, in-place version of transonic_lift_limiter.\n\nDifferent Arguments:\n\ncl::AbstractVector{Float} : vector of lift coefficients\n\nAdditional Keyword Argument:\n\nblend_hardness::Float=50 : hardenss of smoothing blends\n\n\n\n\n\n","category":"method"},{"location":"DuctAPE/api/private_postprocess/","page":"Postprocess","title":"Postprocess","text":"DuctAPE.post_process","category":"page"},{"location":"DuctAPE/api/private_postprocess/#DuctAPE.post_process","page":"Postprocess","title":"DuctAPE.post_process","text":"post_process(\n solver_options,\n converged_states,\n prepost_containers,\n solve_container_caching,\n solve_parameter_cache_vector,\n solve_parameter_cache_dims,\n operating_point,\n reference_parameters,\n A_bb_LU,\n airfoils,\n idmaps,\n problem_dimensions,\n multipoint_index;\n write_outputs=options.write_outputs,\n outfile=options.outfile,\n checkoutfileexists=options.checkoutfileexists,\n output_tuple_name=options.output_tuple_name,\n verbose=options.verbose,\n)\n\nPost-process a converged nonlinear solve solution.\n\nArguments\n\nsolver_options::SolverOptionsType : A SolverOptionsType object (also used for dispatch)\nconverged_states::Vector{Float} : the converged state variables\nprepost_containers::NamedTuple : the named tuple containing pre-allocated containers for the pre- and post-processing intermediate calculations\nsolve_container_cache::NamedTuple : the cache and dimensions for intermediate values in the residual calculation\nsolve_parameter_cache_vector::Vector{Float} : the applicably typed cache vector for the solve parameters\nsolve_parameter_cache_dims::NamedTuple : the dimensions of the solver parameters\noperating_point::OperatingPoint : the operating point being analyzed\nreference_parameters::ReferenceParameters : a ReferenceParameters object\nA_bb_LU::LinearAlgebra.LU : LinearAlgebra LU factorization of the LHS matrix\nairfoils::Vector{AFType} : A matrix of airfoil types associated with each of the blade elements\nidmaps::NamedTuple : A named tuple containing index mapping used in bookkeeping throughout solve and post-process\nproblem_dimensions::ProblemDimensions : A ProblemDimensions object\n\nKeyword Arguments\n\nmultipoint_index::Vector{Int} : a one-dimensional vector containing the index of which multipoint analysis operating point is being analyzed.\nwrite_outputs=options.write_outputs::Vector{Bool} : a vector with the same length as number of multipoints indicating if the outputs should be saved.\noutfile=options.outfile::Vector{String} : a vector of file paths/names for where outputs should be written\ncheckoutfileexists=options.checkoutfileexists::Bool : a flag for whether existing files should be checked for or if blind overwriting is okay.\noutput_tuple_name=options.output_tuple_name::Vector{String} : the variable name(s) of the named tuple of outputs to be written.\nverbose::Bool=false : flag to print verbose statements\n\nReturns\n\nouts::NamedTuple : A named tuple containing all the output values including\n\nbodies\npanel_strengths\ntotal_thrust\nthrust_comp\ninduced_efficiency\ncp_in\ncp_out\ncp_casing_in\ncp_casing_out\ncasing_zpts\ncp_nacelle_in\ncp_nacelle_out\nnacelle_zpts\ncp_centerbody_in\ncp_centerbody_out\ncenterbody_zpts\nVtot_in\nVtot_out\nVtot_prejump\nvtot_body\nvtot_jump\nvtot_wake\nvtot_rotors\nVtan_in\nVtan_out\nvtan_casing_in\nvtan_casing_out\nvtan_nacelle_in\nvtan_nacelle_out\nvtan_centerbody_in\nvtan_centerbody_out\nrotors\ncirculation\npanel_strengths\nefficiency\ninviscid_thrust\ninviscid_thrust_dist\nviscous_thrust\nviscous_thrust_dist\nthrust\nCT\ninviscid_torque\ninviscid_torque_dist\nviscous_torque\nviscous_torque_dist\ntorque\nCQ\ninviscid_power\ninviscid_power_dist\nviscous_power\nviscous_power_dist\npower\nCP\ncl\ncd\nalpha\nbeta1\nblade_normal_force_per_unit_span\nblade_tangential_force_per_unit_span\nwake\npanel_strengths\ntotals\nthrust\ntorque\npower\nCT\nCQ\nCP\ntotal_efficiency\nideal_efficiency\nintermediate_solve_values\nvz_rotor\nvtheta_rotor\nCm_wake\nreynolds\nmach\nCz_rotor\nCtheta_rotor\nCmag_rotor\nGamma_tilde\nH_tilde\ndeltaGamma2\ndeltaH\nvz_wake\nvr_wake\nCm_avg\n\n\n\n\n\n","category":"function"},{"location":"DuctAPE/api/private_postprocess/#Velocities","page":"Postprocess","title":"Velocities","text":"","category":"section"},{"location":"DuctAPE/api/private_postprocess/","page":"Postprocess","title":"Postprocess","text":"DuctAPE.get_body_tangential_velocities\nDuctAPE.get_body_tangential_velocities!\nDuctAPE.calculate_vtheta\nDuctAPE.calculate_induced_velocities_on_bodywake","category":"page"},{"location":"DuctAPE/api/private_postprocess/#DuctAPE.get_body_tangential_velocities","page":"Postprocess","title":"DuctAPE.get_body_tangential_velocities","text":"get_body_tangential_velocities(\n gamb,\n gamw,\n sigr,\n ivb,\n Vinf,\n totnode,\n totpanel,\n nnode,\n npanel,\n tangent,\n controlpoints,\n endpanelidxs,\n wake_panel_ids_along_centerbody_wake_interface,\n wake_panel_ids_along_casing_wake_interface,\n centerbody_panel_ids_along_centerbody_wake_interface,\n duct_panel_ids_along_casing_wake_interface,\n num_casing_panels,\n)\n\nGet the tangential velocities along the body surfaces.\n\nArguments\n\ngamb::Vector{Float} : the body panel strengths\ngamw::Vector{Float} : the wake panel strengths\nsigr::Vector{Float} : the rotor panel strengths\nivb::NamedTuple : the unit induced velocities on the bodies\nVinf::Vector{Float} : one element vector containing the freestream magnitude\ntotnode::Int : total number of nodes between all bodies\ntotpanel::Int : total number of panels between all bodies\nnnode::Vector{Int} : number of nodes in each body\nnpanel::Vector{Int} : number of panels in each body.\ntangent::Matrix{Float} : unit tangent vectors for each panel\ncontrolpoints::Matrix{Float} : control point locations for each panel\nendpanelidxs::Matrix{Int} : the indices of the first and last panels for each body\nwake_panel_ids_along_centerbody_wake_interface::Vector{Int} : the indices of the wake panels coincident with the centerbody panels\nwake_panel_ids_along_casing_wake_interface::Vector{Int} : the indices of the wake panels coincident with the duct casing (inner surface) panels\ncenterbody_panel_ids_along_centerbody_wake_interface::Vector{Int} : the indices of the centerbody panels coincident with the wake panels\nduct_panel_ids_along_casing_wake_interface::Vector{Int} : the indices of the duct panels coincident with the wake panels\nnum_casing_panels::Int : the number of panels between the leading and trailing edge of the duct on the duct inner side (casing)\n\nReturns\n\nvtan_tuple::NamedTuple : a named tuple containing the body tangential surface velocities and various useful breakdowns thereof.\n\n\n\n\n\n","category":"function"},{"location":"DuctAPE/api/private_postprocess/#DuctAPE.get_body_tangential_velocities!","page":"Postprocess","title":"DuctAPE.get_body_tangential_velocities!","text":"function getbodytangentialvelocities!( vtantuple, gamb, gamw, sigr, ivb, Vinf, totnode, totpanel, nnode, npanel, tangent, controlpoints, endpanelidxs, wakepanelidsalongcenterbodywakeinterface, wakepanelidsalongcasingwakeinterface, centerbodypanelidsalongcenterbodywakeinterface, ductpanelidsalongcasingwakeinterface, zpts, )\n\nIn-place version of get_body_tangential_velocities.\n\nAdditional Arguments\n\nzpts::NamedTuple : a named tuple containing the z-coordinates of the control points of the duct casing, duct nacelle, and centerbody.\n\n\n\n\n\n","category":"function"},{"location":"DuctAPE/api/private_postprocess/#DuctAPE.calculate_vtheta","page":"Postprocess","title":"DuctAPE.calculate_vtheta","text":"calculate_vtheta(Gamma_tilde, r)\n\nCalculate tangential velocity for a given net circulation and radial location\n\nArguments\n\nGamma_tilde::Matrix{Float} : Sum of upstream circulation values\nr::Matrix{Float} : blade element radial positions\n\n\n\n\n\n","category":"function"},{"location":"DuctAPE/api/private_postprocess/#DuctAPE.calculate_induced_velocities_on_bodywake","page":"Postprocess","title":"DuctAPE.calculate_induced_velocities_on_bodywake","text":"calculate_induced_velocities_on_bodywake(\n vz_w, vr_w, gamw, vz_r, vr_r, sigr, vz_b, vr_b, gamb, Vinf\n)\n\nCalculate the induced velocities on one of the body wakes (unit velocity inputs determine which one)\n\nArguments\n\nvz_w::Matrix{Float} : unit axial induced velocity of the wake onto the body wake\nvr_w::Matrix{Float} : unit radial induced velocity of the wake onto the body wake\ngamw::Vector{Float} : wake panel strengths\nvz_r::Matrix{Float} : unit axial induced velocity of the rotor onto the body wake\nvr_r::Matrix{Float} : unit radial induced velocity of the rotor onto the body wake\nsigr::Vector{Float} : rotor panel strengths\nvz_b::Matrix{Float} : unit axial induced velocity of the bodies onto the body wake\nvr_b::Matrix{Float} : unit radial induced velocity of the bodies onto the body wake\ngamb::Vector{Float} : body panel strengths\nVinf::Vector{Float} : one element vector containing the velocity magnitude\n\n\n\n\n\n","category":"function"},{"location":"DuctAPE/api/private_postprocess/#Pressures","page":"Postprocess","title":"Pressures","text":"","category":"section"},{"location":"DuctAPE/api/private_postprocess/","page":"Postprocess","title":"Postprocess","text":"DuctAPE.steady_cp\nDuctAPE.steady_cp!\nDuctAPE.calculate_entropy_jumps\nDuctAPE.calculate_rotor_jumps\nDuctAPE.delta_cp\nDuctAPE.calculate_body_delta_cp!\nDuctAPE.calculate_bodywake_delta_cp\nDuctAPE.get_body_cps\nDuctAPE.get_body_cps!\nDuctAPE.get_bodywake_cps\nDuctAPE.forces_from_pressure\nDuctAPE.forces_from_pressure!\nDuctAPE.forces_from_TEpanels!","category":"page"},{"location":"DuctAPE/api/private_postprocess/#DuctAPE.steady_cp","page":"Postprocess","title":"DuctAPE.steady_cp","text":"steady_cp(Vs, Vinf, Vref)\n\nCalculate steady pressure coefficients for a given surface velocity.\n\nArguments\n\nVs::Vector{Float} : the surface velocities\nVinf::Vector{Float} : one element vector with freestream mangnitude\nVref::Vector{Float} : one element vector with reference velocity used for non-dimensionalization\n\nReturns\n\ncp::Vector{Float} : the steady pressure coefficients\n\n\n\n\n\n","category":"function"},{"location":"DuctAPE/api/private_postprocess/#DuctAPE.steady_cp!","page":"Postprocess","title":"DuctAPE.steady_cp!","text":"steady_cp!(cp, Vs, Vinf, Vref)\n\nIn-place verison of steady_cp.\n\n\n\n\n\n","category":"function"},{"location":"DuctAPE/api/private_postprocess/#DuctAPE.calculate_entropy_jumps","page":"Postprocess","title":"DuctAPE.calculate_entropy_jumps","text":"calculate_entropy_jumps(sigr, Cz_rotor)\n\nCalculate jumps in entropy across the disks.\n\nArguments\n\nsigr::Matrix{Float} : rotor source panel strengths\nCz_rotor::Vector{Float} : absolute axial velocity on rotor blade elements\n\nReturns\n\ndeltaS::Vector{Float} : entropy jump across rotor disks\n\n\n\n\n\n","category":"function"},{"location":"DuctAPE/api/private_postprocess/#DuctAPE.calculate_rotor_jumps","page":"Postprocess","title":"DuctAPE.calculate_rotor_jumps","text":"calculate_rotor_jumps(Gamr, Omega, B, sigr, Cz_rotor)\n\nCalculate net circulation and enthalpy and entropy disk jumps\n\nArguments\n\nGamr::Matrix{Float} : Blade element circulation strengths\nOmega::Vector{Float} : rotor rotation rates\nB::Vector{Float} : blade count for each rotor (usually integers but could be a float)\nsigr::Matrix{Float} : rotor source panel strengths\nCz_rotor::Vector{Float} : absolute axial velocity on rotor blade elements\n\nReturns\n\nGamma_tilde::Matrix{Float} : net upstream circulation\nHtilde::Matrix{Float} : net upstream enthalpy jumps\nStilde::Matrix{Float} : net upstream entropy jumps\n\n\n\n\n\n","category":"function"},{"location":"DuctAPE/api/private_postprocess/#DuctAPE.delta_cp","page":"Postprocess","title":"DuctAPE.delta_cp","text":"delta_cp(deltaH, deltaS, Ctheta, Vref)\n\nCalculate change in pressure coefficient aft of rotor, due to rotor\n\nArguments\n\ndeltaH::Vector{Float} : Enthalpy jumps across disks\ndeltaS::Vector{Float} : Entropy jumps across disks`\nCtheta::Vector{Float} : tangenetial velocity\nVref::Vector{Float} : reference velocity for non-dimensionalization\n\nReturns\n\ndelta_cp::Vector{Float} : pressure rises due to rotor disks\n\n\n\n\n\n","category":"function"},{"location":"DuctAPE/api/private_postprocess/#DuctAPE.calculate_body_delta_cp!","page":"Postprocess","title":"DuctAPE.calculate_body_delta_cp!","text":"calculate_body_delta_cp!(cp, Gamr, sigr, Cz_rotor, Vref, Omega, B, cpr, casing_panel_ids_aft_of_rotors, centerbody_panel_ids_aft_of_rotors)\n\nAugment surface pressure by change in pressure coefficient due to rotors specifically on the body panels aft of the rotors.\n\nArguments\n\ncp::Vector{Float} : steady pressure coeffients, modified in-place to include rotor effects.\nGamr::Matrix{Float} : Blade element circulation strengths\nsigr::Matrix{Float} : rotor source panel strengths\nCz_rotor::Vector{Float} : absolute axial velocity on rotor blade elements\nVref::Vector{Float} : one element vector with reference velocity used for non-dimensionalization\nOmega::Vector{Float} : rotor rotation rates\nB::Vector{Float} : blade count for each rotor (usually integers but could be a float)\ncpr::Vector{Float} : control point radial positions of body panels\ncasing_panel_ids_aft_of_rotors::Vector{Int} : duct indices of control point radial positions aft of rotors\ncenterbody_panel_ids_aft_of_rotors::Vector{Int} : centerbody indices of control point radial positions aft of rotors\n\n\n\n\n\n","category":"function"},{"location":"DuctAPE/api/private_postprocess/#DuctAPE.calculate_bodywake_delta_cp","page":"Postprocess","title":"DuctAPE.calculate_bodywake_delta_cp","text":"calculate_bodywake_delta_cp(Gamr, sigr, Cz_rotor, Vref, Omega, B, cpr; body=\"duct\")\n\nCalculate change in pressure coefficient due to rotors specifically on the body wakes\n\nArguments\n\nGamr::Matrix{Float} : Blade element circulation strengths\nsigr::Matrix{Float} : rotor source panel strengths\nCz_rotor::Vector{Float} : absolute axial velocity on rotor blade elements\nVref::Vector{Float} : one element vector with reference velocity used for non-dimensionalization\nOmega::Vector{Float} : rotor rotation rates\nB::Vector{Float} : blade count for each rotor (usually integers but could be a float)\ncpr::Vector{Float} : control point radial positions of body wake \"panels\"\n\nKeyword Arguments\n\nbody::String=\"duct\" : flag as to whether the body in question is a duct or centerbody.\n\n\n\n\n\n","category":"function"},{"location":"DuctAPE/api/private_postprocess/#DuctAPE.get_body_cps","page":"Postprocess","title":"DuctAPE.get_body_cps","text":"getbodycps( Vtanin, Vtanout, Gamr, sigr, Czrotor, Vinf, Vref, B, Omega, casingpanelidsaftofrotors, centerbodypanelidsaftof_rotors, controlpoints, endpanelidxs, zpts, )\n\nDescription\n\nArguments\n\nVtan_in::Vector{Float} : Tangential velocity on the inside of the body panels\nVtan_out::Vector{Float} : Tangential velocity on the outside of the body panels\nGamr::Matrix{Float} : Blade element circulation strengths\nsigr::Matrix{Float} : rotor source panel strengths\nCz_rotor::Vector{Float} : absolute axial velocity on rotor blade elements\nVinf::Vector{Float} : one element vector with freestream mangnitude\nVref::Vector{Float} : one element vector with reference velocity used for non-dimensionalization\nB::Vector{Float} : blade count for each rotor (usually integers but could be a float)\nOmega::Vector{Float} : rotor rotation rates\ncasing_panel_ids_aft_of_rotors::Vector{Int} : duct indices of control point radial positions aft of rotors\ncenterbody_panel_ids_aft_of_rotors::Vector{Int} : centerbody indices of control point radial positions aft of rotors\ncontrolpoints::Matrix{Float} : control point locations for each panel\nendpanelidxs::Matrix{Int} : the indices of the first and last panels for each body\nzpts::NamedTuple : a named tuple containing the z-coordinates of the control points of the duct casing, duct nacelle, and centerbody.\n\nReturns\n\ncp_tuple::NamedTuple : body surface velocities and various useful breakdowns thereof.\n\n\n\n\n\n","category":"function"},{"location":"DuctAPE/api/private_postprocess/#DuctAPE.get_body_cps!","page":"Postprocess","title":"DuctAPE.get_body_cps!","text":"get_body_cps!(\n cp_tuple,\n Vtan_in,\n Vtan_out,\n Gamr,\n sigr,\n Cz_rotor,\n Vinf,\n Vref,\n B,\n Omega,\n duct_panel_ids_aft_of_rotors,\n centerbody_panel_ids_aft_of_rotors,\n controlpoints,\n endpanelidxs,\n zpts,\n)\n\nIn-place version of get_body_cps.\n\n\n\n\n\n","category":"function"},{"location":"DuctAPE/api/private_postprocess/#DuctAPE.get_bodywake_cps","page":"Postprocess","title":"DuctAPE.get_bodywake_cps","text":"get_bodywake_cps(\n Gamr,\n vz_w,\n vr_w,\n gamw,\n vz_r,\n vr_r,\n sigr,\n vz_b,\n vr_b,\n gamb,\n panels,\n Cz_rotor,\n Omega,\n B,\n Vinf,\n Vref;\n body=\"duct\",\n)\n\nCalculate the pressure coefficient distributions on one of the body wakes\n\nArguments\n\nGamr::Matrix{Float} : Blade element circulation strengths\nvz_w::Matrix{Float} : unit axial induced velocity of the wake onto the body wake\nvr_w::Matrix{Float} : unit radial induced velocity of the wake onto the body wake\ngamw::Vector{Float} : wake panel strengths\nvz_r::Matrix{Float} : unit axial induced velocity of the rotor onto the body wake\nvr_r::Matrix{Float} : unit radial induced velocity of the rotor onto the body wake\nsigr::Vector{Float} : rotor panel strengths\nvz_b::Matrix{Float} : unit axial induced velocity of the bodies onto the body wake\nvr_b::Matrix{Float} : unit radial induced velocity of the bodies onto the body wake\ngamb::Vector{Float} : body panel strengths\npanels::NamedTuple : A named tuple containing bodywake \"panel\" geometries\nCz_rotor::Vector{Float} : absolute axial velocity on rotor blade elements\nOmega::Vector{Float} : rotor rotation rates\nB::Vector{Float} : blade count for each rotor (usually integers but could be a float)\nVinf::Vector{Float} : one element vector containing the velocity magnitude\nVref::Vector{Float} : one element vector with reference velocity used for non-dimensionalization\n\nKeyword Arguments\n\nbody::String=\"duct\" : flag as to whether the body in question is a duct or centerbody.\n\n\n\n\n\n","category":"function"},{"location":"DuctAPE/api/private_postprocess/#DuctAPE.forces_from_pressure","page":"Postprocess","title":"DuctAPE.forces_from_pressure","text":"forces_from_pressure(cp_in, cp_out, panels; rhoinf=1.225, Vref=1.0)\n\nCalculate dimensional and non-dimensional axial force on a single body\n\nArguments\n\ncp_in::Vector{Float} : pressure coefficient on inside of body surfaces\ncp_out::Vector{Float} : pressure coefficients on outside of body surfaces\npanels::NamedTuple : A named tuple containing panel geometry information\n\nKeyword Arguments\n\nrhoinf::Float=1.225 : reference density for non-dimensionalization\nVref::Float=1.0 : reference velocity for non-dimensionalization\n\nReturns\n\nthrust::Vector{Float} : dimensional axial force\nforce_coeff::Vector{Float} : non-dimensional axial force\n\n\n\n\n\n","category":"function"},{"location":"DuctAPE/api/private_postprocess/#DuctAPE.forces_from_pressure!","page":"Postprocess","title":"DuctAPE.forces_from_pressure!","text":"forces_from_pressure!(CFx, cfx, cp_in, cp_out, panels; rhoinf=1.225, Vref=1.0)\n\nIn-place version of forces_from_pressure.\n\n\n\n\n\n","category":"function"},{"location":"DuctAPE/api/private_postprocess/#DuctAPE.forces_from_TEpanels!","page":"Postprocess","title":"DuctAPE.forces_from_TEpanels!","text":"forces_from_TEpanels!(\n thrust, force_coeff, cp_in, cp_out, panels; rhoinf=1.225, Vref=1.0\n)\n\nAdd force induced by trailing edge gap panels to total forces.\n\nArguments\n\nthrust::Vector{Float} : dimensional axial force\nforce_coeff::Vector{Float} : non-dimensional axial force\ncp_in::Vector{Float} : pressure coefficient on inside of body surfaces\ncp_out::Vector{Float} : pressure coefficients on outside of body surfaces\npanels::NamedTuple : A named tuple containing panel geometry information\n\nKeyword Arguments\n\nrhoinf::Float=1.225 : reference density for non-dimensionalization\nVref::Float=1.0 : reference velocity for non-dimensionalization\n\n\n\n\n\n","category":"function"},{"location":"DuctAPE/api/private_postprocess/#Rotor-Performance","page":"Postprocess","title":"Rotor Performance","text":"","category":"section"},{"location":"DuctAPE/api/private_postprocess/","page":"Postprocess","title":"Postprocess","text":"DuctAPE.inviscid_rotor_thrust\nDuctAPE.inviscid_rotor_thrust!\nDuctAPE.viscous_rotor_thrust\nDuctAPE.viscous_rotor_thrust!\nDuctAPE.inviscid_rotor_torque\nDuctAPE.inviscid_rotor_torque!\nDuctAPE.viscous_rotor_torque\nDuctAPE.viscous_rotor_torque!\nDuctAPE.rotor_power\nDuctAPE.rotor_power!\nDuctAPE.get_total_efficiency\nDuctAPE.get_total_efficiency!\nDuctAPE.get_induced_efficiency\nDuctAPE.get_induced_efficiency!\nDuctAPE.get_ideal_efficiency\nDuctAPE.tqpcoeff\nDuctAPE.tqpcoeff!\nDuctAPE.get_blade_loads\nDuctAPE.get_blade_loads!","category":"page"},{"location":"DuctAPE/api/private_postprocess/#DuctAPE.inviscid_rotor_thrust","page":"Postprocess","title":"DuctAPE.inviscid_rotor_thrust","text":"inviscid_rotor_thrust(Ctheta_rotor, Gamma_tilde, rotor_panel_length, rhoinf)\n\nCalculate inviscid rotor thrust.\n\nArguments\n\nCtheta_rotor::Vector{Float} : Absolute tangential velocity on rotor blade elements\nGamma_tilde::Matrix{Float} : net upstream rotor circulation\nrotor_panel_length::Vector{Float} : dimensional lengths on which blade element values apply\nrhoinf::Float : freestream density\n\nReturns\n\nTinv::Vector{Float} : inviscid dimensional thrust\ndTi::Vector{Float} : inviscid dimensional thrust distribution\n\n\n\n\n\n","category":"function"},{"location":"DuctAPE/api/private_postprocess/#DuctAPE.inviscid_rotor_thrust!","page":"Postprocess","title":"DuctAPE.inviscid_rotor_thrust!","text":"inviscid_rotor_thrust!(\n Tinv, dTi, Ctheta_rotor, Gamma_tilde, rotor_panel_length, rhoinf\n)\n\nIn-place version of inviscid_rotor_thrust.\n\n\n\n\n\n","category":"function"},{"location":"DuctAPE/api/private_postprocess/#DuctAPE.viscous_rotor_thrust","page":"Postprocess","title":"DuctAPE.viscous_rotor_thrust","text":"viscous_rotor_thrust(\n Cz_rotor, Cmag_rotor, B, chord, rotor_panel_length, cd, rhoinf\n)\n\nCalculate visous rotor \"thrust.\"\n\nArguments\n\nCz_rotor::Vector{Float} : Absolute axial velocity on rotor blade elements\nCmag_rotor::Vector{Float} : Absolute inflow velocity magnitude on rotor blade elements\nB::Vector{Float} : blade count for each rotor (usually integers but could be a float)\nchord::Vector{Float} : blade element chord lengths\nrotor_panel_length::Vector{Float} : dimensional lengths on which blade element values apply\ncd::Vector{Float} : drag coefficient for each blade element\nrhoinf::Float : freestream density\n\nReturns\n\nTvisc::Vector{Float} : viscous dimensional thrust\ndTv::Vector{Float} : viscous dimensional thrust distribution\n\n\n\n\n\n","category":"function"},{"location":"DuctAPE/api/private_postprocess/#DuctAPE.viscous_rotor_thrust!","page":"Postprocess","title":"DuctAPE.viscous_rotor_thrust!","text":"viscous_rotor_thrust!(\n Tvisc, dTv, Cz_rotor, Cmag_rotor, B, chord, rotor_panel_length, cd, rhoinf\n)\n\nIn-place version of viscous_rotor_thrust.\n\n\n\n\n\n","category":"function"},{"location":"DuctAPE/api/private_postprocess/#DuctAPE.inviscid_rotor_torque","page":"Postprocess","title":"DuctAPE.inviscid_rotor_torque","text":"inviscid_rotor_torque(\n Cz_rotor, rotor_panel_center, rotor_panel_length, Gamma_tilde, rhoinf\n)\n\nCalculate inviscid rotor torque.\n\nArguments\n\nCz_rotor::Vector{Float} : Absolute axial velocity on rotor blade elements\nrotor_panel_center::Vector{Float} : radial location of rotor blade elements\nrotor_panel_length::Vector{Float} : dimensional lengths on which blade element values apply\nGamma_tilde::Matrix{Float} : net upstream rotor circulation\nrhoinf::Float : freestream density\n\nReturns\n\nQinv::Vector{Float} : inviscid dimensional thrust\ndQi::Vector{Float} : inviscid dimensional thrust distribution\n\n\n\n\n\n","category":"function"},{"location":"DuctAPE/api/private_postprocess/#DuctAPE.inviscid_rotor_torque!","page":"Postprocess","title":"DuctAPE.inviscid_rotor_torque!","text":"inviscid_rotor_torque!(\n Qinv, dQi, Cz_rotor, rotor_panel_center, rotor_panel_length, Gamma_tilde, rhoinf\n)\n\nIn-place version of inviscid_rotor_torque.\n\n\n\n\n\n","category":"function"},{"location":"DuctAPE/api/private_postprocess/#DuctAPE.viscous_rotor_torque","page":"Postprocess","title":"DuctAPE.viscous_rotor_torque","text":"viscous_rotor_torque(\n Ctheta_rotor, Cmag_rotor, B, chord, rotor_panel_center, rotor_panel_length, cd, rhoinf\n)\n\nCalculate viscous rotor torque.\n\nArguments\n\nCtheta_rotor::Vector{Float} : Absolute tangential velocity on rotor blade elements\nCmag_rotor::Vector{Float} : Absolute inflow velocity magnitude on rotor blade elements\nB::Vector{Float} : blade count for each rotor (usually integers but could be a float)\nchord::Vector{Float} : blade element chord lengths\nrotor_panel_center::Vector{Float} : radial location of rotor blade elements\nrotor_panel_length::Vector{Float} : dimensional lengths on which blade element values apply\ncd::Vector{Float} : drag coefficient for each blade element\nrhoinf::Float : freestream density\n\nReturns\n\nQvisc::Vector{Float} : viscous dimensional thrust\ndQv::Vector{Float} : viscous dimensional thrust distribution\n\n\n\n\n\n","category":"function"},{"location":"DuctAPE/api/private_postprocess/#DuctAPE.viscous_rotor_torque!","page":"Postprocess","title":"DuctAPE.viscous_rotor_torque!","text":"viscous_rotor_torque!(\n Qvisc,\n dQv,\n Ctheta_rotor,\n Cmag_rotor,\n B,\n chord,\n rotor_panel_center,\n rotor_panel_length,\n cd,\n rhoinf\n)\n\nIn-place version of viscous_rotor_torque.\n\n\n\n\n\n","category":"function"},{"location":"DuctAPE/api/private_postprocess/#DuctAPE.rotor_power","page":"Postprocess","title":"DuctAPE.rotor_power","text":"rotor_power(Q, dQ, Omega)\n\nCalculate power from torque and rotation rate.\n\nArguments\n\nQ::Vector{Float} : dimensional thrust\ndQ::Vector{Float} : dimensional thrust distribution\nOmega::Vector{Float} : rotor rotation rates\n\nReturns\n\nP::Vector{Float} : dimensional power\ndP::Vector{Float} : dimensional thrust distribution\n\n\n\n\n\n","category":"function"},{"location":"DuctAPE/api/private_postprocess/#DuctAPE.rotor_power!","page":"Postprocess","title":"DuctAPE.rotor_power!","text":"rotor_power!(P, dP, Q, dQ, Omega)\n\nIn-place version of rotor_power.\n\n\n\n\n\n","category":"function"},{"location":"DuctAPE/api/private_postprocess/#DuctAPE.get_total_efficiency","page":"Postprocess","title":"DuctAPE.get_total_efficiency","text":"get_total_efficiency(total_thrust, total_power, Vinf)\n\nGet total efficiency.\n\nArguments\n\ntotal_thrust::Vector{Float} : total thrust\ntotal_power::Vector{Float} : total power\nVinf::Vector{Float} : one element vector freestream velocity magnitude\n\nReturns\n\n`total_efficiency::Vector{Float} : total efficiency\n\n\n\n\n\n","category":"function"},{"location":"DuctAPE/api/private_postprocess/#DuctAPE.get_total_efficiency!","page":"Postprocess","title":"DuctAPE.get_total_efficiency!","text":"get_total_efficiency!(eta, total_thrust, total_power, Vinf)\n\nIn-place version of get_total_efficiency.\n\n\n\n\n\n","category":"function"},{"location":"DuctAPE/api/private_postprocess/#DuctAPE.get_induced_efficiency","page":"Postprocess","title":"DuctAPE.get_induced_efficiency","text":"get_induced_efficiency(Tinv, Tduct, Pinv, Vinf)\n\nGet rotor efficiency induced by presence of the duct.\n\nArguments\n\nTinv::Vector{Float} : inviscid dimensional thrust\nTduct::Vector{Float} : duct thrust\nPinv::Vector{Float} : inviscid dimensional power\nVinf::Vector{Float} : one element vector freestream velocity magnitude\n\nReturns\n\ninduced_efficiency::Vector{Float} : rotor efficiency induced by duct\n\n\n\n\n\n","category":"function"},{"location":"DuctAPE/api/private_postprocess/#DuctAPE.get_induced_efficiency!","page":"Postprocess","title":"DuctAPE.get_induced_efficiency!","text":"get_induced_efficiency!(eta_inv, Tinv, Tduct, Pinv, Vinf)\n\nIn-place version of get_induced_efficiency.\n\n\n\n\n\n","category":"function"},{"location":"DuctAPE/api/private_postprocess/#DuctAPE.get_ideal_efficiency","page":"Postprocess","title":"DuctAPE.get_ideal_efficiency","text":"get_ideal_efficiency(total_thrust, rhoinf, Vinf, Rref)\n\nCompute ducted fan ideal efficiency\n\nArguments\n\ntotal_thrust::Vector{Float} : total thrust from rotors and duct\nrhoinf::Float : freestream density\nVinf::Vector{Float} : one element vector freestream velocity magnitude\nRref::Vector{Float} : one element vector reference rotor tip radius\n\nReturns\n\nideal_efficiency::Vector{Float} : ideal ducted fan efficiency\n\n\n\n\n\n","category":"function"},{"location":"DuctAPE/api/private_postprocess/#DuctAPE.tqpcoeff","page":"Postprocess","title":"DuctAPE.tqpcoeff","text":"tqpcoeff(thrust, torque, power, rhoinf, Omega, Rref)\n\nCalculate non-dimensional thrust, torque, and power coefficients\n\nArguments\n\nthrust::Vector{Float} : dimensional thrust\ntorque::Vector{Float} : dimensional torque\npower::Vector{Float} : dimensional power\nrhoinf::Float : freestream density\nOmega::Vector{Float} : rotor rotation rates\nRref::Vector{Float} : one element vector reference rotor tip radius\n\nReturns\n\nCT::Vector{Float} : thrust coefficient\nCQ::Vector{Float} : torque coefficient\nCP::Vector{Float} : power coefficient\n\n\n\n\n\n","category":"function"},{"location":"DuctAPE/api/private_postprocess/#DuctAPE.tqpcoeff!","page":"Postprocess","title":"DuctAPE.tqpcoeff!","text":"tqpcoeff!(CT, CQ, CP, thrust, torque, power, rhoinf, Omega, Rref)\n\nIn-place version of tqpcoeff.\n\n\n\n\n\n","category":"function"},{"location":"DuctAPE/api/private_postprocess/#DuctAPE.get_blade_loads","page":"Postprocess","title":"DuctAPE.get_blade_loads","text":"get_blade_loads(Cmag_rotor, beta1, cl, cd, chords, rhoinf)\n\nGet loading along blades.\n\nArguments\n\nCmag_rotor::Vector{Float} : blade element inflow magnitudes\nbeta1::Vector{Float} : blade element inflow angles\ncl::Vector{Float} : blade element lift coefficients\ncd::Vector{Float} : blade element drag coefficients\nchords::Vector{Float} : blade element chord lengths\nrhoinf::Vector{Float} : one element freestream density\n\nReturns\n\nNp::Vector{Float} : blade loading per unit length in the normal direction: N'\nTp::Vector{Float} : blade loading per unit length in the tangential direction: T'\n\n\n\n\n\n","category":"function"},{"location":"DuctAPE/api/private_postprocess/#DuctAPE.get_blade_loads!","page":"Postprocess","title":"DuctAPE.get_blade_loads!","text":"get_blade_loads!(Np, Tp, Cmag_rotor, beta1, cl, cd, chords, rhoinf, cache)\n\nIn-place version of get_blade_loads.\n\n\n\n\n\n","category":"function"},{"location":"C4Blade/intro/#C\\textrm{4}Blade-[[C](#)ascade-[C](#)ompatible-[CCBlade](https://flow.byu.edu/CCBlade.jl/stable/)]","page":"Intro","title":"C^textrm4Blade [Cascade Compatible CCBlade]","text":"","category":"section"},{"location":"C4Blade/intro/","page":"Intro","title":"Intro","text":"C^4Blade is a DuctAPE submodule containing a modified version of CCBlade that includes capabilities for cascade types.","category":"page"},{"location":"DuctAPE/theory/#Theory","page":"Theory","title":"Theory","text":"","category":"section"},{"location":"DuctAPE/theory/","page":"Theory","title":"Theory","text":"For a brief overview of the theory behind DuctAPE, see:","category":"page"},{"location":"DuctAPE/theory/","page":"Theory","title":"Theory","text":"Mehr, J. and Ning, A., \"DuctAPE: A steady-state, axisymmetric ducted fan analysis code designed for gradient-based optimization.,\" AIAA Aviation Forum, July 2024.","category":"page"},{"location":"DuctAPE/theory/","page":"Theory","title":"Theory","text":"For a more thorough dive into the details see this pdf document.","category":"page"},{"location":"#DuctAPE.jl-[[Duct](#)ed-[A](#)xisymmetric-[P](#)ropulsor-[E](#)valuation]","page":"Home","title":"DuctAPE.jl [Ducted Axisymmetric Propulsor Evaluation]","text":"","category":"section"},{"location":"","page":"Home","title":"Home","text":"Authors: Judd Mehr,","category":"page"},{"location":"","page":"Home","title":"Home","text":"Contributers: Taylor McDonnell,","category":"page"},{"location":"","page":"Home","title":"Home","text":"DuctAPE is a code for the aerodynamic evaluation of axisymmetric ducted propulsors designed for incompressible (low mach) applications. It is strongly influenced by the underlying theory of Ducted Fan Design Code (DFDC), utilizing a linear axisymmetric vortex panel method for duct and center body, blade element lifting line rotor representation, and wake model axisymmetrically smeared onto an elliptic grid for efficient computation. DuctAPE has been developed specifically for applications in gradient-based optimization settings.","category":"page"},{"location":"#Installation","page":"Home","title":"Installation","text":"","category":"section"},{"location":"","page":"Home","title":"Home","text":"pkg> add DuctAPE","category":"page"},{"location":"#Documentation","page":"Home","title":"Documentation","text":"","category":"section"},{"location":"","page":"Home","title":"Home","text":"Start with Getting Started to get up and running.\nThe Advanced Usage tab includes several pages of additional information for customizing your usage.\nThe API tab contains public and private method descriptions.\nThe Theory tab contain several pages on the underlying theory of DuctAPE.\nThe C^4Blade tab contains documentation for the C^4Blade submodule used for airfoil/cascade management within DuctAPE as well as state initialization.","category":"page"},{"location":"#Citing","page":"Home","title":"Citing","text":"","category":"section"},{"location":"","page":"Home","title":"Home","text":"Mehr, J. and Ning, A., \"DuctAPE: A steady-state, axisymmetric ducted fan analysis code designed for gradient-based optimization.,\" AIAA Aviation Forum, July 2024.","category":"page"},{"location":"DuctAPE/tutorial/#Getting-Started","page":"Getting Started","title":"Getting Started","text":"","category":"section"},{"location":"DuctAPE/tutorial/","page":"Getting Started","title":"Getting Started","text":"Pages = [\"tutorial.md\"]\nDepth = 5","category":"page"},{"location":"DuctAPE/tutorial/","page":"Getting Started","title":"Getting Started","text":"The following is a basic tutorial on how to set up the inputs to, and run, an analysis of a ducted fan in DuctAPE.","category":"page"},{"location":"DuctAPE/tutorial/","page":"Getting Started","title":"Getting Started","text":"include(\"../assets/plots_default.jl\")\ngr()","category":"page"},{"location":"DuctAPE/tutorial/","page":"Getting Started","title":"Getting Started","text":"We begin by loading the package, and optionally create a shorthand name.","category":"page"},{"location":"DuctAPE/tutorial/","page":"Getting Started","title":"Getting Started","text":"using DuctAPE\nconst dt = DuctAPE\nnothing # hide","category":"page"},{"location":"DuctAPE/tutorial/#Assemble-Inputs","page":"Getting Started","title":"Assemble Inputs","text":"","category":"section"},{"location":"DuctAPE/tutorial/","page":"Getting Started","title":"Getting Started","text":"The next step is to create the input object of type Propulsor.","category":"page"},{"location":"DuctAPE/tutorial/","page":"Getting Started","title":"Getting Started","text":"DuctAPE.Propulsor","category":"page"},{"location":"DuctAPE/tutorial/#DuctAPE.Propulsor-DuctAPE-tutorial","page":"Getting Started","title":"DuctAPE.Propulsor","text":"Propulsor(duct_coordinates, centerbody_coordinates, rotorstator_parameters, operating_point, paneling_constants, reference_parameters)\n\nArguments\n\nduct_coordinates::AbstractMatrix : The [z, r] coordinates of the duct geometry beginning at the inner (casing) side trailing edge and proceeding clockwise. Note that the duct geometry absolute radial position does not need to be included here if the autoshiftduct option is selected.\ncenterbody_coordinates::AbstractMatrix : The [z, r] coordinates of the centerbody beginning at the leading edge and ending at the trailing edge. Note that the leading edge is assumed to be placed at a radial distance of 0.0 from the axis of rotation.\noperating_point::OperatingPoint : The operating point values.\npaneling_constants::PanelingConstants : Constants used in re-paneling the geometry.\nrotorstator_parameters::RotorStatorParameters : Rotor (and possibly stator) geometric paramters.\nreference_parameters::ReferenceParameters : Reference Parameters.\n\n\n\n\n\n","category":"type"},{"location":"DuctAPE/tutorial/#Body-Geometry","page":"Getting Started","title":"Body Geometry","text":"","category":"section"},{"location":"DuctAPE/tutorial/","page":"Getting Started","title":"Getting Started","text":"We begin by defining a matrix of coordinates for the duct and another for the centerbody geometries, for example:","category":"page"},{"location":"DuctAPE/tutorial/","page":"Getting Started","title":"Getting Started","text":"duct_coordinates = [\n 0.304466 0.158439\n 0.294972 0.158441\n 0.28113 0.158423\n 0.266505 0.158365\n 0.251898 0.158254\n 0.237332 0.158088\n 0.222751 0.157864\n 0.208123 0.157586\n 0.193399 0.157258\n 0.178507 0.156897\n 0.16349 0.156523\n 0.148679 0.156177\n 0.134222 0.155902\n 0.12 0.155721\n 0.106044 0.155585\n 0.092531 0.155498\n 0.079836 0.155546\n 0.067995 0.155792\n 0.057025 0.156294\n 0.046983 0.157103\n 0.037937 0.158256\n 0.029956 0.159771\n 0.02311 0.161648\n 0.017419 0.163862\n 0.012842 0.166404\n 0.009324 0.169289\n 0.006854 0.172546\n 0.005484 0.176154\n 0.005242 0.180005\n 0.006112 0.184067\n 0.00809 0.188086\n 0.011135 0.192004\n 0.015227 0.19579\n 0.020339 0.199393\n 0.026403 0.202735\n 0.033312 0.205736\n 0.040949 0.208332\n 0.049193 0.210487\n 0.057935 0.212174\n 0.067113 0.21339\n 0.076647 0.214136\n 0.086499 0.214421\n 0.09661 0.214255\n 0.10695 0.213649\n 0.117508 0.212618\n 0.12838 0.211153\n 0.139859 0.209267\n 0.151644 0.207051\n 0.163586 0.204547\n 0.175647 0.201771\n 0.187807 0.198746\n 0.20002 0.19549\n 0.212269 0.192017\n 0.224549 0.188335\n 0.236794 0.18447\n 0.249026 0.180416\n 0.261206 0.176188\n 0.273301 0.171796\n 0.28524 0.16727\n 0.29644 0.162842\n 0.304542 0.159526\n]\nnothing # hide","category":"page"},{"location":"DuctAPE/tutorial/","page":"Getting Started","title":"Getting Started","text":"centerbody_coordinates = [\n 0.0 0.0\n 0.000586 0.005293\n 0.002179 0.010047\n 0.004736 0.014551\n 0.008231 0.018825\n 0.012632 0.022848\n 0.01788 0.026585\n 0.023901 0.030001\n 0.030604 0.033068\n 0.0379 0.035771\n 0.045705 0.038107\n 0.053933 0.040075\n 0.06254 0.04169\n 0.071451 0.042966\n 0.08063 0.043916\n 0.090039 0.044561\n 0.09968 0.044922\n 0.109361 0.044999\n 0.12 0.044952\n 0.135773 0.04495\n 0.151899 0.04493\n 0.16806 0.044913\n 0.184232 0.044898\n 0.200407 0.044882\n 0.21658 0.044866\n 0.232723 0.044847\n 0.248578 0.044839\n 0.262095 0.044564\n 0.274184 0.043576\n 0.285768 0.041795\n 0.296701 0.039168\n 0.306379 0.035928\n]\nnothing # hide","category":"page"},{"location":"DuctAPE/tutorial/","page":"Getting Started","title":"Getting Started","text":"pg = plot(\n duct_coordinates[:, 1],\n duct_coordinates[:, 2];\n aspectratio=1,\n color=1,\n linewidth=2,\n label=\"Duct\",\n xlabel=\"z\",\n ylabel=\"r\",\n legend=:left,\n) # hide\nplot!(\n pg,\n centerbody_coordinates[:, 1],\n centerbody_coordinates[:, 2];\n color=2,\n linewidth=2,\n label=\"Center Body\",\n) # hide","category":"page"},{"location":"DuctAPE/tutorial/","page":"Getting Started","title":"Getting Started","text":"note: Note\nThe body geometry coordinates must be input as columns of z (axial) and r (radial) coordinates, in that order.","category":"page"},{"location":"DuctAPE/tutorial/#Rotor-Geometry","page":"Getting Started","title":"Rotor Geometry","text":"","category":"section"},{"location":"DuctAPE/tutorial/","page":"Getting Started","title":"Getting Started","text":"The next step is to assemble an object of type RotorStatorParameters which contains the geometric information required to define the rotor(s) and their respective blade elements.","category":"page"},{"location":"DuctAPE/tutorial/","page":"Getting Started","title":"Getting Started","text":"DuctAPE.RotorStatorParameters","category":"page"},{"location":"DuctAPE/tutorial/#DuctAPE.RotorStatorParameters-DuctAPE-tutorial","page":"Getting Started","title":"DuctAPE.RotorStatorParameters","text":"RotorStatorParameters(\n B, rotorzloc, r, Rhub, Rtip, chords, twists, tip_gap, airfoils, fliplift\n)\n\nComposite type containing the rotor(s) geometric properties.\n\nNote that the actual struct requires the inputs to be arrays, but there is a constructor function that will take in scalars and automatically build the array-based struct.\n\nArguments\n\nB::AbstractVector{Float} : The number of blades for each rotor. May not be an integer, but usually is.\nrotorzloc::AbstractVector{Float} : Dimensional, axial position of each rotor.\nr::AbstractArray{Float} : Non-dimensional radial locations of each blade element.\nRhub::AbstractVector{Float} : Dimensional hub radius of rotor. (may be changed if it does not match the radial position of the centerbody geometry at the selected rotorzloc.\nRtip::AbstractVector{Float} : Dimensional tip radius of rotor. Is used to determine the radial position of the duct if the autoshiftduct option is selected.\nchords::AbstractArray{Float} : Dimensional chord lengths of the blade elements.\ntwists::AbstractArray{Float} : Blade element angles, in radians.\ntip_gap::AbstractVector{Float} : Currently unused, do not set to anything other than zeros.\nairfoils::AbstractArray{AFType} : Airfoil types describing the airfoil polars for each blade element. Currently only fully tested with C4Blade.DFDCairfoil types.\nfliplift::AbstractVector{Bool} : flag to indicate if the airfoil lift values should be flipped or not.\n\n\n\n\n\n","category":"type"},{"location":"DuctAPE/tutorial/","page":"Getting Started","title":"Getting Started","text":"In this example, we have a single rotor defined as follows.","category":"page"},{"location":"DuctAPE/tutorial/","page":"Getting Started","title":"Getting Started","text":"# number of rotors\nB = 5\n\n# rotor axial location\nrotorzloc = 0.12\n\n# rotor tip radius\nRtip = 0.15572081487373543\n\n# rotor hub radius\nRhub = 0.04495252299071941\n\n# non-dimensional blade element radial stations\nr = [\n 0.050491\n 0.061567\n 0.072644\n 0.083721\n 0.094798\n 0.10587\n 0.11695\n 0.12803\n 0.13911\n 0.15018\n] ./ Rtip\n\n# dimensional chord lengths\nchords = [\n 0.089142\n 0.079785\n 0.0713\n 0.063979\n 0.057777\n 0.052541\n 0.048103\n 0.044316\n 0.041061\n 0.038243\n]\n\n# twist angles (from plane of rotation) in radians\ntwists = [\n 69.012\n 59.142\n 51.825\n 46.272\n 41.952\n 38.509\n 35.699\n 33.354\n 31.349\n 29.596\n] .* pi / 180.0\n\n# DFDC-type airfoil object\nafparams = DuctAPE.c4b.DFDCairfoil(;\n alpha0=0.0,\n clmax=1.5,\n clmin=-1.0,\n dclda=6.28,\n dclda_stall=0.5,\n dcl_stall=0.2,\n cdmin=0.012,\n clcdmin=0.1,\n dcddcl2=0.005,\n cmcon=0.0,\n Re_ref=2e5,\n Re_exp=0.35,\n mcrit=0.7,\n)\n\n# all airfoils are the same\nairfoils = fill(afparams, length(r)) # specify the airfoil array\n\n# assemble rotor parameters\nrotorstator_parameters = dt.RotorStatorParameters(\n [B],\n [rotorzloc],\n r,\n [Rhub],\n [Rtip],\n chords,\n twists,\n [0.0], # currently only zero tip gaps work.\n airfoils,\n [0.0], # can flip the cl lookups on the fly if desired, say, for stator sections\n)\nnothing # hide","category":"page"},{"location":"DuctAPE/tutorial/","page":"Getting Started","title":"Getting Started","text":"plot!(\n pg,\n rotorzloc * ones(length(r)),\n r .* Rtip;\n seriestype=:scatter,\n markersize=3,\n markerstrokewidth=0,\n label=\"Blade Elements\",\n) # hide","category":"page"},{"location":"DuctAPE/tutorial/","page":"Getting Started","title":"Getting Started","text":"note: Airfoils\nAirfoil types for DuctAPE are currently contained in the C4Blade (Cascade Compatible CCBlade) sub-module of DuctAPE which is exported as c4b and also contains the various airfoil evaluation functions used for the blade element lookups. The available airfoil types include all the airfoil types from CCBlade, as well as DFDCairfoil which is an XROTOR-like parametric cascade polar used in DFDC. In addition there are untested cascade types with similar structure to CCBlades airfoil types called DTCascade. Furthermore, there is an experimental actuator disk model implemented via the ADM airfoil type in C4Blade.","category":"page"},{"location":"DuctAPE/tutorial/#Operating-Point","page":"Getting Started","title":"Operating Point","text":"","category":"section"},{"location":"DuctAPE/tutorial/","page":"Getting Started","title":"Getting Started","text":"Next we will assemble the operating point which contains information about the freestream as well as the rotor rotation rate(s).","category":"page"},{"location":"DuctAPE/tutorial/","page":"Getting Started","title":"Getting Started","text":"DuctAPE.OperatingPoint","category":"page"},{"location":"DuctAPE/tutorial/#DuctAPE.OperatingPoint-DuctAPE-tutorial","page":"Getting Started","title":"DuctAPE.OperatingPoint","text":"OperatingPoint(Vinf, rhoinf, muinf, asound, Omega)\n\nPropulsor operating point information.\n\nNote that the actual struct requires the inputs to be arrays, but there is a constructor function that will take in scalars and automatically build the array-based struct.\n\nAlso note that even though each field is required to be a vector, only Omega should have more than one entry, and only then if there are more than one rotor. The purpose behind having vector rather than constant scalar inputs here is for ease of redefinition in an optimization setting when freestream design variables may be present.\n\nArguments\n\nVinf::AbstractVector{Float} : Freestream velocity magnitude (which is only in the axial direction).\nrhoinf::AbstractVector{Float} : Freestream density\nmuinf::AbstractVector{Float} : Freestream viscosity\nasound::AbstractVector{Float} : Freestream speed of sound\nOmega::AbstractVector{Float} : Rotor rototation rate(s)\n\n\n\n\n\n","category":"type"},{"location":"DuctAPE/tutorial/","page":"Getting Started","title":"Getting Started","text":"# Freestream\nVinf = 0.0 # hover condition\nrhoinf = 1.226\nasound = 340.0\nmuinf = 1.78e-5\n\n# Rotation Rate\nRPM = 8000.0\nOmega = RPM * pi / 30 # if using RPM, be sure to convert to rad/s\n\n# utilizing the constructor function to put things in vector types\noperating_point = dt.OperatingPoint(Vinf, rhoinf, muinf, asound, Omega)\nnothing # hide","category":"page"},{"location":"DuctAPE/tutorial/#Paneling-Constants","page":"Getting Started","title":"Paneling Constants","text":"","category":"section"},{"location":"DuctAPE/tutorial/","page":"Getting Started","title":"Getting Started","text":"The PanelingConstants object contains the constants required for DuctAPE to re-panel the provided geometry into a format compatible with the solve structure. The PanelingConstants object is also used to build all of the preallocated caches inside DuctAPE, which can be done up-front if desired. Note that there is some functionality in place for cases when the user wants to keep their own specified geometry, but this functionality should be used with caution and only by users who are certain their provided geometry is in the compatible format. See the Examples for an example.","category":"page"},{"location":"DuctAPE/tutorial/","page":"Getting Started","title":"Getting Started","text":"DuctAPE.PanelingConstants","category":"page"},{"location":"DuctAPE/tutorial/#DuctAPE.PanelingConstants-DuctAPE-tutorial","page":"Getting Started","title":"DuctAPE.PanelingConstants","text":"PanelingConstants(\n nduct_inlet,\n ncenterbody_inlet,\n npanels,\n dte_minus_cbte,\n nwake_sheets,\n wake_length=1.0,\n)\n\nConstants used in re-paneling geometry.\n\nNote that unlike other input structures, this one, in general, does not define fields as vectors. This is because these values should not change throughout an optimization, even if the geometry may change. Otherwise, discontinuities could be experienced.\n\nArguments\n\nnduct_inlet::Int : The number of panels to use for the duct inlet (this number is used for both the casing and nacelle re-paneling)\nncenterbody_inlet::Int : The number of panels to use for the centerbody inlet.\nnpanels::AbstractVector{Int} : A vector containing the number of panels between discrete locations inside the wake. Specifically, the number of panels between the rotors, between the last rotor and the first body trailing edge, between the body trailing edges (if different), and between the last body trailing edge and the end of the wake. The length of this vector should be N+1 (where N is the number of rotors) if the duct and centerbody trailing edges are aligned, and N+2 if not.\ndte_minus_cbte::Float : An indicator concerning the hub and duct trailing edge relative locations. Should be set to -1 if the duct trailing edge axial position minus the centerbody trailing edge axial position is negative, +1 if positive (though any positive or negative number will suffice), and zero if the trailing edges are aligned.\nnwake_sheets::Int : The number of wake sheets to use. Note this will also be setting the number of blade elements to use.\nwake_length::Float=1.0 : Non-dimensional (based on the length from the foremost body leading edge and the aftmost body trailing edge) length of the wake extending behind the aftmost body trailing edge.\n\n\n\n\n\n","category":"type"},{"location":"DuctAPE/tutorial/","page":"Getting Started","title":"Getting Started","text":"# number of panels for the duct inlet\nnduct_inlet = 30\n\n# number of panels for the center body inlet\nncenterbody_inlet = 30\n\n# number of panels from:\n# - rotor to duct trailing edge\n# - duct trailing edge to center body trailing edge\n# - center body trailing edge to end of wake\nnpanels = [30, 1, 30]\n\n# the duct trailing edge is ahead of the centerbody trailing edge.\ndte_minus_cbte = -1.0\n\n# number of wake sheets (one more than blade elements to use)\nnwake_sheets = 11\n\n# non-dimensional wake length aft of rear-most trailing edge\nwake_length = 0.8\n\n# assemble paneling constants\npaneling_constants = dt.PanelingConstants(\n nduct_inlet, ncenterbody_inlet, npanels, dte_minus_cbte, nwake_sheets, wake_length\n)\nnothing # hide","category":"page"},{"location":"DuctAPE/tutorial/#Reference-Parameters","page":"Getting Started","title":"Reference Parameters","text":"","category":"section"},{"location":"DuctAPE/tutorial/","page":"Getting Started","title":"Getting Started","text":"The reference parameters are used in the post-processing non-dimensionalizations.","category":"page"},{"location":"DuctAPE/tutorial/","page":"Getting Started","title":"Getting Started","text":"DuctAPE.ReferenceParameters","category":"page"},{"location":"DuctAPE/tutorial/#DuctAPE.ReferenceParameters-DuctAPE-tutorial","page":"Getting Started","title":"DuctAPE.ReferenceParameters","text":"ReferenceParameters(Vref, Rref)\n\nReference parameters for post-process non-dimensionalization.\n\nNote that the actual struct requires the inputs to be arrays, but there is a constructor function that will take in scalars and automatically build the array-based struct.\n\nArguments\n\nVref::AbstractVector{Float} : Reference velocity.\nRref::AbstractVector{Float} : Reference rotor tip radius.\n\n\n\n\n\n","category":"type"},{"location":"DuctAPE/tutorial/","page":"Getting Started","title":"Getting Started","text":"# reference velocity (close to average axial velocity at rotor in this case)\nVref = 50.0\n\n# reference radius (usually tip radius of rotor)\nRref = Rtip\n\n# assemble reference parameters\nreference_parameters = dt.ReferenceParameters([Vref], [Rref])\nnothing # hide","category":"page"},{"location":"DuctAPE/tutorial/#All-Together","page":"Getting Started","title":"All Together","text":"","category":"section"},{"location":"DuctAPE/tutorial/","page":"Getting Started","title":"Getting Started","text":"We are now posed to construct the Propulsor input type.","category":"page"},{"location":"DuctAPE/tutorial/","page":"Getting Started","title":"Getting Started","text":"# assemble propulsor object\npropulsor = dt.Propulsor(\n duct_coordinates,\n centerbody_coordinates,\n rotorstator_parameters,\n operating_point,\n paneling_constants,\n reference_parameters,\n)\nnothing # hide","category":"page"},{"location":"DuctAPE/tutorial/#Set-Options","page":"Getting Started","title":"Set Options","text":"","category":"section"},{"location":"DuctAPE/tutorial/","page":"Getting Started","title":"Getting Started","text":"The default options should be sufficient for just starting out and are set through the set_options function.","category":"page"},{"location":"DuctAPE/tutorial/","page":"Getting Started","title":"Getting Started","text":"DuctAPE.set_options","category":"page"},{"location":"DuctAPE/tutorial/#DuctAPE.set_options-DuctAPE-tutorial","page":"Getting Started","title":"DuctAPE.set_options","text":"set_options(; kwargs...)\nset_options(multipoint; kwargs...)\n\nSet the options for DuctAPE to use.\n\nNote that the vast majority of the available options are defined through keyword arguments. See the documentation for the various option types for more information.\n\nArguments\n\nmultipoint::AbstractArray{OperatingPoint} : a vector of operating points to use if running a multi-point analysis.\n\n\n\n\n\n","category":"function"},{"location":"DuctAPE/tutorial/","page":"Getting Started","title":"Getting Started","text":"options = dt.set_options()","category":"page"},{"location":"DuctAPE/tutorial/","page":"Getting Started","title":"Getting Started","text":"For more advanced option selection, see the examples and API reference.","category":"page"},{"location":"DuctAPE/tutorial/#Run-a-Single-Analysis","page":"Getting Started","title":"Run a Single Analysis","text":"","category":"section"},{"location":"DuctAPE/tutorial/","page":"Getting Started","title":"Getting Started","text":"With the propulsor input build, and the options selected, we are now ready to run an analysis. This is done simply with the analyze function which dispatches the appropriate analysis, solve, and post-processing functions based on the selected options.","category":"page"},{"location":"DuctAPE/tutorial/","page":"Getting Started","title":"Getting Started","text":"DuctAPE.analyze(::DuctAPE.Propulsor, ::DuctAPE.Options)","category":"page"},{"location":"DuctAPE/tutorial/#DuctAPE.analyze-Tuple{Propulsor, Options}-DuctAPE-tutorial","page":"Getting Started","title":"DuctAPE.analyze","text":"analyze(\n propulsor::Propulsor,\n options::Options=set_options();\n prepost_container_caching=nothing,\n solve_parameter_caching=nothing,\n solve_container_caching=nothing,\n return_inputs=false,\n)\n\nAnalyze propulsor, including preprocessing.\n\nArguments\n\npropulsor::Propulsor : Propulsor input object (see docstring for Propulsor type)\noptions::Options=set_options() : Options object (see set_options and related functions)\n\nKeyword Arguments\n\nprepost_container_caching=nothing : Output of allocate_prepost_container_cache\nsolve_parameter_caching=nothing : Output of allocate_solve_parameter_container_cache\nsolve_container_caching=nothing : Output of allocate_solve_container_cache\nreturn_inputs=false : flag as to whether or not to return the pre-processed inputs\n\nReturns\n\nouts::NamedTuple : Named Tuple of various analysis outputs (see docstring for postprocess for details), note, if linear system decomposition fails, no solve is performed and an empty vector is returned.\nins::NamedTuple : Named Tuple of various pre-processed inputs (e.g. panels and body linear system), will only be returned if return_inputs=true\nconvergence_flag : Flag for successful solve convergence\n\n\n\n\n\n","category":"method"},{"location":"DuctAPE/tutorial/","page":"Getting Started","title":"Getting Started","text":"outs, success_flag = dt.analyze(propulsor, options)\nnothing # hide","category":"page"},{"location":"DuctAPE/tutorial/#Single-Run-Outputs","page":"Getting Started","title":"Single Run Outputs","text":"","category":"section"},{"location":"DuctAPE/tutorial/","page":"Getting Started","title":"Getting Started","text":"There are many outputs contained in the named tuple output from the analyze function (see the post_process() docstring), but some that may be of immediate interest include:","category":"page"},{"location":"DuctAPE/tutorial/","page":"Getting Started","title":"Getting Started","text":"# Total Thrust Coefficient\nouts.totals.CT","category":"page"},{"location":"DuctAPE/tutorial/","page":"Getting Started","title":"Getting Started","text":"# Total Torque Coefficient\nouts.totals.CQ","category":"page"},{"location":"DuctAPE/tutorial/#Run-a-Multi-Point-Analysis","page":"Getting Started","title":"Run a Multi-Point Analysis","text":"","category":"section"},{"location":"DuctAPE/tutorial/","page":"Getting Started","title":"Getting Started","text":"In the case that one wants to run the same geometry at several different operating points, for example: for a range of advance ratios, there is another dispatch of the analyze function that takes in an input, multipoint, that is a vector of operating points.","category":"page"},{"location":"DuctAPE/tutorial/","page":"Getting Started","title":"Getting Started","text":"DuctAPE.analyze(multipoint::AbstractVector{TO},propulsor::Propulsor,options::Options) where TO<:OperatingPoint","category":"page"},{"location":"DuctAPE/tutorial/#DuctAPE.analyze-Union{Tuple{TO}, Tuple{AbstractVector{TO}, Propulsor, Options}} where TO<:OperatingPoint-DuctAPE-tutorial","page":"Getting Started","title":"DuctAPE.analyze","text":"analyze(\n multipoint::AbstractVector{OperatingPoint},\n propulsor::Propulsor,\n options::Options=set_options();\n prepost_container_caching=nothing,\n solve_parameter_caching=nothing,\n solve_container_caching=nothing,\n return_inputs=false,\n)\n\nAnalyze propulsor, including preprocessing, for a set of operating points.\n\nArguments\n\nmultipoint::AbstractVector{OperatingPoint} : Vector of Operating Points at which to analyze the propulsor (note that the operating point within the propulsor input will be overwritten with these)\npropulsor::Propulsor : Propulsor input object\noptions::Options=set_options() : Options object\n\nKeyword Arguments\n\nprepost_container_caching=nothing : Output of allocate_prepost_container_cache\nsolve_parameter_caching=nothing : Output of allocate_solve_parameter_container_cache\nsolve_container_caching=nothing : Output of allocate_solve_container_cache\nreturn_inputs=false : flag as to whether or not to return the pre-processed inputs\n\nReturns\n\nouts::Vector{NamedTuple} : Vector of named tuples of various analysis outputs (see docstring for postprocess for details), note, if linear system decomposition fails, no solve is performed and an empty vector is returned.\nins::NamedTuple : Named Tuple of various pre-processed inputs (e.g. panels and body linear system), will only be returned if return_inputs=true\nconvergence_flag : Flag for successful solve convergence\n\n\n\n\n\n","category":"method"},{"location":"DuctAPE/tutorial/","page":"Getting Started","title":"Getting Started","text":"Running a multi-point analysis on the example geometry given there, it might look something like this:","category":"page"},{"location":"DuctAPE/tutorial/","page":"Getting Started","title":"Getting Started","text":"# - Advance Ratio Range - #\nJs = range(0.0, 2.0; step=0.01)\n\n# - Calculate Vinfs - #\nD = 2.0 * rotorstator_parameters.Rtip[1] # rotor diameter\nn = RPM / 60.0 # rotation rate in revolutions per second\nVinfs = Js * n * D\n\n# - Set Operating Points - #\nops = [deepcopy(operating_point) for i in 1:length(Vinfs)]\nfor (iv, v) in enumerate(Vinfs)\n ops[iv].Vinf[] = v\nend\n\n# - Run Multi-point Analysis - #\nouts_vec, success_flags = DuctAPE.analyze(ops, propulsor, DuctAPE.set_options(ops))\nnothing #hide","category":"page"},{"location":"DuctAPE/tutorial/","page":"Getting Started","title":"Getting Started","text":"There are a few things to note here.","category":"page"},{"location":"DuctAPE/tutorial/","page":"Getting Started","title":"Getting Started","text":"We want to make sure that the operating point objects we put into the input vector are unique instances.\nWe need to use the dispatch of set_options that takes in the operating point vector to set up the right number of things in the background (like convergence flags for each operating point).\nThe outputs of the analysis are vectors of the same outputs for a single analysis.","category":"page"},{"location":"DuctAPE/tutorial/#Multi-point-Outputs","page":"Getting Started","title":"Multi-point Outputs","text":"","category":"section"},{"location":"DuctAPE/tutorial/","page":"Getting Started","title":"Getting Started","text":"For multi-point analysis outputs, which are given as a vector of output objects, we might access and plot things as follows. We also take the opportunity to present some verification against DFDC, showing that DuctAPE matches remarkably well (within 0.5%) of DFDC. We therefore first provide data from DFDC analyses of the above example geometry at various advance ratios.","category":"page"},{"location":"DuctAPE/tutorial/","page":"Getting Started","title":"Getting Started","text":"# Verification Data From DFDC\n\ndfdc_jept = [\n 0.0 0.0 0.64763 0.96692\n 0.1 0.1366 0.64716 0.88394\n 0.2 0.2506 0.6448 0.80785\n 0.3 0.3457 0.64044 0.73801\n 0.4 0.4251 0.63401 0.67382\n 0.5 0.4915 0.62534 0.61468\n 0.6 0.547 0.61428 0.56001\n 0.7 0.5935 0.6006 0.50925\n 0.8 0.6326 0.58411 0.46187\n 0.9 0.6654 0.56452 0.41738\n 1.0 0.693 0.54158 0.37531\n 1.1 0.716 0.51499 0.33522\n 1.2 0.7349 0.48446 0.2967\n 1.3 0.7499 0.44966 0.25937\n 1.4 0.7606 0.41031 0.2229\n 1.5 0.7661 0.36604 0.18694\n 1.6 0.7643 0.31654 0.15121\n 1.7 0.7506 0.26153 0.11547\n 1.8 0.7126 0.20061 0.07941\n 1.9 0.61 0.13355 0.04287\n 2.0 0.1861 0.05993 0.00558\n]\n\ndfdc_J = dfdc_jept[:,1]\ndfdc_eta = dfdc_jept[:,2]\ndfdc_cp = dfdc_jept[:,3]\ndfdc_ct = dfdc_jept[:,4]\nnothing #hide","category":"page"},{"location":"DuctAPE/tutorial/","page":"Getting Started","title":"Getting Started","text":"We can then access the various multi-point analysis outputs however is convenient, we choose a broadcasting approach here:","category":"page"},{"location":"DuctAPE/tutorial/","page":"Getting Started","title":"Getting Started","text":"\n# - extract efficiency, power, and thrust coefficients - #\n# efficiency\neta = (p->p.totals.total_efficiency[1]).(outs_vec)\n# power\ncp = (p->p.totals.CP[1]).(outs_vec)\n# thrust\nct = (p->p.totals.CT[1]).(outs_vec)\nnothing #hide","category":"page"},{"location":"DuctAPE/tutorial/","page":"Getting Started","title":"Getting Started","text":"And then we can plot the data to compare DFDC and DuctAPE.","category":"page"},{"location":"DuctAPE/tutorial/","page":"Getting Started","title":"Getting Started","text":"\n# set up efficiency plot\npe = plot(; xlabel=\"Advance Ratio\", ylabel=\"Efficiency\")\n\n# plot DFDC data\nplot!(\n pe,\n dfdc_J,\n dfdc_eta;\n seriestype=:scatter,\n markersize=5,\n markercolor=plotsgray,\n markerstrokecolor=plotsgray,\n label=\"DFDC\"\n)\n\n# Plot DuctAPE outputs\nplot!(pe, Js, eta; linewidth=2, color=primary, label = \"DuctAPE\")\n\n# setup cp/ct plot\nppt = plot(; xlabel=\"Advance Ratio\")\n\n# plot DFDC data\nplot!(\n ppt,\n dfdc_J,\n dfdc_cp;\n seriestype=:scatter,\n markersize=5,\n markercolor=plotsgray,\n markerstrokecolor=primary,\n markerstrokewidth=2,\n label=\"DFDC Cp\"\n)\nplot!(\n ppt,\n dfdc_J,\n dfdc_ct;\n seriestype=:scatter,\n markersize=5,\n markercolor=plotsgray,\n markerstrokecolor=secondary,\n markerstrokewidth=2,\n label=\"DFDC Ct\"\n)\n\n# plot DuctAPE outputs\nplot!(\n ppt,\n Js,\n cp;\n linewidth=1.5,\n color=primary,\n label=\"DuctAPE Cp\"\n)\nplot!(\n ppt,\n Js,\n ct;\n linewidth=1.5,\n color=secondary,\n label=\"DuctAPE Ct\"\n)\n\nplot(pe, ppt; size=(700,350), layout=(1,2), margin=2mm)","category":"page"},{"location":"DuctAPE/api/api_index/#Index","page":"API Index","title":"Index","text":"","category":"section"},{"location":"DuctAPE/api/api_index/","page":"API Index","title":"API Index","text":"Modules=[DuctAPE]","category":"page"}] +[{"location":"DuctAPE/advanced_usage/outputs/#Available-Outputs","page":"Outputs","title":"Available Outputs","text":"","category":"section"},{"location":"DuctAPE/advanced_usage/outputs/","page":"Outputs","title":"Outputs","text":"The output tuple contains many items. The post_process function docstring lists them:","category":"page"},{"location":"DuctAPE/advanced_usage/outputs/","page":"Outputs","title":"Outputs","text":"DuctAPE.post_process","category":"page"},{"location":"DuctAPE/advanced_usage/outputs/#DuctAPE.post_process-DuctAPE-advanced_usage-outputs","page":"Outputs","title":"DuctAPE.post_process","text":"post_process(\n solver_options,\n converged_states,\n prepost_containers,\n solve_container_caching,\n solve_parameter_cache_vector,\n solve_parameter_cache_dims,\n operating_point,\n reference_parameters,\n A_bb_LU,\n airfoils,\n idmaps,\n problem_dimensions,\n multipoint_index;\n write_outputs=options.write_outputs,\n outfile=options.outfile,\n checkoutfileexists=options.checkoutfileexists,\n output_tuple_name=options.output_tuple_name,\n verbose=options.verbose,\n)\n\nPost-process a converged nonlinear solve solution.\n\nArguments\n\nsolver_options::SolverOptionsType : A SolverOptionsType object (also used for dispatch)\nconverged_states::Vector{Float} : the converged state variables\nprepost_containers::NamedTuple : the named tuple containing pre-allocated containers for the pre- and post-processing intermediate calculations\nsolve_container_cache::NamedTuple : the cache and dimensions for intermediate values in the residual calculation\nsolve_parameter_cache_vector::Vector{Float} : the applicably typed cache vector for the solve parameters\nsolve_parameter_cache_dims::NamedTuple : the dimensions of the solver parameters\noperating_point::OperatingPoint : the operating point being analyzed\nreference_parameters::ReferenceParameters : a ReferenceParameters object\nA_bb_LU::LinearAlgebra.LU : LinearAlgebra LU factorization of the LHS matrix\nairfoils::Vector{AFType} : A matrix of airfoil types associated with each of the blade elements\nidmaps::NamedTuple : A named tuple containing index mapping used in bookkeeping throughout solve and post-process\nproblem_dimensions::ProblemDimensions : A ProblemDimensions object\n\nKeyword Arguments\n\nmultipoint_index::Vector{Int} : a one-dimensional vector containing the index of which multipoint analysis operating point is being analyzed.\nwrite_outputs=options.write_outputs::Vector{Bool} : a vector with the same length as number of multipoints indicating if the outputs should be saved.\noutfile=options.outfile::Vector{String} : a vector of file paths/names for where outputs should be written\ncheckoutfileexists=options.checkoutfileexists::Bool : a flag for whether existing files should be checked for or if blind overwriting is okay.\noutput_tuple_name=options.output_tuple_name::Vector{String} : the variable name(s) of the named tuple of outputs to be written.\nverbose::Bool=false : flag to print verbose statements\n\nReturns\n\nouts::NamedTuple : A named tuple containing all the output values including\n\nbodies\npanel_strengths\ntotal_thrust\nthrust_comp\ninduced_efficiency\ncp_in\ncp_out\ncp_casing_in\ncp_casing_out\ncasing_zpts\ncp_nacelle_in\ncp_nacelle_out\nnacelle_zpts\ncp_centerbody_in\ncp_centerbody_out\ncenterbody_zpts\nVtot_in\nVtot_out\nVtot_prejump\nvtot_body\nvtot_jump\nvtot_wake\nvtot_rotors\nVtan_in\nVtan_out\nvtan_casing_in\nvtan_casing_out\nvtan_nacelle_in\nvtan_nacelle_out\nvtan_centerbody_in\nvtan_centerbody_out\nrotors\ncirculation\npanel_strengths\nefficiency\ninviscid_thrust\ninviscid_thrust_dist\nviscous_thrust\nviscous_thrust_dist\nthrust\nCT\ninviscid_torque\ninviscid_torque_dist\nviscous_torque\nviscous_torque_dist\ntorque\nCQ\ninviscid_power\ninviscid_power_dist\nviscous_power\nviscous_power_dist\npower\nCP\ncl\ncd\nalpha\nbeta1\nblade_normal_force_per_unit_span\nblade_tangential_force_per_unit_span\nwake\npanel_strengths\ntotals\nthrust\ntorque\npower\nCT\nCQ\nCP\ntotal_efficiency\nideal_efficiency\nintermediate_solve_values\nvz_rotor\nvtheta_rotor\nCm_wake\nreynolds\nmach\nCz_rotor\nCtheta_rotor\nCmag_rotor\nGamma_tilde\nH_tilde\ndeltaGamma2\ndeltaH\nvz_wake\nvr_wake\nCm_avg\n\n\n\n\n\n","category":"function"},{"location":"DuctAPE/advanced_usage/outputs/#Returning-the-Pre-process-Objects","page":"Outputs","title":"Returning the Pre-process Objects","text":"","category":"section"},{"location":"DuctAPE/advanced_usage/outputs/","page":"Outputs","title":"Outputs","text":"Sometimes, it may be desireable to return the pre-process objects, including:","category":"page"},{"location":"DuctAPE/advanced_usage/outputs/","page":"Outputs","title":"Outputs","text":"panels which is a named tuple containing the body, rotor, and wake panel objects\nivb which are the unit induced velocities on the body panels\nsolve_parameter_tuple which contains all of the solver parameters\nblade_elements which contains all of the blade element geometry and airfoil information\nlinsys which contains all the linear system objects for the panel method\nidmaps which contains all the index mapping used throughout the solve and post-process.","category":"page"},{"location":"DuctAPE/advanced_usage/outputs/","page":"Outputs","title":"Outputs","text":"In this case, we can use the return_inputs keyword argument when calling the analyze function to return a named tuple containing those pre-process objects.","category":"page"},{"location":"DuctAPE/advanced_usage/outputs/","page":"Outputs","title":"Outputs","text":"outs, ins, success_flag = dt.analyze(propulsor; return_inputs=true)","category":"page"},{"location":"DuctAPE/advanced_usage/manual_repaneling/#Circumventing-the-Automated-Geometry-Re-paneling","page":"-","title":"Circumventing the Automated Geometry Re-paneling","text":"","category":"section"},{"location":"DuctAPE/advanced_usage/manual_repaneling/","page":"-","title":"-","text":"It is not advised to circument the automated geometry re-paneling, but if it must be done, the user needs to provide duct, centerbody, and wake nodes conforming to compatible geometry formatting. The best use case for this is to use previously generated geometry or perhaps geometry exported from DFDC.","category":"page"},{"location":"DuctAPE/advanced_usage/manual_repaneling/","page":"-","title":"-","text":"The process is not simple, but is possible. You would have to manually run the dispatches of precompute_parameters that take in the the repaneled body nodes and wake grid. These dispatches exist for this purpose, but there is, by design, no convenience functions at this time to aid the user in easily bypassing the automated repaneling.","category":"page"},{"location":"DuctAPE/advanced_usage/precompilation/#Pre-compiling-the-Caches","page":"Preallocation","title":"Pre-compiling the Caches","text":"","category":"section"},{"location":"DuctAPE/advanced_usage/precompilation/","page":"Preallocation","title":"Preallocation","text":"There are several available caches that can be precompiled to help speed up multiple analyses. The first is a cache used for intermediate calculations in the pre- and post-processing phases of the analysis. It can be preallocated using allocate_prepost_container_cache","category":"page"},{"location":"DuctAPE/advanced_usage/precompilation/","page":"Preallocation","title":"Preallocation","text":"DuctAPE.allocate_prepost_container_cache","category":"page"},{"location":"DuctAPE/advanced_usage/precompilation/#DuctAPE.allocate_prepost_container_cache-DuctAPE-advanced_usage-precompilation","page":"Preallocation","title":"DuctAPE.allocate_prepost_container_cache","text":"allocate_prepost_container_cache(paneling_constants::PanelingConstants)\nallocate_prepost_container_cache(problem_dimensions::ProblemDimensions)\n\nAllocate the pre- and post-processing cache (used for intermediate calculations) based on paneling constants or problem dimensions.\n\nArguments\n\npaneling_constants::PanelingConstants : a PanelingConstants object\n\nOR\n\nproblem_dimensions::ProblemDimensions : a ProblemDimensions object\n\nKeyword Arguments\n\nfd_chunk_size::Int=12 : chunk size to use for PreallocationTools caches. Note that the automated chuck size for DuctAPE will always be the ForwardDiff threshold of 12 due to the size of the system, so it will be best to leave this at the default unless further development allows for chunk size selection for individual solvers.\nlevels::Int=1 : levels for nested duals. Note that since ImplicitAD is being used for all solves, there should be no need for more than 1 level.\n\nReturns\n\nprepost_container_caching::NamedTuple : a Named Tuple containing:\nprepost_container_cache::PreallocationTools.DiffCache : the cache\nprepost_container_cache_dims::NamedTuple : a named tuple containing the dimensions used for reshaping the cache when needed.\n\n\n\n\n\n","category":"function"},{"location":"DuctAPE/advanced_usage/precompilation/","page":"Preallocation","title":"Preallocation","text":"The second is a cache containing parameters used in the solver, in other words, the results of the pre-processing phase. It can be preallocated using allocate_solve_parameter_cache.","category":"page"},{"location":"DuctAPE/advanced_usage/precompilation/","page":"Preallocation","title":"Preallocation","text":"DuctAPE.allocate_solve_parameter_cache","category":"page"},{"location":"DuctAPE/advanced_usage/precompilation/#DuctAPE.allocate_solve_parameter_cache-DuctAPE-advanced_usage-precompilation","page":"Preallocation","title":"DuctAPE.allocate_solve_parameter_cache","text":"allocate_solve_parameter_cache(\n solve_type::SolverOptionsType,\n paneling_constants::PanelingConstants;\n fd_chunk_size=12,\n levels=1,\n)\nallocate_solve_parameter_cache(\n solve_type::SolverOptionsType,\n problem_dimensions::ProblemDimensions;\n fd_chunk_size=12,\n levels=1\n)\n\nAllocate the solve parameter cache for parameters passed into the solver(s).\n\nArguments\n\nsolve_type::SolverOptionsType : Solver options type used for dispatch\npaneling_constants::PanelingConstants : a PanlingConstants object used for sizing\n\nOR\n\nproblem_dimensions::ProblemDimensions : a ProblemDimensions object used for sizing\n\nKeyword Arguments\n\nfd_chunk_size::Int=12 : chunk size to use for PreallocationTools caches. Note that the automated chuck size for DuctAPE will always be the ForwardDiff threshold of 12 due to the size of the system, so it will be best to leave this at the default unless further development allows for chunk size selection for individual solvers.\nlevels::Int=1 : levels for nested duals. Note that since ImplicitAD is being used for all solves, there should be no need for more than 1 level.\n\nReturns\n\nsolve_parameter_caching::NamedTuple : a Named Tuple containing:\nsolve_parameter_cache::PreallocationTools.DiffCache : the cache\nsolve_parameter_cache_dims::NamedTuple : a named tuple containing the dimensions used for reshaping the cache when needed.\n\n\n\n\n\n","category":"function"},{"location":"DuctAPE/advanced_usage/precompilation/","page":"Preallocation","title":"Preallocation","text":"The final precompileable cache is for intermediate calculations within the solve and can be preallocated using allocate_solve_container_cache","category":"page"},{"location":"DuctAPE/advanced_usage/precompilation/","page":"Preallocation","title":"Preallocation","text":"DuctAPE.allocate_solve_container_cache","category":"page"},{"location":"DuctAPE/advanced_usage/precompilation/#DuctAPE.allocate_solve_container_cache-DuctAPE-advanced_usage-precompilation","page":"Preallocation","title":"DuctAPE.allocate_solve_container_cache","text":"allocate_solve_container_cache(\n solve_type::SolverOptionsType,\n paneling_constants::PanelingConstants;\n fd_chunk_size=12,\n levels=1,\n)\nallocate_solve_container_cache(\n solve_type::SolverOptionsType,\n problem_dimensions::ProblemDimensions;\n fd_chunk_size=12,\n levels=1,\n)\n\nAllocate the solve cache (used for intermediate calculations) based on paneling constants or problem dimensions.\n\nArguments\n\npaneling_constants::PanelingConstants : a PanelingConstants object\n\nOR\n\nproblem_dimensions::ProblemDimensions : a ProblemDimensions object\n\nKeyword Arguments\n\nfd_chunk_size::Int=12 : chunk size to use for PreallocationTools caches. Note that the automated chuck size for DuctAPE will always be the ForwardDiff threshold of 12 due to the size of the system, so it will be best to leave this at the default unless further development allows for chunk size selection for individual solvers.\nlevels::Int=1 : levels for nested duals. Note that since ImplicitAD is being used for all solves, there should be no need for more than 1 level.\n\nReturns\n\nsolve_container_caching::NamedTuple : a Named Tuple containing:\nsolve_container_cache::PreallocationTools.DiffCache : the cache\nsolve_container_cache_dims::NamedTuple : a named tuple containing the dimensions used for reshaping the cache when needed.\n\n\n\n\n\n","category":"function"},{"location":"DuctAPE/advanced_usage/precompilation/","page":"Preallocation","title":"Preallocation","text":"You may run all these simultaneously using the initialize_all_caches function.","category":"page"},{"location":"DuctAPE/advanced_usage/precompilation/","page":"Preallocation","title":"Preallocation","text":"DuctAPE.initialize_all_caches","category":"page"},{"location":"DuctAPE/advanced_usage/precompilation/#DuctAPE.initialize_all_caches-DuctAPE-advanced_usage-precompilation","page":"Preallocation","title":"DuctAPE.initialize_all_caches","text":"initialize_all_caches(solver_options, paneling_constants)\n\nConvenience function to initialize all caches before calling analysis.\n\nArguments\n\nsolver_options::SolverOptionsType : solver options used for cache allocation dispatch\npaneling_constants::PanelingConstants : PanelingConstants object upon which all cache sizing depends\n\nKeyword Arguments\n\nfd_chunk_size::Int=12 : chunk size to use for PreallocationTools caches. Note that the automated chuck size for DuctAPE will always be the ForwardDiff threshold of 12 due to the size of the system, so it will be best to leave this at the default unless further development allows for chunk size selection for individual solvers.\nlevels::Int=1 : levels for nested duals. Note that since ImplicitAD is being used for all solves, there should be no need for more than 1 level.\n\nReturns\n\nprepost_container_caching::NamedTuple : A named tuple containing the PreallocationTools DiffCache and a named tuple with relevant dimensions for accessing the cache.\nsolve_parameter_caching::NamedTuple : A named tuple containing the PreallocationTools DiffCache and a named tuple with relevant dimensions for accessing the cache.\nsolve_container_caching::NamedTuple : A named tuple containing the PreallocationTools DiffCache and a named tuple with relevant dimensions for accessing the cache.\n\n\n\n\n\n","category":"function"},{"location":"DuctAPE/advanced_usage/precompilation/#How-to-pass-the-caches-into-an-analysis","page":"Preallocation","title":"How to pass the caches into an analysis","text":"","category":"section"},{"location":"DuctAPE/advanced_usage/precompilation/","page":"Preallocation","title":"Preallocation","text":"The precompiled caches can be passed in via keyword arguments to the analysis functions. If they are not, they are generated as the first step in the analysis.","category":"page"},{"location":"DuctAPE/advanced_usage/precompilation/","page":"Preallocation","title":"Preallocation","text":"DuctAPE.analyze(\n propulsor::Propulsor,\n options::Options=set_options())","category":"page"},{"location":"DuctAPE/advanced_usage/precompilation/#DuctAPE.analyze-DuctAPE-advanced_usage-precompilation","page":"Preallocation","title":"DuctAPE.analyze","text":"analyze(\n propulsor::Propulsor,\n options::Options=set_options();\n prepost_container_caching=nothing,\n solve_parameter_caching=nothing,\n solve_container_caching=nothing,\n return_inputs=false,\n)\n\nAnalyze propulsor, including preprocessing.\n\nArguments\n\npropulsor::Propulsor : Propulsor input object (see docstring for Propulsor type)\noptions::Options=set_options() : Options object (see set_options and related functions)\n\nKeyword Arguments\n\nprepost_container_caching=nothing : Output of allocate_prepost_container_cache\nsolve_parameter_caching=nothing : Output of allocate_solve_parameter_container_cache\nsolve_container_caching=nothing : Output of allocate_solve_container_cache\nreturn_inputs=false : flag as to whether or not to return the pre-processed inputs\n\nReturns\n\nouts::NamedTuple : Named Tuple of various analysis outputs (see docstring for postprocess for details), note, if linear system decomposition fails, no solve is performed and an empty vector is returned.\nins::NamedTuple : Named Tuple of various pre-processed inputs (e.g. panels and body linear system), will only be returned if return_inputs=true\nconvergence_flag : Flag for successful solve convergence\n\n\n\n\n\n","category":"function"},{"location":"DuctAPE/api/public_api/#Public-API","page":"Public API Reference","title":"Public API","text":"","category":"section"},{"location":"DuctAPE/api/public_api/","page":"Public API Reference","title":"Public API Reference","text":"Pages = [\"public_api.md\"]\nDepth = 5","category":"page"},{"location":"DuctAPE/api/public_api/#Input-Types","page":"Public API Reference","title":"Input Types","text":"","category":"section"},{"location":"DuctAPE/api/public_api/","page":"Public API Reference","title":"Public API Reference","text":"DuctAPE.Propulsor\nDuctAPE.RotorStatorParameters\nDuctAPE.OperatingPoint\nDuctAPE.PanelingConstants\nDuctAPE.ReferenceParameters","category":"page"},{"location":"DuctAPE/api/public_api/#DuctAPE.Propulsor","page":"Public API Reference","title":"DuctAPE.Propulsor","text":"Propulsor(duct_coordinates, centerbody_coordinates, rotorstator_parameters, operating_point, paneling_constants, reference_parameters)\n\nArguments\n\nduct_coordinates::AbstractMatrix : The [z, r] coordinates of the duct geometry beginning at the inner (casing) side trailing edge and proceeding clockwise. Note that the duct geometry absolute radial position does not need to be included here if the autoshiftduct option is selected.\ncenterbody_coordinates::AbstractMatrix : The [z, r] coordinates of the centerbody beginning at the leading edge and ending at the trailing edge. Note that the leading edge is assumed to be placed at a radial distance of 0.0 from the axis of rotation.\noperating_point::OperatingPoint : The operating point values.\npaneling_constants::PanelingConstants : Constants used in re-paneling the geometry.\nrotorstator_parameters::RotorStatorParameters : Rotor (and possibly stator) geometric paramters.\nreference_parameters::ReferenceParameters : Reference Parameters.\n\n\n\n\n\n","category":"type"},{"location":"DuctAPE/api/public_api/#DuctAPE.RotorStatorParameters","page":"Public API Reference","title":"DuctAPE.RotorStatorParameters","text":"RotorStatorParameters(\n B, rotorzloc, r, Rhub, Rtip, chords, twists, tip_gap, airfoils, fliplift\n)\n\nComposite type containing the rotor(s) geometric properties.\n\nNote that the actual struct requires the inputs to be arrays, but there is a constructor function that will take in scalars and automatically build the array-based struct.\n\nArguments\n\nB::AbstractVector{Float} : The number of blades for each rotor. May not be an integer, but usually is.\nrotorzloc::AbstractVector{Float} : Dimensional, axial position of each rotor.\nr::AbstractArray{Float} : Non-dimensional radial locations of each blade element.\nRhub::AbstractVector{Float} : Dimensional hub radius of rotor. (may be changed if it does not match the radial position of the centerbody geometry at the selected rotorzloc.\nRtip::AbstractVector{Float} : Dimensional tip radius of rotor. Is used to determine the radial position of the duct if the autoshiftduct option is selected.\nchords::AbstractArray{Float} : Dimensional chord lengths of the blade elements.\ntwists::AbstractArray{Float} : Blade element angles, in radians.\ntip_gap::AbstractVector{Float} : Currently unused, do not set to anything other than zeros.\nairfoils::AbstractArray{AFType} : Airfoil types describing the airfoil polars for each blade element. Currently only fully tested with C4Blade.DFDCairfoil types.\nfliplift::AbstractVector{Bool} : flag to indicate if the airfoil lift values should be flipped or not.\n\n\n\n\n\n","category":"type"},{"location":"DuctAPE/api/public_api/#DuctAPE.OperatingPoint","page":"Public API Reference","title":"DuctAPE.OperatingPoint","text":"OperatingPoint(Vinf, rhoinf, muinf, asound, Omega)\n\nPropulsor operating point information.\n\nNote that the actual struct requires the inputs to be arrays, but there is a constructor function that will take in scalars and automatically build the array-based struct.\n\nAlso note that even though each field is required to be a vector, only Omega should have more than one entry, and only then if there are more than one rotor. The purpose behind having vector rather than constant scalar inputs here is for ease of redefinition in an optimization setting when freestream design variables may be present.\n\nArguments\n\nVinf::AbstractVector{Float} : Freestream velocity magnitude (which is only in the axial direction).\nrhoinf::AbstractVector{Float} : Freestream density\nmuinf::AbstractVector{Float} : Freestream viscosity\nasound::AbstractVector{Float} : Freestream speed of sound\nOmega::AbstractVector{Float} : Rotor rototation rate(s)\n\n\n\n\n\n","category":"type"},{"location":"DuctAPE/api/public_api/#DuctAPE.PanelingConstants","page":"Public API Reference","title":"DuctAPE.PanelingConstants","text":"PanelingConstants(\n nduct_inlet,\n ncenterbody_inlet,\n npanels,\n dte_minus_cbte,\n nwake_sheets,\n wake_length=1.0,\n)\n\nConstants used in re-paneling geometry.\n\nNote that unlike other input structures, this one, in general, does not define fields as vectors. This is because these values should not change throughout an optimization, even if the geometry may change. Otherwise, discontinuities could be experienced.\n\nArguments\n\nnduct_inlet::Int : The number of panels to use for the duct inlet (this number is used for both the casing and nacelle re-paneling)\nncenterbody_inlet::Int : The number of panels to use for the centerbody inlet.\nnpanels::AbstractVector{Int} : A vector containing the number of panels between discrete locations inside the wake. Specifically, the number of panels between the rotors, between the last rotor and the first body trailing edge, between the body trailing edges (if different), and between the last body trailing edge and the end of the wake. The length of this vector should be N+1 (where N is the number of rotors) if the duct and centerbody trailing edges are aligned, and N+2 if not.\ndte_minus_cbte::Float : An indicator concerning the hub and duct trailing edge relative locations. Should be set to -1 if the duct trailing edge axial position minus the centerbody trailing edge axial position is negative, +1 if positive (though any positive or negative number will suffice), and zero if the trailing edges are aligned.\nnwake_sheets::Int : The number of wake sheets to use. Note this will also be setting the number of blade elements to use.\nwake_length::Float=1.0 : Non-dimensional (based on the length from the foremost body leading edge and the aftmost body trailing edge) length of the wake extending behind the aftmost body trailing edge.\n\n\n\n\n\n","category":"type"},{"location":"DuctAPE/api/public_api/#DuctAPE.ReferenceParameters","page":"Public API Reference","title":"DuctAPE.ReferenceParameters","text":"ReferenceParameters(Vref, Rref)\n\nReference parameters for post-process non-dimensionalization.\n\nNote that the actual struct requires the inputs to be arrays, but there is a constructor function that will take in scalars and automatically build the array-based struct.\n\nArguments\n\nVref::AbstractVector{Float} : Reference velocity.\nRref::AbstractVector{Float} : Reference rotor tip radius.\n\n\n\n\n\n","category":"type"},{"location":"DuctAPE/api/public_api/#Preallocations","page":"Public API Reference","title":"Preallocations","text":"","category":"section"},{"location":"DuctAPE/api/public_api/","page":"Public API Reference","title":"Public API Reference","text":"DuctAPE.allocate_prepost_container_cache\nDuctAPE.allocate_solve_parameter_cache\nDuctAPE.allocate_solve_container_cache","category":"page"},{"location":"DuctAPE/api/public_api/#DuctAPE.allocate_prepost_container_cache","page":"Public API Reference","title":"DuctAPE.allocate_prepost_container_cache","text":"allocate_prepost_container_cache(paneling_constants::PanelingConstants)\nallocate_prepost_container_cache(problem_dimensions::ProblemDimensions)\n\nAllocate the pre- and post-processing cache (used for intermediate calculations) based on paneling constants or problem dimensions.\n\nArguments\n\npaneling_constants::PanelingConstants : a PanelingConstants object\n\nOR\n\nproblem_dimensions::ProblemDimensions : a ProblemDimensions object\n\nKeyword Arguments\n\nfd_chunk_size::Int=12 : chunk size to use for PreallocationTools caches. Note that the automated chuck size for DuctAPE will always be the ForwardDiff threshold of 12 due to the size of the system, so it will be best to leave this at the default unless further development allows for chunk size selection for individual solvers.\nlevels::Int=1 : levels for nested duals. Note that since ImplicitAD is being used for all solves, there should be no need for more than 1 level.\n\nReturns\n\nprepost_container_caching::NamedTuple : a Named Tuple containing:\nprepost_container_cache::PreallocationTools.DiffCache : the cache\nprepost_container_cache_dims::NamedTuple : a named tuple containing the dimensions used for reshaping the cache when needed.\n\n\n\n\n\n","category":"function"},{"location":"DuctAPE/api/public_api/#DuctAPE.allocate_solve_parameter_cache","page":"Public API Reference","title":"DuctAPE.allocate_solve_parameter_cache","text":"allocate_solve_parameter_cache(\n solve_type::SolverOptionsType,\n paneling_constants::PanelingConstants;\n fd_chunk_size=12,\n levels=1,\n)\nallocate_solve_parameter_cache(\n solve_type::SolverOptionsType,\n problem_dimensions::ProblemDimensions;\n fd_chunk_size=12,\n levels=1\n)\n\nAllocate the solve parameter cache for parameters passed into the solver(s).\n\nArguments\n\nsolve_type::SolverOptionsType : Solver options type used for dispatch\npaneling_constants::PanelingConstants : a PanlingConstants object used for sizing\n\nOR\n\nproblem_dimensions::ProblemDimensions : a ProblemDimensions object used for sizing\n\nKeyword Arguments\n\nfd_chunk_size::Int=12 : chunk size to use for PreallocationTools caches. Note that the automated chuck size for DuctAPE will always be the ForwardDiff threshold of 12 due to the size of the system, so it will be best to leave this at the default unless further development allows for chunk size selection for individual solvers.\nlevels::Int=1 : levels for nested duals. Note that since ImplicitAD is being used for all solves, there should be no need for more than 1 level.\n\nReturns\n\nsolve_parameter_caching::NamedTuple : a Named Tuple containing:\nsolve_parameter_cache::PreallocationTools.DiffCache : the cache\nsolve_parameter_cache_dims::NamedTuple : a named tuple containing the dimensions used for reshaping the cache when needed.\n\n\n\n\n\n","category":"function"},{"location":"DuctAPE/api/public_api/#DuctAPE.allocate_solve_container_cache","page":"Public API Reference","title":"DuctAPE.allocate_solve_container_cache","text":"allocate_solve_container_cache(\n solve_type::SolverOptionsType,\n paneling_constants::PanelingConstants;\n fd_chunk_size=12,\n levels=1,\n)\nallocate_solve_container_cache(\n solve_type::SolverOptionsType,\n problem_dimensions::ProblemDimensions;\n fd_chunk_size=12,\n levels=1,\n)\n\nAllocate the solve cache (used for intermediate calculations) based on paneling constants or problem dimensions.\n\nArguments\n\npaneling_constants::PanelingConstants : a PanelingConstants object\n\nOR\n\nproblem_dimensions::ProblemDimensions : a ProblemDimensions object\n\nKeyword Arguments\n\nfd_chunk_size::Int=12 : chunk size to use for PreallocationTools caches. Note that the automated chuck size for DuctAPE will always be the ForwardDiff threshold of 12 due to the size of the system, so it will be best to leave this at the default unless further development allows for chunk size selection for individual solvers.\nlevels::Int=1 : levels for nested duals. Note that since ImplicitAD is being used for all solves, there should be no need for more than 1 level.\n\nReturns\n\nsolve_container_caching::NamedTuple : a Named Tuple containing:\nsolve_container_cache::PreallocationTools.DiffCache : the cache\nsolve_container_cache_dims::NamedTuple : a named tuple containing the dimensions used for reshaping the cache when needed.\n\n\n\n\n\n","category":"function"},{"location":"DuctAPE/api/public_api/#Options","page":"Public API Reference","title":"Options","text":"","category":"section"},{"location":"DuctAPE/api/public_api/#General-Options","page":"Public API Reference","title":"General Options","text":"","category":"section"},{"location":"DuctAPE/api/public_api/","page":"Public API Reference","title":"Public API Reference","text":"DuctAPE.Options\nDuctAPE.set_options","category":"page"},{"location":"DuctAPE/api/public_api/#DuctAPE.Options","page":"Public API Reference","title":"DuctAPE.Options","text":"struct Options{\n TB,\n TBwo,\n TF,\n TI,\n TSf,\n TSt,\n Tin,\n TIo<:IntegrationOptions,\n TSo<:SolverOptionsType,\n WS<:GridSolverOptionsType,\n}\n\nType containing (nearly) all the available user options.\n\nFields\n\nGeneral Options\n\nverbose::TB = false : flag to print verbose statements\nsilence_warnings::TB = true : flag to silence warnings\nmultipoint_index::TI = [1] : holds current index of multi-point solver (no need for user to change this usually)\n\nPre-processing Options\n\nGeometry ee-interpolation and generation options :\n\nfinterp::Tin = FLOWMath.akima : interpolation method used for re-paneling bodies\nautoshiftduct::TB = true : flag as to whether duct geometry should be shifted based on rotor tip location\nlu_decomp_flag::TB = false : flag indicating if panel method LHS matrix factorization was successful\n\npaneling options\n\nitcpshift::TF = 0.05 : factor for internal trailing edge psuedo-panel placement (default is DFDC hard-coded value)\naxistol::TF = 1e-15 : tolerance for how close the the axis of rotation should be considered on the axis\ntegaptol::TF = 1e1 * eps() : tolerance for how large of a trailing edge gap should be considered a gap\n\nIntegration Options\n\nintegration_options::TIo = IntegrationOptions() : integration options\n\nPost-processing Options\n\nwrite_outputs::TBwo = [false] : Bool for whether to write the outputs of the analysis to an external file (slow)\noutfile::TSf = [\"outputs.jl\"] : External output file name (including path information) for files to write\ncheckoutfileexists::TB = false : Flag for whether to check if file exists before overwriting\noutput_tuple_name::TSt = [\"outs\"] : variable name for named tuple written to out file\n\nSolving Options\n\ngrid_solver_options::WS = GridSolverOptions() : elliptic grid solver options\nsolver_options::TSo = ChainSolverOptions() : solver options\n\n\n\n\n\n","category":"type"},{"location":"DuctAPE/api/public_api/#DuctAPE.set_options","page":"Public API Reference","title":"DuctAPE.set_options","text":"set_options(; kwargs...)\nset_options(multipoint; kwargs...)\n\nSet the options for DuctAPE to use.\n\nNote that the vast majority of the available options are defined through keyword arguments. See the documentation for the various option types for more information.\n\nArguments\n\nmultipoint::AbstractArray{OperatingPoint} : a vector of operating points to use if running a multi-point analysis.\n\n\n\n\n\n","category":"function"},{"location":"DuctAPE/api/public_api/#Integration-Options","page":"Public API Reference","title":"Integration Options","text":"","category":"section"},{"location":"DuctAPE/api/public_api/","page":"Public API Reference","title":"Public API Reference","text":"DuctAPE.IntegrationOptions\nDuctAPE.GaussLegendre\nDuctAPE.GaussKronrod\nDuctAPE.Romberg","category":"page"},{"location":"DuctAPE/api/public_api/#DuctAPE.IntegrationOptions","page":"Public API Reference","title":"DuctAPE.IntegrationOptions","text":"struct IntegrationOptions{TN<:IntegrationMethod,TS<:IntegrationMethod}\n\nA struct used to hold the integration options for both the nominal and singular cases.\n\nFields\n\nnominal::IntegrationMethod=GaussLegendre(8) : the integration options to use for the nominal case.\nsingular::IntegrationMethod=GaussLegendre(8) : the integration options to use for the self-induced case.\n\n\n\n\n\n","category":"type"},{"location":"DuctAPE/api/public_api/#DuctAPE.GaussLegendre","page":"Public API Reference","title":"DuctAPE.GaussLegendre","text":"struct GaussLegendre{TN,TW} <: IntegrationMethod\n\nOptions for Gauss-Legendre integration method\n\nFields\n\nsample_points::TN : Sample Points\nweights::TW : Gauss weights\n\n\n\n\n\n","category":"type"},{"location":"DuctAPE/api/public_api/#DuctAPE.GaussKronrod","page":"Public API Reference","title":"DuctAPE.GaussKronrod","text":"struct GaussKronrod{TF,TI} <: IntegrationMethod\n\nOptions for Gauss-Kronrod integration method\n\nFields\n\norder::TI = 7 : order of Legendre polynomial to use on each interval\nmaxevales::TI = 10^7 : maximum number of evaluations in the adaptive method\natol::TF = 0.0 : absolute error tolerance. (note, if zero, QuadGK uses sqrt(eps()) relative tolerance).\n\n\n\n\n\n","category":"type"},{"location":"DuctAPE/api/public_api/#DuctAPE.Romberg","page":"Public API Reference","title":"DuctAPE.Romberg","text":"struct Romberg{TF,TI} <: IntegrationMethod\n\nOptions for Romberg integration method\n\nFields\n\nmax_subdivisions::TI = 10 : maximum number of subdivisions. Note, total number of internvals is 2^N, where N is number of subdivisions.\natol::TF = 1e-6 : absolute error tolerance.\n\n\n\n\n\n","category":"type"},{"location":"DuctAPE/api/public_api/#Solver-Options","page":"Public API Reference","title":"Solver Options","text":"","category":"section"},{"location":"DuctAPE/api/public_api/#Elliptic-Grid-Solve","page":"Public API Reference","title":"Elliptic Grid Solve","text":"","category":"section"},{"location":"DuctAPE/api/public_api/","page":"Public API Reference","title":"Public API Reference","text":"DuctAPE.SLORGridSolverOptions\nDuctAPE.GridSolverOptions","category":"page"},{"location":"DuctAPE/api/public_api/#DuctAPE.SLORGridSolverOptions","page":"Public API Reference","title":"DuctAPE.SLORGridSolverOptions","text":"struct SLORGridSolverOptions{TB,TF,TI} <: GridSolverOptionsType\n\nOptions for SLOR (successive line over relaxation) elliptic grid solver.\n\nFields\n\niteration_limit::TI = 100 : maximum number of iterations\natol::TF = 1e-9 : absolute convergence tolerance\n`converged::AbstractArray{TB} = [false]\n\n\n\n\n\n","category":"type"},{"location":"DuctAPE/api/public_api/#DuctAPE.GridSolverOptions","page":"Public API Reference","title":"DuctAPE.GridSolverOptions","text":"struct GridSolverOptions{TB,TF,TI,TSym} <: GridSolverOptionsType\n\nOptions for SLOR + Newton elliptic grid solver.\n\nFields\n\niteration_limit::TI = 10 : maximum number of iterations\natol::TF = 1e-14 : absolute convergence tolerance\nalgorithm::TSym = :newton : algorithm to use in NLsolve.jl\nautodiff::TSym = :forward : differentiation method to use in NLsolve.jl\nconverged::AbstractArray{TB} = [false]\n\n\n\n\n\n","category":"type"},{"location":"DuctAPE/api/public_api/#Aerodynamics-Solve","page":"Public API Reference","title":"Aerodynamics Solve","text":"","category":"section"},{"location":"DuctAPE/api/public_api/","page":"Public API Reference","title":"Public API Reference","text":"DuctAPE.ChainSolverOptions\nDuctAPE.CompositeSolverOptions\nDuctAPE.NLsolveOptions\nDuctAPE.NonlinearSolveOptions\nDuctAPE.MinpackOptions\nDuctAPE.SIAMFANLEOptions\nDuctAPE.SpeedMappingOptions\nDuctAPE.FixedPointOptions\nDuctAPE.CSORSolverOptions","category":"page"},{"location":"DuctAPE/api/public_api/#DuctAPE.ChainSolverOptions","page":"Public API Reference","title":"DuctAPE.ChainSolverOptions","text":"struct ChainSolverOptions{TB,TS<:Union{ExternalSolverOptions,PolyAlgorithmOptions}} <:PolyAlgorithmOptions\n\nOptions for Chain Solvers (try one solver, if it doesn't converge, try another)\n\nFields\n\n`solvers::AbstractArray{TS} = [ NLsolveOptions(; algorithm=:anderson, atol=1e-12), MinpackOptions(; atol=1e-12), NonlinearSolveOptions(; algorithm=SimpleNonlinearSolve.SimpleNewtonRaphson, atol=1e-12, additional_kwargs=(; autodiff=SimpleNonlinearSolve.AutoForwardDiff()), ), ] : Vector of solver options to use.\nconverged::AbstractArray{TB} = [false] : flag to track if convergence took place.\n\n\n\n\n\n","category":"type"},{"location":"DuctAPE/api/public_api/#DuctAPE.CompositeSolverOptions","page":"Public API Reference","title":"DuctAPE.CompositeSolverOptions","text":"struct CompositeSolverOptions{\n TB,TS<:Union{ExternalSolverOptions,PolyAlgorithmOptions}\n} <: PolyAlgorithmOptions\n\nOptions for Composite Solvers (start with a partial solve of one solve, then finish with another starting where the first left off).\n\nFields\n\n`solvers::AbstractArray{TS} = [ NLsolveOptions(; algorithm=:newton, iteration_limit=3), NLsolveOptions(; algorithm=:anderson, atol=1e-12), ]' : Vector of solver options to use.\nconverged::AbstractArray{TB} = [false] : flag to track if convergence took place.\n\n\n\n\n\n","category":"type"},{"location":"DuctAPE/api/public_api/#DuctAPE.NLsolveOptions","page":"Public API Reference","title":"DuctAPE.NLsolveOptions","text":"struct NLsolveOptions{TB,TF,TK,Tls,Tlsk,TSym} <: ExternalSolverOptions\n\nOptions for the NLsolve pacakge solvers\n\nFields\n\nalgorithm::TSym = :anderson : algorithm to use\nadditional_kwargs::TK = (;) : any additional keyword arguments for the solver\natol::TF = 1e-12 : absolute convergence tolerance\niteration_limit::TF = 25 : maximum number of iterations\nlinesearch_method::Tls = LineSearches.MoreThuente : line search method to use\nlinesearch_kwargs::Tlsk = (;) : any additional lineseach keyword arguments\nconverged::AbstractArray{TB} = [false] : flag to track if convergence took place.\n\n\n\n\n\n","category":"type"},{"location":"DuctAPE/api/public_api/#DuctAPE.NonlinearSolveOptions","page":"Public API Reference","title":"DuctAPE.NonlinearSolveOptions","text":"struct NonlinearSolveOptions{TA,TB,TF,TI,TT} <: ExternalSolverOptions\n\nOptions for the SimpleNonlinearSolve pacakge solvers\n\nFields\n\nalgorithm::TA = SimpleNonlinearSolve.SimpleNewtonRaphson : algorithm to use\nadditional_kwargs::TK = (;) : any additional keyword arguments for the solver\natol::TF = 1e-12 : absolute convergence tolerance\niteration_limit::TF = 25 : maximum number of iterations\nconverged::AbstractArray{TB} = [false] : flag to track if convergence took place.\n\n\n\n\n\n","category":"type"},{"location":"DuctAPE/api/public_api/#DuctAPE.MinpackOptions","page":"Public API Reference","title":"DuctAPE.MinpackOptions","text":"struct MinpackOptions{TB,TF,TI,TSym} <: ExternalSolverOptions\n\nOptions for the MINPACK's HYBRJ solver\n\nFields\n\nalgorithm::TSym = :hybr : algorithm to use in MINPACK.jl (hybr is HYBRJ when the jacobian is provided)\natol::TF = 1e-12 : absolute convergence tolerance\niteration_limit::TF = 100 : maximum number of iterations\nconverged::AbstractArray{TB} = [false] : flag to track if convergence took place.\n\n\n\n\n\n","category":"type"},{"location":"DuctAPE/api/public_api/#DuctAPE.SIAMFANLEOptions","page":"Public API Reference","title":"DuctAPE.SIAMFANLEOptions","text":"struct SIAMFANLEOptions{TA,TB,TF,TI,TK} <: ExternalSolverOptions\n\nOptions for the SIAMFANLEquations pacakge solvers\n\nFields\n\nalgorithm::TA = SIAMFANLEquations.nsoli : algorithm to use\nrtol::TF = 0.0 : relative convergence tolerance\natol::TF = 1e-10 : absolute convergence tolerance\niteration_limit::TF = 1000 : maximum number of iterations\nlinear_iteration_limit::TF = 5 : maximum number of linear solve iterations (GMRES)\nadditional_kwargs::TK = (;) : any additional keyword arguments for the solver\nconverged::AbstractArray{TB} = [false] : flag to track if convergence took place.\n\n\n\n\n\n","category":"type"},{"location":"DuctAPE/api/public_api/#DuctAPE.SpeedMappingOptions","page":"Public API Reference","title":"DuctAPE.SpeedMappingOptions","text":"struct SpeedMappingOptions{TB,TF,TI,TL,TSm,TU} <: ExternalSolverOptions\n\nOptions for the SpeedMapping.jl package solver\n\nFields\n\n`orders::AbstractArray{TI} = [3, 2]\nsig_min::TSm = 0 : maybe set to 1?\nstabilize::TB = false : stabilizes before extrapolation\ncheck_obj::TB = false : checks for inf's and nan's and starts from previous finite point\natol::TF = 1e-10 : absolute convergence tolerance\niteration_limit::TF = 1000 : maximum number of iterations\ntime_limit::TF = Inf : time limit in seconds\nlower::TL = nothing : box lower bounds\nupper::TU = nothing : box upper bounds\nbuffer::TF = 0.01 : if using bounds, buffer brings x inside bounds by buffer amountd\nLp::TF = Inf : p value for p-norm for convergence criteria\nconverged::AbstractArray{TB} = [false] : flag to track if convergence took place.\n\n\n\n\n\n","category":"type"},{"location":"DuctAPE/api/public_api/#DuctAPE.FixedPointOptions","page":"Public API Reference","title":"DuctAPE.FixedPointOptions","text":"struct FixedPointOptions{TB,TF,TI} <: ExternalSolverOptions\n\nOptions for the FixedPoint.jl package solver\n\nFields\n\niteration_limit::TF = 1000 : maximum number of iterations\nvel::TF = 0.9 : vel keyword argument, default is package default\nep::TF = 0.01 : ep keyword argument, default is package default\natol::TF = 1e-12 : absolute convergence tolerance\nconverged::AbstractArray{TB} = [false] : flag to track if convergence took place.\n\n\n\n\n\n","category":"type"},{"location":"DuctAPE/api/public_api/#DuctAPE.CSORSolverOptions","page":"Public API Reference","title":"DuctAPE.CSORSolverOptions","text":"struct CSORSolverOptions{TB,TC<:ConvergenceType,TF,TS} <: SolverOptionsType\n\nType containing all the options for the CSOR (controlled successive over relaxation) solver.\n\nNote that the defaults match DFDC with the exception of the relaxation schedule, which is an experimental feature.\n\nFields\n\nvar::type :\nverbose::TB = false : flag to print verbose statements\niteration_limit::TF = 1e2 : maximum number of iterations\nnrf::TF = 0.4 : nominal relaxation factor\nbt1::TF = 0.2 : backtracking factor 1\nbt2::TF = 0.6 : backtracking factor 2\npf1::TF = 0.4 : press forward factor 1\npf2::TF = 0.5 : press forward factor 2\nbtw::TF = 0.6 : backtracking factor for wake\npfw::TF = 1.2 : press forward factor for wake\nrelaxation_schedule::TS = [[0.0;1e-14;1e-13;1e10]), [1.0;1.0;0.0;0.0])] : values used in spline definition for scaling the relaxation factors (second vector) after various convergence values (first vector).\nf_circ::TF = 1e-3 : convergence tolerance for rotor circulation\nf_dgamw::TF = 2e-4 : convergence tolerance for wake vortex strength\nconvergence_type::TC = Relative() : dispatch for relative or absolute convergence criteria.\nVconv::AbstractArray{TF} = [1.0] : velocity used in relative convergence criteria (should be set to Vref).\nconverged::AbstractArray{TB} = [false] : flag to track if convergence took place.\n\n\n\n\n\n","category":"type"},{"location":"DuctAPE/api/public_api/#Preprocess","page":"Public API Reference","title":"Preprocess","text":"","category":"section"},{"location":"DuctAPE/api/public_api/","page":"Public API Reference","title":"Public API Reference","text":"DuctAPE.setup_analysis","category":"page"},{"location":"DuctAPE/api/public_api/#DuctAPE.setup_analysis","page":"Public API Reference","title":"DuctAPE.setup_analysis","text":"setup_analysis(\n propulsor::Propulsor,\n options::Options=set_options();\n prepost_container_caching=nothing,\n solve_parameter_caching=nothing,\n solve_container_caching=nothing,\n)\n\nPerform pre-processing and cache setup (as needed) for propuslor analysis.\n\nArguments\n\npropulsor::Propulsor : Propulsor input object (see docstring for Propulsor type)\noptions::Options=set_options() : Options object (see set_options and related functions)\n\nKeyword Arguments\n\nprepost_container_caching=nothing : Output of allocate_prepost_container_cache\nsolve_parameter_caching=nothing : Output of allocate_solve_parameter_container_cache\nsolve_container_caching=nothing : Output of allocate_solve_container_cache\n\nReturns\n\nproblem_dimensions::NamedTuple : Named Tuple contiaining bookkeeping information (problem dimensions)\nprepost_containers::NamedTuple : Named Tuple containing reshaped views into the prepost cache\nsolve_parameter_cache_vector::Vector : Vector containing the relevant typed cache vector of solve parameters\nsolve_parameter_cache_dims::NamedTuple : Named Tuple containing dimensions used for reshaping the solve parameter cache\nA_bb_LU::LinearAlgebra.LU : The LU factorization of the AIC matrix used in the panel method\nlu_decomp_flag::Bool : flag indicating if the LU decomposition was successful\nairfoils::Matrix{AFType} : Matrix contiaining the blade element airfoil polar objects\nidmaps::NamedTuple : Named Tuple containing bookkeeping information (index mappings)\n\n\n\n\n\n","category":"function"},{"location":"DuctAPE/api/public_api/#Analysis","page":"Public API Reference","title":"Analysis","text":"","category":"section"},{"location":"DuctAPE/api/public_api/","page":"Public API Reference","title":"Public API Reference","text":"DuctAPE.analyze","category":"page"},{"location":"DuctAPE/api/public_api/#DuctAPE.analyze","page":"Public API Reference","title":"DuctAPE.analyze","text":"analyze(\n propulsor::Propulsor,\n options::Options=set_options();\n prepost_container_caching=nothing,\n solve_parameter_caching=nothing,\n solve_container_caching=nothing,\n return_inputs=false,\n)\n\nAnalyze propulsor, including preprocessing.\n\nArguments\n\npropulsor::Propulsor : Propulsor input object (see docstring for Propulsor type)\noptions::Options=set_options() : Options object (see set_options and related functions)\n\nKeyword Arguments\n\nprepost_container_caching=nothing : Output of allocate_prepost_container_cache\nsolve_parameter_caching=nothing : Output of allocate_solve_parameter_container_cache\nsolve_container_caching=nothing : Output of allocate_solve_container_cache\nreturn_inputs=false : flag as to whether or not to return the pre-processed inputs\n\nReturns\n\nouts::NamedTuple : Named Tuple of various analysis outputs (see docstring for postprocess for details), note, if linear system decomposition fails, no solve is performed and an empty vector is returned.\nins::NamedTuple : Named Tuple of various pre-processed inputs (e.g. panels and body linear system), will only be returned if return_inputs=true\nconvergence_flag : Flag for successful solve convergence\n\n\n\n\n\nanalyze(\n propulsor::Propulsor,\n prepost_containers,\n solve_parameter_cache_vector,\n solve_parameter_cache_dims,\n airfoils,\n A_bb_LU,\n idmaps,\n problem_dimensions,\n options::Options=set_options();\n return_inputs=false,\n solve_container_caching=nothing,\n)\n\nAnalyze propulsor, assuming setup_analysis has been called and the outputs thereof are being passed in here.\n\nArguments\n\npropulsor::Propulsor : Propulsor input object\nprepost_containers::NamedTuple : An output from setup_analysis containing reshaped views into the prepost cache\nsolve_parameter_cache_vector::Vector : An output from setup_analysis containing the relevant typed cache vector of solve parameters\nsolve_parameter_cache_dims::NamedTuple : An output from setup_analysis containing dimensions used for reshaping the solve parameter cache\nairfoils::Vector{AFType} : An output from setup_analysis contiaining the blade element airfoil polar objects\nA_bb_LU::LinearAlgebra.LU : An output from setup_analysis that is the LU decomposition of the AIC matrix used in the panel method\nidmaps::NamedTuple : An output from setup_analysis containing bookkeeping information (index mappings)\nproblem_dimensions::NamedTuple : An output from setup_analysis contiaining bookkeeping information (problem dimensions)\noptions::Options=set_options() : Options object\n\nKeyword Arguments\n\nsolve_container_caching=nothing : Output of allocate_solve_container_cache\nreturn_inputs=false : flag as to whether or not to return the pre-processed inputs\n\nReturns\n\nouts::NamedTuple : Named Tuple of various analysis outputs (see docstring for postprocess for details), note, if linear system decomposition fails, no solve is performed and an empty vector is returned.\nins::NamedTuple : Named Tuple of various pre-processed inputs (e.g. panels and body linear system), will only be returned if return_inputs=true\nconvergence_flag : Flag for successful solve convergence\n\n\n\n\n\nanalyze(\n multipoint::AbstractVector{OperatingPoint},\n propulsor::Propulsor,\n options::Options=set_options();\n prepost_container_caching=nothing,\n solve_parameter_caching=nothing,\n solve_container_caching=nothing,\n return_inputs=false,\n)\n\nAnalyze propulsor, including preprocessing, for a set of operating points.\n\nArguments\n\nmultipoint::AbstractVector{OperatingPoint} : Vector of Operating Points at which to analyze the propulsor (note that the operating point within the propulsor input will be overwritten with these)\npropulsor::Propulsor : Propulsor input object\noptions::Options=set_options() : Options object\n\nKeyword Arguments\n\nprepost_container_caching=nothing : Output of allocate_prepost_container_cache\nsolve_parameter_caching=nothing : Output of allocate_solve_parameter_container_cache\nsolve_container_caching=nothing : Output of allocate_solve_container_cache\nreturn_inputs=false : flag as to whether or not to return the pre-processed inputs\n\nReturns\n\nouts::Vector{NamedTuple} : Vector of named tuples of various analysis outputs (see docstring for postprocess for details), note, if linear system decomposition fails, no solve is performed and an empty vector is returned.\nins::NamedTuple : Named Tuple of various pre-processed inputs (e.g. panels and body linear system), will only be returned if return_inputs=true\nconvergence_flag : Flag for successful solve convergence\n\n\n\n\n\nanalyze(\n multipoint::Vector{OperatingPoint},\n propulsor::Propulsor,\n prepost_containers,\n solve_parameter_cache_vector,\n solve_parameter_cache_dims,\n airfoils,\n A_bb_LU,\n idmaps,\n problem_dimensions,\n options::Options=set_options();\n return_inputs=false,\n solve_container_caching=nothing,\n)\n\nAnalyze propulsor, assuming setup_analysis has been called and the inputs are being passed in here.\n\nArguments\n\nmultipoint::AbstractVector{OperatingPoint} : Vector of Operating Points at which to analyze the propulsor (note that the operating point within the propulsor input will be overwritten with these)\npropulsor::Propulsor : Propulsor input object\nprepost_containers::NamedTuple : An output from setup_analysis containing reshaped views into the prepost cache\nsolve_parameter_cache_vector::Vector : An output from setup_analysis containing the relevant typed cache vector of solve parameters\nsolve_parameter_cache_dims::NamedTuple : An output from setup_analysis containing dimensions used for reshaping the solve parameter cache\nairfoils::Vector{AFType} : An output from setup_analysis contiaining the blade element airfoil polar objects\nA_bb_LU::LinearAlgebra.LU : An output from setup_analysis that is the LU decomposition of the AIC matrix used in the panel method\nidmaps::NamedTuple : An output from setup_analysis containing bookkeeping information (index mappings)\nproblem_dimensions::NamedTuple : An output from setup_analysis contiaining bookkeeping information (problem dimensions)\noptions::Options=set_options() : Options object\n\nKeyword Arguments\n\nsolve_container_caching=nothing : Output of allocate_solve_container_cache\nreturn_inputs=false : flag as to whether or not to return the pre-processed inputs\n\nReturns\n\nouts::Vector{NamedTuple} : Named Tuple of various analysis outputs (see docstring for postprocess for details), note, if linear system decomposition fails, no solve is performed and an empty vector is returned.\nins::NamedTuple : Named Tuple of various pre-processed inputs (e.g. panels and body linear system), will only be returned if return_inputs=true. Note that some inputs will be overwritten (e.g. the linear system RHS components related to the freestream) and only those associated with the final operating point will be returned.\nconvergence_flag : Flag for successful solve convergence\n\n\n\n\n\n","category":"function"},{"location":"DuctAPE/api/public_api/#Miscellaneous","page":"Public API Reference","title":"Miscellaneous","text":"","category":"section"},{"location":"DuctAPE/api/public_api/#Airfoil/Geometry-Manipulation","page":"Public API Reference","title":"Airfoil/Geometry Manipulation","text":"","category":"section"},{"location":"DuctAPE/api/public_api/#NACA-6-Series-Cascade-Geometry-Generation","page":"Public API Reference","title":"NACA 6-Series Cascade Geometry Generation","text":"","category":"section"},{"location":"DuctAPE/api/private_utilities/#Utility-Functions","page":"Utilities","title":"Utility Functions","text":"","category":"section"},{"location":"DuctAPE/api/private_utilities/","page":"Utilities","title":"Utilities","text":"DuctAPE.promote_propulsor_type\nDuctAPE.update_operating_point!\nDuctAPE.isscalar\nDuctAPE.dot\nDuctAPE.norm\nDuctAPE.cross2mag\nDuctAPE.linear_transform\nDuctAPE.extract_primals!\nDuctAPE.lfs\nDuctAPE.reset_containers!\nDuctAPE.cache_dims!\nDuctAPE.write_data","category":"page"},{"location":"DuctAPE/api/private_utilities/#DuctAPE.promote_propulsor_type","page":"Utilities","title":"DuctAPE.promote_propulsor_type","text":"promote_propulsor_type(propulsor)\n\nConvenience function for promoting types based on any potential elements of the propulsor object dependent on optimization design variables.\n\nArguments\n\npropulsor::Propulsor : the propulsor input\n\nReturns\n\nTP::Type : the promoted type\n\n\n\n\n\n","category":"function"},{"location":"DuctAPE/api/private_utilities/#DuctAPE.update_operating_point!","page":"Utilities","title":"DuctAPE.update_operating_point!","text":"update_operating_point!(op_old, op_new)\n\nOverwrites all the values of an OperatingPoint object with another OperatingPoint object's values (or NamedTuple with the same field names).\n\nArguments\n\nop_old::OperatingPoint : the OperatingPoint to be overwritten (can also be a NamedTuple with the same field names as an OperatingPoint).\nop_new::OperatingPoint : the OperatingPoint values to be used (can also be a NamedTuple with the same field names as an OperatingPoint).\n\n\n\n\n\n","category":"function"},{"location":"DuctAPE/api/private_utilities/#DuctAPE.isscalar","page":"Utilities","title":"DuctAPE.isscalar","text":"isscalar(x::T) where {T} = isscalar(T)\nisscalar(::Type{T}) where {T} = BroadcastStyle(T) isa Broadcast.DefaultArrayStyle{0}\n\nDetermines if the input is a scalar. Note that Base.BroadcastStyle is imported.\n\n\n\n\n\n","category":"function"},{"location":"DuctAPE/api/private_utilities/#DuctAPE.dot","page":"Utilities","title":"DuctAPE.dot","text":"dot(A, B) = sum(a * b for (a, b) in zip(A, B))\n\nA faster dot product.\n\n\n\n\n\n","category":"function"},{"location":"DuctAPE/api/private_utilities/#DuctAPE.norm","page":"Utilities","title":"DuctAPE.norm","text":"norm(A) = sqrt(mapreduce(x -> x^2, +, A))\n\nA faster 2-norm.\n\n\n\n\n\n","category":"function"},{"location":"DuctAPE/api/private_utilities/#DuctAPE.cross2mag","page":"Utilities","title":"DuctAPE.cross2mag","text":"cross2mag(A, B) = A[1] * B[2] - A[2] * B[1]\n\n2D \"cross product\" magnitude\n\n\n\n\n\n","category":"function"},{"location":"DuctAPE/api/private_utilities/#DuctAPE.linear_transform","page":"Utilities","title":"DuctAPE.linear_transform","text":"linear_transform(range1, range2, values)\n\nLinear transfrom of values from range (source_range[1], source_range[end]) to (target_range[1], target_range[end])\n\nArguments\n\nsource_range::Vector{Float} : range values come from (can also be a Tuple)\ntarget_range::Vector{Float} : range onto which we are transforming (can also be a Tuple)\nsource_values::Array{Float} : array of source values to transform\n\nReturns\n\ntarget_values::Array{Float} : array of transformed sourcevalues onto target range\n\n\n\n\n\n","category":"function"},{"location":"DuctAPE/api/private_utilities/#DuctAPE.extract_primals!","page":"Utilities","title":"DuctAPE.extract_primals!","text":"extract_primals!(Avalue, A::AbstractMatrix{T}) where {T}\n\nExtracts primals of A and places them in Avalue.\n\n\n\n\n\n","category":"function"},{"location":"DuctAPE/api/private_utilities/#DuctAPE.lfs","page":"Utilities","title":"DuctAPE.lfs","text":"lfs(shape)\n\nDetermines length from shape (output of size function).\n\n\n\n\n\n","category":"function"},{"location":"DuctAPE/api/private_utilities/#DuctAPE.reset_containers!","page":"Utilities","title":"DuctAPE.reset_containers!","text":"reset_containers!(containers; exception_keys=[])\n\nResets all fields (not incluing any contained in exception keys) of containers–-which must be arrays, structs of arrays, or tuples of arrays–-to zeros.\n\n\n\n\n\n","category":"function"},{"location":"DuctAPE/api/private_utilities/#DuctAPE.cache_dims!","page":"Utilities","title":"DuctAPE.cache_dims!","text":"cache_dims!(total_length, l, s)\n\nA function that returns a named tuple containing an index range and shape and increases total_length by l.\n\nThis function is used heavily in the cache allocation functions for setting up the dimension maps used to access the vectorized caches.\n\nArguments\n\ntotal_length::Vector{Int} : single element vector containing the current total length of the eventual cache vector. Modified in place.\nl::Int : total length of the object in question\ns::Int : size of the object in question\n\nReturns\n\ndims::NamedTuple : A named tuple containing index and shape fields\n\n\n\n\n\n","category":"function"},{"location":"DuctAPE/api/private_utilities/#DuctAPE.write_data","page":"Utilities","title":"DuctAPE.write_data","text":"write_data(outs, filename; checkoutfileexists=false)\n\nWrites NamedTuples, specifically for writing out the output of the post_procces() function.\n\nArguments:\n\nouts::NamedTuple : Named tuple to write to file.\nfilename::String : file name (including full desired path and file type) for file to write\n\nKeyword Arguments:\n\noutput_tuple_name::String : desired variable name of written NamedTuple\ncheckoutfileexists::Bool=false : boolean for whether to check if the outfile already exists and whether or not to overwrite it.\n\n\n\n\n\n","category":"function"},{"location":"DuctAPE/api/private_process/#Analysis","page":"Process","title":"Analysis","text":"","category":"section"},{"location":"DuctAPE/api/private_process/","page":"Process","title":"Process","text":"DuctAPE.analyze_multipoint","category":"page"},{"location":"DuctAPE/api/private_process/#DuctAPE.analyze_multipoint","page":"Process","title":"DuctAPE.analyze_multipoint","text":"analyze_multipoint(\n operating_point::OperatingPoint,\n propulsor::Propulsor,\n prepost_containers,\n solve_parameter_cache_vector,\n solve_parameter_cache_dims,\n airfoils,\n A_bb_LU,\n idmaps,\n problem_dimensions,\n options::Options;\n solve_container_caching=nothing,\n return_inputs=false,\n)\n\nIdentical to the single analyze function assuming setup_analysis has been called; except here we are running a single operating point for a multipoint analysis, and overwriting the operating point in the propulsor with the explicit operating point input.\n\n\n\n\n\n","category":"function"},{"location":"DuctAPE/api/private_process/#Process","page":"Process","title":"Process","text":"","category":"section"},{"location":"DuctAPE/api/private_process/","page":"Process","title":"Process","text":"DuctAPE.process\nDuctAPE.solve","category":"page"},{"location":"DuctAPE/api/private_process/#DuctAPE.process","page":"Process","title":"DuctAPE.process","text":"process(\n solver_options::SolverOptionsType,\n solve_parameter_cache_vector,\n solve_parameter_cache_dims,\n airfoils,\n A_bb_LU,\n solve_container_caching,\n idmaps,\n options,\n)\n\nProcess (the step between pre-process and post-process) the solution, in other words: call the solver(s).\n\nArguments\n\nsolver_options::SolverOptionsType : the solver options contained in the options object, used for dispatch.\nsolve_parameter_cache_vector::Vector{Float} : The vector cache for parameters used in the solve.\nsolve_parameter_cache_dims::NamedTuple : A named tuple containing the dimensions of the solve parameters.\nairfoils::NamedTuple : The airfoils to be interpolated that are associated with each blade element\nA_bb_LU::LinearAlgebra.LU : The LU decomposition of the panel method LHS matrix\nsolve_container_caching::NamedTuple : A named tuple containing the cache and dimensions for the intermediate solve values.\nidmaps::NamedTuple : The set of index maps used in various solve sub-functions\noptions::Options : User options\n\nReturns\n\nconverged_states::Vector{Float} : The output of a call to ImplicitAD.implicit\n\n\n\n\n\n","category":"function"},{"location":"DuctAPE/api/private_process/#DuctAPE.solve","page":"Process","title":"DuctAPE.solve","text":"solve(sensitivity_parameters, const_cache; initial_guess=nothing)\n\nA compact dispatch of solve that automatically dispatches based on the solveroptions contained in constcache.\n\n\n\n\n\nsolve(\n solver_options::SolverOptionsType,\n sensitivity_parameters,\n const_cache;\n initial_guess=nothing,\n)\n\nConverge the residual, solving for the state variables that do so.\n\nArguments\n\nsolver_options::SolverOptionsType : SolverOptionsType used for dispatch\nsensitivity_parameters::Vector{Float} : Sensitivity parameters for solve (parameters passed in through ImplicitAD)\nconst_cache::NamedTuple : A named tuple containing constants and caching helpers.\n\nKeyword Arguments\n\ninitial_guess=nothing::Vector{Float} : An optional manually provided initial guess (contained in the sensitivity parameters anyway).\n\nReturns\n\nconverged_states::Vector{Float} : the states for which the residual has converged.\n\n\n\n\n\n","category":"function"},{"location":"DuctAPE/api/private_process/#Residuals","page":"Process","title":"Residuals","text":"","category":"section"},{"location":"DuctAPE/api/private_process/#CSOR","page":"Process","title":"CSOR","text":"","category":"section"},{"location":"DuctAPE/api/private_process/","page":"Process","title":"Process","text":"DuctAPE.CSOR_residual!\nDuctAPE.compute_CSOR_residual!\nDuctAPE.relax_Gamr!\nDuctAPE.relax_gamw!\nDuctAPE.apply_relaxation_schedule\nDuctAPE.update_CSOR_residual_values!\nDuctAPE.check_CSOR_convergence!","category":"page"},{"location":"DuctAPE/api/private_process/#DuctAPE.CSOR_residual!","page":"Process","title":"DuctAPE.CSOR_residual!","text":"CSOR_residual!(resid, state_variables, sensitivity_parameters, constants)\n\nThe in-place residual used for the CSOR solve method.\n\nArguments\n\nresid::Vector{Float} : In-place residual.\nstate_variables::Vector{Float} : The state variables\nsensitivity_parameters::Vector{Float} : The parameters to which the solution is sensitive.\nconstants::NamedTuple : Various constants required in the solve\n\nReturns\n\nstate_variables::Vector{Float} : The state variables (modified in place)\n\n\n\n\n\n","category":"function"},{"location":"DuctAPE/api/private_process/#DuctAPE.compute_CSOR_residual!","page":"Process","title":"DuctAPE.compute_CSOR_residual!","text":"compute_CSOR_residual!(\n resid,\n solver_options,\n solve_containers,\n Gamr,\n sigr,\n gamw,\n operating_point,\n ivr,\n ivw,\n linsys,\n blade_elements,\n wakeK,\n idmaps;\n verbose=false,\n)\n\nDescription\n\nArguments\n\nresid::Vector{Float} : the residual vector\nsolver_options::SolverOptionsType : solver options (used for convergence criteria)\nsolve_containers::NamedTuple : cache for intermediate solve values\nGamr::type : Blade element circulation strengths\nsigr::type : Rotor source panel strengths\ngamw::type : Wake vortex panel strengths\noperating_point::NamedTuple : Named tuple containing operating_point information\nivr::NamedTuple : unit induced velocities on rotor(s)\nivw::NamedTuple : unit induced velocities on wake\nlinsys::NamedTuple : vectors and matricies comprising the panel method linear system\nblade_elements::NamedTuple : blade element geometry and airfoil polar information\nwakeK::Vector{Float} : geometric constants used in caculating wake strengths\nidmaps::NamedTuple : index maps used throughout solve\n\nKeyword Arguments\n\nverbose::Bool=false : Flag to print verbose statements\n\n\n\n\n\ncompute_CSOR_residual!(\n resid,\n solver_options,\n solve_containers,\n Gamr,\n sigr,\n gamw,\n operating_point,\n ivr,\n ivw,\n linsys,\n blade_elements,\n wakeK,\n idmaps;\n verbose=false,\n)\n\nDescription\n\nArguments\n\nresid::Vector{Float} : the residual vector\nsolver_options::SolverOptionsType : solver options (used for convergence criteria)\nsolve_containers::NamedTuple : cache for intermediate solve values\nGamr::type : Blade element circulation strengths\nsigr::type : Rotor source panel strengths\ngamw::type : Wake vortex panel strengths\noperating_point::NamedTuple : Named tuple containing operating_point information\nivr::NamedTuple : unit induced velocities on rotor(s)\nivw::NamedTuple : unit induced velocities on wake\nlinsys::NamedTuple : vectors and matricies comprising the panel method linear system\nblade_elements::NamedTuple : blade element geometry and airfoil polar information\nwakeK::Vector{Float} : geometric constants used in caculating wake strengths\nidmaps::NamedTuple : index maps used throughout solve\n\nKeyword Arguments\n\nverbose::Bool=false : Flag to print verbose statements\n\n\n\n\n\n","category":"function"},{"location":"DuctAPE/api/private_process/#DuctAPE.relax_Gamr!","page":"Process","title":"DuctAPE.relax_Gamr!","text":"relax_Gamr!(\n Gamr,\n delta_prev_mat,\n delta_mat,\n maxBGamr,\n maxdeltaBGamr,\n B;\n nrf=0.4,\n bt1=0.2,\n bt2=0.6,\n pf1=0.4,\n pf2=0.5,\n test=false,\n)\n\nApply relaxed step to Gamr.\n\nArguments\n\nGamr::Array{Float} : Array of rotor circulations (columns = rotors, rows = blade elements), updated in place\ndelta_prev_mat::Array{Float} : Array of previous iteration's differences in circulation values, updated in place\ndelta_mat::Array{Float} : Array of current iteration's differences in circulation values\nB::Vector{Float} : number of blades on each rotor\nnrf::Float=0.4 : nominal relaxation factor\nbt1::Float=0.2 : backtrack factor 1\nbt2::Float=0.6 : backtrack factor 2\npf1::Float=0.4 : press forward factor 1\npf2::Float=0.5 : press forward factor 2\n\n\n\n\n\nrelax_Gamr!(\n Gamr,\n delta_prev_mat,\n delta_mat,\n maxBGamr,\n B;\n nrf=0.4,\n bt1=0.2,\n bt2=0.6,\n pf1=0.4,\n pf2=0.5,\n test=false,\n)\n\nApply relaxed step to Gamr.\n\nArguments\n\nGamr::Array{Float} : Array of rotor circulations (columns = rotors, rows = blade elements), updated in place\ndelta_prev_mat::Array{Float} : Array of previous iteration's differences in circulation values, updated in place\ndelta_mat::Array{Float} : Array of current iteration's differences in circulation values\nB::Vector{Float} : number of blades on each rotor\nnrf::Float=0.4 : nominal relaxation factor\nbt1::Float=0.2 : backtrack factor 1\nbt2::Float=0.6 : backtrack factor 2\npf1::Float=0.4 : press forward factor 1\npf2::Float=0.5 : press forward factor 2\n\n\n\n\n\n","category":"function"},{"location":"DuctAPE/api/private_process/#DuctAPE.relax_gamw!","page":"Process","title":"DuctAPE.relax_gamw!","text":"relax_gamw!(\n gamw, delta_prev, delta, maxdeltagamw; nrf=0.4, btw=0.6, pfw=1.2, test=false\n)\n\nApply relaxed step to gamw.\n\nArguments\n\ngamw::Array{Float} : Array of rotor circulations (columns = rotors, rows = blade elements), updated in place\ndelta_prev_mat::Array{Float} : Array of previous iteration's differences in circulation values, updated in place\ndelta_mat::Array{Float} : Array of current iteration's differences in circulation values\nB::Vector{Float} : number of blades on each rotor\nnrf::Float=0.4 : nominal relaxation factor\nbt1::Float=0.2 : backtrack factor 1\nbt2::Float=0.6 : backtrack factor 2\npf1::Float=0.4 : press forward factor 1\npf2::Float=0.5 : press forward factor 2\n\n\n\n\n\nrelax_gamw!(\n gamw, delta_prev, delta; nrf=0.4, btw=0.6, pfw=1.2, test=false\n)\n\nApply relaxed step to gamw.\n\nArguments\n\ngamw::Array{Float} : Array of rotor circulations (columns = rotors, rows = blade elements), updated in place\ndelta_prev_mat::Array{Float} : Array of previous iteration's differences in circulation values, updated in place\ndelta_mat::Array{Float} : Array of current iteration's differences in circulation values\nB::Vector{Float} : number of blades on each rotor\nnrf::Float=0.4 : nominal relaxation factor\nbt1::Float=0.2 : backtrack factor 1\nbt2::Float=0.6 : backtrack factor 2\npf1::Float=0.4 : press forward factor 1\npf2::Float=0.5 : press forward factor 2\n\n\n\n\n\n","category":"function"},{"location":"DuctAPE/api/private_process/#DuctAPE.apply_relaxation_schedule","page":"Process","title":"DuctAPE.apply_relaxation_schedule","text":"apply_relaxation_schedule(\n resid::AbstractVector, solver_options::TS\n) where {TS<:SolverOptionsType}\n\nApply custom relaxation schedule to all relaxation factor inputs based on residual values.\n\nArguments\n\nresid::AbstractVector{Float} : current residual values\nsolver_options::SolverOptionsType : SolverOptions containing relaxation schedule\n\nReturns\n\nnrf::Float : nominal relaxation factor\nbt1::Float : backtrack factor 1\nbt2::Float : backtrack factor 2\npf1::Float : press forward factor 1\npf2::Float : press forward factor 2\n\n\n\n\n\napply_relaxation_schedule(resid, nominal, schedule)\n\nApply custom relaxation schedule to a single relaxation factor input.\n\nArguments\n\nresid::Float : residual value\nnominal::Float : nominal relaxation value\nschedule::AbstractVector{AbstractVector{Float}} : values between which to interpolate to scale the nominal relaxation value.\n\nReturns\n\nrf::Float : the updated relaxation factor\n\n\n\n\n\n","category":"function"},{"location":"DuctAPE/api/private_process/#DuctAPE.update_CSOR_residual_values!","page":"Process","title":"DuctAPE.update_CSOR_residual_values!","text":"update_CSOR_residual_values!(\n convergence_type::ConvergenceType, resid, maxBGamr, maxdeltaBGamr, maxdeltagamw, Vconv\n)\n\nUpdate CSOR residual values in place.\n\nArguments\n\nconvergence_type::ConvergenceType : used for dispatch of relative or absolute residual values.\nresid::Vector{Float} : residual values modified in place\nmaxBGamr::Float : Maximum value of B*Gamr among all blade elements\nmaxdeltaBGamr::Float : Maximum change in B*Gamr between iterations among all blade elements\nmaxdeltagamw::Vector{Float} : Maximum change in gamw among all wake nodes (one element)\nVconv::Float : Reference velocity upon which the relative convergence criteria is based (one element)\n\n\n\n\n\n","category":"function"},{"location":"DuctAPE/api/private_process/#DuctAPE.check_CSOR_convergence!","page":"Process","title":"DuctAPE.check_CSOR_convergence!","text":"check_CSOR_convergence!(\n conv, resid; f_circ=1e-3, f_dgamw=2e-4, convergence_type=Relative(), verbose=false\n)\n\nDescription\n\nArguments\n\nconv::Vector{Float} : container holding convergence flag\nresid::Vector{Float} : residual vector\n\nKeyword Arguments\n\nf_circ::Float=1e-3 : convergence criteria for circulation residual\nf_dgamw::Float=2e-4 : convergence criteria for wake strength residual\nconvergence_type::ConvergenceType=Relative() : convergence type (absolute or relative) for print statements\nverbose::Bool=false : flag for verbose print statements\n\n\n\n\n\n","category":"function"},{"location":"DuctAPE/api/private_process/#External-Solvers","page":"Process","title":"External Solvers","text":"","category":"section"},{"location":"DuctAPE/api/private_process/","page":"Process","title":"Process","text":"DuctAPE.system_residual\nDuctAPE.system_residual!\nDuctAPE.update_system_residual!\nDuctAPE.estimate_states!","category":"page"},{"location":"DuctAPE/api/private_process/#DuctAPE.system_residual","page":"Process","title":"DuctAPE.system_residual","text":"system_residual(state_variables, sensitivity_parameters, constants)\n\nThe residual function for external solvers.\n\nArguments\n\nstate_variables::Vector{Float} : the state variables\nsensitivity_parameters::Vector{Float} : parameters to which the solution derivatives are sensitive\nconstants::NamedTuple : parameters to which the solution derivatives are constant\n\nReturs\n\nresid::Vector{Float} : residual vector\n\n\n\n\n\n","category":"function"},{"location":"DuctAPE/api/private_process/#DuctAPE.system_residual!","page":"Process","title":"DuctAPE.system_residual!","text":"system_residual!(resid, state_variables, sensitivity_parameters, constants)\n\nIn-place version of system_residual.\n\n\n\n\n\n","category":"function"},{"location":"DuctAPE/api/private_process/#DuctAPE.update_system_residual!","page":"Process","title":"DuctAPE.update_system_residual!","text":"update_system_residual!(\n solver_options::SolverOptionsType\n resid,\n vz_est,\n vz_rotor,\n vtheta_est,\n vtheta_rotor,\n Cm_est,\n Cm_wake,\n solve_parameter_cache_dims,\n)\n\nUpdate the residual for external solvers.\n\nArguments\n\n`solver_options::SolverOptionsType\nresid::Vector{Float} : residual vector\nvz_est::Vector{Float} : axial induced rotor velocity estimate container\nvz_rotor::Vector{Float} : axial induced rotor velocity state container\nvtheta_est::Vector{Float} : tangential induced rotor velocity estimate container\nvtheta_rotor::Vector{Float} : tangential induced rotor velocity state container\nCm_est::Vector{Float} : absolute meridional wake control point velocity estimate container\nCm_wake::Vector{Float} : absolute meridional wake control point velocity state container\nsolve_parameter_cache_dims::Vector{Float} : dimensions of state vectors to use in accessing the residual vector\n\n\n\n\n\n","category":"function"},{"location":"DuctAPE/api/private_process/#DuctAPE.estimate_states!","page":"Process","title":"DuctAPE.estimate_states!","text":"estimate_states!(\n solve_containers,\n vz_rotor,\n vtheta_rotor,\n Cm_wake,\n operating_point,\n ivr,\n ivw,\n linsys,\n blade_elements,\n wakeK,\n idmaps;\n verbose=false,\n)\n\nEstimate velocity states.\n\nArguments\n\nsolve_containers::NamedTuple : cache for intermediate values in solve\nvz_rotor::Vector{Float} : axial induced rotor velocity state container\nvtheta_rotor::Vector{Float} : tangential induced rotor velocity state container\nCm_wake::Vector{Float} : absolute meridional wake control point velocity state container\noperating_point::NamedTuple : Named tuple containing operating_point information\nivr::NamedTuple : unit induced velocities on rotor(s)\nivw::NamedTuple : unit induced velocities on wake\nlinsys::NamedTuple : vectors and matricies comprising the panel method linear system\nblade_elements::NamedTuple : blade element geometry and airfoil polar information\nwakeK::Vector{Float} : geometric constants used in caculating wake strengths\nidmaps::NamedTuple : index maps used throughout solve\n\nKeyword Arguments\n\nverbose::Bool=false : flag for verbose print statements\n\n\n\n\n\n","category":"function"},{"location":"DuctAPE/api/private_process/#Solve-Utilities","page":"Process","title":"Solve Utilities","text":"","category":"section"},{"location":"DuctAPE/api/private_process/","page":"Process","title":"Process","text":"DuctAPE.extract_initial_guess\nDuctAPE.extract_state_variables","category":"page"},{"location":"DuctAPE/api/private_process/#DuctAPE.extract_initial_guess","page":"Process","title":"DuctAPE.extract_initial_guess","text":"extract_initial_guess(\n solver_options::SolverOptionsType, sensitivity_parameters, state_dims\n)\n\nExtract initial guess from the solve parameters cache vector.\n\nArguments\n\nsolver_options::SolverOptionsType : used for dispatch\nsensitivity_parameters::Vector{Float} : vector form of solve parameter cache passed into the solver.\nstate_dims::NamedTuple : dimensions and indices of state variables within the solve parameter cache vector\n\nReturns\n\ninitial_guess::Vector{Float}` : a vector of the solver initial guess\n\n\n\n\n\n","category":"function"},{"location":"DuctAPE/api/private_process/#DuctAPE.extract_state_variables","page":"Process","title":"DuctAPE.extract_state_variables","text":"extract_state_variables(solver_options::SolverOptionsType, vars, dims)\n\nReshape the state variables from a single vector, to multiple arrays.\n\nArguments\n\nReturns if solver_options <: CSORSolverOptions\n\nGamr::type : Blade element circulation strengths\nsigr::type : Rotor source panel strengths\ngamw::type : Wake vortex panel strengths\n\nReturns if solver_options <: Union{ExternalSolverOptions, PolyAlgorithmOptions}\n\nvz_rotor::Vector{Float} : axial induced rotor velocity state container\nvtheta_rotor::Vector{Float} : tangential induced rotor velocity state container\nCm_wake::Vector{Float} : absolute meridional wake control point velocity state container\n\n\n\n\n\n","category":"function"},{"location":"C4Blade/api/#Index","page":"API Reference","title":"Index","text":"","category":"section"},{"location":"C4Blade/api/","page":"API Reference","title":"API Reference","text":"Pages = [\"C4Blade/api.md\"]\nDepth = 5","category":"page"},{"location":"C4Blade/api/","page":"API Reference","title":"API Reference","text":"Modules=[DuctAPE.C4Blade]","category":"page"},{"location":"DuctAPE/api/private_preprocess/#General","page":"Preprocess","title":"General","text":"","category":"section"},{"location":"DuctAPE/api/private_preprocess/","page":"Preprocess","title":"Preprocess","text":"DuctAPE.set_index_maps\nDuctAPE.precompute_parameters\nDuctAPE.precompute_parameters!","category":"page"},{"location":"DuctAPE/api/private_preprocess/#DuctAPE.set_index_maps","page":"Preprocess","title":"DuctAPE.set_index_maps","text":"set_index_maps(\n npanels,\n ncenterbody_inlet,\n nwake_sheets,\n dte_minus_cbte,\n wnm,\n wenids,\n nwp,\n nwsp,\n nbn,\n ndp,\n riiw,\n nrotor,\n)\n\nSet values for index map to be used throughout solve and post-process.\n\nArguments\n\nnpanels : paneling_constants.npanels\nncenterbody_inlet : paneling_constants.ncenterbody_inlet\nnwake_sheets : paneling_constants.nwake_sheets\ndte_minus_cbte : paneling_constants.dte_minus_cbte\nwnm : wake_vortex_panels.nodemap\nwenids : wake_vortex_panels.endnodeidxs\nnwp : problem_dimensions.nwp\nnwsp : problem_dimensions.nwsp\nnbn : problem_dimensions.nbn\nndp : body_vortex_panels.npanel[1]\nriiw : rotor_indices_in_wake\nnrotor : problem_dimensions.nrotor\n\nReturns\n\nidmaps::NamedTuple : A named tuple containing index mapping used in bookkeeping throughout solve and post-process\n\n\n\n\n\n","category":"function"},{"location":"DuctAPE/api/private_preprocess/#DuctAPE.precompute_parameters","page":"Preprocess","title":"DuctAPE.precompute_parameters","text":"precompute_parameters(\n propulsor;\n grid_solver_options=GridSolverOptions(),\n integration_options=IntegrationOptions(),\n autoshiftduct=true,\n itcpshift=0.05,\n axistol=1e-15,\n tegaptol=1e1 * eps(),\n finterp=(x,y,xp)->FLOWMath.akima(x,y,xp,2.0*eps(),eps()),\n silence_warnings=true,\n verbose=false,\n)\n\nOut of place main pre-processing function that computes all the required parameters for the solve.\n\nArguments\n\npropulsor::Propulsor : A Propuslor object\n\nKeyword Arguments\n\ngrid_solver_options::GridSolverOptionsType=GridSolverOptions() : A GridSolverOptionsType object\nintegration_options::IntegrationMethod=IntegrationOptions() : An IntegrationMethod object\nautoshiftduct::Bool=true : flag to shift duct geometry based on rotor tip radius\nitcpshift::Float=0.05 : value used in positioning the internal pseudo control point in the solid bodies. Default is DFDC hard-coded value.\naxistol::Float=1e-15 : tolerance for how close to the axis of rotation to be considered on the axis.\ntegaptol::Float=1e1 * eps() : tolerance for how large of a trailing edge gap is considered a gap.\nfinterp::Function=FLOWMath.akima : interpolation method for re-interpolating body coordinates\nsilence_warnings::Bool=true : flag to silence warnings\nverbose::Bool=false : flag to print verbose statements\n\nReturns\n\nivr::NamedTuple : A named tuple containing arrays of induced velocities on the rotors\nivw::NamedTuple : A named tuple containing arrays of induced velocities on the wake\nivb::NamedTuple : A named tuple containing arrays of induced velocities on the bodies\nlinsys::NamedTuple : A named tuple containing cacheable data for the linear system, including:\nA_bb::Array{Float} : AIC (LHS) matrix for the panel method system\nb_bf::Array{Float} : Initial system RHS vector based on freestrem magnitude\nA_br::Array{Float} : Unit normal velocity from rotors onto body panels\nA_pr::Array{Float} : Unit normal velocity from rotors onto body internal psuedo control points\nA_bw::Array{Float} : Unit normal velocity from wake onto body panels\nA_pw::Array{Float} : Unit normal velocity from wake onto body internal psuedo control points\nA_bb_LU::LinearAlgebra.LU : LinearAlgebra LU factorization of the LHS matrix\nlu_decomp_flag::Vector{Bool} : flag for whether factorization was successful\nblade_elements::NamedTuple : A named tuple containing cacheable blade element information (see docs for interpolate_blade_elements)\nairfoils::Vector{AFType} : A matrix of airfoil types associated with each of the blade elements\nwakeK::Matrix{Float} : A matrix of precomputed geometric constants used in the calculation of the wake vortex strengths\nidmaps::NamedTuple : A named tuple containing index mapping used in bookkeeping throughout solve and post-process\npanels::NamedTuple : A named tuple of panel objects including:\nbody_vortex_panels::NamedTuple : the named tuple containing the body vortex panel information\nrotor_source_panels::NamedTuple : the named tuple containing the rotor source panel information\nwake_vortex_panels::NamedTuple : the named tuple containing the wake vortex panel information\nproblem_dimensions::ProblemDimensions : A ProblemDimensions object\n\n\n\n\n\nprecompute_parameters(\n rp_duct_coordinates,\n rp_centerbody_coordinates,\n wake_grid,\n rotor_indices_in_wake,\n Rtips,\n Rhubs,\n rotorstator_parameters,\n paneling_constants,\n operating_point,\n integration_options,\n problem_dimensions=nothing;\n itcpshift=0.05,\n axistol=1e-15,\n tegaptol=1e1 * eps(),\n silence_warnings=true,\n verbose=false,\n)\n\nAn alternate version of precompute_parameters allowing for user defined geometry that does not go through a re-panling step (use with caution).\n\nThe first inputs are the outputs of the reinterpolate_geometry and get_blade_ends_from_body_geometry functions.\n\n\n\n\n\n","category":"function"},{"location":"DuctAPE/api/private_preprocess/#DuctAPE.precompute_parameters!","page":"Preprocess","title":"DuctAPE.precompute_parameters!","text":"precompute_parameters!(\n ivr,\n ivw,\n blade_element_cache,\n linsys,\n wakeK,\n propulsor,\n prepost_containers,\n problem_dimensions;\n grid_solver_options=GridSolverOptions(),\n integration_options=IntegrationOptions(),\n autoshiftduct=true,\n itcpshift=0.05,\n axistol=1e-15,\n tegaptol=1e1 * eps(),\n finterp=(x,y,xp)->FLOWMath.akima(x,y,xp,2.0*eps(),eps()),\n silence_warnings=true,\n verbose=false,\n)\n\nIn-place version of precompute_parameters.\n\n\n\n\n\nprecompute_parameters!(\n ivr,\n ivw,\n blade_element_cache,\n linsys,\n wakeK,\n wake_grid,\n rp_duct_coordinates,\n rp_centerbody_coordinates,\n rotor_indices_in_wake,\n rotorstator_parameters,\n paneling_constants,\n operating_point,\n prepost_containers,\n problem_dimensions=nothing;\n integration_options=IntegrationOptions(),\n itcpshift=0.05,\n axistol=1e-15,\n tegaptol=1e1 * eps(),\n finterp=(x,y,xp)->FLOWMath.akima(x,y,xp,2.0*eps(),eps()),\n silence_warnings=true,\n verbose=false,\n)\n\nIn-place version of the precompute_parameters function by-passing the geometry reinterpolateion. (Use with caution)\n\n\n\n\n\n","category":"function"},{"location":"DuctAPE/api/private_preprocess/#Geometry","page":"Preprocess","title":"Geometry","text":"","category":"section"},{"location":"DuctAPE/api/private_preprocess/","page":"Preprocess","title":"Preprocess","text":"DuctAPE.reinterpolate_geometry\nDuctAPE.reinterpolate_geometry!\nDuctAPE.generate_all_panels\nDuctAPE.generate_all_panels!","category":"page"},{"location":"DuctAPE/api/private_preprocess/#DuctAPE.reinterpolate_geometry","page":"Preprocess","title":"DuctAPE.reinterpolate_geometry","text":"reinterpolate_geometry(\n problem_dimensions,\n duct_coordinates,\n centerbody_coordinates,\n rotorstator_parameters,\n paneling_constants;\n autoshiftduct=true,\n grid_solver_options=GridSolverOptions(),\n finterp=(x,y,xp)->FLOWMath.akima(x,y,xp,2.0*eps(),eps()),\n verbose=false,\n silence_warnings=true,\n)\n\nRe-interpolate the body geometry and return compatible body and way geometry.\n\nArguments\n\nproblem_dimensions::ProblemDimensions : A ProblemDimensions object\nduct_coordinates::Matrix{Float} : [z,r] coordinates of duct geometry\ncenterbody_coordinates::Matrix{Float} : [z,r] coordinates of centerbody geometry\nrotorstator_parameters::RotorStatorParameters : A RotorStatorParameters object\npaneling_constants::PanelingConstants : A PanelingConstants object\n\nKeyword Arguments\n\nautoshiftduct::Bool=true : flag to shift duct geometry based on rotor tip radius\ngrid_solver_options::SolverOptionsType=GridSolverOptions() : options for the wake grid position solver\nfinterp::Function=FLOWMath.akima : interpolation method for re-interpolating body coordinates\nverbose::Bool=false : flag to print verbose statements\nsilence_warnings::Bool=true : flag to silence warnings\n\nReturns\n\nwake_grid::Array{Float} : array containig the z and r elliptic grid points defning the wake geometry.\nrp_duct_coordinates::Matrix{Float} : matrix containing the re-paneled duct coordinates\nrp_centerbody_coordinates::Matrix{Float} : matrix containing the re-paneled centerbody coordinates\nrotor_indices_in_wake::Vector{Int} : vector containing the indices of where in the wake the rotors reside (used later to define the rotor panel edges).\n\n\n\n\n\n","category":"function"},{"location":"DuctAPE/api/private_preprocess/#DuctAPE.reinterpolate_geometry!","page":"Preprocess","title":"DuctAPE.reinterpolate_geometry!","text":"reinterpolate_geometry!(\n wake_grid,\n rp_duct_coordinates,\n rp_centerbody_coordinates,\n rotor_indices_in_wake,\n duct_coordinates,\n centerbody_coordinates,\n rotorstator_parameters,\n blade_element_cache,\n paneling_constants;\n autoshiftduct=true,\n grid_solver_options=GridSolverOptions(),\n finterp=(x,y,xp)->FLOWMath.akima(x,y,xp,2.0*eps(),eps()),\n verbose=false,\n silence_warnings=true,\n)\n\nIn-place version of reinterpolate_geometry.\n\n\n\n\n\n","category":"function"},{"location":"DuctAPE/api/private_preprocess/#DuctAPE.generate_all_panels","page":"Preprocess","title":"DuctAPE.generate_all_panels","text":"generate_all_panels(\n rp_duct_coordinates,\n rp_centerbody_coordinates,\n nwake_sheets,\n rotor_indices_in_wake,\n rotorzloc,\n wake_grid;\n itcpshift=0.05,\n axistol=1e-15,\n tegaptol=1e1 * eps(),\n silence_warnings=true,\n)\n\nFunction that calls all of the various panel generation functions are returns a named tuple containing all the panels\n\nArguments\n\nrp_duct_coordinates::Matrix{Float} : matrix containing the re-paneled duct coordinates\nrp_centerbody_coordinates::Matrix{Float} : matrix containing the re-paneled centerbody coordinates\nnwake_sheets::Int : number of wake sheets\nrotor_indices_in_wake::Vector{Int} : vector containing the indices of where in the wake the rotors reside (used later to define the rotor panel edges).\nrotorzloc:Vector{Float} : axial locations of rotor lifting lines (contained in RotorStatorParameters)\nwake_grid::Array{Float} : array containig the z and r elliptic grid points defning the wake geometry.\n\nKeyword Arguments\n\nitcpshift::Float=0.05 : value used in positioning the internal pseudo control point in the solid bodies. Default is DFDC hard-coded value.\naxistol::Float=1e-15 : tolerance for how close to the axis of rotation to be considered on the axis.\ntegaptol::Float=1e1 * eps() : tolerance for how large of a trailing edge gap is considered a gap.\nsilence_warnings::Bool=true : flag to silence warnings\n\nReturns\n\npanels::NamedTuple : A named tuple of named tuples containing paneling information, including:\nbody_vortex_panels::NamedTuple\nrotor_source_panels::NamedTuple\nwake_vortex_panels::NamedTuple\n\n\n\n\n\n","category":"function"},{"location":"DuctAPE/api/private_preprocess/#DuctAPE.generate_all_panels!","page":"Preprocess","title":"DuctAPE.generate_all_panels!","text":"generate_all_panels!(\n panels,\n wake_grid,\n rp_duct_coordinates,\n rp_centerbody_coordinates,\n rotor_indices_in_wake,\n rotorzloc,\n nwake_sheets;\n itcpshift=0.05,\n axistol=1e-15,\n tegaptol=1e1 * eps(),\n silence_warnings=true,\n)\n\nIn-place version of generate_all_panels.\n\n\n\n\n\n","category":"function"},{"location":"DuctAPE/api/private_preprocess/#Wake","page":"Preprocess","title":"Wake","text":"","category":"section"},{"location":"DuctAPE/api/private_preprocess/","page":"Preprocess","title":"Preprocess","text":"DuctAPE.discretize_wake\nDuctAPE.generate_wake_grid\nDuctAPE.generate_wake_grid!\nDuctAPE.initialize_wake_grid\nDuctAPE.initialize_wake_grid!\nDuctAPE.relax_grid!\nDuctAPE.generate_wake_panels\nDuctAPE.generate_wake_panels!\nDuctAPE.get_wake_k\nDuctAPE.get_wake_k!","category":"page"},{"location":"DuctAPE/api/private_preprocess/#DuctAPE.discretize_wake","page":"Preprocess","title":"DuctAPE.discretize_wake","text":"discretize_wake(\n duct_coordinates,\n centerbody_coordinates,\n rotorzloc, # rotor axial locations\n wake_length,\n npanels,\n dte_minus_cbte;\n)\n\nCalculate wake sheet panel node z-coordinates.\n\nArguments\n\nduct_coordinates::Matrix{Float} : Array of input duct coordinates\ncenterbody_coordinates::Matrix{Float} : Array of input centerbody_coordinates coordinates\nrotorzloc ::Vector{Float} : rotor axial locations\nwake_length::Float : non-dimensional length of wake to extend beyond aft-most body trailing edge.\nnpanels::Vector{Int} : A vector of the number of panels between each discrete point. For example: [number of panels between the rotors; number of panels between the stator and the first trailing edge; number of panels between the trailing edges; number of panels between the last trailing edge and the end of the wake]\ndte_minus_cbte::Float : indicator as to whether the duct trailing edge minus the centerbody trailing edge is positive, zero, or negative.\n\n\n\n\n\n","category":"function"},{"location":"DuctAPE/api/private_preprocess/#DuctAPE.generate_wake_grid","page":"Preprocess","title":"DuctAPE.generate_wake_grid","text":"generate_wake_grid(\n problem_dimensions,\n rp_duct_coordinates,\n rp_centerbody_coordinates,\n Rhub1,\n Rtip1,\n tip_gap1,\n zwake;\n grid_solver_options=GridSolverOptions(),\n verbose=false,\n silence_warnings=true,\n)\n\nInitialize and solve for elliptic grid on which wake sheets are defined.\n\nArguments\n\nproblem_dimensions:: : A ProblemDimensions object\nrp_duct_coordinates:: : repaneled duct coordinates\nrp_centerbody_coordinates:: : repaneled centerbody coordinates\nRhub1:: : Hub radius of first rotor\nRtip1:: : Tip radius of first rotor\ntip_gap1:: : Tip gap of first rotor (MUST BE ZERO for now)\nzwake:: : axial positions of wake sheet panel nodes\n\nKeyword Arguments\n\ngrid_solver_options::GridSolverOptionsType=GridSolverOptions() : options for solving the elliptic grid.\nverbose::Bool=false : flag to print verbose statements\nsilence_warnings::Bool=true : flag to supress warnings\n\nReturns\n\nwake_grid::Array{Float,3} : 3D Array of axial and radial wake_grid points after solution of elliptic system.\n\n\n\n\n\n","category":"function"},{"location":"DuctAPE/api/private_preprocess/#DuctAPE.generate_wake_grid!","page":"Preprocess","title":"DuctAPE.generate_wake_grid!","text":"generate_wake_grid!(\n wake_grid,\n rp_duct_coordinates,\n rp_centerbody_coordinates,\n Rhub1,\n Rtip1,\n tip_gap1,\n zwake;\n grid_solver_options=grid_solver_options,\n verbose=false,\n silence_warnings=true,\n)\n\nIn-place version of generate_wake_grid.\n\n\n\n\n\n","category":"function"},{"location":"DuctAPE/api/private_preprocess/#DuctAPE.initialize_wake_grid","page":"Preprocess","title":"DuctAPE.initialize_wake_grid","text":"initialize_wake_grid(rp_duct_coordinates, rp_centerbody_coordinates, zwake, rwake)\n\nInitialize the wake grid.\n\nArguments:\n\nrp_duct_coordinates::Matrix{Float} : The re-paneled duct coordinates\nrp_centerbody_coordinates::Matrix{Float} : The re-paneled centerbody coordinates\nzwake::Vector{Float} : The axial positions of the wake sheet panel nodes\nrwake::Vector{Float} : The radial positions of the blade elements for the foremost rotor\n\nReturns:\n\nwake_grid::Array{Float,3} : 3D Array of axial and radial wake_grid points\n\n\n\n\n\n","category":"function"},{"location":"DuctAPE/api/private_preprocess/#DuctAPE.initialize_wake_grid!","page":"Preprocess","title":"DuctAPE.initialize_wake_grid!","text":"initialize_wake_grid!(\n wake_grid, rp_duct_coordinates, rp_centerbody_coordinates, zwake, rwake\n)\n\nIn-place version of initialize_wake_grid.\n\n\n\n\n\n","category":"function"},{"location":"DuctAPE/api/private_preprocess/#DuctAPE.relax_grid!","page":"Preprocess","title":"DuctAPE.relax_grid!","text":"relax_grid!(\n grid_solver_options::GridSolverOptionsType,\n wake_grid;\n verbose=false,\n silence_warnings=true,\n tabchar=\" \",\n ntab=1,\n)\n\nRelax/Solve initial wake grid according to elliptic system of equations.\n\nArguments\n\n`gridsolveroptions::GridSolverOptionsType' : options for elliptic grid solver\nwake_grid::Array{Float,3} : Initialized wake grid\n\nKeyword Arguments\n\n`verbose=false::' : flag for printing verbose statements\n`silence_warnings=true::' : flag for supressing warnings\n`tabchar::String=\" \"::' : string to use for tabbing over verbose statements.\n`ntab::Int=1' : number of tabs for printing verbose statements\n\n\n\n\n\nrelax_grid!(xg, rg, nxi, neta; iteration_limit, atol)\n\nRelax wakegrid using elliptic wakegrid solver.\n\nArguments:\n\nKeyword Arguments:\n\niteration_limit::Int : maximum number of iterations to run, default=100\natol::Float : convergence tolerance, default = 1e-9\n\nReturns:\n\n\n\n\n\n","category":"function"},{"location":"DuctAPE/api/private_preprocess/#DuctAPE.generate_wake_panels","page":"Preprocess","title":"DuctAPE.generate_wake_panels","text":"generate_wake_panels(wake_grid)\n\nGenerate paneling for each wake sheet emanating from the rotor blade elements.\n\nArguments:\n\nwake_grid::Array{Float,3} : axial and radial locations of each wake_grid point (after relaxation/solution)\n\nReturns:\n\nwake_vortex_panels::NamedTuple : A named tuple of panel values describing the wake vortex panels\n\n\n\n\n\n","category":"function"},{"location":"DuctAPE/api/private_preprocess/#DuctAPE.generate_wake_panels!","page":"Preprocess","title":"DuctAPE.generate_wake_panels!","text":"generate_wake_panels!(wake_panels, wake_grid)\n\nIn-place version of generate_wake_panels.\n\n\n\n\n\n","category":"function"},{"location":"DuctAPE/api/private_preprocess/#DuctAPE.get_wake_k","page":"Preprocess","title":"DuctAPE.get_wake_k","text":"get_wake_k(r, nwn)\n\nCalculate geometric constant for use in later calculation of wake panel node strengths.\n\nArguments\n\nr::Vector{Float} : Vector of wake panel node radial positions\n\nReturns\n\nK::Vector{Float} : Vector of geometric constants used in calculation of panel node strengths.\n\n\n\n\n\n","category":"function"},{"location":"DuctAPE/api/private_preprocess/#DuctAPE.get_wake_k!","page":"Preprocess","title":"DuctAPE.get_wake_k!","text":"get_wake_k!(K, r)\n\nIn-place version of get_wake_k.\n\n\n\n\n\n","category":"function"},{"location":"DuctAPE/api/private_preprocess/#Bodies","page":"Preprocess","title":"Bodies","text":"","category":"section"},{"location":"DuctAPE/api/private_preprocess/","page":"Preprocess","title":"Preprocess","text":"DuctAPE.reinterpolate_bodies!\nDuctAPE.place_duct!","category":"page"},{"location":"DuctAPE/api/private_preprocess/#DuctAPE.reinterpolate_bodies!","page":"Preprocess","title":"DuctAPE.reinterpolate_bodies!","text":"reinterpolate_bodies!(\n rp_duct_coordinates,\n rp_centerbody_coordinates,\n duct_coordinates,\n centerbody_coordinates,\n zwake,\n ncenterbody_inlet,\n nduct_inlet;\n finterp=FLOWMath.akima,\n)\n\nReinterpolate duct and centerbody coordinates in order to make them compatible with the calculated wake sheet panel axial positions.\n\nArguments\n\nrp_duct_coordinates::Matrix{Float} : the re-paneled duct coordinates\nrp_centerbody_coordinates::Matrix{Float} : the re-paneled centerbody coordinates\nduct_coordinates::Matrix{Float} : the input duct coordinates\ncenterbody_coordinates::Matrix{Float} : the input centerbody coordinates\nzwake::Matrix{Float} : the wake sheet panel node axial positions\nncenterbody_inlet::Matrix{Float} : the number of panels to use for the centerbody inlet\nnduct_inlet::Matrix{Float} : the number of panels to use for the duct inlet\n\nKeyword Arguments\n\nfinterp::Function=FLOWMath.akima : interpolation method\n\n\n\n\n\n","category":"function"},{"location":"DuctAPE/api/private_preprocess/#DuctAPE.place_duct!","page":"Preprocess","title":"DuctAPE.place_duct!","text":"place_duct!(rp_duct_coordinates, Rtip, rotorzloc, tip_gap)\n\nTransform the duct radial coordinates such that the leading rotor radius touches the duct wall.\n\nNote that this function is called AFTER the repanling function is called, such that the rotorzloc locations should line up directly with the duct and centerbody coordinates.\n\nArguments\n\nrp_duct_coordinates::Matrix{Float} : the re-paneled duct coordinates\nRtip::Vector{Float} : Tip radii for the rotor(s)\nrotorzloc::Vector{Float} : axial position(s) of the rotor(s)\ntip_gap::Vector{Float} : tip gap for the fore-most rotor (MUST BE ZERO for now)\n\n\n\n\n\n","category":"function"},{"location":"DuctAPE/api/private_preprocess/#Rotors","page":"Preprocess","title":"Rotors","text":"","category":"section"},{"location":"DuctAPE/api/private_preprocess/","page":"Preprocess","title":"Preprocess","text":"DuctAPE.interpolate_blade_elements\nDuctAPE.interpolate_blade_elements!\nDuctAPE.get_blade_ends_from_body_geometry\nDuctAPE.get_blade_ends_from_body_geometry!\nDuctAPE.get_local_solidity\nDuctAPE.get_stagger\nDuctAPE.generate_rotor_panels\nDuctAPE.generate_rotor_panels!","category":"page"},{"location":"DuctAPE/api/private_preprocess/#DuctAPE.interpolate_blade_elements","page":"Preprocess","title":"DuctAPE.interpolate_blade_elements","text":"interpolate_blade_elements(\n rsp, Rtips, Rhubs, rotor_panel_centers, nbe; finterp=FLOWMath.linear\n)\n\nInterpolate blade elements based on RotorStatorParameters inputs and number of desired blade elements (from number of wake sheet in PanelingConstants input)\n\nArguments\n\nrsp::RotorStatorParameters : A RotorStatorParameters object\n`Rtips::Vector{Float}' : Vector of rotor tip radii\n`Rhubs::Vector{Float}' : Vector of rotor hub radii\n`rotorpanelcenters::Vector{Float}' : Vector of rotor panel centers\nnbe::Int : number of blade elements per rotor\n\nKeyword Arguments\n\nfinterp::Function=FLOWMath.linear : interpolation method (note, using Akima splines as is done for the body geometry can lead to negative chord in some cases)\n\nReturns\n\nblade_element_cache::NamedTuple : A named tuple containing the cacheable blade element information excluding the airfoil data.\nairfoils::NamedTuple : A named tuple containing vectors of inner and outer airfoil polar data for each blade element, used in interpolating the input data at blade element locations.\n\n\n\n\n\n","category":"function"},{"location":"DuctAPE/api/private_preprocess/#DuctAPE.interpolate_blade_elements!","page":"Preprocess","title":"DuctAPE.interpolate_blade_elements!","text":"interpolate_blade_elements!(\n blade_element_cache, rsp, rotor_panel_centers, nbe; finterp=FLOWMath.linear\n)\n\nIn-place version of interpolate_blade_elements.\n\nReturns\n\nairfoils::NamedTuple : A named tuple containing vectors of inner and outer airfoil polar data for each blade element, used in interpolating the input data at blade element locations.\n\n\n\n\n\n","category":"function"},{"location":"DuctAPE/api/private_preprocess/#DuctAPE.get_blade_ends_from_body_geometry","page":"Preprocess","title":"DuctAPE.get_blade_ends_from_body_geometry","text":"get_blade_ends_from_body_geometry(\n rp_duct_coordinates, rp_centerbody_coordinates, tip_gaps, rotorzloc\n)\n\nObtain rotor hub and tip radii based on duct and centerbody geometry.\n\nArguments\n\nvar::type :\nrp_duct_coordinates::Matrix{Float} : re-paneled duct coordinates\nrp_centerbody_coordinates::Matrix{Float} : re-paneled centerbody coordinates\ntip_gaps::Vector{Float} : gaps between blade tips and duct surface (MUST BE ZEROS for now)\nrotorzloc::Vector{Float} : rotor lifting line axial positions.\n\nReturns\n\nRtips::Vector{Float} : rotor tip radii\nRhubs::Vector{Float} : rotor hub radii\n\n\n\n\n\n","category":"function"},{"location":"DuctAPE/api/private_preprocess/#DuctAPE.get_blade_ends_from_body_geometry!","page":"Preprocess","title":"DuctAPE.get_blade_ends_from_body_geometry!","text":"get_blade_ends_from_body_geometry!(\n Rtip,\n Rhub,\n rp_duct_coordinates,\n rp_centerbody_coordinates,\n tip_gaps,\n rotorzloc;\n silence_warnings=true,\n)\n\nIn-place version of get_blade_ends_from_body_geometry.\n\n\n\n\n\n","category":"function"},{"location":"DuctAPE/api/private_preprocess/#DuctAPE.get_local_solidity","page":"Preprocess","title":"DuctAPE.get_local_solidity","text":"get_local_solidity(B, chord, r)\n\nCalculate local solidity from local chord, radial position, and number of blades.\n\nArguments\n\nB::Float : number of blades on rotor (usually an integer, but not necessarily).\nchord::Vector{Float} : chord lengths at each radial station.\nr::Vector{Float} : dimensional radial positions.\n\nReturns\n\nsolidity::Vector{Float} : local solidity at each radial station\n\n\n\n\n\n","category":"function"},{"location":"DuctAPE/api/private_preprocess/#DuctAPE.get_stagger","page":"Preprocess","title":"DuctAPE.get_stagger","text":"get_stagger(twists)\n\nConvert twist angle to stagger angle\n\n\n\n\n\n","category":"function"},{"location":"DuctAPE/api/private_preprocess/#DuctAPE.generate_rotor_panels","page":"Preprocess","title":"DuctAPE.generate_rotor_panels","text":"generate_rotor_panels(rotorzloc, wake_grid, rotor_indices_in_wake, nwake_sheets)\n\nGenerate rotor panel objects.\n\nArguments\n\nrotorzloc::Vector{Float} : rotor lifting line axial position\nwake_grid::Array{Float,3} : wake elliptic grid axial and radial locations\nrotor_indices_in_wake::Vector{Int} : indices of where along wake the rotors are placed\nnwake_sheets::Int : number of wake sheets\n\nReturns\n\nrotor_source_panels::NamedTuple : A named tuple containing the rotor source panel variables.\n\n\n\n\n\n","category":"function"},{"location":"DuctAPE/api/private_preprocess/#DuctAPE.generate_rotor_panels!","page":"Preprocess","title":"DuctAPE.generate_rotor_panels!","text":"generate_rotor_panels!(\n rotor_source_panels, rotorzloc, wake_grid, rotor_indices_in_wake, nwake_sheets\n)\n\nIn-place version of generate_rotor_panels.\n\n\n\n\n\n","category":"function"},{"location":"DuctAPE/api/private_preprocess/#Induced-Velocities","page":"Preprocess","title":"Induced Velocities","text":"","category":"section"},{"location":"DuctAPE/api/private_preprocess/","page":"Preprocess","title":"Preprocess","text":"DuctAPE.calculate_unit_induced_velocities\nDuctAPE.calculate_unit_induced_velocities!\nDuctAPE.initialize_linear_system\nDuctAPE.initialize_linear_system!","category":"page"},{"location":"DuctAPE/api/private_preprocess/#DuctAPE.calculate_unit_induced_velocities","page":"Preprocess","title":"DuctAPE.calculate_unit_induced_velocities","text":"calculate_unit_induced_velocities(problem_dimensions, panels, integration_options)\n\nCalculate all the unit-induced velocties of all panels on all control points\n\nArguments\n\nproblem_dimensions::ProblemDimensions : A ProblemDimensions object\npanels::NamedTuple : A named tuple containing all the paneling information\nintegration_options::IntegrationOptions : Options used for integration of velocity kernals across panels\n\nReturns\n\nivr::NamedTuple : A named tuple containing arrays of induced velocities on the rotors\nivw::NamedTuple : A named tuple containing arrays of induced velocities on the wake\nivb::NamedTuple : A named tuple containing arrays of induced velocities on the bodies\n\n\n\n\n\n","category":"function"},{"location":"DuctAPE/api/private_preprocess/#DuctAPE.calculate_unit_induced_velocities!","page":"Preprocess","title":"DuctAPE.calculate_unit_induced_velocities!","text":"calculate_unit_induced_velocities!(ivr, ivw, ivb, panels, integration_options)\n\nIn-place version of calculate_unit_induced_velocities.\n\n\n\n\n\n","category":"function"},{"location":"DuctAPE/api/private_preprocess/#DuctAPE.initialize_linear_system","page":"Preprocess","title":"DuctAPE.initialize_linear_system","text":"initialize_linear_system(\n ivb,\n body_vortex_panels,\n rotor_source_panels,\n wake_vortex_panels,\n Vinf,\n integration_options,\n)\n\nSet up the linear system used in the panel method solve.\n\nArguments\n\nivb::NamedTuple : the named tuple containing all the unit induced velocities on the bodies\nbody_vortex_panels::NamedTuple : the named tuple containing the body vortex panel information\nrotor_source_panels::NamedTuple : the named tuple containing the rotor source panel information\nwake_vortex_panels::NamedTuple : the named tuple containing the wake vortex panel information\nVinf::Vector{Float} : the one-element vector containing the Freestream velocity magnitude\nintegration_options::IntegrationOptions : the integration options used in integrating the panel induced velocities\n\nReturns\n\nlinsys::NamedTuple : A named tuple containing cacheable data for the linear system, including:\nA_bb::Array{Float} : AIC (LHS) matrix for the panel method system\nb_bf::Array{Float} : Initial system RHS vector based on freestrem magnitude\nA_br::Array{Float} : Unit normal velocity from rotors onto body panels\nA_pr::Array{Float} : Unit normal velocity from rotors onto body internal psuedo control points\nA_bw::Array{Float} : Unit normal velocity from wake onto body panels\nA_pw::Array{Float} : Unit normal velocity from wake onto body internal psuedo control points\nA_bb_LU::LinearAlgebra.LU : LinearAlgebra LU factorization of the LHS matrix\nlu_decomp_flag::Vector{Bool} : flag for whether factorization was successful\n\n\n\n\n\n","category":"function"},{"location":"DuctAPE/api/private_preprocess/#DuctAPE.initialize_linear_system!","page":"Preprocess","title":"DuctAPE.initialize_linear_system!","text":"initialize_linear_system!(\n linsys,\n ivb,\n body_vortex_panels,\n rotor_source_panels,\n wake_vortex_panels,\n Vinf,\n intermediate_containers,\n integration_options,\n)\n\nIn-place version of initialize_linear_system.\n\n\n\n\n\n","category":"function"},{"location":"DuctAPE/api/private_preprocess/#Unit-Induced-Velocities","page":"Preprocess","title":"Unit Induced Velocities","text":"","category":"section"},{"location":"DuctAPE/api/private_preprocess/","page":"Preprocess","title":"Preprocess","text":"DuctAPE.calculate_xrm\nDuctAPE.calculate_xrm!\nDuctAPE.get_elliptics\nDuctAPE.vortex_ring_vz\nDuctAPE.vortex_ring_vz!\nDuctAPE.smoke_ring_vz\nDuctAPE.vortex_ring_vr\nDuctAPE.vortex_ring_vr!\nDuctAPE.source_ring_vz\nDuctAPE.source_ring_vz!\nDuctAPE.source_ring_vr\nDuctAPE.source_ring_vr!","category":"page"},{"location":"DuctAPE/api/private_preprocess/#DuctAPE.calculate_xrm","page":"Preprocess","title":"DuctAPE.calculate_xrm","text":"calculate_xrm(controlpoint, node)\n\nCalculate xi, rho, and m for vortex and/or source ring induced velocity calculation.\n\nReturns zeros if ring is on (or approximately on) the axis of rotation (zero radius).\n\nArguments\n\ncontrolpoint::Vector{Float} [z r] coordinates of point being influenced\nnode::Vector{Float} : [z r] coordinates of singularity ring\n\nReturns\n\nxi::Float : normalized relative axial position\nrho::Float : normalized relative radial position\nm::Float : Elliptic integral input\nrj::Float : radial position of the ring\n\n\n\n\n\n","category":"function"},{"location":"DuctAPE/api/private_preprocess/#DuctAPE.calculate_xrm!","page":"Preprocess","title":"DuctAPE.calculate_xrm!","text":"calculate_xrm!(cache_vec, controlpoint, node)\n\nIn-place version of calculate_xrm.\n\nCache_vec is a vector used to hold intermediate values as well as the outputs.\n\n\n\n\n\n","category":"function"},{"location":"DuctAPE/api/private_preprocess/#DuctAPE.get_elliptics","page":"Preprocess","title":"DuctAPE.get_elliptics","text":"get_elliptics(m)\n\nCalculate value of elliptic functions for the given geometry parameter.\n\nArguments\n\nm::Float : Elliptic Function parameter\n\nReturns\n\nK::Float : K(m), value of elliptic function of the first kind at m.\nE::Float : E(m), value of eeliptic function of the second kind at m.\n\n\n\n\n\n","category":"function"},{"location":"DuctAPE/api/private_preprocess/#DuctAPE.vortex_ring_vz","page":"Preprocess","title":"DuctAPE.vortex_ring_vz","text":"vortex_ring_vz(xi, rho, m, r_influence, influence_length)\n\nAxial velocity induced by axisymmetric vortex ring.\n\nUses equivalent smoke ring induced velocity for self-induction, and returns zero if vortex ring is on axis of rotation (zero radius).\n\nArguments\n\nxi::Float : normalized z-coordinate, (z-zo)/ro\nrho::Float : normalized r-coordinate, r/ro\nm::Float : Elliptic Integral parameter, 4rho/sqrt(xi^2+(rho+1)^2)\nr_influence::Float : radial location of vortex ring, ro\ninfluence_length::Float : length of panel used in calculating self-induction\n\nReturns\n\nvz::Float : axially induced velocity of vortex ring\n\n\n\n\n\n","category":"function"},{"location":"DuctAPE/api/private_preprocess/#DuctAPE.vortex_ring_vz!","page":"Preprocess","title":"DuctAPE.vortex_ring_vz!","text":"vortex_ring_vz!(xi, rho, m, r_influence, influence_length, cache_vec)\n\nSame as vortexringvz, but uses the cache_vec to store intermediate calculations.\n\n\n\n\n\n","category":"function"},{"location":"DuctAPE/api/private_preprocess/#DuctAPE.smoke_ring_vz","page":"Preprocess","title":"DuctAPE.smoke_ring_vz","text":"smoke_ring_vz(r_influence, influence_length)\n\nEquivalent \"smoke\" ring self-induced velocity.\n\nArguments\n\nr_influence::Float : radial position of ring (i.e. the ring raidus)\ninfluence_length::Float : length of influencing panel\n\nReturs\n\nvz::Float : axially induced velocity of vortex ring\n\n\n\n\n\n","category":"function"},{"location":"DuctAPE/api/private_preprocess/#DuctAPE.vortex_ring_vr","page":"Preprocess","title":"DuctAPE.vortex_ring_vr","text":"vortex_ring_vr(xi, rho, m, r_influence)\n\nRadial velocity induced by axisymmetric vortex ring.\n\nReturns zero if vortex ring is on axis of rotation (zero radius), the point of influence is on the axis, or if self-inducing velocity.\n\nArguments\n\nxi::Float : normalized z-coordinate, (z-zo)/ro\nrho::Float : normalized r-coordinate, r/ro\nm::Float : Elliptic Integral parameter, 4rho/sqrt(xi^2+(rho+1)^2)\nr_influence::Float : radial location of vortex ring, ro\n\nReturns\n\nvr::Float : radially induced velocity of vortex ring\n\n\n\n\n\n","category":"function"},{"location":"DuctAPE/api/private_preprocess/#DuctAPE.vortex_ring_vr!","page":"Preprocess","title":"DuctAPE.vortex_ring_vr!","text":"vortex_ring_vr!(xi, rho, m, r_influence, cache_vec)\n\nSame as vortexringvr, but uses the cache_vec to store intermediate calculations.\n\n\n\n\n\n","category":"function"},{"location":"DuctAPE/api/private_preprocess/#DuctAPE.source_ring_vz","page":"Preprocess","title":"DuctAPE.source_ring_vz","text":"source_ring_vz(xi, rho, m, r_influence)\n\nAxial velocity induced by axisymmetric source ring.\n\nReturns zero if source ring is on axis of rotation (zero radius), the point of influence is on the axis, or if self-inducing velocity.\n\nArguments:\n\nxi::Float : normalized z-coordinate, (z-zo)/ro\nrho::Float : normalized r-coordinate, r/ro\nm::Float : Elliptic Integral parameter, 4rho/sqrt(xi^2+(rho+1)^2)\nr_influence::Float : radial location of vortex ring, ro\n\nReturns:\n\nvz::Float : axially induced velocity of source ring\n\n\n\n\n\n","category":"function"},{"location":"DuctAPE/api/private_preprocess/#DuctAPE.source_ring_vz!","page":"Preprocess","title":"DuctAPE.source_ring_vz!","text":"source_ring_vz!(xi, rho, m, r_influence, cache_vec)\n\nSame as sourceringvz, but uses cache_vec to store intermediate values.\n\n\n\n\n\n","category":"function"},{"location":"DuctAPE/api/private_preprocess/#DuctAPE.source_ring_vr","page":"Preprocess","title":"DuctAPE.source_ring_vr","text":"source_ring_vr(xi, rho, m, r_influence)\n\nRadial velocity induced by axisymmetric source ring.\n\nReturns zero if source ring is on axis of rotation (zero radius), the point of influence is on the axis, or if self-inducing velocity.\n\nArguments:\n\nxi::Float : normalized z-coordinate, (z-zo)/ro\nrho::Float : normalized r-coordinate, r/ro\nm::Float : Elliptic Integral parameter, 4rho/sqrt(xi^2+(rho+1)^2)\nr_influence::Float : radial location of vortex ring, ro\n\nReturns:\n\nvr::Float : radially induced velocity of source ring\n\n\n\n\n\n","category":"function"},{"location":"DuctAPE/api/private_preprocess/#DuctAPE.source_ring_vr!","page":"Preprocess","title":"DuctAPE.source_ring_vr!","text":"source_ring_vr!(xi, rho, m, r_influence, cache_vec)\n\nSame as sourceringvr, but uses cache_vec to store intermediate values.\n\n\n\n\n\n","category":"function"},{"location":"DuctAPE/api/private_preprocess/#Unit-Induced-Velocity-Matrices","page":"Preprocess","title":"Unit Induced Velocity Matrices","text":"","category":"section"},{"location":"DuctAPE/api/private_preprocess/","page":"Preprocess","title":"Preprocess","text":"DuctAPE.induced_velocities_from_vortex_panels_on_points\nDuctAPE.induced_velocities_from_vortex_panels_on_points!\nDuctAPE.induced_velocities_from_source_panels_on_points\nDuctAPE.induced_velocities_from_source_panels_on_points!\nDuctAPE.induced_velocities_from_trailing_edge_gap_panel!","category":"page"},{"location":"DuctAPE/api/private_preprocess/#DuctAPE.induced_velocities_from_vortex_panels_on_points","page":"Preprocess","title":"DuctAPE.induced_velocities_from_vortex_panels_on_points","text":"induced_velocities_from_vortex_panels_on_points(\n controlpoints,\n nodes,\n nodemap,\n influence_lengths,\n integration_options;\n integration_caches=nothing,\n)\n\nCalculate axial and radial components of induced velocity for a set of control points due to a set of axisymmetric vortex panels (bands).\n\nUsed for getting the unit induced velocities due to the body panels on the rotor/wake as well as the unit induced velocity due to the wake on the body/rotor.\n\nArguments\n\ncontrolpoints::Matrix{Float} [z r] coordinates of points being influenced\nnodes::Matrix{Float} : [z r] coordinates of vortex rings\nnodemap::Matrix{Int} : mapping from panel index to associated node indices\ninfluence_lengths::Vector{Float} : lengths over which vortex ring influence is applied on the surface.\nintegration_options::IntegrationOptions : integration options\n\nKeyword Arguments\n\nintegration_caches::NamedTuple=nothing : cache used in in-place quadrature functions.\n\nReturns\n\nVEL::Array{Float} : N-controlpoint x N-node x [vz, vr] array of induced velocity components\n\n\n\n\n\n","category":"function"},{"location":"DuctAPE/api/private_preprocess/#DuctAPE.induced_velocities_from_vortex_panels_on_points!","page":"Preprocess","title":"DuctAPE.induced_velocities_from_vortex_panels_on_points!","text":"induced_velocities_from_vortex_panels_on_points!(\n VEL,\n controlpoint,\n node,\n nodemap,\n influence_length,\n integration_options;\n integration_caches=nothing,\n)\n\nIn-place version of induced_velocities_from_vortex_panels_on_points.\n\n\n\n\n\n","category":"function"},{"location":"DuctAPE/api/private_preprocess/#DuctAPE.induced_velocities_from_source_panels_on_points","page":"Preprocess","title":"DuctAPE.induced_velocities_from_source_panels_on_points","text":"induced_velocities_from_source_panels_on_points(\n controlpoints,\n nodes,\n nodemap,\n influence_lengths,\n integration_options;\n integration_caches=nothing,\n)\n\nCalculate axial and radial components of induced velocity for a set of control points due to a set of axisymmetric source panels (bands)\n\nUsed for getting the unit induced velocities due to the body panels on the rotor/wake as well as the unit induced velocity due to the wake on the body/rotor.\n\nArguments\n\ncontrolpoints::Matrix{Float} [z r] coordinates of points being influenced\nnodes::Matrix{Float} : [z r] coordinates of vortex rings\nnodemap::Matrix{Int} : mapping from panel index to associated node indices\ninfluence_lengths::Vector{Float} : lengths over which vortex ring influence is applied on the surface.\nintegration_options::IntegrationOptions : integration options\n\nReturns:\n\nVEL::Array{Float} : N-controlpoint x N-node x [vz, vr] array of induced velocity components\n\n\n\n\n\n","category":"function"},{"location":"DuctAPE/api/private_preprocess/#DuctAPE.induced_velocities_from_source_panels_on_points!","page":"Preprocess","title":"DuctAPE.induced_velocities_from_source_panels_on_points!","text":"induced_velocities_from_source_panels_on_points!(\n VEL,\n controlpoint,\n node,\n nodemap,\n influence_length,\n integration_options;\n integration_caches=nothing,\n)\n\nIn-place version of induced_velocities_from_source_panels_on_points.\n\n\n\n\n\n","category":"function"},{"location":"DuctAPE/api/private_preprocess/#DuctAPE.induced_velocities_from_trailing_edge_gap_panel!","page":"Preprocess","title":"DuctAPE.induced_velocities_from_trailing_edge_gap_panel!","text":"induced_velocities_from_trailing_edge_gap_panel!(\n VEL,\n controlpoint,\n tenode,\n teinfluence_length,\n tendotn,\n tencrossn,\n teadjnodeidxs,\n integration_options;\n wake=false,\n integration_caches=nothing,\n)\n\nCalculate axial and radial components of induced velocity for a set of control points due to any trailing edge gap panels.\n\nUsed for getting the unit induced velocities due to the body body trailing edge gap panels on the body/rotor/wake.\n\nNote, this function is also used to calculate the influence of the wake ends rather than modeling a semi-infinite fortex sheet.\n\nArguments\n\nVEL::Array{Float} : N-controlpoint x N-node x [vz, vr] array of induced velocity components (modified in place)\ncontrolpoints::Matrix{Float} [z r] coordinates of points being influenced\nnodes::Matrix{Float} : [z r] coordinates of vortex rings\nnodemap::Matrix{Int} : mapping from panel index to associated node indices\ninfluence_lengths::Vector{Float} : lengths over which vortex ring influence is applied on the surface.\nstrengths::Matrix{Float} : vortex constant circulation values\nintegration_options::IntegrationOptions : integration options\n\nKeyword Arguments\n\nwake::Bool=false : flag to indicate if this is being used for a wake sheet.\nintegration_caches::NamedTuple=nothing : cache used in in-place quadrature functions.\n\n\n\n\n\n","category":"function"},{"location":"DuctAPE/api/private_preprocess/#Panel-Method-Velocity-Functions","page":"Preprocess","title":"Panel Method Velocity Functions","text":"","category":"section"},{"location":"DuctAPE/api/private_preprocess/","page":"Preprocess","title":"Preprocess","text":"DuctAPE.vortex_aic_boundary_on_boundary\nDuctAPE.vortex_aic_boundary_on_boundary!\nDuctAPE.vortex_aic_boundary_on_field\nDuctAPE.vortex_aic_boundary_on_field!\nDuctAPE.add_kutta!\nDuctAPE.add_te_gap_aic!\nDuctAPE.source_aic\nDuctAPE.source_aic!\nDuctAPE.freestream_influence_vector\nDuctAPE.freestream_influence_vector!\nDuctAPE.assemble_lhs_matrix\nDuctAPE.assemble_lhs_matrix!\nDuctAPE.factorize_LHS\nDuctAPE.factorize_LHS!\nDuctAPE.assemble_rhs_matrix\nDuctAPE.assemble_rhs_matrix!\nDuctAPE.calculate_normal_velocity\nDuctAPE.calculate_normal_velocity!","category":"page"},{"location":"DuctAPE/api/private_preprocess/#DuctAPE.vortex_aic_boundary_on_boundary","page":"Preprocess","title":"DuctAPE.vortex_aic_boundary_on_boundary","text":"vortex_aic_boundary_on_boundary(\n controlpoint, normal, node, nodemap, influence_length, integration_options\n)\n\nCalculate panel method influence coefficients (V dot nhat) for a set of control points (on panels) due to a set of axisymmetric vortex rings (also on body surface)\n\nCan be used for constructing the LHS influence Matrix for the panel method system.\n\nArguments\n\ncontrolpoint::Matrix{Float} [z r] coordinates of points being influenced\nnormal::Matrix{Float} : unit normal vectors of the panels on which the control points are situated.\nnode::Matrix{Float} : [z r] coordinates of panel nodes (edges)\nnodemap::Matrix{Int} : [1 2] node indices for each panel\ninfluence_length::Vector{Float} : lengths of influencing panels\nintegration_options::IntegrationOptions : integration options\n\nReturns\n\nAICn::Matrix{Float} : N controlpoint x N+1 node array of V dot nhat values\n\n\n\n\n\n","category":"function"},{"location":"DuctAPE/api/private_preprocess/#DuctAPE.vortex_aic_boundary_on_boundary!","page":"Preprocess","title":"DuctAPE.vortex_aic_boundary_on_boundary!","text":"vortex_aic_boundary_on_boundary!(\n AICn,\n controlpoint,\n normal,\n node,\n nodemap,\n influence_length,\n integration_options;\n integration_caches=nothing,\n)\n\nIn-place verion of vortex_aic_boundary_on_boundary.\n\nintegration_caches is a named tuple containing caching for intermediate calculation values.\n\n\n\n\n\n","category":"function"},{"location":"DuctAPE/api/private_preprocess/#DuctAPE.vortex_aic_boundary_on_field","page":"Preprocess","title":"DuctAPE.vortex_aic_boundary_on_field","text":"vortex_aic_boundary_on_field(\n controlpoint,\n normal,\n node,\n nodemap,\n influence_length,\n integration_options;\n integration_caches=nothing,\n)\n\nCalculate panel method influence coefficients (V dot nhat) for a set of control points (NOT on panels) due to a set of axisymmetric vortex rings (on body surface)\n\nUsed for constructing portions of the panel method LHS matrix related to the pseudo control points in the bodies.\n\nArguments:\n\ncontrolpoint::Matrix{Float} [z r] coordinates of points being influenced\nnormal::Matrix{Float} : unit normal vectors of the panels on which the control points are situated.\nnode::Matrix{Float} : [z r] coordinates of panel nodes (edges)\nnodemap::Matrix{Int} : [1 2] node indices for each panel\ninfluence_length::Vector{Float} : lengths of influencing panels\nintegration_options::IntegrationOptions : integration options\n\nKeyword Arguments\n\nintegration_caches::NamedTuple=nothing : caches for intermediate values in integration.\n\nReturns:\n\nAICn::Matrix{Float} : N controlpoint x N+1 node array of V dot nhat values\n\n\n\n\n\n","category":"function"},{"location":"DuctAPE/api/private_preprocess/#DuctAPE.vortex_aic_boundary_on_field!","page":"Preprocess","title":"DuctAPE.vortex_aic_boundary_on_field!","text":"vortex_aic_boundary_on_field!(\n AICn,\n controlpoint,\n normal,\n node,\n nodemap,\n influence_length,\n integration_options;\n integration_caches=nothing,\n)\n\nIn-place version of vortex_aic_boundary_on_field.\n\n\n\n\n\n","category":"function"},{"location":"DuctAPE/api/private_preprocess/#DuctAPE.add_kutta!","page":"Preprocess","title":"DuctAPE.add_kutta!","text":"add_kutta!(LHS, AICn, kids)\n\nAdd Kutta condition (γ1 + γN = 0) to LHS matrix.\n\nLHS::Matrix{Float} : a pre-allocated (zeros) full size left-hand side matrix\nAICn::Matrix{Float} : influence coefficients for panels/nodes\nkids::Vector{Int} : [1 2] indices of where to put 1's for kutta condition\n\n\n\n\n\n","category":"function"},{"location":"DuctAPE/api/private_preprocess/#DuctAPE.add_te_gap_aic!","page":"Preprocess","title":"DuctAPE.add_te_gap_aic!","text":"add_te_gap_aic!(\n AICn,\n controlpoint,\n normal,\n tenode,\n teinfluence_length,\n tendotn,\n tencrossn,\n teadjnodeidxs,\n integration_options;\n wake=false,\n integration_caches=nothing,\n)\n\nAdd trailing edge gap aerodynmic influence coefficient contributions to the AIC matrix.\n\nArguments\n\nAICn::Matrix{Float} : N controlpoint x N+1 node array of V dot nhat values\ncontrolpoint::Matrix{Float} [z r] coordinates of points being influenced\nnormal::Matrix{Float} : unit normal vectors of the panels on which the control points are situated.\ntenode::Matrix{Float} : [z r] coordinates of trailing edge panel nodes (edges)\nteinfluence_length::Vector{Float} : lengths of influencing trailing edge panels\ntendotn::Matrix{Float} : nhat of trailing edge panel dotted with nhat of adjacent panels\ntencrossn::Matrix{Float} : nhat of trailing edge panel crossed with nhat of adjacent panels\nteadjnodeidxs::Matrix{Float} : indices of nodes adjacent to trailing edge panel\nintegration_options::IntegrationOptions : integration options\n\nKeyword Arguments\n\nwake::Bool=false : flag as to whether this function is being applied to a wake sheet.\nintegration_caches::NamedTuple=nothing : caches for intermediate values in integration.\n\n\n\n\n\n","category":"function"},{"location":"DuctAPE/api/private_preprocess/#DuctAPE.source_aic","page":"Preprocess","title":"DuctAPE.source_aic","text":"source_aic(\n controlpoint,\n normal,\n node,\n nodemap,\n influence_length,\n integration_options;\n integration_caches=nothing,\n)\n\nCalculate panel method influence coefficients (V dot nhat) for a set of control points (on panels) due to a set of axisymmetric source rings not on body surface.\n\nCan be used for constructing the RHS boundary conditions due to rotor source panels.\n\nArguments\n\ncontrolpoint::Matrix{Float} [z r] coordinates of points being influenced\nnormal::Matrix{Float} : unit normal vectors of the panels on which the control points are situated.\nnode::Matrix{Float} : [z r] coordinates of panel nodes (edges)\nnodemap::Matrix{Int} : [1 2] node indices for each panel\ninfluence_length::Vector{Float} : lengths of influencing panels\nintegration_options::IntegrationOptions : integration options\n\nKeyword Arguments\n\nintegration_caches::NamedTuple=nothing : caches for intermediate values in integration.\n\nReturns\n\nAICn::Matrix{Float} : N controlpoint x N+1 node array of V dot nhat values\n\n\n\n\n\n","category":"function"},{"location":"DuctAPE/api/private_preprocess/#DuctAPE.source_aic!","page":"Preprocess","title":"DuctAPE.source_aic!","text":"source_aic!(\n AICn,\n controlpoint,\n normal,\n node,\n nodemap,\n influence_length,\n integration_options;\n integration_caches=nothing,\n)\n\nIn-place version of source_aic.\n\n\n\n\n\n","category":"function"},{"location":"DuctAPE/api/private_preprocess/#DuctAPE.freestream_influence_vector","page":"Preprocess","title":"DuctAPE.freestream_influence_vector","text":"freestream_influence_vector(normals, Vinfmat)\n\nCalculate RHS contributions due to freestream.\n\nNote that the freestream is assumed to have zero radial component in the underlying theory, but here we allow an arbitrary 2D vector for velocity for taking the dot product easier.\n\nArguments\n\nnormals::Matrix{Float} : unit normal vectors of the panels on which the control points are situated.\nVinfmat::Matrix{Float} : [z r] components of freestream velocity (r's should be zero)\n\nReturns\n\nRHS::Vector{Float} : vector of normal components of freestream velocity on input panels\n\n\n\n\n\n","category":"function"},{"location":"DuctAPE/api/private_preprocess/#DuctAPE.freestream_influence_vector!","page":"Preprocess","title":"DuctAPE.freestream_influence_vector!","text":"freestream_influence_vector!(RHS, normals, Vinfmat)\n\nIn-place version of freestream_influence_vector.\n\n\n\n\n\n","category":"function"},{"location":"DuctAPE/api/private_preprocess/#DuctAPE.assemble_lhs_matrix","page":"Preprocess","title":"DuctAPE.assemble_lhs_matrix","text":"assemble_lhs_matrix(\n AICn, AICpcp, npanel, nnode, totpanel, totnode, prescribednodeidxs; dummyval=1.0\n)\n\nAssemble the LHS matrix of the panel method.\n\nArguments\n\nAICn::Matrix{Float} : N controlpoint x N+1 node array of V dot nhat values\nAICpcp::Matrix{Float} : Nbodies controlpoint x N+1 node array of V dot nhat values (influence on psuedo control points)\nnpanel::Vector{Int} : number of panels comprising each body\nnnode::Vector{Int} : number of nodes comprising each body\ntotpanel::Int : total number of panels\ntotnode::Int : total number of nodes\nprescribednodeidxs::Vector{Int} : indices of nodes with prescribed strengths (those on the axis of rotation).\n\nKeyword Arguments\n\ndummyval::Float=1.0 : value for dummy input for prescribed and internal control points in the system. Do not change except for debugging purposes.\n\nReturns\n\nLHS::Matrix{Float} : The full LHS matrix for the panel method.\n\n\n\n\n\n","category":"function"},{"location":"DuctAPE/api/private_preprocess/#DuctAPE.assemble_lhs_matrix!","page":"Preprocess","title":"DuctAPE.assemble_lhs_matrix!","text":"assemble_lhs_matrix!(\n LHS, AICn, AICpcp, npanel, nnode, totpanel, totnode, prescribednodeidxs; dummyval=1.0\n)\n\nIn-place version of assemble_lhs_matrix.\n\n\n\n\n\n","category":"function"},{"location":"DuctAPE/api/private_preprocess/#DuctAPE.factorize_LHS","page":"Preprocess","title":"DuctAPE.factorize_LHS","text":"factorize_LHS(A::AbstractMatrix)\n\nReturns the LU decomposition of A.\n\n\n\n\n\n","category":"function"},{"location":"DuctAPE/api/private_preprocess/#DuctAPE.factorize_LHS!","page":"Preprocess","title":"DuctAPE.factorize_LHS!","text":"factorize_LHS!(Apivot::AbstractMatrix, A::AbstractMatrix)\n\nReturns the LU decomposition of A using Apivot as storage memory to pivot leaving A unchanged.\n\n\n\n\n\n","category":"function"},{"location":"DuctAPE/api/private_preprocess/#DuctAPE.assemble_rhs_matrix","page":"Preprocess","title":"DuctAPE.assemble_rhs_matrix","text":"assemble_rhs_matrix(\n vdnb, vdnpcp, npanel, nnode, totpanel, totnode, prescribednodeidxs\n)\n\nArguments\n\nvdnb::Vector{Float} : V dot nhat for body panels\nvdnpcp::Vector{Float} : V dot nhat for pseudo control points\nnpanel::Vector{Int} : number of panels comprising each body\nnnode::Vector{Int} : number of nodes comprising each body\ntotpanel::Int : total number of body panels\ntotnode::Int : total number of body nodes\nprescribednodeidxs::Vector{Int} : indices of nodes with prescribed strengths (those on the axis of rotation)\n\nReturns\n\nRHS::Vector{Float} : the RHS vector of the panel method.\n\n\n\n\n\n","category":"function"},{"location":"DuctAPE/api/private_preprocess/#DuctAPE.assemble_rhs_matrix!","page":"Preprocess","title":"DuctAPE.assemble_rhs_matrix!","text":"assemble_rhs_matrix!(\n RHS, vdnb, vdnpcp, npanel, nnode, totpanel, totnode, prescribednodeidxs\n)\n\nIn-place version of assemble_rhs_matrix.\n\n\n\n\n\n","category":"function"},{"location":"DuctAPE/api/private_preprocess/#DuctAPE.calculate_normal_velocity","page":"Preprocess","title":"DuctAPE.calculate_normal_velocity","text":"calculate_normal_velocity(velocity_vector, normal)\n\nCalculate normal velocity_vector (V dot nhat).\n\nArguments\n\nvelocity_vector::Matrix{Float} : velocity vector [z r] on each panel\nnormal::Matrix{Float} : the panel unit normals\n\nReturns\n\nAIC::Matrix{Float} : V dot n on each panel\n\n\n\n\n\n","category":"function"},{"location":"DuctAPE/api/private_preprocess/#DuctAPE.calculate_normal_velocity!","page":"Preprocess","title":"DuctAPE.calculate_normal_velocity!","text":"calculate_normal_velocity!(AIC, velocity_vector, normal)\n\nIn-place version of calculate_normal_velocity.\n\n\n\n\n\n","category":"function"},{"location":"DuctAPE/api/private_preprocess/#Quadrature","page":"Preprocess","title":"Quadrature","text":"","category":"section"},{"location":"DuctAPE/api/private_preprocess/#Integrands","page":"Preprocess","title":"Integrands","text":"","category":"section"},{"location":"DuctAPE/api/private_preprocess/","page":"Preprocess","title":"Preprocess","text":"DuctAPE.nominal_vortex_induced_velocity_sample\nDuctAPE.nominal_vortex_induced_velocity_sample!\nDuctAPE.subtracted_singular_vortex_influence\nDuctAPE.subtracted_singular_vortex_influence!\nDuctAPE.analytically_integrated_vortex_influence\nDuctAPE.analytically_integrated_vortex_influence!\nDuctAPE.self_vortex_induced_velocity_sample\nDuctAPE.self_vortex_induced_velocity_sample!\nDuctAPE.nominal_source_induced_velocity_sample\nDuctAPE.nominal_source_induced_velocity_sample!\nDuctAPE.subtracted_singular_source_influence\nDuctAPE.subtracted_singular_source_influence!\nDuctAPE.analytically_integrated_source_influence\nDuctAPE.analytically_integrated_source_influence!\nDuctAPE.self_source_induced_velocity_sample\nDuctAPE.self_source_induced_velocity_sample!","category":"page"},{"location":"DuctAPE/api/private_preprocess/#DuctAPE.nominal_vortex_induced_velocity_sample","page":"Preprocess","title":"DuctAPE.nominal_vortex_induced_velocity_sample","text":"nominal_vortex_induced_velocity_sample(\n t, node1, node2, influence_length, controlpoint, cache_vec; nondimrange=(0.0, 1.0)\n)\n\nCalculate the velocity induced by a linear vortex panel on a point.\n\nArguments\n\nt::Float : sample point in range (0,1) selected by quadrature method.\nnode1::Vector{Float} : first panel node (edge) position.\nnode2::Vector{Float} : second panel node (edge) position.\ninfluence_length::Float : dimensional length of panel.\ncontrolpoint::Vector{Float} : controlpoint position\ncache_vec::Vector{Float} : cache for intermediate calculations\n\nKeyword Arguments\n\nnondimrange::Tuple=(0.0,1.0) : Non-dimensional range describing the panel length. Do not change excpet for debugging purposes. Note, can also be a vector.\n\nReturns\n\nV::Matrix{Float} : 2x2 matrix of axial and radial induced velocities from each of the nodes.\n\n\n\n\n\n","category":"function"},{"location":"DuctAPE/api/private_preprocess/#DuctAPE.nominal_vortex_induced_velocity_sample!","page":"Preprocess","title":"DuctAPE.nominal_vortex_induced_velocity_sample!","text":"nominal_vortex_induced_velocity_sample!(\n V, t, node1, node2, influence_length, controlpoint, cache_vec; nondimrange=(0.0, 1.0)\n)\n\nIn-place version of nominal_vortex_induced_velocity_sample.\n\n\n\n\n\n","category":"function"},{"location":"DuctAPE/api/private_preprocess/#DuctAPE.subtracted_singular_vortex_influence","page":"Preprocess","title":"DuctAPE.subtracted_singular_vortex_influence","text":"subtracted_singular_vortex_influence(node, controlpoint)\n\nCalculate the singular portions of the self-induced vortex panel influence to subtract off the integral in the separation of singularity method.\n\nArguments\n\nnode::Vector{Float} : node position\ncontrolpoint::Vector{Float} : controlpoint position\n\nReturns\n\naxial::Float : axial direction influence\nradial::Float : radial direction influence\n\n\n\n\n\n","category":"function"},{"location":"DuctAPE/api/private_preprocess/#DuctAPE.subtracted_singular_vortex_influence!","page":"Preprocess","title":"DuctAPE.subtracted_singular_vortex_influence!","text":"subtracted_singular_vortex_influence!(node, controlpoint, cache_vec)\n\nSomewhat in-place version of subtracted_singular_vortex_influence.\n\nArguments\n\nnode::Vector{Float} : node position\ncontrolpoint::Vector{Float} : controlpoint position\ncache_vec::Vector{Float} : used to store intermediate values.\n\nReturns\n\naxial::Float : axial direction influence\nradial::Float : radial direction influence\n\n\n\n\n\n","category":"function"},{"location":"DuctAPE/api/private_preprocess/#DuctAPE.analytically_integrated_vortex_influence","page":"Preprocess","title":"DuctAPE.analytically_integrated_vortex_influence","text":"analytically_integrated_vortex_influence(r, influence_length)\n\nAnalytical approximation of the singular portions of the self-induced vortex panel velocities to be added back in as part of the separation of singularity method.\n\nArguments\n\nr::Float : radial position of self-induced control point\ninfluence_length::Float : dimensional length of the panel\n\nReturns\n\nV::Vector{Float} : axial and radial induced velocities\n\n\n\n\n\n","category":"function"},{"location":"DuctAPE/api/private_preprocess/#DuctAPE.analytically_integrated_vortex_influence!","page":"Preprocess","title":"DuctAPE.analytically_integrated_vortex_influence!","text":"analytically_integrated_vortex_influence!(V, r, influence_length)\n\nIn-place version of analytically_integrated_vortex_influence.\n\n\n\n\n\n","category":"function"},{"location":"DuctAPE/api/private_preprocess/#DuctAPE.self_vortex_induced_velocity_sample","page":"Preprocess","title":"DuctAPE.self_vortex_induced_velocity_sample","text":"self_vortex_induced_velocity_sample(\n t, node1, node2, influence_length, controlpoint, cache_vec; nondimrange=(0.0, 1.0)\n)\n\nCalculate the velocity induced by a linear vortex panel on a point at the midpoint between the panel edges.\n\nArguments\n\nt::Float : sample point in range (0,1) selected by quadrature method.\nnode1::Vector{Float} : first panel node (edge) position.\nnode2::Vector{Float} : second panel node (edge) position.\ninfluence_length::Float : dimensional length of panel.\ncontrolpoint::Vector{Float} : controlpoint position\ncache_vec::Vector{Float} : cache for intermediate calculations\n\nKeyword Arguments\n\nnondimrange::Tuple=(0.0,1.0) : Non-dimensional range describing the panel length. Do not change excpet for debugging purposes. Note, can also be a vector.\n\nReturns\n\nV::Matrix{Float} : 2x2 matrix of axial and radial induced velocities from each of the nodes.\n\n\n\n\n\n","category":"function"},{"location":"DuctAPE/api/private_preprocess/#DuctAPE.self_vortex_induced_velocity_sample!","page":"Preprocess","title":"DuctAPE.self_vortex_induced_velocity_sample!","text":"self_vortex_induced_velocity_sample!(\n V, t, node1, node2, influence_length, controlpoint, cache_vec; nondimrange=(0.0, 1.0)\n)\n\nIn-place version of self_vortex_induced_velocity_sample.\n\n\n\n\n\n","category":"function"},{"location":"DuctAPE/api/private_preprocess/#DuctAPE.nominal_source_induced_velocity_sample","page":"Preprocess","title":"DuctAPE.nominal_source_induced_velocity_sample","text":"nominal_source_induced_velocity_sample(\n t, node1, node2, influence_length, controlpoint, cache_vec; nondimrange=(0.0, 1.0)\n)\n\nCalculate the velocity induced by a source panel on a point.\n\nArguments\n\nt::Float : sample point in range (0,1) selected by quadrature method.\nnode1::Vector{Float} : first panel node (edge) position.\nnode2::Vector{Float} : second panel node (edge) position.\ninfluence_length::Float : dimensional length of panel.\ncontrolpoint::Vector{Float} : controlpoint position\ncache_vec::Vector{Float} : cache for intermediate calculations\n\nKeyword Arguments\n\nnondimrange::Tuple=(0.0,1.0) : Non-dimensional range describing the panel length. Do not change excpet for debugging purposes. Note, can also be a vector.\n\nReturns\n\nV::Matrix{Float} : 2x2 matrix of axial and radial induced velocities from each of the nodes.\n\n\n\n\n\n","category":"function"},{"location":"DuctAPE/api/private_preprocess/#DuctAPE.nominal_source_induced_velocity_sample!","page":"Preprocess","title":"DuctAPE.nominal_source_induced_velocity_sample!","text":"nominal_source_induced_velocity_sample!(\n V, t, node1, node2, influence_length, controlpoint, cache_vec; nondimrange=(0.0,1.0)\n)\n\nIn-place version of nominal_source_induced_velocity_sample.\n\n\n\n\n\n","category":"function"},{"location":"DuctAPE/api/private_preprocess/#DuctAPE.subtracted_singular_source_influence","page":"Preprocess","title":"DuctAPE.subtracted_singular_source_influence","text":"subtracted_singular_source_influence(node, controlpoint)\n\nCalculate the singular portions of the self-induced source panel influence to subtract off the integral in the separation of singularity method.\n\nArguments\n\nnode::Vector{Float} : node position\ncontrolpoint::Vector{Float} : controlpoint position\n\nReturns\n\naxial::Float : axial direction influence\nradial::Float : radial direction influence\n\n\n\n\n\n","category":"function"},{"location":"DuctAPE/api/private_preprocess/#DuctAPE.subtracted_singular_source_influence!","page":"Preprocess","title":"DuctAPE.subtracted_singular_source_influence!","text":"subtracted_singular_source_influence!(node, controlpoint, cache_vec)\n\nIn-place version of subtracted_singular_source_influence.\n\n\n\n\n\n","category":"function"},{"location":"DuctAPE/api/private_preprocess/#DuctAPE.analytically_integrated_source_influence","page":"Preprocess","title":"DuctAPE.analytically_integrated_source_influence","text":"analytically_integrated_source_influence(r, influence_length)\n\nIn-place version of analytically_integrated_source_influence.\n\n\n\n\n\n","category":"function"},{"location":"DuctAPE/api/private_preprocess/#DuctAPE.analytically_integrated_source_influence!","page":"Preprocess","title":"DuctAPE.analytically_integrated_source_influence!","text":"analytically_integrated_source_influence(r, influence_length)\n\nAnalytical approximation of the singular portions of the self-induced source panel velocities to be added back in as part of the separation of singularity method.\n\nArguments\n\nr::Float : radial position of self-induced control point\ninfluence_length::Float : dimensional length of the panel\n\nReturns\n\nV::Vector{Float} : axial and radial induced velocities\n\n\n\n\n\n","category":"function"},{"location":"DuctAPE/api/private_preprocess/#DuctAPE.self_source_induced_velocity_sample","page":"Preprocess","title":"DuctAPE.self_source_induced_velocity_sample","text":"self_source_induced_velocity_sample(\n t, node1, node2, influence_length, controlpoint, cache_vec; nondimrange=(0.0, 1.0)\n)\n\nCalculate the velocity induced by a linear source panel on a point at the midpoint between the panel edges.\n\nArguments\n\nt::Float : sample point in range (0,1) selected by quadrature method.\nnode1::Vector{Float} : first panel node (edge) position.\nnode2::Vector{Float} : second panel node (edge) position.\ninfluence_length::Float : dimensional length of panel.\ncontrolpoint::Vector{Float} : controlpoint position\ncache_vec::Vector{Float} : cache for intermediate calculations\n\nKeyword Arguments\n\nnondimrange::Tuple=(0.0,1.0) : Non-dimensional range describing the panel length. Do not change excpet for debugging purposes. Note, can also be a vector.\n\nReturns\n\nV::Matrix{Float} : 2x2 matrix of axial and radial induced velocities from each of the nodes.\n\n\n\n\n\n","category":"function"},{"location":"DuctAPE/api/private_preprocess/#DuctAPE.self_source_induced_velocity_sample!","page":"Preprocess","title":"DuctAPE.self_source_induced_velocity_sample!","text":"self_source_induced_velocity_sample!(\n V, t, node1, node2, influence_length, controlpoint, cache_vec; nondimrange=(0.0, 1.0)\n)\n\nIn-place version of self_source_induced_velocity_sample.\n\n\n\n\n\n","category":"function"},{"location":"DuctAPE/api/private_preprocess/#Integrals","page":"Preprocess","title":"Integrals","text":"","category":"section"},{"location":"DuctAPE/api/private_preprocess/","page":"Preprocess","title":"Preprocess","text":"DuctAPE.nominal_vortex_panel_integration\nDuctAPE.nominal_vortex_panel_integration!\nDuctAPE.self_vortex_panel_integration\nDuctAPE.self_vortex_panel_integration!\nDuctAPE.nominal_source_panel_integration\nDuctAPE.nominal_source_panel_integration!\nDuctAPE.self_source_panel_integration\nDuctAPE.self_source_panel_integration!\nDuctAPE.extrapolate!","category":"page"},{"location":"DuctAPE/api/private_preprocess/#DuctAPE.nominal_vortex_panel_integration","page":"Preprocess","title":"DuctAPE.nominal_vortex_panel_integration","text":"nominal_vortex_panel_integration(\n integration_options,\n node1,\n node2,\n influence_length,\n controlpoint,\n containers;\n debug=false,\n)\n\nIntegration of vortex panel induced velocity on a point far away.\n\nArguments\n\nintegration_options::IntegrationMethod : options for itegration methods\nnode1::Vector{Float} : first panel node (edge) position.\nnode2::Vector{Float} : second panel node (edge) position.\ninfluence_length::Float : dimensional length of panel.\ncontrolpoint::Vector{Float} : controlpoint position\ncontainers::NamedTuple : cache for intermediate calculations\n\nKeyword Arguments\n\ndebug::Bool=false : if true, some methods will return the estimation error.\n\nReturns\n\nV::Matrix{Float} : velocity components due to the jth and j+1th nodes in the format: [vz_j vr_j; vz_{j+1} vr_{j+1}]\n\n\n\n\n\n","category":"function"},{"location":"DuctAPE/api/private_preprocess/#DuctAPE.nominal_vortex_panel_integration!","page":"Preprocess","title":"DuctAPE.nominal_vortex_panel_integration!","text":"nominal_vortex_panel_integration!(\n integration_options,\n V,\n node1,\n node2,\n influence_length,\n controlpoint,\n containers;\n debug=false,\n)\n\nIn-place version of nominal_vortex_panel_integration.\n\n\n\n\n\n","category":"function"},{"location":"DuctAPE/api/private_preprocess/#DuctAPE.self_vortex_panel_integration","page":"Preprocess","title":"DuctAPE.self_vortex_panel_integration","text":"self_vortex_panel_integration(\n integration_options,\n node1,\n node2,\n influence_length,\n controlpoint,\n containers;\n debug=false,\n)\n\nIntegration of linear vortex panel self-induced velocity.\n\nArguments\n\nintegration_options::IntegrationMethod : options for itegration methods\nnode1::Vector{Float} : first panel node (edge) position.\nnode2::Vector{Float} : second panel node (edge) position.\ninfluence_length::Float : dimensional length of panel.\ncontrolpoint::Vector{Float} : controlpoint position\ncontainers::NamedTuple : cache for intermediate calculations\n\nKeyword Arguments\n\ndebug::Bool=false : if true, some methods will return the estimation error.\n\nReturns\n\nV::Matrix{Float} : velocity components due to the jth and j+1th nodes in the format: [vz_j vr_j; vz_{j+1} vr_{j+1}]\n\n\n\n\n\n","category":"function"},{"location":"DuctAPE/api/private_preprocess/#DuctAPE.self_vortex_panel_integration!","page":"Preprocess","title":"DuctAPE.self_vortex_panel_integration!","text":"self_vortex_panel_integration!(\n integration_options,\n V,\n node1,\n node2,\n influence_length,\n controlpoint,\n containers;\n debug=false,\n)\n\nIn-place version of self_vortex_panel_integration.\n\n\n\n\n\n","category":"function"},{"location":"DuctAPE/api/private_preprocess/#DuctAPE.nominal_source_panel_integration","page":"Preprocess","title":"DuctAPE.nominal_source_panel_integration","text":"nominal_source_panel_integration(\n integration_options,\n node1,\n node2,\n influence_length,\n controlpoint,\n containers;\n debug=false,\n)\n\nIntegration of source panel induced velocity on a point far away.\n\nArguments\n\nintegration_options::IntegrationMethod : options for itegration methods\nnode1::Vector{Float} : first panel node (edge) position.\nnode2::Vector{Float} : second panel node (edge) position.\ninfluence_length::Float : dimensional length of panel.\ncontrolpoint::Vector{Float} : controlpoint position\ncontainers::NamedTuple : cache for intermediate calculations\n\nKeyword Arguments\n\ndebug::Bool=false : if true, some methods will return the estimation error.\n\nReturns\n\nV::Matrix{Float} : velocity components due to the jth and j+1th nodes in the format: [vz_j vr_j; vz_{j+1} vr_{j+1}]\n\n\n\n\n\n","category":"function"},{"location":"DuctAPE/api/private_preprocess/#DuctAPE.nominal_source_panel_integration!","page":"Preprocess","title":"DuctAPE.nominal_source_panel_integration!","text":"nominal_source_panel_integration!(\n integration_options,\n V,\n node1,\n node2,\n influence_length,\n controlpoint,\n containers;\n debug=false,\n)\n\nIn-place version of nominal_source_panel_integration.\n\n\n\n\n\n","category":"function"},{"location":"DuctAPE/api/private_preprocess/#DuctAPE.self_source_panel_integration","page":"Preprocess","title":"DuctAPE.self_source_panel_integration","text":"self_source_panel_integration(\n integration_options,\n node1,\n node2,\n influence_length,\n controlpoint,\n containers;\n debug=false,\n)\n\nIntegration of linear source panel self-induced velocity.\n\nArguments\n\nintegration_options::IntegrationMethod : options for itegration methods\nnode1::Vector{Float} : first panel node (edge) position.\nnode2::Vector{Float} : second panel node (edge) position.\ninfluence_length::Float : dimensional length of panel.\ncontrolpoint::Vector{Float} : controlpoint position\ncontainers::NamedTuple : cache for intermediate calculations\n\nKeyword Arguments\n\ndebug::Bool=false : if true, some methods will return the estimation error.\n\nReturns\n\nV::Matrix{Float} : velocity components due to the jth and j+1th nodes in the format: [vz_j vr_j; vz_{j+1} vr_{j+1}]\n\n\n\n\n\n","category":"function"},{"location":"DuctAPE/api/private_preprocess/#DuctAPE.self_source_panel_integration!","page":"Preprocess","title":"DuctAPE.self_source_panel_integration!","text":"self_source_panel_integration!(\n integration_options,\n V,\n node1,\n node2,\n influence_length,\n controlpoint,\n containers;\n debug=false,\n)\n\nIn-place version of self_source_panel_integration.\n\n\n\n\n\n","category":"function"},{"location":"DuctAPE/api/private_preprocess/#DuctAPE.extrapolate!","page":"Preprocess","title":"DuctAPE.extrapolate!","text":"extrapolate!(V, err, fh; power=2, atol=1e-6)\n\nPerforms Richardson extrapolation on an array fh for use in Romberg integration.\n\nArguments\n\nV::Matrix{Float} : velocity components due to the jth and j+1th nodes in the format: [vz_j vr_j; vz_{j+1} vr_{j+1}]\nerr::Vector{Float} : estimated errors in velocity approximation\nfh::Tuple : (f(h), h) tuples (in order of decreasing |h|)\n\n\n\n\n\n","category":"function"},{"location":"DuctAPE/api/private_preprocess/#State-Initialization","page":"Preprocess","title":"State Initialization","text":"","category":"section"},{"location":"DuctAPE/api/private_preprocess/","page":"Preprocess","title":"Preprocess","text":"DuctAPE.initialize_velocities\nDuctAPE.initialize_velocities!\nDuctAPE.initialize_strengths!","category":"page"},{"location":"DuctAPE/api/private_preprocess/#DuctAPE.initialize_velocities","page":"Preprocess","title":"DuctAPE.initialize_velocities","text":"initialize_velocities(\n solver_options::SolverOptionsType,\n operating_point,\n blade_elements,\n linsys,\n ivr,\n ivw,\n body_totnodes,\n wake_panel_sheet_be_map,\n)\n\nInitialize velocity state variables.\n\nArguments\n\nsolver_options::SolverOptionsType : solver options type for dispatch\noperating_point::OperatingPoint : an OperatingPoint object\nblade_elements::NamedTuple : A named tuple containing the blade element geometry and airfoil information.\nlinsys::NamedTuple : A named tuple containing the panel method linear system information.\nivr::NamedTuple : A named tuple containing the unit induced velocities on the rotors\nivw::NamedTuple : A named tuple containing the unit induced velocities on the wake\nbody_totnodes::Int : the total number of panel nodes comprising the duct and centerbody geometry\nwake_panel_sheet_be_map::Matrix{Int} : An index map from the wake panels to the nearest ahead rotor blade element along the wake sheets\n\nReturns\n\nvz_rotor::Vector{Float} : a vector of the velocity state variables associated with the rotor axially induced velocity\nvtheta_rotor::Vector{Float} : a vector of the velocity state variables associated with the rotor tangentially induced velocity\nCm_wake::Vector{Float} : a vector of the velocity state variables associated with the wake control point meridional velocity\n\n\n\n\n\n","category":"function"},{"location":"DuctAPE/api/private_preprocess/#DuctAPE.initialize_velocities!","page":"Preprocess","title":"DuctAPE.initialize_velocities!","text":"function initializevelocities!( solveroptions::SolverOptionsType, vzrotor, vthetarotor, Cmwake, operatingpoint, bladeelements, linsys, ivr, ivw, bodytotnodes, wakepanelsheetbemap, )\n\nIn-place version of initialize_velocities.\n\n\n\n\n\n","category":"function"},{"location":"DuctAPE/api/private_preprocess/#DuctAPE.initialize_strengths!","page":"Preprocess","title":"DuctAPE.initialize_strengths!","text":"initialize_strengths!(\n solver_options::SolverOptionsType,\n Gamr,\n sigr,\n gamw,\n operating_point,\n blade_elements,\n linsys,\n ivr,\n ivw,\n wakeK,\n body_totnodes,\n wake_nodemap,\n wake_endnodeidxs,\n wake_panel_sheet_be_map,\n wake_node_sheet_be_map,\n wake_node_ids_along_casing_wake_interface,\n wake_node_ids_along_centerbody_wake_interface,\n)\n\nInitialize strength state variables.\n\nArguments\n\nsolver_options::SolverOptionsType : solver options type for dispatch\nGamr::Vector{Float} : Rotor circulation state variables (modified in place)\nsigr::Vector{Float} : Rotor panel strength state variables (modified in place)\ngamw::Vector{Float} : Wake panel strength state variables (modified in place)\noperating_point::OperatingPoint : an OperatingPoint object\nblade_elements::NamedTuple : A named tuple containing the blade element geometry and airfoil information.\nlinsys::NamedTuple : A named tuple containing the panel method linear system information.\nivr::NamedTuple : A named tuple containing the unit induced velocities on the rotors\nivw::NamedTuple : A named tuple containing the unit induced velocities on the wake\nwakeK::Vector{Float} : geometric constants of wake nodes used in calculating wake strengths\nbody_totnodes::Int : the total number of panel nodes comprising the duct and centerbody geometry\nwake_nodemap::Matrix{Int} : an index map of wake panel to the associated node indices\nwake_endnodeidxs::Matrix{Int} : the node indices of the start and end of the wake sheets.\nwake_panel_sheet_be_map::Matrix{Int} : An index map from the wake panels to the nearest ahead rotor blade element along the wake sheets\nwake_node_sheet_be_map::Matrix{Int} : An index map from the wake nodes to the nearest ahead rotor blade element along the wake sheets\nwake_node_ids_along_casing_wake_interface::type : An index map indicating which wake nodes interface with the duct wall\nwake_node_ids_along_centerbody_wake_interface::type : An index map indicating which wake nodes interface with the centerbody wall\n\n\n\n\n\nfunction initialize_strengths!(\n solver_options::CSORSolverOptions,\n Gamr,\n sigr,\n gamw,\n solve_containers,\n operating_point,\n blade_elements,\n wakeK,\n wake_nodemap,\n wake_endnodeidxs,\n wake_panel_sheet_be_map,\n wake_node_sheet_be_map,\n wake_node_ids_along_casing_wake_interface,\n wake_node_ids_along_centerbody_wake_interface;\n niter=10,\n rlx=0.5,\n)\n\nRefactored from DFDC SUBROUTINE ROTINITBLD\n\nFrom the subroutine notes: Sets reasonable initial circulation using current rotor blade geometry (chord, beta). Initial circulations are set w/o induced effects An iteration is done using the self-induced velocity from momentum theory to converge an approximate induced axial velocity\n\nArguments\n\nsolver_options::SolverOptionsType : solver options type for dispatch\nGamr::Vector{Float} : Rotor circulation state variables (modified in place)\nsigr::Vector{Float} : Rotor panel strength state variables (modified in place)\ngamw::Vector{Float} : Wake panel strength state variables (modified in place)\noperating_point::OperatingPoint : an OperatingPoint object\nblade_elements::NamedTuple : A named tuple containing the blade element geometry and airfoil information.\nwakeK::Vector{Float} : geometric constants of wake nodes used in calculating wake strengths\nwake_nodemap::Matrix{Int} : an index map of wake panel to the associated node indices\nwake_endnodeidxs::Matrix{Int} : the node indices of the start and end of the wake sheets.\nwake_panel_sheet_be_map::Matrix{Int} : An index map from the wake panels to the nearest ahead rotor blade element along the wake sheets\nwake_node_sheet_be_map::Matrix{Int} : An index map from the wake nodes to the nearest ahead rotor blade element along the wake sheets\nwake_node_ids_along_casing_wake_interface::type : An index map indicating which wake nodes interface with the duct wall\nwake_node_ids_along_centerbody_wake_interface::type : An index map indicating which wake nodes interface with the centerbody wall\n\nKeyword Arguments\n\nrlx::Float=0.5 : factor for under-relaxation to reduce transients in CL\n\nReturns\n\n\n\n\n\n","category":"function"},{"location":"C4Blade/airfoil_types/CCBlade/#CCBlade-Airfoil-Types","page":"CCBlade Airfoil Types","title":"CCBlade Airfoil Types","text":"","category":"section"},{"location":"C4Blade/airfoil_types/CCBlade/","page":"CCBlade Airfoil Types","title":"CCBlade Airfoil Types","text":"DuctAPE includes all the airfoil types and methods available in CCBlade. We repeat them here for convenience, but refer the user to the CCBlade documentation for more context if advanced usage is desired.","category":"page"},{"location":"C4Blade/airfoil_types/CCBlade/","page":"CCBlade Airfoil Types","title":"CCBlade Airfoil Types","text":"Modules = [DuctAPE.C4Blade]\nPages = [\"C4Blade/airfoils.jl\"]","category":"page"},{"location":"C4Blade/airfoil_types/CCBlade/#DuctAPE.C4Blade.AlphaAF","page":"CCBlade Airfoil Types","title":"DuctAPE.C4Blade.AlphaAF","text":"AlphaAF(alpha, cl, cd, info, Re, Mach)\nAlphaAF(alpha, cl, cd, info, Re=0.0, Mach=0.0)\nAlphaAF(alpha, cl, cd, info=\"CCBlade generated airfoil\", Re=0.0, Mach=0.0)\nAlphaAF(filename::String; radians=true)\n\nAirfoil data that varies with angle of attack. Data is fit with an Akima spline.\n\nArguments:\n\nalpha::Vector{Float64}: angles of attack\ncl::Vector{Float64}: corresponding lift coefficients\ncd::Vector{Float64}: corresponding drag coefficients\ninfo::String: a description of this airfoil data (just informational)\nRe::Float64: Reynolds number data was taken at (just informational)\nMach::Float64: Mach number data was taken at (just informational)\n\nor\n\na file\n\nArguments:\n\nfilename::String: name/path of file to read in\nradians::Bool: true if angle of attack in file is given in radians\n\n\n\n\n\n","category":"type"},{"location":"C4Blade/airfoil_types/CCBlade/#DuctAPE.C4Blade.AlphaMachAF","page":"CCBlade Airfoil Types","title":"DuctAPE.C4Blade.AlphaMachAF","text":"AlphaMachAF(alpha, Mach, cl, cd, info, Re)\nAlphaMachAF(alpha, Mach, cl, cd, info)\nAlphaMachAF(alpha, Mach, cl, cd)\nAlphaMachAF(filenames::Vector{String}; radians=true)\n\nAirfoil data that varies with angle of attack and Mach number. Data is fit with a recursive Akima spline.\n\nArguments:\n\nalpha::Vector{Float64}: angles of attack\nMach::Vector{Float64}: Mach numbers\ncl::Matrix{Float64}: lift coefficients where cl[i, j] corresponds to alpha[i], Mach[j]\ncd::Matrix{Float64}: drag coefficients where cd[i, j] corresponds to alpha[i], Mach[j]\ninfo::String: a description of this airfoil data (just informational)\nRe::Float64: Reynolds number data was taken at (just informational)\n\nor\n\nfilenames with one file per Mach number.\n\nArguments:\n\nfilenames::Vector{String}: name/path of files to read in, each at a different Mach number in ascending order\nradians::Bool: true if angle of attack in file is given in radians\n\n\n\n\n\n","category":"type"},{"location":"C4Blade/airfoil_types/CCBlade/#DuctAPE.C4Blade.AlphaReAF","page":"CCBlade Airfoil Types","title":"DuctAPE.C4Blade.AlphaReAF","text":"AlphaReAF(alpha, Re, cl, cd, info, Mach)\nAlphaReAF(alpha, Re, cl, cd, info)\nAlphaReAF(alpha, Re, cl, cd)\nread_AlphaReAF(filenames::Vector{String}; radians=true)\n\nAirfoil data that varies with angle of attack and Reynolds number. Data is fit with a recursive Akima spline.\n\nArguments:\n\nalpha::Vector{Float64}: angles of attack\nRe::Vector{Float64}: Reynolds numbers\ncl::Matrix{Float64}: lift coefficients where cl[i, j] corresponds to alpha[i], Re[j]\ncd::Matrix{Float64}: drag coefficients where cd[i, j] corresponds to alpha[i], Re[j]\ninfo::String: a description of this airfoil data (just informational)\nMach::Float64: Mach number data was taken at (just informational)\n\nor\n\nfilenames with one file per Reynolds number.\n\nArguments:\n\nfilenames::Vector{String}: name/path of files to read in, each at a different Reynolds number in ascending order\nradians::Bool: true if angle of attack in file is given in radians\n\n\n\n\n\n","category":"type"},{"location":"C4Blade/airfoil_types/CCBlade/#DuctAPE.C4Blade.AlphaReMachAF","page":"CCBlade Airfoil Types","title":"DuctAPE.C4Blade.AlphaReMachAF","text":"AlphaReMachAF(alpha, Re, Mach, cl, cd, info)\nAlphaReMachAF(alpha, Re, Mach, cl, cd)\nAlphaReMachAF(filenames::Matrix{String}; radians=true)\n\nAirfoil data that varies with angle of attack, Reynolds number, and Mach number. Data is fit with a recursive Akima spline.\n\nArguments:\n\nalpha::Vector{Float64}: angles of attack\nRe::Vector{Float64}: Reynolds numbers\nMach::Vector{Float64}: Mach numbers\ncl::Array{Float64}: lift coefficients where cl[i, j, k] corresponds to alpha[i], Re[j], Mach[k]\ncd::Array{Float64}: drag coefficients where cd[i, j, k] corresponds to alpha[i], Re[j], Mach[k]\ninfo::String: a description of this airfoil data (just informational)\n\nor files with one per Re/Mach combination\n\nArguments:\n\nfilenames::Matrix{String}: name/path of files to read in. filenames[i, j] corresponds to Re[i] Mach[j] with Reynolds number and Mach number in ascending order.\nradians::Bool: true if angle of attack in file is given in radians\n\n\n\n\n\n","category":"type"},{"location":"C4Blade/airfoil_types/CCBlade/#DuctAPE.C4Blade.DuSeligEggers","page":"CCBlade Airfoil Types","title":"DuctAPE.C4Blade.DuSeligEggers","text":"DuSeligEggers(a, b, d, m, alpha0)\nDuSeligEggers(a=1.0, b=1.0, d=1.0, m=2*pi, alpha0=0.0) # uses defaults\n\nDuSelig correction for lift an Eggers correction for drag.\n\nArguments:\n\na, b, d::Float64: parameters in Du-Selig paper. Normally just 1.0 for each.\nm::Float64: lift curve slope. Defaults to 2 pi for zero argument version.\nalpha0::Float64: zero-lift angle of attack. Defaults to 0 for zero argument version.\n\n\n\n\n\n","category":"type"},{"location":"C4Blade/airfoil_types/CCBlade/#DuctAPE.C4Blade.PrandtlTip","page":"CCBlade Airfoil Types","title":"DuctAPE.C4Blade.PrandtlTip","text":"PrandtlTip()\n\nStandard Prandtl tip loss correction.\n\n\n\n\n\n","category":"type"},{"location":"C4Blade/airfoil_types/CCBlade/#DuctAPE.C4Blade.PrandtlTipHub","page":"CCBlade Airfoil Types","title":"DuctAPE.C4Blade.PrandtlTipHub","text":"PrandtlTipHub()\n\nStandard Prandtl tip loss correction plus hub loss correction of same form.\n\n\n\n\n\n","category":"type"},{"location":"C4Blade/airfoil_types/CCBlade/#DuctAPE.C4Blade.SimpleAF","page":"CCBlade Airfoil Types","title":"DuctAPE.C4Blade.SimpleAF","text":"SimpleAF(m, alpha0, clmax, clmin, cd0, cd2)\n\nA simple parameterized lift and drag curve.\n\ncl = m (alpha - alpha0) (capped by clmax/clmin)\ncd = cd0 + cd2 * cl^2\n\nArguments:\n\nm::Float64: lift curve slope\nalpha0::Float64: zero-lift angle of attack\nclmax::Float64: maximum lift coefficient\nclmin::Float64: minimum lift coefficient\ncd0::Float64: zero lift drag\ncd2::Float64: quadratic drag term\n\n\n\n\n\n","category":"type"},{"location":"C4Blade/airfoil_types/CCBlade/#DuctAPE.C4Blade.SkinFriction","page":"CCBlade Airfoil Types","title":"DuctAPE.C4Blade.SkinFriction","text":"SkinFriction(Re0, p)\n\nSkin friction model for a flat plate. cd *= (Re0 / Re)^p\n\nArguments:\n\nRe0::Float64: reference Reynolds number (i.e., no corrections at this number)\np::Float64: exponent in flat plate model. 0.5 for laminar (Blasius solution), ~0.2 for fully turbulent (Schlichting empirical fit)\n\n\n\n\n\n","category":"type"},{"location":"C4Blade/airfoil_types/CCBlade/#DuctAPE.C4Blade.afeval-Tuple{DuctAPE.C4Blade.AFType, Any, Any, Any}","page":"CCBlade Airfoil Types","title":"DuctAPE.C4Blade.afeval","text":"afeval(af::AFType, alpha, Re, Mach)\n\nEvaluate airfoil aerodynamic performance\n\nArguments:\n\naf::AFType or Function: dispatch on AFType or if function call: cl, cd = af(alpha, Re, Mach)\nalpha::Float64: angle of attack in radians\nRe::Float64: Reynolds number\nMach::Float64: Mach number\n\nReturns:\n\ncl::Float64: lift coefficient\ncd::Float64: drag coefficient\n\n\n\n\n\n","category":"method"},{"location":"C4Blade/airfoil_types/CCBlade/#DuctAPE.C4Blade.mach_correction-Tuple{DuctAPE.C4Blade.MachCorrection, Any, Any, Any}","page":"CCBlade Airfoil Types","title":"DuctAPE.C4Blade.mach_correction","text":"mach_correction(::MachCorrection, cl, cd, Mach)\n\nMach number correction for lift/drag coefficient\n\nArguments:\n\nmc::MachCorrection: used for dispatch\ncl::Float64: lift coefficient before correction\ncd::Float64: drag coefficient before correction\nMach::Float64: Mach number\n\nReturns:\n\ncl::Float64: lift coefficient after correction\ncd::Float64: drag coefficient after correction\n\n\n\n\n\n","category":"method"},{"location":"C4Blade/airfoil_types/CCBlade/#DuctAPE.C4Blade.mach_correction-Tuple{DuctAPE.C4Blade.PrandtlGlauert, Any, Any, Any}","page":"CCBlade Airfoil Types","title":"DuctAPE.C4Blade.mach_correction","text":"mach_correction(::PrandtlGlauert, cl, cd, Mach)\n\nPrandtl/Glauert Mach number correction for lift coefficient\n\n\n\n\n\n","category":"method"},{"location":"C4Blade/airfoil_types/CCBlade/#DuctAPE.C4Blade.parsefile-Tuple{Any, Any}","page":"CCBlade Airfoil Types","title":"DuctAPE.C4Blade.parsefile","text":"A basic airfoil file format. nheader is the number of header lines, which will be skipped. For one Reynolds/Mach number. Additional data like cm is optional but will be ignored.\n\nformat:\n\ninformational header\n\nRe\n\nMach\n\nalpha1 cl1 cd1 ...\n\nalpha2 cl2 cd2\n\nalpha3 cl3 cd3\n\n...\n\n\n\n\n\n","category":"method"},{"location":"C4Blade/airfoil_types/CCBlade/#DuctAPE.C4Blade.re_correction-Tuple{DuctAPE.C4Blade.ReCorrection, Any, Any, Any}","page":"CCBlade Airfoil Types","title":"DuctAPE.C4Blade.re_correction","text":"re_correction(re::ReCorrection, cl, cd, Re)\n\nReynolds number correction for lift/drag coefficient\n\nArguments:\n\nre::ReCorrection: used for dispatch\ncl::Float64: lift coefficient before correction\ncd::Float64: drag coefficient before correction\nRe::Float64: Reynolds number\n\nReturns:\n\ncl::Float64: lift coefficient after correction\ncd::Float64: drag coefficient after correction\n\n\n\n\n\n","category":"method"},{"location":"C4Blade/airfoil_types/CCBlade/#DuctAPE.C4Blade.re_correction-Tuple{DuctAPE.C4Blade.SkinFriction, Any, Any, Any}","page":"CCBlade Airfoil Types","title":"DuctAPE.C4Blade.re_correction","text":"re_correction(sf::SkinFriction, cl, cd, Re)\n\nSkin friction coefficient correction based on flat plat drag increases with Reynolds number.\n\n\n\n\n\n","category":"method"},{"location":"C4Blade/airfoil_types/CCBlade/#DuctAPE.C4Blade.rotation_correction","page":"CCBlade Airfoil Types","title":"DuctAPE.C4Blade.rotation_correction","text":"rotation_correction(rc::RotationCorrection, cl, cd, cr, rR, tsr, alpha, phi=alpha, alpha_max_corr=30*pi/180)\n\nRotation correction (3D stall delay).\n\nArguments:\n\nrc::RotationCorrection: used for dispatch\ncl::Float64: lift coefficient before correction\ncd::Float64: drag coefficient before correction\ncr::Float64: local chord / local radius\nrR::Float64: local radius / tip radius\ntsr::Float64: local tip speed ratio (Omega r / Vinf)\nalpha::Float64: local angle of attack\nphi::Float64: local inflow angles (defaults to angle of attack is precomputing since it is only known for on-the-fly computations)\nalpha_max_corr::Float64: angle of attack for maximum correction (tapers off to zero by 90 degrees)\n\nReturns:\n\ncl::Float64: lift coefficient after correction\ncd::Float64: drag coefficient after correction\n\n\n\n\n\n","category":"function"},{"location":"C4Blade/airfoil_types/CCBlade/#DuctAPE.C4Blade.tip_correction-Tuple{DuctAPE.C4Blade.TipCorrection, Vararg{Any, 5}}","page":"CCBlade Airfoil Types","title":"DuctAPE.C4Blade.tip_correction","text":"tip_correction(::TipCorrection, r, Rhub, Rtip, phi, B)\n\nTip corrections for 3D flow.\n\nArguments:\n\ntc::TipCorrection: used for dispatch\nr::Float64: local radius\nRhub::Float64: hub radius\nRtip::Float64: tip radius\nphi::Float64: inflow angle\nB::Integer: number of blades\n\nReturns:\n\nF::Float64: tip loss factor to multiple against loads.\n\n\n\n\n\n","category":"method"},{"location":"C4Blade/airfoil_types/CCBlade/#DuctAPE.C4Blade.viterna","page":"CCBlade Airfoil Types","title":"DuctAPE.C4Blade.viterna","text":"viterna(alpha, cl, cd, cr75, nalpha=50)\n\nViterna extrapolation. Follows Viterna paper and somewhat follows NREL version of AirfoilPrep, but with some modifications for better robustness and smoothness.\n\nArguments:\n\nalpha::Vector{Float64}: angles of attack\ncl::Vector{Float64}: correspnding lift coefficients\ncd::Vector{Float64}: correspnding drag coefficients\ncr75::Float64: chord/Rtip at 75% Rtip\nnalpha::Int64: number of discrete points (angles of attack) to include in extrapolation\n\nReturns:\n\nalpha::Vector{Float64}: angle of attack from -pi to pi\ncl::Vector{Float64}: correspnding extrapolated lift coefficients\ncd::Vector{Float64}: correspnding extrapolated drag coefficients\n\n\n\n\n\n","category":"function"},{"location":"C4Blade/airfoil_types/CCBlade/#DuctAPE.C4Blade.write_af-Tuple{Any, DuctAPE.C4Blade.AlphaAF}","page":"CCBlade Airfoil Types","title":"DuctAPE.C4Blade.write_af","text":"write_af(filename(s), af::AFType; radians=true)\n\nWrite airfoil data to file\n\nArguments:\n\nfilename(s)::String or Vector{String} or Matrix{String}: name/path of file to write to\naf::AFType: writing is dispatched based on type (AlphaAF, AlphaReAF, etc.)\nradians::Bool: true if you want angle of attack to be written in radians\n\n\n\n\n\n","category":"method"},{"location":"DuctAPE/api/private_prelims/#Option-Types","page":"Prelims","title":"Option Types","text":"","category":"section"},{"location":"DuctAPE/api/private_prelims/","page":"Prelims","title":"Prelims","text":"DuctAPE.DFDC_options\nDuctAPE.ConvergenceType\nDuctAPE.Relative\nDuctAPE.Absolute\nDuctAPE.SolverOptionsType\nDuctAPE.ExternalSolverOptions\nDuctAPE.PolyAlgorithmOptions\nDuctAPE.GridSolverOptionsType\nDuctAPE.IntegrationMethod","category":"page"},{"location":"DuctAPE/api/private_prelims/#DuctAPE.DFDC_options","page":"Prelims","title":"DuctAPE.DFDC_options","text":"function DFDC_options(;\n grid_solver_options=SLORGridSolverOptions(),\n solver_options=CSORSolverOptions(),\n kwargs...,\n)\n\nConvenience function to select options used in DFDC.\n\n\n\n\n\nfunction DFDC_options(\n multipoint;\n grid_solver_options=SLORGridSolverOptions(),\n solver_options=CSORSolverOptions(),\n kwargs...,\n)\n\nConvenience function to select options used in DFDC and run multipoint analysis.\n\nArguments\n\nmultipoint::Vector : doesn't need to be anything but a vector of the length of multipoints.\n\n\n\n\n\n","category":"function"},{"location":"DuctAPE/api/private_prelims/#DuctAPE.ConvergenceType","page":"Prelims","title":"DuctAPE.ConvergenceType","text":"abstract type ConvergenceType\n\nUsed in dispatching the CSOR (controlled successive over relaxation) residual as relative or absolute.\n\n\n\n\n\n","category":"type"},{"location":"DuctAPE/api/private_prelims/#DuctAPE.Relative","page":"Prelims","title":"DuctAPE.Relative","text":"struct Relative <: ConvergenceType\n\nUsed to dispatch the relative residual for CSOR (controlled successive over relaxation) method\n\n\n\n\n\n","category":"type"},{"location":"DuctAPE/api/private_prelims/#DuctAPE.Absolute","page":"Prelims","title":"DuctAPE.Absolute","text":"struct Absolute <: ConvergenceType\n\nUsed to dispatch the absolute residual for CSOR (controlled successive over relaxation) method\n\n\n\n\n\n","category":"type"},{"location":"DuctAPE/api/private_prelims/#DuctAPE.SolverOptionsType","page":"Prelims","title":"DuctAPE.SolverOptionsType","text":"abstract type SolverOptionsType\n\nUsed for solver dispatch.\n\n\n\n\n\n","category":"type"},{"location":"DuctAPE/api/private_prelims/#DuctAPE.ExternalSolverOptions","page":"Prelims","title":"DuctAPE.ExternalSolverOptions","text":"abstract type ExternalSolverOptions <: SolverOptionsType\n\nUsed for solver dispatch.\n\n\n\n\n\n","category":"type"},{"location":"DuctAPE/api/private_prelims/#DuctAPE.PolyAlgorithmOptions","page":"Prelims","title":"DuctAPE.PolyAlgorithmOptions","text":"abstract type PolyAlgorithmOptions <: SolverOptionsType\n\nUsed for solver dispatch.\n\n\n\n\n\n","category":"type"},{"location":"DuctAPE/api/private_prelims/#DuctAPE.GridSolverOptionsType","page":"Prelims","title":"DuctAPE.GridSolverOptionsType","text":"abstract type GridSolverOptionsType\n\nUsed for elliptic grid solver dispatch\n\n\n\n\n\n","category":"type"},{"location":"DuctAPE/api/private_prelims/#DuctAPE.IntegrationMethod","page":"Prelims","title":"DuctAPE.IntegrationMethod","text":"abstract type IntegrationMethod\n\nUsed in integration method dispatch\n\n\n\n\n\n","category":"type"},{"location":"DuctAPE/api/private_prelims/#Bookkeeping","page":"Prelims","title":"Bookkeeping","text":"","category":"section"},{"location":"DuctAPE/api/private_prelims/","page":"Prelims","title":"Prelims","text":"DuctAPE.get_problem_dimensions","category":"page"},{"location":"DuctAPE/api/private_prelims/#DuctAPE.get_problem_dimensions","page":"Prelims","title":"DuctAPE.get_problem_dimensions","text":"get_problem_dimensions(paneling_constants::PanelingConstants)\nget_problem_dimensions(body_vortex_panels, rotor_source_panels, wake_vortex_panels)\n\nDetermine all relevant dimensions to the problem based either on the paneling_constants or the panels themselves.\n\nArguments\n\npaneling_constants::PanelingConstants : Rotor (and possibly stator) geometric paramters.\n\nReturns\n\nproblem_dimensions::ProblemDimensions : ProblemDimensions object.\n\n\n\n\n\n\n\n\n\n","category":"function"},{"location":"DuctAPE/api/private_prelims/#Caching","page":"Prelims","title":"Caching","text":"","category":"section"},{"location":"DuctAPE/api/private_prelims/#Allocation","page":"Prelims","title":"Allocation","text":"","category":"section"},{"location":"DuctAPE/api/private_prelims/","page":"Prelims","title":"Prelims","text":"The following are various helper functions used in preallocating the various caches.","category":"page"},{"location":"DuctAPE/api/private_prelims/","page":"Prelims","title":"Prelims","text":"DuctAPE.initialize_all_caches\nDuctAPE.allocate_wake_panel_container!\nDuctAPE.allocate_panel_containers!\nDuctAPE.allocate_panel_container!\nDuctAPE.allocate_body_panel_container!\nDuctAPE.allocate_rotor_panel_container!\nDuctAPE.allocate_solve_parameter_extras!\nDuctAPE.allocate_grid_parameter_cache\nDuctAPE.allocate_integration_containers","category":"page"},{"location":"DuctAPE/api/private_prelims/#DuctAPE.initialize_all_caches","page":"Prelims","title":"DuctAPE.initialize_all_caches","text":"initialize_all_caches(solver_options, paneling_constants)\n\nConvenience function to initialize all caches before calling analysis.\n\nArguments\n\nsolver_options::SolverOptionsType : solver options used for cache allocation dispatch\npaneling_constants::PanelingConstants : PanelingConstants object upon which all cache sizing depends\n\nKeyword Arguments\n\nfd_chunk_size::Int=12 : chunk size to use for PreallocationTools caches. Note that the automated chuck size for DuctAPE will always be the ForwardDiff threshold of 12 due to the size of the system, so it will be best to leave this at the default unless further development allows for chunk size selection for individual solvers.\nlevels::Int=1 : levels for nested duals. Note that since ImplicitAD is being used for all solves, there should be no need for more than 1 level.\n\nReturns\n\nprepost_container_caching::NamedTuple : A named tuple containing the PreallocationTools DiffCache and a named tuple with relevant dimensions for accessing the cache.\nsolve_parameter_caching::NamedTuple : A named tuple containing the PreallocationTools DiffCache and a named tuple with relevant dimensions for accessing the cache.\nsolve_container_caching::NamedTuple : A named tuple containing the PreallocationTools DiffCache and a named tuple with relevant dimensions for accessing the cache.\n\n\n\n\n\n","category":"function"},{"location":"DuctAPE/api/private_prelims/#DuctAPE.allocate_wake_panel_container!","page":"Prelims","title":"DuctAPE.allocate_wake_panel_container!","text":"allocate_wake_panel_containers!(total_length, problem_dimensions::ProblemDimensions)\n\nA helper function is assembling the prepostcontainercache.\n\nArguments\n\ntotal_length::Vector{Int} : a one-element vector used to store the total length in order to know how large of a cache to allocate. Is updated in place.\nproblem_dimensions::ProblemDimensions : a ProblemDimensions object\n\nReturns\n\nwake_vortex_panels::NamedTuple : A named containing the dimensions needed to reshape the cache with regards to the wake vortex panel object\n\n\n\n\n\n","category":"function"},{"location":"DuctAPE/api/private_prelims/#DuctAPE.allocate_panel_containers!","page":"Prelims","title":"DuctAPE.allocate_panel_containers!","text":"allocate_panel_containers!(total_length, problem_dimensions::ProblemDimensions)\n\nA helper function is assembling the prepostcontainercache.\n\nArguments\n\ntotal_length::Vector{Int} : a one-element vector used to store the total length in order to know how large of a cache to allocate. Is updated in place.\nproblem_dimensions::ProblemDimensions : a ProblemDimensions object\n\nReturns\n\npanels::NamedTuple : A named tuple of named tuples containing the dimensions needed to reshape the cache with regards to the panel objects\n\n\n\n\n\n","category":"function"},{"location":"DuctAPE/api/private_prelims/#DuctAPE.allocate_panel_container!","page":"Prelims","title":"DuctAPE.allocate_panel_container!","text":"allocate_panel_container!(total_length, nn, np, tn, tp, nb)\n\nA helper function is assembling the prepostcontainercache.\n\nArguments\n\ntotal_length::Vector{Int} : a one-element vector used to store the total length in order to know how large of a cache to allocate. Is updated in place.\nnn::Int : number of nodes in each body, rotor, or wake sheet\nnp::Int : number of panels in each body, rotor, or wake sheet\ntn::Int : number of total nodes among the bodies, rotors, or wake sheets\ntp::Int : number of total panels among the bodies, rotors, or wake sheets\nnb::Int : number of bodies, rotors, or wake sheets\n\nReturns\n\npanel::NamedTuple : A named containing the dimensions needed to reshape the cache with regards to an arbitrary panel set\n\n\n\n\n\n","category":"function"},{"location":"DuctAPE/api/private_prelims/#DuctAPE.allocate_body_panel_container!","page":"Prelims","title":"DuctAPE.allocate_body_panel_container!","text":"allocate_body_panel_containers!(total_length, problem_dimensions::ProblemDimensions)\n\nA helper function is assembling the prepostcontainercache.\n\nArguments\n\ntotal_length::Vector{Int} : a one-element vector used to store the total length in order to know how large of a cache to allocate. Is updated in place.\nproblem_dimensions::ProblemDimensions : a ProblemDimensions object\n\nReturns\n\nbody_vortex_panels::NamedTuple : A named tuple containing the dimensions needed to reshape the cache with regards to the body vortex panel object\n\n\n\n\n\n","category":"function"},{"location":"DuctAPE/api/private_prelims/#DuctAPE.allocate_rotor_panel_container!","page":"Prelims","title":"DuctAPE.allocate_rotor_panel_container!","text":"allocate_rotor_panel_containers!(total_length, problem_dimensions::ProblemDimensions)\n\nA helper function is assembling the prepostcontainercache.\n\nArguments\n\ntotal_length::Vector{Int} : a one-element vector used to store the total length in order to know how large of a cache to allocate. Is updated in place.\nproblem_dimensions::ProblemDimensions : a ProblemDimensions object\n\nReturns\n\nrotor_source_panels::NamedTuple : A named containing the dimensions needed to reshape the cache with regards to the rotor source panel object\n\n\n\n\n\n","category":"function"},{"location":"DuctAPE/api/private_prelims/#DuctAPE.allocate_solve_parameter_extras!","page":"Prelims","title":"DuctAPE.allocate_solve_parameter_extras!","text":"allocate_solve_parameter_extras!(\n solver_options::SolverOptionsType, input_length, total_length\n)\n\nIncludes additional caching for various solvers. Currently only does anything for SIAMFANLEOptions types.\n\nArguments\n\ninput_length::Int : the number of state variables in the solver\ntotal_length::Vector{Int} : a one-element vector used to store the total length in order to know how large of a cache to allocate. Is updated in place.\n\nReturns\n\nsolve_parameter_extras::NamedTuple : A named tuple containing dimensions related to extra caching parameters used in various solvers.\n\n\n\n\n\n","category":"function"},{"location":"DuctAPE/api/private_prelims/#DuctAPE.allocate_grid_parameter_cache","page":"Prelims","title":"DuctAPE.allocate_grid_parameter_cache","text":"allocate_grid_parameter_cache(pg, x, n)\n\nAllocate a cache used inside the elliptic grid solve.\n\nArguments\n\npg::AbstractArray{Float,3} : the proposed grid array\nx::AbstractVector{Float} : the array of ξ values used in the solve\nn::AbstractVector{Float} : the array of η values used in the solve\n\nReturns\n\ngrid_parameter_cache::NamedTuple : A named tuple containing the PreallocationTools DiffCache and dimensions for accessing it.\n\n\n\n\n\n","category":"function"},{"location":"DuctAPE/api/private_prelims/#DuctAPE.allocate_integration_containers","page":"Prelims","title":"DuctAPE.allocate_integration_containers","text":"allocate_integration_containers(\n integration_options::IntegrationMethod, dispatch_type; cache_size=20\n)\n\nDescription\n\nArguments\n\nintegration_options::IntegrationMethod : options for integration used for dispatch and to size cache\ndispatch_type:: : an object with eltype(dispatch_type) with which to define the type for cache initialization.\n\nKeyword Arguments\n\ncache_size::Int=20 : size needed for intermediate calculations for integration.\n\nReturns\n\nintegration_containers::NamedTuple : A named tuple containing the cache(s) needed for integration.\n\n\n\n\n\n","category":"function"},{"location":"DuctAPE/api/private_prelims/#Reshaping","page":"Prelims","title":"Reshaping","text":"","category":"section"},{"location":"DuctAPE/api/private_prelims/","page":"Prelims","title":"Prelims","text":"The following are used internally to reshape the cache vectors into more usable formats.","category":"page"},{"location":"DuctAPE/api/private_prelims/","page":"Prelims","title":"Prelims","text":"DuctAPE.withdraw_prepost_container_cache\nDuctAPE.withdraw_solve_parameter_cache\nDuctAPE.withdraw_solve_container_cache\nDuctAPE.withdraw_grid_parameter_cache","category":"page"},{"location":"DuctAPE/api/private_prelims/#DuctAPE.withdraw_prepost_container_cache","page":"Prelims","title":"DuctAPE.withdraw_prepost_container_cache","text":"withdraw_prepost_container_cache(vec, dims)\n\nReshape the prepost cache vector using the saved dimensions tuple.\n\nArguments\n\nvec::Vector{Float} : vector cache of pre- and post-processing intermediate containers.\ndims::NamedTuple : Named tuple containing the indices and shape of the various items stored in the cache vector.\n\nReturns\n\nprepost_container_caching::NamedTuple : Named tuple containing reshaped views of sections of the cache vector.\n\n\n\n\n\n","category":"function"},{"location":"DuctAPE/api/private_prelims/#DuctAPE.withdraw_solve_parameter_cache","page":"Prelims","title":"DuctAPE.withdraw_solve_parameter_cache","text":"withdraw_solve_parameter_cache(solver_options::SolverOptionsType, vec, dims)\n\nReshape the solve parameter cache vector using the saved dimensions tuple.\n\nArguments\n\nsolver_options::SolverOptionsType : Solver options type for dispatch.\nvec::Vector{Float} : vector cache of pre- and post-processing intermediate containers.\ndims::NamedTuple : Named tuple containing the indices and shape of the various items stored in the cache vector.\n\nReturns\n\nsolve_parameter_caching::NamedTuple : Named tuple containing reshaped views of sections of the cache vector.\n\n\n\n\n\n","category":"function"},{"location":"DuctAPE/api/private_prelims/#DuctAPE.withdraw_solve_container_cache","page":"Prelims","title":"DuctAPE.withdraw_solve_container_cache","text":"withdraw_solve_container_cache(solver_options::SolverOptionsType, vec, dims)\n\nReshape the intermediate solve container cache vector using the saved dimensions tuple.\n\nArguments\n\nsolver_options::SolverOptionsType : Solver options type for dispatch.\nvec::Vector{Float} : vector cache of pre- and post-processing intermediate containers.\ndims::NamedTuple : Named tuple containing the indices and shape of the various items stored in the cache vector.\n\nReturns\n\nsolve_container_caching::NamedTuple : Named tuple containing reshaped views of sections of the cache vector.\n\n\n\n\n\n","category":"function"},{"location":"DuctAPE/api/private_prelims/#DuctAPE.withdraw_grid_parameter_cache","page":"Prelims","title":"DuctAPE.withdraw_grid_parameter_cache","text":"withdraw_grid_parameter_cache(vec, dims)\n\nReshape the cache used inside the elliptic grid solve.\n\nArguments\n\nvec::Vector{Float} : the cache vector\ndims::NamedTuple : the named tuple of dimensions used to reshape the cache vector\n\nReturns\n\nproposed_grid::AbstractArray{Float,3} : the proposed grid array\nxi::AbstractVector{Float} : the array of ξ values used in the solve\neta::AbstractVector{Float} : the array of η values used in the solve\n\n\n\n\n\n","category":"function"},{"location":"C4Blade/airfoil_types/DFDC/#DFDC-Airfoil-Type","page":"DFDC Airfoil Type","title":"DFDC Airfoil Type","text":"","category":"section"},{"location":"C4Blade/airfoil_types/DFDC/","page":"DFDC Airfoil Type","title":"DFDC Airfoil Type","text":"The DFDC Airfoil type is very similar to the XROTOR airfoil type, but includes additions for cascade corrections based on stagger and solidity. The cascade corrections aren't particularly accurate, but they do apply ballpark effects resulting from high solidity blade sections. The main benefit to this airfoil type is its simplicity and that the post-stall behavior is already in a format allowing more robust convergence of the DuctAPE solvers.","category":"page"},{"location":"C4Blade/airfoil_types/DFDC/","page":"DFDC Airfoil Type","title":"DFDC Airfoil Type","text":"DuctAPE.C4Blade.DFDCairfoil","category":"page"},{"location":"C4Blade/airfoil_types/DFDC/#DuctAPE.C4Blade.DFDCairfoil","page":"DFDC Airfoil Type","title":"DuctAPE.C4Blade.DFDCairfoil","text":"Fields:\n\nalpha0::Float : zero lift angle of attack\nclmax::Float : maximum cl\nclmin::Float : minimum cl\ndclda::Float : lift curve slope (1/radians)\ndclda_stall::Float : lift curve slope post-stall (1/radians)\ndcl_stall::Float : cl increment from initial to total stall.\ncdmin::Float : minimum cd\ncldmin::Float : cl at cdmin\ndcddcl2::Float : quadratic curve factor for cl vs cd curve left(fracd(c_d)d(c_l^2)right)\ncmcon::Float : pitching moment constant (unused right now)\nRe_ref::Float : reference Reynolds number at which cd values apply\nRe_exp::Float : Reynolds number exponent scaling left( c_d = c_d(ReRe_ref)^Re_expright) should be 0.2 for fully laminar and 0.5 for fully turbulent\nmcrit::Float : critical Mach number\ncorrect_for_mach::Bool : flag to add Prandtl-Glauert correction\ncorrect_for_cascade::Bool : flag to add cascade corrections\ncorrect_for_reynolds::Bool : flag to add reynolds drag correction\ncorrect_for_transonic::Bool : flag to add drag correction above critical mach number\n\n\n\n\n\n","category":"type"},{"location":"C4Blade/airfoil_types/actuator_disk/#Actuator-Disk-Type","page":"Actuator Disk Type","title":"Actuator Disk Type","text":"","category":"section"},{"location":"C4Blade/airfoil_types/actuator_disk/","page":"Actuator Disk Type","title":"Actuator Disk Type","text":"warning: Warning\nActuator disk types are currently in development and not ready for general use.","category":"page"},{"location":"C4Blade/airfoil_types/actuator_disk/","page":"Actuator Disk Type","title":"Actuator Disk Type","text":"DuctAPE currently implements an actuator disk type that can be used to directly define the rotor blade circulation.","category":"page"},{"location":"C4Blade/airfoil_types/actuator_disk/","page":"Actuator Disk Type","title":"Actuator Disk Type","text":"DuctAPE.C4Blade.ADM","category":"page"},{"location":"C4Blade/airfoil_types/actuator_disk/#DuctAPE.C4Blade.ADM","page":"Actuator Disk Type","title":"DuctAPE.C4Blade.ADM","text":"Fields:\n\nprescribed_circulation::Float=0.0 : Prescribed circulation strength\nprescribed_source_strength::Float=0.0 : Prescribed source panel strength\n\n\n\n\n\n","category":"type"},{"location":"DuctAPE/api/private_api/#Private-API","page":"Private API","title":"Private API","text":"","category":"section"},{"location":"DuctAPE/api/private_api/","page":"Private API","title":"Private API","text":"Pages = [\"private_api.md\",\n\"private_prelims.md\",\n\"private_preprocess.md\",\n\"private_process.md\",\n\"private_postprocess.md\",\n\"private_utlities.md\"]\nDepth = 5","category":"page"},{"location":"DuctAPE/advanced_usage/option/#Advanced-Option-Selection","page":"Options","title":"Advanced Option Selection","text":"","category":"section"},{"location":"DuctAPE/advanced_usage/option/","page":"Options","title":"Options","text":"DuctAPE has been written in an attempt to make as many of the available options exposed to the user as possible. This means that there are quite a few options to select from if not using the option convenience functions. To help the user, the majority of overarching option types are defined using the @kwdef macro and have default values that should be reasonable in most cases. We will introduce some of the available options here that may be of common interest.","category":"page"},{"location":"DuctAPE/advanced_usage/option/#General-Option-Selection","page":"Options","title":"General Option Selection","text":"","category":"section"},{"location":"DuctAPE/advanced_usage/option/","page":"Options","title":"Options","text":"In general, options are all accessed through the options argument of the analysis function being called. Said options are passed via an Options struct.","category":"page"},{"location":"DuctAPE/advanced_usage/option/","page":"Options","title":"Options","text":"DuctAPE.Options","category":"page"},{"location":"DuctAPE/advanced_usage/option/#DuctAPE.Options-DuctAPE-advanced_usage-option","page":"Options","title":"DuctAPE.Options","text":"struct Options{\n TB,\n TBwo,\n TF,\n TI,\n TSf,\n TSt,\n Tin,\n TIo<:IntegrationOptions,\n TSo<:SolverOptionsType,\n WS<:GridSolverOptionsType,\n}\n\nType containing (nearly) all the available user options.\n\nFields\n\nGeneral Options\n\nverbose::TB = false : flag to print verbose statements\nsilence_warnings::TB = true : flag to silence warnings\nmultipoint_index::TI = [1] : holds current index of multi-point solver (no need for user to change this usually)\n\nPre-processing Options\n\nGeometry ee-interpolation and generation options :\n\nfinterp::Tin = FLOWMath.akima : interpolation method used for re-paneling bodies\nautoshiftduct::TB = true : flag as to whether duct geometry should be shifted based on rotor tip location\nlu_decomp_flag::TB = false : flag indicating if panel method LHS matrix factorization was successful\n\npaneling options\n\nitcpshift::TF = 0.05 : factor for internal trailing edge psuedo-panel placement (default is DFDC hard-coded value)\naxistol::TF = 1e-15 : tolerance for how close the the axis of rotation should be considered on the axis\ntegaptol::TF = 1e1 * eps() : tolerance for how large of a trailing edge gap should be considered a gap\n\nIntegration Options\n\nintegration_options::TIo = IntegrationOptions() : integration options\n\nPost-processing Options\n\nwrite_outputs::TBwo = [false] : Bool for whether to write the outputs of the analysis to an external file (slow)\noutfile::TSf = [\"outputs.jl\"] : External output file name (including path information) for files to write\ncheckoutfileexists::TB = false : Flag for whether to check if file exists before overwriting\noutput_tuple_name::TSt = [\"outs\"] : variable name for named tuple written to out file\n\nSolving Options\n\ngrid_solver_options::WS = GridSolverOptions() : elliptic grid solver options\nsolver_options::TSo = ChainSolverOptions() : solver options\n\n\n\n\n\n","category":"type"},{"location":"DuctAPE/advanced_usage/option/","page":"Options","title":"Options","text":"Options are selected through the set_options function","category":"page"},{"location":"DuctAPE/advanced_usage/option/","page":"Options","title":"Options","text":"DuctAPE.set_options","category":"page"},{"location":"DuctAPE/advanced_usage/option/#DuctAPE.set_options-DuctAPE-advanced_usage-option","page":"Options","title":"DuctAPE.set_options","text":"set_options(; kwargs...)\nset_options(multipoint; kwargs...)\n\nSet the options for DuctAPE to use.\n\nNote that the vast majority of the available options are defined through keyword arguments. See the documentation for the various option types for more information.\n\nArguments\n\nmultipoint::AbstractArray{OperatingPoint} : a vector of operating points to use if running a multi-point analysis.\n\n\n\n\n\n","category":"function"},{"location":"DuctAPE/advanced_usage/option/","page":"Options","title":"Options","text":"There are three main sub-option objects for quadrature, wake geometry solver, and aerodyanmic solver; these are explained in more detail below. In addition, there are various options for pre- and post-processing as well as miscellaneous options for things such as supressing warnings and printing verbose statements throughout the analysis, which can be seen in the docstring above.","category":"page"},{"location":"DuctAPE/advanced_usage/option/#Quadrature","page":"Options","title":"Quadrature","text":"","category":"section"},{"location":"DuctAPE/advanced_usage/option/","page":"Options","title":"Options","text":"There are several implementations for different quadrature approaches depending on user desires; they include:","category":"page"},{"location":"DuctAPE/advanced_usage/option/","page":"Options","title":"Options","text":"Gauss-Legendre quadature (default),\nGauss-Kronrod Quadrature, and\nRomberg Quadrature methods.","category":"page"},{"location":"DuctAPE/advanced_usage/option/","page":"Options","title":"Options","text":"The default method is Gauss-Legendre quadrature using 8 sample points for both the nominal and singular integrals. To modify the quadrature methods and settings, an IntegrationOptions struct needs to be passed to the set_options method.","category":"page"},{"location":"DuctAPE/advanced_usage/option/","page":"Options","title":"Options","text":"DuctAPE.IntegrationOptions","category":"page"},{"location":"DuctAPE/advanced_usage/option/#DuctAPE.IntegrationOptions-DuctAPE-advanced_usage-option","page":"Options","title":"DuctAPE.IntegrationOptions","text":"struct IntegrationOptions{TN<:IntegrationMethod,TS<:IntegrationMethod}\n\nA struct used to hold the integration options for both the nominal and singular cases.\n\nFields\n\nnominal::IntegrationMethod=GaussLegendre(8) : the integration options to use for the nominal case.\nsingular::IntegrationMethod=GaussLegendre(8) : the integration options to use for the self-induced case.\n\n\n\n\n\n","category":"type"},{"location":"DuctAPE/advanced_usage/option/","page":"Options","title":"Options","text":"The IntegraionOptions type takes in two objects of type IntegrationMethod, one for the nominal integrals, and one for the singular integrals. These methods can be mixed and matched between quadrature methods as well as settings.","category":"page"},{"location":"DuctAPE/advanced_usage/option/","page":"Options","title":"Options","text":"For example, if one wanted to use a 10-point Gauss-Legendre method for the nominal integrals, and a order 7 Gauss-Kronrod method with an absolute tolerance of 2e-16 the following would need to be included in the set_options call:","category":"page"},{"location":"DuctAPE/advanced_usage/option/","page":"Options","title":"Options","text":"# set nominal options using a GaussLegendre object (which is an InterationMethod type)\n# note that a convenience method is used here that takes in the number of points and\n#calculates the appropriate sample locations and weights.\nnominal_integration_method = DuctAPE.GaussLegendre(10)\n\n# set singular options using a GaussKronrod object (which is an InterationMethod type)\n# note that like most option structs, these are defined using @kwdef allowing the fields\n#to be treated as keyword arguments.\n# also note that we haven't changed the evaluation limit (default 10^7)\nsingular_integration_method = DuctAPE.GaussKronrod(; order=7, atol=2e-16)\n\n# put the quadrature options together\nintegration_options = DuctAPE.IntegrationOptions(;\n nominal=nominal_integration_method, singular=singular_integration_method\n)\n\n# example of calling the set_options function\noptions = DuctAPE.set_options(; integration_options=integration_options)","category":"page"},{"location":"DuctAPE/advanced_usage/option/#Elliptic-Grid-Solvers","page":"Options","title":"Elliptic Grid Solvers","text":"","category":"section"},{"location":"DuctAPE/advanced_usage/option/","page":"Options","title":"Options","text":"As part of the pre-process, an elliptic grid defining the wake geometry is solved with a system of Poisson equations. For this solve there currently two options:","category":"page"},{"location":"DuctAPE/advanced_usage/option/","page":"Options","title":"Options","text":"SLOR: DFDC grid solver\nSLOR+Newton","category":"page"},{"location":"DuctAPE/advanced_usage/option/","page":"Options","title":"Options","text":"The SLOR (successive line over relaxation) is the method employed by DFDC, and can be used by itself, or as a preconditioner to a Newton solve (using NLsolve.jl).","category":"page"},{"location":"DuctAPE/advanced_usage/option/","page":"Options","title":"Options","text":"Selection of solver and solver settings follows the same pattern as with the quadrature settings, in that the user must pass the appropriate GridSolverOptionsType into the set_options call.","category":"page"},{"location":"DuctAPE/advanced_usage/option/","page":"Options","title":"Options","text":"For the SLOR method alone, the type is","category":"page"},{"location":"DuctAPE/advanced_usage/option/","page":"Options","title":"Options","text":"DuctAPE.SLORGridSolverOptions","category":"page"},{"location":"DuctAPE/advanced_usage/option/#DuctAPE.SLORGridSolverOptions-DuctAPE-advanced_usage-option","page":"Options","title":"DuctAPE.SLORGridSolverOptions","text":"struct SLORGridSolverOptions{TB,TF,TI} <: GridSolverOptionsType\n\nOptions for SLOR (successive line over relaxation) elliptic grid solver.\n\nFields\n\niteration_limit::TI = 100 : maximum number of iterations\natol::TF = 1e-9 : absolute convergence tolerance\n`converged::AbstractArray{TB} = [false]\n\n\n\n\n\n","category":"type"},{"location":"DuctAPE/advanced_usage/option/","page":"Options","title":"Options","text":"And for the SLOR+Newton method, the type is","category":"page"},{"location":"DuctAPE/advanced_usage/option/","page":"Options","title":"Options","text":"DuctAPE.GridSolverOptions","category":"page"},{"location":"DuctAPE/advanced_usage/option/#DuctAPE.GridSolverOptions-DuctAPE-advanced_usage-option","page":"Options","title":"DuctAPE.GridSolverOptions","text":"struct GridSolverOptions{TB,TF,TI,TSym} <: GridSolverOptionsType\n\nOptions for SLOR + Newton elliptic grid solver.\n\nFields\n\niteration_limit::TI = 10 : maximum number of iterations\natol::TF = 1e-14 : absolute convergence tolerance\nalgorithm::TSym = :newton : algorithm to use in NLsolve.jl\nautodiff::TSym = :forward : differentiation method to use in NLsolve.jl\nconverged::AbstractArray{TB} = [false]\n\n\n\n\n\n","category":"type"},{"location":"DuctAPE/advanced_usage/option/","page":"Options","title":"Options","text":"As an example, this is the input that would be required to use the SLOR+Newton method with an absolute convergence tolerance of 1e-12, and also including the quadrature settings from above:","category":"page"},{"location":"DuctAPE/advanced_usage/option/","page":"Options","title":"Options","text":"# define wake grid solver settings\nwake_solve_options = DuctAPE.GridSolverOptions(; atol=1e-12)\n\n# set all options\noptions = DuctAPE.set_options(;\n integration_options=integration_options, grid_solver_options=wake_solve_options\n)","category":"page"},{"location":"DuctAPE/advanced_usage/option/","page":"Options","title":"Options","text":"note: Convergence Flags\nThe convergence flags default to false, and in general should be left alone as they are modified in-place in the various solves by the analysis.","category":"page"},{"location":"DuctAPE/advanced_usage/option/#Aerodynamics-Solvers","page":"Options","title":"Aerodynamics Solvers","text":"","category":"section"},{"location":"DuctAPE/advanced_usage/option/","page":"Options","title":"Options","text":"There are two general types of solvers available in DuctAPE, the first is very similar to the solver in DFDC and converges a residual very similar to DFDC's. The other type is for external solvers that converge an alternate residual that is default in DuctAPE. The various solver options include:","category":"page"},{"location":"DuctAPE/advanced_usage/option/","page":"Options","title":"Options","text":"CSOR: the DFDC solver\nFixedPoint.jl\nSpeedMapping.jl\nMINPACK.jl\nSIAMFANLEquations.jl\nNLsolve.jl\nSimpleNonlinearSolve.jl","category":"page"},{"location":"DuctAPE/advanced_usage/option/","page":"Options","title":"Options","text":"Note that the CSOR, FixedPoint.jl, and SpeedMapping.jl are all different fixed-point iteration solvers, MINPACK.jl and SIAMFANLEquations.jl are primarily quasi-newton solvers, and NLsolve.jl and SimpleNonlinearSolve.jl have various solver options.","category":"page"},{"location":"DuctAPE/advanced_usage/option/","page":"Options","title":"Options","text":"DuctAPE also has some poly-algorithm solvers that employ more than one solver. The Chain Solver option is the default which starts with a fixed-point iteration, and if it doesn't converge, moves on to a quasi-, then full Newton solver until either convergence is reached, or no convergence is found. The other poly-algorithm that is available, but is less robust is the Composite Solver which partially converges with one solver, and finishes with another.","category":"page"},{"location":"DuctAPE/advanced_usage/option/","page":"Options","title":"Options","text":"Each of the solve methods have a variety of different settings associated with them, detailed in their respective docstrings. The following example should contain all the principles required to be able to adapt to the most complex use cases.","category":"page"},{"location":"DuctAPE/advanced_usage/option/","page":"Options","title":"Options","text":"# Define settings for NLsolve's newton method\naero_solver_options = DuctAPE.NLsolveOptions(;\n algorithm=:newton,\n atol=1e-10,\n iteration_limite=30,\n linesearch_method=LineSearches.BackTracking, #don't include parentheses on method handle\n linesearch_kwargs=(; order=3, maxstep=1e6),\n additional_kwargs=(; autoscale=false),\n)\n\n# set all the options\nDuctAPE.set_options(;\n integration_options=integration_options,\n grid_solver_options=wake_solve_options,\n solver_options=aero_solver_options,\n)","category":"page"},{"location":"DuctAPE/advanced_usage/option/","page":"Options","title":"Options","text":"note: Iteration Counters\nThe iterations field (not to be confused with the iterations_limit field) in the solver options should generally not be changed. They automatically save (in-place) the number of iterations the solver performs and can be accessed after the analysis is run.","category":"page"},{"location":"DuctAPE/advanced_usage/option/#Advanced-Options-for-Multi-point-analyses","page":"Options","title":"Advanced Options for Multi-point analyses","text":"","category":"section"},{"location":"DuctAPE/advanced_usage/option/","page":"Options","title":"Options","text":"For using advanced options in multi-point analyses, there are various changes that need to be made to avoid run-time errors. Here is an example for setting options with the CSOR solver.","category":"page"},{"location":"DuctAPE/advanced_usage/option/","page":"Options","title":"Options","text":"# number of operating points to analyze\nnop = 3\n\noptions = DuctAPE.set_options(;\n solver_options=DuctAPE.CSORSolverOptions(;\n converged=fill(false, (1, nop)), # need a convergence flag for each operating point\n iterations=zeros(Int, (1, nop)), # need a iteration count for each operating point\n Vconv=ones(nop), # in this case, we need a reference velocity for each operating point\n ),\n write_outputs=fill(false, nop), # we need to know which of the operating point outputs to write\n outfile=fill(\"\", nop), # we need to include names, even if they won't be used.\n output_tuple_name=fill(\"outs\", nop), # we need to include names, even if they won't be used.\n)","category":"page"},{"location":"DuctAPE/advanced_usage/option/","page":"Options","title":"Options","text":"If using a poly-algorithm with a multi-point solve, then each of the solvers needs to have the multiple converged and iterations fields for each operating point, and the overall solve type needs to have a converged and iterations field for each solver and each operating point.","category":"page"},{"location":"DuctAPE/advanced_usage/option/","page":"Options","title":"Options","text":"options = DuctAPE.set_options(;\n solver_options=DuctAPE.ChainSolverOptions(;\n solvers=[ # vector of solvers to use in poly-algorithm\n DuctAPE.NLsolveOptions(;\n algorithm=:anderson,\n atol=1e-12,\n iteration_limit=200,\n converged=fill(false, (1, nop)), # flags for each operating point\n iterations=zeros(Int, (1, nop)), # counters for each operating point\n ),\n DuctAPE.MinpackOptions(;\n atol=1e-12,\n iteration_limit=100,\n converged=fill(false, (1, nop)),\n iterations=zeros(Int, (1, nop)),\n ),\n ],\n converged=fill(false, (2, nop)), # flags for each solver and each operating point\n iterations=zeros(Int, (2, nop)), # counts for each solver and each operating point\n ),\n)","category":"page"},{"location":"C4Blade/airfoil_types/cascade/#Cascade-Types","page":"Cascade Types","title":"Cascade Types","text":"","category":"section"},{"location":"C4Blade/airfoil_types/cascade/","page":"Cascade Types","title":"Cascade Types","text":"warning: Warning\nCascade types are currently in development and not ready for general use.","category":"page"},{"location":"C4Blade/airfoil_types/cascade/","page":"Cascade Types","title":"Cascade Types","text":"Cascade types are defined analogous to CCBlade airfoil types. Instead of angle of attack, however, cascade types take in both inflow and stagger angles. In addition, cascade types are dependent on local solidity.","category":"page"},{"location":"C4Blade/airfoil_types/cascade/","page":"Cascade Types","title":"Cascade Types","text":"Modules = [DuctAPE.C4Blade]\nPages = [\"C4Blade/cascades.jl\"]","category":"page"},{"location":"C4Blade/airfoil_types/cascade/#DuctAPE.C4Blade.InReStSoMaCAS","page":"Cascade Types","title":"DuctAPE.C4Blade.InReStSoMaCAS","text":"InReStSoMaCAS(inflow, Re, stagger, solidity, Mach, cl, cd, info)\nInReStSoMaCAS(inflow, Re, stagger, solidity, Mach, cl, cd)\nInReStSoMaCAS(filenames::Matrix{String}; radians=true)\n\nData is fit recursively with Akima splines.\n\nArguments:\n\ninflow::Vector{Float64}: inflow angles\nRe::Vector{Float64}: Reynolds numbers\nstagger::Vector{Float64}: stagger angles\nsolidity::Vector{Float64}: local solidity\nMach::Vector{Float64}: Mach numbers\ncl::Array{Float64}: lift coefficients where cl[i, j, k, ell] corresponds to stagger[i], Re[j], Mach[k], solidity[ell]\ncd::Array{Float64}: drag coefficients where cd[i, j, k, ell] corresponds to stagger[i], Re[j], Mach[k], solidity[ell]\ninfo::String: a description of this airfoil data (just informational)\n\nor files with one per Re/Stagger/Solidty/Mach combination\n\nArguments:\n\nfilenames::Matrix{String}: name/path of files to read in. filenames[i, j, k, ell] corresponds to Re[i] Stagger[j] Stagger[k] and Solidity[k] with each in ascending order.\nradians::Bool: true if angle of attack in file is given in radians\n\n\n\n\n\n","category":"type"},{"location":"C4Blade/airfoil_types/cascade/#DuctAPE.C4Blade.interp5d-NTuple{12, Any}","page":"Cascade Types","title":"DuctAPE.C4Blade.interp5d","text":" interp5d(interp1d, x1data, x2data, x3data, x4data, fdata, x1pt, x2pt, x3pt, x4pt)\n\nSame as FLOWMath.interp4d, ex1cept in five dimensions.\n\n\n\n\n\n","category":"method"},{"location":"C4Blade/airfoil_types/cascade/#DuctAPE.C4Blade.parsecascadefile-Tuple{Any, Any}","page":"Cascade Types","title":"DuctAPE.C4Blade.parsecascadefile","text":"parsefile(filename, radians, solidity)\n\nCascade version of parsefile function from CCBlade. Assumes stagger is given before reynolds and Mach number, and solidity is given after\n\n\n\n\n\n","category":"method"},{"location":"C4Blade/airfoil_types/cascade/#DuctAPE.C4Blade.writecascadefile-NTuple{10, Any}","page":"Cascade Types","title":"DuctAPE.C4Blade.writecascadefile","text":"writecascadefile(filename, info, Re, Mach, stagger, inflow, cl, cd, radians)\n\nCascade version of writecascadefile function from CCBlade. Writes solidity after Mach number\n\n\n\n\n\n","category":"method"},{"location":"C4Blade/corrections/#Airfoil-Polar-Corrections","page":"Polar Modification","title":"Airfoil Polar Corrections","text":"","category":"section"},{"location":"C4Blade/corrections/","page":"Polar Modification","title":"Polar Modification","text":"In some cases various airfoil polar corrections may be required. Of specific note are modifications to airfoil polars for post-stall behavior. Thus far, DuctAPE is much more robust if the post-stall behavior in the lift polars does not exhibit a decrease in lift at angles of attack beyond that of the maximum lift coefficient. Therefore a function is provided to help modify polars as needed:","category":"page"},{"location":"C4Blade/corrections/","page":"Polar Modification","title":"Polar Modification","text":"DuctAPE.C4Blade.stall_limiters","category":"page"},{"location":"C4Blade/corrections/#DuctAPE.C4Blade.stall_limiters","page":"Polar Modification","title":"DuctAPE.C4Blade.stall_limiters","text":"stall_limiters(\n aoa,\n cl,\n cd;\n clminid=nothing,\n clmaxid=nothing,\n cl_cutoff_slope=0.1,\n cd_cutoff_slope=0.9,\n N=20,\n blend_hardness=50\n)\n\nCuts off coefficient vs alpha curve at min and max coefficient and places rest of curve from -pi to min coeff and max coeff to pi according to user defined clcutoffslope (default 0.1)\n\nArguments:\n\naoa::AbstractVector{Float} : input angles of attack, in radians\ncl::AbstractVector{Float} : input lift coefficients\ncd::AbstractVector{Float} : input drag coefficients\n\nKeyword Arguments:\n\nclminid::Float=nothing : manually set index for minimum cl\nclmaxid::Float=nothing : manually set index for maximum cl\ncl_cutoff_slope::Float=0.1 : \"post-stall\" slope for cl\ncd_cutoff_slope::Float=0.1 : \"post-stall\" slope for cd\nblend_hardness::Float=50 : hardenss of blend between nominal polar and post-stall modifications.\n\nReturns:\n\naoa_ext::AbstractVector{Float} : angles of attack for modified polar, in radians\ncl_ext::AbstractVector{Float} : modified lift coefficients\ncd_ext::AbstractVector{Float} : modified drag coefficients\n\n\n\n\n\n","category":"function"},{"location":"C4Blade/corrections/","page":"Polar Modification","title":"Polar Modification","text":"Various other correction methods are available, including the cascade corrections inherent in the DuctAPE.C4Blade.DFDCairfoil type. The following methods are in addition to the various corrections available alongside the CCBlade Airfoil Types.","category":"page"},{"location":"C4Blade/corrections/","page":"Polar Modification","title":"Polar Modification","text":"Modules = [DuctAPE.C4Blade]\nPages = [\"C4Blade/airfoil_corrections.jl\"]","category":"page"},{"location":"C4Blade/corrections/#DuctAPE.C4Blade.corrected_clcd-Tuple{DuctAPE.C4Blade.AlphaReAF, Vararg{Any, 9}}","page":"Polar Modification","title":"DuctAPE.C4Blade.corrected_clcd","text":"corrected_clcd(af::AlphaReAF, alpha, Re, Mach, solidity, stagger; kwargs...)\n\nEvaluates and applies on-the-fly corrections for airfoil lift and drag. On-the-fly airfoil polar corrections include solidity/stagger corrections, Prandtl-Glauert compressibility corrections, and transonic lift limits and drag additions.\n\ncorrected_clcd!(cl, cd, af::AlphaReAF, Re, alpha, Mach, solidity, stagger; kwargs...)\n\nEvaluates and applies on-the-fly corrections for airfoil lift and drag in place.\n\ncorrected_clcd!(cl, cd, Mach, solidity, stagger; kwargs...)\n\nApplies on-the-fly corrections for airfoil lift and drag in place.\n\ncorrected_clcd!(cl, cd, af::AlphaAF, alpha, Re, Mach, solidity, stagger; kwargs...)\n\nEvaluates and applies on-the-fly corrections, including Reynolds corrections, for airfoil lift and drag in place\n\ncorrected_clcd(cas::InReStSoMaCAS, inflow, Re, Mach, solidity, stagger)\n\nEvaluates cascade lift and drag.\n\nArguments:\n\nCoefficients\n\ncl::Float : local lift coefficient\ncd::Float : local drag coefficient\n\nAirfoil Object\n\naf::AlphaReAF : airfoil object of CCBlade type dependent on angle of attack and Reynolds number\n\nor\n\naf::AlphaAF : airfoil object of CCBlade type dependent on angle of attack only\n\nor\n\ncas::InReStSoMaCAS : cascade object depentent on inflow angle, Reynolds number, stagger, solidity, and Mach number.\n\nFlow Angle\n\nalpha::Float : angle of attack, radians. Used with airfoil types\n\nor\n\ninflow::Float : inflow angle, radians. Used with cascade types\n\nFlow Conditions\n\nRe::Float : Reynolds number\nMach::Float : Mach number\n\nGeometry\n\nsolidity::Float : Local solidity\nstagger::Float : Stagger angle, radians\n\nKeyword Arguments:\n\nmcrit::Float=0.7 : Critical Mach number\n\nrotorzloc airfoil type parameters for post-stall behavior\n\ndcl_stall::Float=0.1 : change in cl from incipient to total stall, used in transonic lift limiter correction\ndclda_stall::Float=0.1 : Post-stall lift curve slope\n\nCorrection factors that were hard coded in rotorzloc and DFDC\n\ncdmfactor::Float=10.0 :\nclmfactor::Float=0.25 :\nmexp::Float=3.0 :\ncdmstall::Float=0.1 :\ncdmdd::Float=0.0020 :\n\nSmoothing Paramters\n\nssblend_hardness::Float=100.0 : sigmoid blending hardness for solidity/stagger corrections\ntransblendhardness::Float=75.0 : sigmoid blending hardness for transonic corrections\nabsdx::Float=0.0625 : smooth absolute value Δα (radians) for transonic drag addition\n\nMiscellaneous\n\nverbose::Bool=false : Boolean of whether to print warnings, etc.\n\n\n\n\n\n","category":"method"},{"location":"C4Blade/corrections/#DuctAPE.C4Blade.prandtl_glauert!-Tuple{Any, Any}","page":"Polar Modification","title":"DuctAPE.C4Blade.prandtl_glauert!","text":"prandtl_glauert!(cl, ma)\n\nIn place version of pradtl_glauert.\n\n\n\n\n\n","category":"method"},{"location":"C4Blade/corrections/#DuctAPE.C4Blade.prandtl_glauert-Tuple{Any, Any}","page":"Polar Modification","title":"DuctAPE.C4Blade.prandtl_glauert","text":"prandtl_glauert(cl, ma)\n\nApplies Prandtl-Glauert correction\n\nArguments:\n\ncl::Float : local lift coefficient\n\nReturns\n\ncl_corr::AbstractVector{Float} : corrected lift coefficients\n\n\n\n\n\n","category":"method"},{"location":"C4Blade/corrections/#DuctAPE.C4Blade.prandtl_glauert_factor-Tuple{Any}","page":"Polar Modification","title":"DuctAPE.C4Blade.prandtl_glauert_factor","text":"prandtl_glauert_factor(mach; verbose=false, blend_range=0.02)\n\nSmoothed Prandtl-Glauert Mach correction factor\n\nArguments:\n\nmach::Float : Mach number\n\nKeyword Arguments:\n\nblend_range::Float=0.02 : range for blending factor and max cutoff (allowing Mach >= 1.0 for continuity)\n\n\n\n\n\n","category":"method"},{"location":"C4Blade/corrections/#DuctAPE.C4Blade.quadspline-Tuple{Any, Any, Any}","page":"Polar Modification","title":"DuctAPE.C4Blade.quadspline","text":"quadspline(xdata, ydata, xpoint)\n\nSample data in quadratic spline at give point.\n\n\n\n\n\n","category":"method"},{"location":"C4Blade/corrections/#DuctAPE.C4Blade.re_drag!-Tuple{Any, Any, Any}","page":"Polar Modification","title":"DuctAPE.C4Blade.re_drag!","text":"re_drag!(cd, re, re_ref; re_exp=0.5)\n\nIn-place version of re_drag.\n\n\n\n\n\n","category":"method"},{"location":"C4Blade/corrections/#DuctAPE.C4Blade.re_drag-Tuple{Any, Any, Any}","page":"Polar Modification","title":"DuctAPE.C4Blade.re_drag","text":"re_drag(cd, re, re_ref; re_exp=0.5)\n\nArguments:\n\ncd::AbstractVector{Float} : input drag coefficients\nre::Float : Current Reynolds number\nre_ref::Float : Reference Reynolds number (at which the cd's were generated)\n\nKeyword Arguments:\n\nre_exp::Float=0.5 : should be 0.2 for laminar and 0.5 for turbulent flow\n\nReturns:\n\ncd_corr::AbstractVector{Float} : Reynolds corrected drag coefficients\n\n\n\n\n\n","category":"method"},{"location":"C4Blade/corrections/#DuctAPE.C4Blade.solidity_and_stagger!-Tuple{Any, Any, Any}","page":"Polar Modification","title":"DuctAPE.C4Blade.solidity_and_stagger!","text":"solidity_and_stagger!(cl, solidity, stagger; blend_hardness=100)\n\nIn-place version of solidity_and_stagger.\n\n\n\n\n\n","category":"method"},{"location":"C4Blade/corrections/#DuctAPE.C4Blade.solidity_and_stagger-Tuple{Any, Any, Any}","page":"Polar Modification","title":"DuctAPE.C4Blade.solidity_and_stagger","text":"solidity_and_stagger(cl, solidity, stagger; blend_hardness=100)\n\nApply smoothed Wallis' cascade correction (see solidity_and_stagger_factor_smooth) to local lift.\n\nArguments:\n\ncl::AbstractVector{Float} : input lift coefficients\nsolidity::Float : local solidity\nstagger::Float : local stagger (in radians)\n\nKeyword Arguments:\n\nblend_hardness::Float=100 : hardness of smoothing blends\n\nReturns:\n\ncl_corr::AbstractVector{Float} : corrected lift coefficients.\n\n\n\n\n\n","category":"method"},{"location":"C4Blade/corrections/#DuctAPE.C4Blade.solidity_and_stagger_factor-Tuple{Any, Any}","page":"Polar Modification","title":"DuctAPE.C4Blade.solidity_and_stagger_factor","text":"solidity_and_stagger_factor(solidity, stagger; blend_hardness=100)\n\nCorrection for airfoil data used in a high-solidity cascade application. Correction is used in DFDC airfoils nominally and come from quadratic fits to curves in fig 6-29 \"Axial Flow Fans and Ducts\" by Wallis (1983). Note that the corrections are really only meant for Wallis' custom airfoil design and specific conditions mentioned in the book.\n\nArguments:\n\nsolidity::Float : local solidity\nstagger::Float : local stagger (in radians)\n\nKeyword Arguments:\n\nblend_hardness::Float=100 : hardness for smoothing blends\n\n\n\n\n\n","category":"method"},{"location":"C4Blade/corrections/#DuctAPE.C4Blade.solidity_and_stagger_factor_smooth-Tuple{Any, Any}","page":"Polar Modification","title":"DuctAPE.C4Blade.solidity_and_stagger_factor_smooth","text":"solidity_and_stagger_factor_smooth(solidity, stagger; blend_hardness=100)\n\nA smoothed version of solidity_and_stagger_factor.\n\nArguments:\n\nsolidity::Float : local solidity\nstagger::Float : local stagger (in radians)\n\nKeyword Arguments:\n\nblend_hardness::Float=100 : hardness for smoothing blends\n\n\n\n\n\n","category":"method"},{"location":"C4Blade/corrections/#DuctAPE.C4Blade.stall_limiters-Tuple{Any, Any, Any}","page":"Polar Modification","title":"DuctAPE.C4Blade.stall_limiters","text":"stall_limiters(\n aoa,\n cl,\n cd;\n clminid=nothing,\n clmaxid=nothing,\n cl_cutoff_slope=0.1,\n cd_cutoff_slope=0.9,\n N=20,\n blend_hardness=50\n)\n\nCuts off coefficient vs alpha curve at min and max coefficient and places rest of curve from -pi to min coeff and max coeff to pi according to user defined clcutoffslope (default 0.1)\n\nArguments:\n\naoa::AbstractVector{Float} : input angles of attack, in radians\ncl::AbstractVector{Float} : input lift coefficients\ncd::AbstractVector{Float} : input drag coefficients\n\nKeyword Arguments:\n\nclminid::Float=nothing : manually set index for minimum cl\nclmaxid::Float=nothing : manually set index for maximum cl\ncl_cutoff_slope::Float=0.1 : \"post-stall\" slope for cl\ncd_cutoff_slope::Float=0.1 : \"post-stall\" slope for cd\nblend_hardness::Float=50 : hardenss of blend between nominal polar and post-stall modifications.\n\nReturns:\n\naoa_ext::AbstractVector{Float} : angles of attack for modified polar, in radians\ncl_ext::AbstractVector{Float} : modified lift coefficients\ncd_ext::AbstractVector{Float} : modified drag coefficients\n\n\n\n\n\n","category":"method"},{"location":"C4Blade/corrections/#DuctAPE.C4Blade.transonic_drag_addition!-NTuple{4, Any}","page":"Polar Modification","title":"DuctAPE.C4Blade.transonic_drag_addition!","text":"transonic_drag_addition!(\n cd,\n cl,\n clcdmin,\n mach;\n mcrit=0.7,\n cdmfactor=10.0,\n clmfactor=0.25,\n mexp=3.0,\n cdmdd=0.0020,\n cdmstall=0.1000,\n absdx=0.0625,\n blend_hardness=50,\n)\n\nSmoothed, vecotrized, in-place version of transonic_drag_addition.\n\nDifferent Arguments:\n\ncd::AbstractVector{Float} : vector of drag coefficients\ncl::AbstractVector{Float} : vector of lift coefficients\n\nAdditional Keyword Argument:\n\nblend_hardness::Float=50 : hardenss of smoothing blends\n\n\n\n\n\n","category":"method"},{"location":"C4Blade/corrections/#DuctAPE.C4Blade.transonic_drag_addition-NTuple{4, Any}","page":"Polar Modification","title":"DuctAPE.C4Blade.transonic_drag_addition","text":"transonic_drag_addition(\n cd,\n cl,\n clcdmin,\n mach;\n mcrit=0.7,\n cdmfactor=10.0,\n clmfactor=0.25,\n mexp=3.0,\n cdmdd=0.0020,\n cdmstall=0.1000,\n absdx=0.0625,\n)\n\nDrag augmentation due to transonic effects as found in XROTOR and DFDC. Note this is nominally applied to DFDC airfoil evaluation.\n\nArguments:\n\ncd::Float : input drag coefficient\ncl::Float : input lift coefficient\nclcdmin::Float : lift coefficient at minimum drag coefficient.\nmach::Float : Mach number\n\nKeyword Arguments\n\nmcrit::Float=0.7 : critical Mach number\ncdmfactor::Float=10.0 : factor hard coded in XROTOR and DFDC\nclmfactor::Float=0.25 : factor hard coded in XROTOR and DFDC\nmexp::Float=3.0 : factor hard coded in XROTOR and DFDC\ncdmstall::Float=0.1000 : factor hard coded in XROTOR and DFDC\nabsdx::Float=0.0625 : smoothing factor for smooth absolute value function\n\nReturns:\n\ncl_corr:Float : corrected lift coefficient\n\n\n\n\n\n","category":"method"},{"location":"C4Blade/corrections/#DuctAPE.C4Blade.transonic_lift_limiter-NTuple{6, Any}","page":"Polar Modification","title":"DuctAPE.C4Blade.transonic_lift_limiter","text":"transonic_lift_limiter(\n cl,\n mach,\n clcdmin,\n clmax,\n clmin,\n dclda;\n mcrit=0.7,\n dcl_stall=0.1,\n dclda_stall=0.1,\n cdmfactor=10.0,\n clmfactor=0.25,\n mexp=3.0,\n cdmstall=0.1000,\n)\n\nAirfoil polar corrections due to transonic effects as found in XROTOR and DFDC. Note that this correction is done nominally in the DFDC airfoil evaluation.\n\nArguments:\n\ncl::Float : input lift coefficient\nmach::Float : Mach number\nclcdmin::Float : lift coefficient at minimum drag coefficient.\nclmax::Float : maximum lift coefficient\nclmin::Float : minimum lift coefficient\ndclda::Float : lift-curve slope\nmcrit::Float=0.7 : critical Mach number\ndcl_stall::Float=0.1 : cl increment from initial to total stall\ndclda_stall::Float=0.1 : lift curve slope post-stall (1/radians)\ncdmfactor::Float=10.0 : factor hard coded in XROTOR and DFDC\nclmfactor::Float=0.25 : factor hard coded in XROTOR and DFDC\nmexp::Float=3.0 : factor hard coded in XROTOR and DFDC\ncdmstall::Float=0.1000 : factor hard coded in XROTOR and DFDC\n\nReturns:\n\ncl_corr:Float : corrected lift coefficient\n\n\n\n\n\n","category":"method"},{"location":"C4Blade/corrections/#DuctAPE.C4Blade.transonic_lift_limiter_smooth!-NTuple{6, Any}","page":"Polar Modification","title":"DuctAPE.C4Blade.transonic_lift_limiter_smooth!","text":"transonic_lift_limiter_smooth!(\n cl,\n mach,\n clcdmin,\n clmax,\n clmin,\n dclda;\n mcrit=0.7,\n dcl_stall=0.1,\n dclda_stall=0.1,\n cdmfactor=10.0,\n clmfactor=0.25,\n mexp=3.0,\n cdmstall=0.1000,\n blend_hardness=50,\n)\n\nSmoothed, vectorized, in-place version of transonic_lift_limiter.\n\nDifferent Arguments:\n\ncl::AbstractVector{Float} : vector of lift coefficients\n\nAdditional Keyword Argument:\n\nblend_hardness::Float=50 : hardenss of smoothing blends\n\n\n\n\n\n","category":"method"},{"location":"DuctAPE/api/private_postprocess/","page":"Postprocess","title":"Postprocess","text":"DuctAPE.post_process","category":"page"},{"location":"DuctAPE/api/private_postprocess/#DuctAPE.post_process","page":"Postprocess","title":"DuctAPE.post_process","text":"post_process(\n solver_options,\n converged_states,\n prepost_containers,\n solve_container_caching,\n solve_parameter_cache_vector,\n solve_parameter_cache_dims,\n operating_point,\n reference_parameters,\n A_bb_LU,\n airfoils,\n idmaps,\n problem_dimensions,\n multipoint_index;\n write_outputs=options.write_outputs,\n outfile=options.outfile,\n checkoutfileexists=options.checkoutfileexists,\n output_tuple_name=options.output_tuple_name,\n verbose=options.verbose,\n)\n\nPost-process a converged nonlinear solve solution.\n\nArguments\n\nsolver_options::SolverOptionsType : A SolverOptionsType object (also used for dispatch)\nconverged_states::Vector{Float} : the converged state variables\nprepost_containers::NamedTuple : the named tuple containing pre-allocated containers for the pre- and post-processing intermediate calculations\nsolve_container_cache::NamedTuple : the cache and dimensions for intermediate values in the residual calculation\nsolve_parameter_cache_vector::Vector{Float} : the applicably typed cache vector for the solve parameters\nsolve_parameter_cache_dims::NamedTuple : the dimensions of the solver parameters\noperating_point::OperatingPoint : the operating point being analyzed\nreference_parameters::ReferenceParameters : a ReferenceParameters object\nA_bb_LU::LinearAlgebra.LU : LinearAlgebra LU factorization of the LHS matrix\nairfoils::Vector{AFType} : A matrix of airfoil types associated with each of the blade elements\nidmaps::NamedTuple : A named tuple containing index mapping used in bookkeeping throughout solve and post-process\nproblem_dimensions::ProblemDimensions : A ProblemDimensions object\n\nKeyword Arguments\n\nmultipoint_index::Vector{Int} : a one-dimensional vector containing the index of which multipoint analysis operating point is being analyzed.\nwrite_outputs=options.write_outputs::Vector{Bool} : a vector with the same length as number of multipoints indicating if the outputs should be saved.\noutfile=options.outfile::Vector{String} : a vector of file paths/names for where outputs should be written\ncheckoutfileexists=options.checkoutfileexists::Bool : a flag for whether existing files should be checked for or if blind overwriting is okay.\noutput_tuple_name=options.output_tuple_name::Vector{String} : the variable name(s) of the named tuple of outputs to be written.\nverbose::Bool=false : flag to print verbose statements\n\nReturns\n\nouts::NamedTuple : A named tuple containing all the output values including\n\nbodies\npanel_strengths\ntotal_thrust\nthrust_comp\ninduced_efficiency\ncp_in\ncp_out\ncp_casing_in\ncp_casing_out\ncasing_zpts\ncp_nacelle_in\ncp_nacelle_out\nnacelle_zpts\ncp_centerbody_in\ncp_centerbody_out\ncenterbody_zpts\nVtot_in\nVtot_out\nVtot_prejump\nvtot_body\nvtot_jump\nvtot_wake\nvtot_rotors\nVtan_in\nVtan_out\nvtan_casing_in\nvtan_casing_out\nvtan_nacelle_in\nvtan_nacelle_out\nvtan_centerbody_in\nvtan_centerbody_out\nrotors\ncirculation\npanel_strengths\nefficiency\ninviscid_thrust\ninviscid_thrust_dist\nviscous_thrust\nviscous_thrust_dist\nthrust\nCT\ninviscid_torque\ninviscid_torque_dist\nviscous_torque\nviscous_torque_dist\ntorque\nCQ\ninviscid_power\ninviscid_power_dist\nviscous_power\nviscous_power_dist\npower\nCP\ncl\ncd\nalpha\nbeta1\nblade_normal_force_per_unit_span\nblade_tangential_force_per_unit_span\nwake\npanel_strengths\ntotals\nthrust\ntorque\npower\nCT\nCQ\nCP\ntotal_efficiency\nideal_efficiency\nintermediate_solve_values\nvz_rotor\nvtheta_rotor\nCm_wake\nreynolds\nmach\nCz_rotor\nCtheta_rotor\nCmag_rotor\nGamma_tilde\nH_tilde\ndeltaGamma2\ndeltaH\nvz_wake\nvr_wake\nCm_avg\n\n\n\n\n\n","category":"function"},{"location":"DuctAPE/api/private_postprocess/#Velocities","page":"Postprocess","title":"Velocities","text":"","category":"section"},{"location":"DuctAPE/api/private_postprocess/","page":"Postprocess","title":"Postprocess","text":"DuctAPE.get_body_tangential_velocities\nDuctAPE.get_body_tangential_velocities!\nDuctAPE.calculate_vtheta\nDuctAPE.calculate_induced_velocities_on_bodywake","category":"page"},{"location":"DuctAPE/api/private_postprocess/#DuctAPE.get_body_tangential_velocities","page":"Postprocess","title":"DuctAPE.get_body_tangential_velocities","text":"get_body_tangential_velocities(\n gamb,\n gamw,\n sigr,\n ivb,\n Vinf,\n totnode,\n totpanel,\n nnode,\n npanel,\n tangent,\n controlpoints,\n endpanelidxs,\n wake_panel_ids_along_centerbody_wake_interface,\n wake_panel_ids_along_casing_wake_interface,\n centerbody_panel_ids_along_centerbody_wake_interface,\n duct_panel_ids_along_casing_wake_interface,\n num_casing_panels,\n)\n\nGet the tangential velocities along the body surfaces.\n\nArguments\n\ngamb::Vector{Float} : the body panel strengths\ngamw::Vector{Float} : the wake panel strengths\nsigr::Vector{Float} : the rotor panel strengths\nivb::NamedTuple : the unit induced velocities on the bodies\nVinf::Vector{Float} : one element vector containing the freestream magnitude\ntotnode::Int : total number of nodes between all bodies\ntotpanel::Int : total number of panels between all bodies\nnnode::Vector{Int} : number of nodes in each body\nnpanel::Vector{Int} : number of panels in each body.\ntangent::Matrix{Float} : unit tangent vectors for each panel\ncontrolpoints::Matrix{Float} : control point locations for each panel\nendpanelidxs::Matrix{Int} : the indices of the first and last panels for each body\nwake_panel_ids_along_centerbody_wake_interface::Vector{Int} : the indices of the wake panels coincident with the centerbody panels\nwake_panel_ids_along_casing_wake_interface::Vector{Int} : the indices of the wake panels coincident with the duct casing (inner surface) panels\ncenterbody_panel_ids_along_centerbody_wake_interface::Vector{Int} : the indices of the centerbody panels coincident with the wake panels\nduct_panel_ids_along_casing_wake_interface::Vector{Int} : the indices of the duct panels coincident with the wake panels\nnum_casing_panels::Int : the number of panels between the leading and trailing edge of the duct on the duct inner side (casing)\n\nReturns\n\nvtan_tuple::NamedTuple : a named tuple containing the body tangential surface velocities and various useful breakdowns thereof.\n\n\n\n\n\n","category":"function"},{"location":"DuctAPE/api/private_postprocess/#DuctAPE.get_body_tangential_velocities!","page":"Postprocess","title":"DuctAPE.get_body_tangential_velocities!","text":"function getbodytangentialvelocities!( vtantuple, gamb, gamw, sigr, ivb, Vinf, totnode, totpanel, nnode, npanel, tangent, controlpoints, endpanelidxs, wakepanelidsalongcenterbodywakeinterface, wakepanelidsalongcasingwakeinterface, centerbodypanelidsalongcenterbodywakeinterface, ductpanelidsalongcasingwakeinterface, zpts, )\n\nIn-place version of get_body_tangential_velocities.\n\nAdditional Arguments\n\nzpts::NamedTuple : a named tuple containing the z-coordinates of the control points of the duct casing, duct nacelle, and centerbody.\n\n\n\n\n\n","category":"function"},{"location":"DuctAPE/api/private_postprocess/#DuctAPE.calculate_vtheta","page":"Postprocess","title":"DuctAPE.calculate_vtheta","text":"calculate_vtheta(Gamma_tilde, r)\n\nCalculate tangential velocity for a given net circulation and radial location\n\nArguments\n\nGamma_tilde::Matrix{Float} : Sum of upstream circulation values\nr::Matrix{Float} : blade element radial positions\n\n\n\n\n\n","category":"function"},{"location":"DuctAPE/api/private_postprocess/#DuctAPE.calculate_induced_velocities_on_bodywake","page":"Postprocess","title":"DuctAPE.calculate_induced_velocities_on_bodywake","text":"calculate_induced_velocities_on_bodywake(\n vz_w, vr_w, gamw, vz_r, vr_r, sigr, vz_b, vr_b, gamb, Vinf\n)\n\nCalculate the induced velocities on one of the body wakes (unit velocity inputs determine which one)\n\nArguments\n\nvz_w::Matrix{Float} : unit axial induced velocity of the wake onto the body wake\nvr_w::Matrix{Float} : unit radial induced velocity of the wake onto the body wake\ngamw::Vector{Float} : wake panel strengths\nvz_r::Matrix{Float} : unit axial induced velocity of the rotor onto the body wake\nvr_r::Matrix{Float} : unit radial induced velocity of the rotor onto the body wake\nsigr::Vector{Float} : rotor panel strengths\nvz_b::Matrix{Float} : unit axial induced velocity of the bodies onto the body wake\nvr_b::Matrix{Float} : unit radial induced velocity of the bodies onto the body wake\ngamb::Vector{Float} : body panel strengths\nVinf::Vector{Float} : one element vector containing the velocity magnitude\n\n\n\n\n\n","category":"function"},{"location":"DuctAPE/api/private_postprocess/#Pressures","page":"Postprocess","title":"Pressures","text":"","category":"section"},{"location":"DuctAPE/api/private_postprocess/","page":"Postprocess","title":"Postprocess","text":"DuctAPE.steady_cp\nDuctAPE.steady_cp!\nDuctAPE.calculate_entropy_jumps\nDuctAPE.calculate_rotor_jumps\nDuctAPE.delta_cp\nDuctAPE.calculate_body_delta_cp!\nDuctAPE.calculate_bodywake_delta_cp\nDuctAPE.get_body_cps\nDuctAPE.get_body_cps!\nDuctAPE.get_bodywake_cps\nDuctAPE.forces_from_pressure\nDuctAPE.forces_from_pressure!\nDuctAPE.forces_from_TEpanels!","category":"page"},{"location":"DuctAPE/api/private_postprocess/#DuctAPE.steady_cp","page":"Postprocess","title":"DuctAPE.steady_cp","text":"steady_cp(Vs, Vinf, Vref)\n\nCalculate steady pressure coefficients for a given surface velocity.\n\nArguments\n\nVs::Vector{Float} : the surface velocities\nVinf::Vector{Float} : one element vector with freestream mangnitude\nVref::Vector{Float} : one element vector with reference velocity used for non-dimensionalization\n\nReturns\n\ncp::Vector{Float} : the steady pressure coefficients\n\n\n\n\n\n","category":"function"},{"location":"DuctAPE/api/private_postprocess/#DuctAPE.steady_cp!","page":"Postprocess","title":"DuctAPE.steady_cp!","text":"steady_cp!(cp, Vs, Vinf, Vref)\n\nIn-place verison of steady_cp.\n\n\n\n\n\n","category":"function"},{"location":"DuctAPE/api/private_postprocess/#DuctAPE.calculate_entropy_jumps","page":"Postprocess","title":"DuctAPE.calculate_entropy_jumps","text":"calculate_entropy_jumps(sigr, Cz_rotor)\n\nCalculate jumps in entropy across the disks.\n\nArguments\n\nsigr::Matrix{Float} : rotor source panel strengths\nCz_rotor::Vector{Float} : absolute axial velocity on rotor blade elements\n\nReturns\n\ndeltaS::Vector{Float} : entropy jump across rotor disks\n\n\n\n\n\n","category":"function"},{"location":"DuctAPE/api/private_postprocess/#DuctAPE.calculate_rotor_jumps","page":"Postprocess","title":"DuctAPE.calculate_rotor_jumps","text":"calculate_rotor_jumps(Gamr, Omega, B, sigr, Cz_rotor)\n\nCalculate net circulation and enthalpy and entropy disk jumps\n\nArguments\n\nGamr::Matrix{Float} : Blade element circulation strengths\nOmega::Vector{Float} : rotor rotation rates\nB::Vector{Float} : blade count for each rotor (usually integers but could be a float)\nsigr::Matrix{Float} : rotor source panel strengths\nCz_rotor::Vector{Float} : absolute axial velocity on rotor blade elements\n\nReturns\n\nGamma_tilde::Matrix{Float} : net upstream circulation\nHtilde::Matrix{Float} : net upstream enthalpy jumps\nStilde::Matrix{Float} : net upstream entropy jumps\n\n\n\n\n\n","category":"function"},{"location":"DuctAPE/api/private_postprocess/#DuctAPE.delta_cp","page":"Postprocess","title":"DuctAPE.delta_cp","text":"delta_cp(deltaH, deltaS, Ctheta, Vref)\n\nCalculate change in pressure coefficient aft of rotor, due to rotor\n\nArguments\n\ndeltaH::Vector{Float} : Enthalpy jumps across disks\ndeltaS::Vector{Float} : Entropy jumps across disks`\nCtheta::Vector{Float} : tangenetial velocity\nVref::Vector{Float} : reference velocity for non-dimensionalization\n\nReturns\n\ndelta_cp::Vector{Float} : pressure rises due to rotor disks\n\n\n\n\n\n","category":"function"},{"location":"DuctAPE/api/private_postprocess/#DuctAPE.calculate_body_delta_cp!","page":"Postprocess","title":"DuctAPE.calculate_body_delta_cp!","text":"calculate_body_delta_cp!(cp, Gamr, sigr, Cz_rotor, Vref, Omega, B, cpr, casing_panel_ids_aft_of_rotors, centerbody_panel_ids_aft_of_rotors)\n\nAugment surface pressure by change in pressure coefficient due to rotors specifically on the body panels aft of the rotors.\n\nArguments\n\ncp::Vector{Float} : steady pressure coeffients, modified in-place to include rotor effects.\nGamr::Matrix{Float} : Blade element circulation strengths\nsigr::Matrix{Float} : rotor source panel strengths\nCz_rotor::Vector{Float} : absolute axial velocity on rotor blade elements\nVref::Vector{Float} : one element vector with reference velocity used for non-dimensionalization\nOmega::Vector{Float} : rotor rotation rates\nB::Vector{Float} : blade count for each rotor (usually integers but could be a float)\ncpr::Vector{Float} : control point radial positions of body panels\ncasing_panel_ids_aft_of_rotors::Vector{Int} : duct indices of control point radial positions aft of rotors\ncenterbody_panel_ids_aft_of_rotors::Vector{Int} : centerbody indices of control point radial positions aft of rotors\n\n\n\n\n\n","category":"function"},{"location":"DuctAPE/api/private_postprocess/#DuctAPE.calculate_bodywake_delta_cp","page":"Postprocess","title":"DuctAPE.calculate_bodywake_delta_cp","text":"calculate_bodywake_delta_cp(Gamr, sigr, Cz_rotor, Vref, Omega, B, cpr; body=\"duct\")\n\nCalculate change in pressure coefficient due to rotors specifically on the body wakes\n\nArguments\n\nGamr::Matrix{Float} : Blade element circulation strengths\nsigr::Matrix{Float} : rotor source panel strengths\nCz_rotor::Vector{Float} : absolute axial velocity on rotor blade elements\nVref::Vector{Float} : one element vector with reference velocity used for non-dimensionalization\nOmega::Vector{Float} : rotor rotation rates\nB::Vector{Float} : blade count for each rotor (usually integers but could be a float)\ncpr::Vector{Float} : control point radial positions of body wake \"panels\"\n\nKeyword Arguments\n\nbody::String=\"duct\" : flag as to whether the body in question is a duct or centerbody.\n\n\n\n\n\n","category":"function"},{"location":"DuctAPE/api/private_postprocess/#DuctAPE.get_body_cps","page":"Postprocess","title":"DuctAPE.get_body_cps","text":"getbodycps( Vtanin, Vtanout, Gamr, sigr, Czrotor, Vinf, Vref, B, Omega, casingpanelidsaftofrotors, centerbodypanelidsaftof_rotors, controlpoints, endpanelidxs, zpts, )\n\nDescription\n\nArguments\n\nVtan_in::Vector{Float} : Tangential velocity on the inside of the body panels\nVtan_out::Vector{Float} : Tangential velocity on the outside of the body panels\nGamr::Matrix{Float} : Blade element circulation strengths\nsigr::Matrix{Float} : rotor source panel strengths\nCz_rotor::Vector{Float} : absolute axial velocity on rotor blade elements\nVinf::Vector{Float} : one element vector with freestream mangnitude\nVref::Vector{Float} : one element vector with reference velocity used for non-dimensionalization\nB::Vector{Float} : blade count for each rotor (usually integers but could be a float)\nOmega::Vector{Float} : rotor rotation rates\ncasing_panel_ids_aft_of_rotors::Vector{Int} : duct indices of control point radial positions aft of rotors\ncenterbody_panel_ids_aft_of_rotors::Vector{Int} : centerbody indices of control point radial positions aft of rotors\ncontrolpoints::Matrix{Float} : control point locations for each panel\nendpanelidxs::Matrix{Int} : the indices of the first and last panels for each body\nzpts::NamedTuple : a named tuple containing the z-coordinates of the control points of the duct casing, duct nacelle, and centerbody.\n\nReturns\n\ncp_tuple::NamedTuple : body surface velocities and various useful breakdowns thereof.\n\n\n\n\n\n","category":"function"},{"location":"DuctAPE/api/private_postprocess/#DuctAPE.get_body_cps!","page":"Postprocess","title":"DuctAPE.get_body_cps!","text":"get_body_cps!(\n cp_tuple,\n Vtan_in,\n Vtan_out,\n Gamr,\n sigr,\n Cz_rotor,\n Vinf,\n Vref,\n B,\n Omega,\n duct_panel_ids_aft_of_rotors,\n centerbody_panel_ids_aft_of_rotors,\n controlpoints,\n endpanelidxs,\n zpts,\n)\n\nIn-place version of get_body_cps.\n\n\n\n\n\n","category":"function"},{"location":"DuctAPE/api/private_postprocess/#DuctAPE.get_bodywake_cps","page":"Postprocess","title":"DuctAPE.get_bodywake_cps","text":"get_bodywake_cps(\n Gamr,\n vz_w,\n vr_w,\n gamw,\n vz_r,\n vr_r,\n sigr,\n vz_b,\n vr_b,\n gamb,\n panels,\n Cz_rotor,\n Omega,\n B,\n Vinf,\n Vref;\n body=\"duct\",\n)\n\nCalculate the pressure coefficient distributions on one of the body wakes\n\nArguments\n\nGamr::Matrix{Float} : Blade element circulation strengths\nvz_w::Matrix{Float} : unit axial induced velocity of the wake onto the body wake\nvr_w::Matrix{Float} : unit radial induced velocity of the wake onto the body wake\ngamw::Vector{Float} : wake panel strengths\nvz_r::Matrix{Float} : unit axial induced velocity of the rotor onto the body wake\nvr_r::Matrix{Float} : unit radial induced velocity of the rotor onto the body wake\nsigr::Vector{Float} : rotor panel strengths\nvz_b::Matrix{Float} : unit axial induced velocity of the bodies onto the body wake\nvr_b::Matrix{Float} : unit radial induced velocity of the bodies onto the body wake\ngamb::Vector{Float} : body panel strengths\npanels::NamedTuple : A named tuple containing bodywake \"panel\" geometries\nCz_rotor::Vector{Float} : absolute axial velocity on rotor blade elements\nOmega::Vector{Float} : rotor rotation rates\nB::Vector{Float} : blade count for each rotor (usually integers but could be a float)\nVinf::Vector{Float} : one element vector containing the velocity magnitude\nVref::Vector{Float} : one element vector with reference velocity used for non-dimensionalization\n\nKeyword Arguments\n\nbody::String=\"duct\" : flag as to whether the body in question is a duct or centerbody.\n\n\n\n\n\n","category":"function"},{"location":"DuctAPE/api/private_postprocess/#DuctAPE.forces_from_pressure","page":"Postprocess","title":"DuctAPE.forces_from_pressure","text":"forces_from_pressure(cp_in, cp_out, panels; rhoinf=1.225, Vref=1.0)\n\nCalculate dimensional and non-dimensional axial force on a single body\n\nArguments\n\ncp_in::Vector{Float} : pressure coefficient on inside of body surfaces\ncp_out::Vector{Float} : pressure coefficients on outside of body surfaces\npanels::NamedTuple : A named tuple containing panel geometry information\n\nKeyword Arguments\n\nrhoinf::Float=1.225 : reference density for non-dimensionalization\nVref::Float=1.0 : reference velocity for non-dimensionalization\n\nReturns\n\nthrust::Vector{Float} : dimensional axial force\nforce_coeff::Vector{Float} : non-dimensional axial force\n\n\n\n\n\n","category":"function"},{"location":"DuctAPE/api/private_postprocess/#DuctAPE.forces_from_pressure!","page":"Postprocess","title":"DuctAPE.forces_from_pressure!","text":"forces_from_pressure!(CFx, cfx, cp_in, cp_out, panels; rhoinf=1.225, Vref=1.0)\n\nIn-place version of forces_from_pressure.\n\n\n\n\n\n","category":"function"},{"location":"DuctAPE/api/private_postprocess/#DuctAPE.forces_from_TEpanels!","page":"Postprocess","title":"DuctAPE.forces_from_TEpanels!","text":"forces_from_TEpanels!(\n thrust, force_coeff, cp_in, cp_out, panels; rhoinf=1.225, Vref=1.0\n)\n\nAdd force induced by trailing edge gap panels to total forces.\n\nArguments\n\nthrust::Vector{Float} : dimensional axial force\nforce_coeff::Vector{Float} : non-dimensional axial force\ncp_in::Vector{Float} : pressure coefficient on inside of body surfaces\ncp_out::Vector{Float} : pressure coefficients on outside of body surfaces\npanels::NamedTuple : A named tuple containing panel geometry information\n\nKeyword Arguments\n\nrhoinf::Float=1.225 : reference density for non-dimensionalization\nVref::Float=1.0 : reference velocity for non-dimensionalization\n\n\n\n\n\n","category":"function"},{"location":"DuctAPE/api/private_postprocess/#Rotor-Performance","page":"Postprocess","title":"Rotor Performance","text":"","category":"section"},{"location":"DuctAPE/api/private_postprocess/","page":"Postprocess","title":"Postprocess","text":"DuctAPE.inviscid_rotor_thrust\nDuctAPE.inviscid_rotor_thrust!\nDuctAPE.viscous_rotor_thrust\nDuctAPE.viscous_rotor_thrust!\nDuctAPE.inviscid_rotor_torque\nDuctAPE.inviscid_rotor_torque!\nDuctAPE.viscous_rotor_torque\nDuctAPE.viscous_rotor_torque!\nDuctAPE.rotor_power\nDuctAPE.rotor_power!\nDuctAPE.get_total_efficiency\nDuctAPE.get_total_efficiency!\nDuctAPE.get_induced_efficiency\nDuctAPE.get_induced_efficiency!\nDuctAPE.get_ideal_efficiency\nDuctAPE.tqpcoeff\nDuctAPE.tqpcoeff!\nDuctAPE.get_blade_loads\nDuctAPE.get_blade_loads!","category":"page"},{"location":"DuctAPE/api/private_postprocess/#DuctAPE.inviscid_rotor_thrust","page":"Postprocess","title":"DuctAPE.inviscid_rotor_thrust","text":"inviscid_rotor_thrust(Ctheta_rotor, Gamma_tilde, rotor_panel_length, rhoinf)\n\nCalculate inviscid rotor thrust.\n\nArguments\n\nCtheta_rotor::Vector{Float} : Absolute tangential velocity on rotor blade elements\nGamma_tilde::Matrix{Float} : net upstream rotor circulation\nrotor_panel_length::Vector{Float} : dimensional lengths on which blade element values apply\nrhoinf::Float : freestream density\n\nReturns\n\nTinv::Vector{Float} : inviscid dimensional thrust\ndTi::Vector{Float} : inviscid dimensional thrust distribution\n\n\n\n\n\n","category":"function"},{"location":"DuctAPE/api/private_postprocess/#DuctAPE.inviscid_rotor_thrust!","page":"Postprocess","title":"DuctAPE.inviscid_rotor_thrust!","text":"inviscid_rotor_thrust!(\n Tinv, dTi, Ctheta_rotor, Gamma_tilde, rotor_panel_length, rhoinf\n)\n\nIn-place version of inviscid_rotor_thrust.\n\n\n\n\n\n","category":"function"},{"location":"DuctAPE/api/private_postprocess/#DuctAPE.viscous_rotor_thrust","page":"Postprocess","title":"DuctAPE.viscous_rotor_thrust","text":"viscous_rotor_thrust(\n Cz_rotor, Cmag_rotor, B, chord, rotor_panel_length, cd, rhoinf\n)\n\nCalculate visous rotor \"thrust.\"\n\nArguments\n\nCz_rotor::Vector{Float} : Absolute axial velocity on rotor blade elements\nCmag_rotor::Vector{Float} : Absolute inflow velocity magnitude on rotor blade elements\nB::Vector{Float} : blade count for each rotor (usually integers but could be a float)\nchord::Vector{Float} : blade element chord lengths\nrotor_panel_length::Vector{Float} : dimensional lengths on which blade element values apply\ncd::Vector{Float} : drag coefficient for each blade element\nrhoinf::Float : freestream density\n\nReturns\n\nTvisc::Vector{Float} : viscous dimensional thrust\ndTv::Vector{Float} : viscous dimensional thrust distribution\n\n\n\n\n\n","category":"function"},{"location":"DuctAPE/api/private_postprocess/#DuctAPE.viscous_rotor_thrust!","page":"Postprocess","title":"DuctAPE.viscous_rotor_thrust!","text":"viscous_rotor_thrust!(\n Tvisc, dTv, Cz_rotor, Cmag_rotor, B, chord, rotor_panel_length, cd, rhoinf\n)\n\nIn-place version of viscous_rotor_thrust.\n\n\n\n\n\n","category":"function"},{"location":"DuctAPE/api/private_postprocess/#DuctAPE.inviscid_rotor_torque","page":"Postprocess","title":"DuctAPE.inviscid_rotor_torque","text":"inviscid_rotor_torque(\n Cz_rotor, rotor_panel_center, rotor_panel_length, Gamma_tilde, rhoinf\n)\n\nCalculate inviscid rotor torque.\n\nArguments\n\nCz_rotor::Vector{Float} : Absolute axial velocity on rotor blade elements\nrotor_panel_center::Vector{Float} : radial location of rotor blade elements\nrotor_panel_length::Vector{Float} : dimensional lengths on which blade element values apply\nGamma_tilde::Matrix{Float} : net upstream rotor circulation\nrhoinf::Float : freestream density\n\nReturns\n\nQinv::Vector{Float} : inviscid dimensional thrust\ndQi::Vector{Float} : inviscid dimensional thrust distribution\n\n\n\n\n\n","category":"function"},{"location":"DuctAPE/api/private_postprocess/#DuctAPE.inviscid_rotor_torque!","page":"Postprocess","title":"DuctAPE.inviscid_rotor_torque!","text":"inviscid_rotor_torque!(\n Qinv, dQi, Cz_rotor, rotor_panel_center, rotor_panel_length, Gamma_tilde, rhoinf\n)\n\nIn-place version of inviscid_rotor_torque.\n\n\n\n\n\n","category":"function"},{"location":"DuctAPE/api/private_postprocess/#DuctAPE.viscous_rotor_torque","page":"Postprocess","title":"DuctAPE.viscous_rotor_torque","text":"viscous_rotor_torque(\n Ctheta_rotor, Cmag_rotor, B, chord, rotor_panel_center, rotor_panel_length, cd, rhoinf\n)\n\nCalculate viscous rotor torque.\n\nArguments\n\nCtheta_rotor::Vector{Float} : Absolute tangential velocity on rotor blade elements\nCmag_rotor::Vector{Float} : Absolute inflow velocity magnitude on rotor blade elements\nB::Vector{Float} : blade count for each rotor (usually integers but could be a float)\nchord::Vector{Float} : blade element chord lengths\nrotor_panel_center::Vector{Float} : radial location of rotor blade elements\nrotor_panel_length::Vector{Float} : dimensional lengths on which blade element values apply\ncd::Vector{Float} : drag coefficient for each blade element\nrhoinf::Float : freestream density\n\nReturns\n\nQvisc::Vector{Float} : viscous dimensional thrust\ndQv::Vector{Float} : viscous dimensional thrust distribution\n\n\n\n\n\n","category":"function"},{"location":"DuctAPE/api/private_postprocess/#DuctAPE.viscous_rotor_torque!","page":"Postprocess","title":"DuctAPE.viscous_rotor_torque!","text":"viscous_rotor_torque!(\n Qvisc,\n dQv,\n Ctheta_rotor,\n Cmag_rotor,\n B,\n chord,\n rotor_panel_center,\n rotor_panel_length,\n cd,\n rhoinf\n)\n\nIn-place version of viscous_rotor_torque.\n\n\n\n\n\n","category":"function"},{"location":"DuctAPE/api/private_postprocess/#DuctAPE.rotor_power","page":"Postprocess","title":"DuctAPE.rotor_power","text":"rotor_power(Q, dQ, Omega)\n\nCalculate power from torque and rotation rate.\n\nArguments\n\nQ::Vector{Float} : dimensional thrust\ndQ::Vector{Float} : dimensional thrust distribution\nOmega::Vector{Float} : rotor rotation rates\n\nReturns\n\nP::Vector{Float} : dimensional power\ndP::Vector{Float} : dimensional thrust distribution\n\n\n\n\n\n","category":"function"},{"location":"DuctAPE/api/private_postprocess/#DuctAPE.rotor_power!","page":"Postprocess","title":"DuctAPE.rotor_power!","text":"rotor_power!(P, dP, Q, dQ, Omega)\n\nIn-place version of rotor_power.\n\n\n\n\n\n","category":"function"},{"location":"DuctAPE/api/private_postprocess/#DuctAPE.get_total_efficiency","page":"Postprocess","title":"DuctAPE.get_total_efficiency","text":"get_total_efficiency(total_thrust, total_power, Vinf)\n\nGet total efficiency.\n\nArguments\n\ntotal_thrust::Vector{Float} : total thrust\ntotal_power::Vector{Float} : total power\nVinf::Vector{Float} : one element vector freestream velocity magnitude\n\nReturns\n\n`total_efficiency::Vector{Float} : total efficiency\n\n\n\n\n\n","category":"function"},{"location":"DuctAPE/api/private_postprocess/#DuctAPE.get_total_efficiency!","page":"Postprocess","title":"DuctAPE.get_total_efficiency!","text":"get_total_efficiency!(eta, total_thrust, total_power, Vinf)\n\nIn-place version of get_total_efficiency.\n\n\n\n\n\n","category":"function"},{"location":"DuctAPE/api/private_postprocess/#DuctAPE.get_induced_efficiency","page":"Postprocess","title":"DuctAPE.get_induced_efficiency","text":"get_induced_efficiency(Tinv, Tduct, Pinv, Vinf)\n\nGet rotor efficiency induced by presence of the duct.\n\nArguments\n\nTinv::Vector{Float} : inviscid dimensional thrust\nTduct::Vector{Float} : duct thrust\nPinv::Vector{Float} : inviscid dimensional power\nVinf::Vector{Float} : one element vector freestream velocity magnitude\n\nReturns\n\ninduced_efficiency::Vector{Float} : rotor efficiency induced by duct\n\n\n\n\n\n","category":"function"},{"location":"DuctAPE/api/private_postprocess/#DuctAPE.get_induced_efficiency!","page":"Postprocess","title":"DuctAPE.get_induced_efficiency!","text":"get_induced_efficiency!(eta_inv, Tinv, Tduct, Pinv, Vinf)\n\nIn-place version of get_induced_efficiency.\n\n\n\n\n\n","category":"function"},{"location":"DuctAPE/api/private_postprocess/#DuctAPE.get_ideal_efficiency","page":"Postprocess","title":"DuctAPE.get_ideal_efficiency","text":"get_ideal_efficiency(total_thrust, rhoinf, Vinf, Rref)\n\nCompute ducted fan ideal efficiency\n\nArguments\n\ntotal_thrust::Vector{Float} : total thrust from rotors and duct\nrhoinf::Float : freestream density\nVinf::Vector{Float} : one element vector freestream velocity magnitude\nRref::Vector{Float} : one element vector reference rotor tip radius\n\nReturns\n\nideal_efficiency::Vector{Float} : ideal ducted fan efficiency\n\n\n\n\n\n","category":"function"},{"location":"DuctAPE/api/private_postprocess/#DuctAPE.tqpcoeff","page":"Postprocess","title":"DuctAPE.tqpcoeff","text":"tqpcoeff(thrust, torque, power, rhoinf, Omega, Rref)\n\nCalculate non-dimensional thrust, torque, and power coefficients\n\nArguments\n\nthrust::Vector{Float} : dimensional thrust\ntorque::Vector{Float} : dimensional torque\npower::Vector{Float} : dimensional power\nrhoinf::Float : freestream density\nOmega::Vector{Float} : rotor rotation rates\nRref::Vector{Float} : one element vector reference rotor tip radius\n\nReturns\n\nCT::Vector{Float} : thrust coefficient\nCQ::Vector{Float} : torque coefficient\nCP::Vector{Float} : power coefficient\n\n\n\n\n\n","category":"function"},{"location":"DuctAPE/api/private_postprocess/#DuctAPE.tqpcoeff!","page":"Postprocess","title":"DuctAPE.tqpcoeff!","text":"tqpcoeff!(CT, CQ, CP, thrust, torque, power, rhoinf, Omega, Rref)\n\nIn-place version of tqpcoeff.\n\n\n\n\n\n","category":"function"},{"location":"DuctAPE/api/private_postprocess/#DuctAPE.get_blade_loads","page":"Postprocess","title":"DuctAPE.get_blade_loads","text":"get_blade_loads(Cmag_rotor, beta1, cl, cd, chords, rhoinf)\n\nGet loading along blades.\n\nArguments\n\nCmag_rotor::Vector{Float} : blade element inflow magnitudes\nbeta1::Vector{Float} : blade element inflow angles\ncl::Vector{Float} : blade element lift coefficients\ncd::Vector{Float} : blade element drag coefficients\nchords::Vector{Float} : blade element chord lengths\nrhoinf::Vector{Float} : one element freestream density\n\nReturns\n\nNp::Vector{Float} : blade loading per unit length in the normal direction: N'\nTp::Vector{Float} : blade loading per unit length in the tangential direction: T'\n\n\n\n\n\n","category":"function"},{"location":"DuctAPE/api/private_postprocess/#DuctAPE.get_blade_loads!","page":"Postprocess","title":"DuctAPE.get_blade_loads!","text":"get_blade_loads!(Np, Tp, Cmag_rotor, beta1, cl, cd, chords, rhoinf, cache)\n\nIn-place version of get_blade_loads.\n\n\n\n\n\n","category":"function"},{"location":"C4Blade/intro/#C\\textrm{4}Blade-[[C](#)ascade-[C](#)ompatible-[CCBlade](https://flow.byu.edu/CCBlade.jl/stable/)]","page":"Intro","title":"C^textrm4Blade [Cascade Compatible CCBlade]","text":"","category":"section"},{"location":"C4Blade/intro/","page":"Intro","title":"Intro","text":"C^4Blade is a DuctAPE submodule containing a modified version of CCBlade that includes capabilities for cascade types.","category":"page"},{"location":"DuctAPE/theory/#Theory","page":"Theory","title":"Theory","text":"","category":"section"},{"location":"DuctAPE/theory/","page":"Theory","title":"Theory","text":"For a brief overview of the theory behind DuctAPE, see:","category":"page"},{"location":"DuctAPE/theory/","page":"Theory","title":"Theory","text":"Mehr, J. and Ning, A., \"DuctAPE: A steady-state, axisymmetric ducted fan analysis code designed for gradient-based optimization.,\" AIAA Aviation Forum, July 2024.","category":"page"},{"location":"DuctAPE/theory/","page":"Theory","title":"Theory","text":"For a more thorough dive into the details see this pdf document.","category":"page"},{"location":"#DuctAPE.jl-[[Duct](#)ed-[A](#)xisymmetric-[P](#)ropulsor-[E](#)valuation]","page":"Home","title":"DuctAPE.jl [Ducted Axisymmetric Propulsor Evaluation]","text":"","category":"section"},{"location":"","page":"Home","title":"Home","text":"Authors: Judd Mehr,","category":"page"},{"location":"","page":"Home","title":"Home","text":"Contributers: Taylor McDonnell,","category":"page"},{"location":"","page":"Home","title":"Home","text":"DuctAPE is a code for the aerodynamic evaluation of axisymmetric ducted propulsors designed for incompressible (low mach) applications. It is strongly influenced by the underlying theory of Ducted Fan Design Code (DFDC), utilizing a linear axisymmetric vortex panel method for duct and center body, blade element lifting line rotor representation, and wake model axisymmetrically smeared onto an elliptic grid for efficient computation. DuctAPE has been developed specifically for applications in gradient-based optimization settings.","category":"page"},{"location":"#Installation","page":"Home","title":"Installation","text":"","category":"section"},{"location":"","page":"Home","title":"Home","text":"pkg> add DuctAPE","category":"page"},{"location":"#Documentation","page":"Home","title":"Documentation","text":"","category":"section"},{"location":"","page":"Home","title":"Home","text":"Start with Getting Started to get up and running.\nThe Advanced Usage tab includes several pages of additional information for customizing your usage.\nThe API tab contains public and private method descriptions.\nThe Theory tab contain several pages on the underlying theory of DuctAPE.\nThe C^4Blade tab contains documentation for the C^4Blade submodule used for airfoil/cascade management within DuctAPE as well as state initialization.","category":"page"},{"location":"#Citing","page":"Home","title":"Citing","text":"","category":"section"},{"location":"","page":"Home","title":"Home","text":"Mehr, J. and Ning, A., \"DuctAPE: A steady-state, axisymmetric ducted fan analysis code designed for gradient-based optimization.,\" AIAA Aviation Forum, July 2024.","category":"page"},{"location":"DuctAPE/tutorial/#Getting-Started","page":"Getting Started","title":"Getting Started","text":"","category":"section"},{"location":"DuctAPE/tutorial/","page":"Getting Started","title":"Getting Started","text":"Pages = [\"tutorial.md\"]\nDepth = 5","category":"page"},{"location":"DuctAPE/tutorial/","page":"Getting Started","title":"Getting Started","text":"The following is a basic tutorial on how to set up the inputs to, and run, an analysis of a ducted fan in DuctAPE.","category":"page"},{"location":"DuctAPE/tutorial/","page":"Getting Started","title":"Getting Started","text":"include(\"../assets/plots_default.jl\")\ngr()","category":"page"},{"location":"DuctAPE/tutorial/","page":"Getting Started","title":"Getting Started","text":"We begin by loading the package, and optionally create a shorthand name.","category":"page"},{"location":"DuctAPE/tutorial/","page":"Getting Started","title":"Getting Started","text":"using DuctAPE\nconst dt = DuctAPE\nnothing # hide","category":"page"},{"location":"DuctAPE/tutorial/#Assemble-Inputs","page":"Getting Started","title":"Assemble Inputs","text":"","category":"section"},{"location":"DuctAPE/tutorial/","page":"Getting Started","title":"Getting Started","text":"The next step is to create the input object of type Propulsor.","category":"page"},{"location":"DuctAPE/tutorial/","page":"Getting Started","title":"Getting Started","text":"DuctAPE.Propulsor","category":"page"},{"location":"DuctAPE/tutorial/#DuctAPE.Propulsor-DuctAPE-tutorial","page":"Getting Started","title":"DuctAPE.Propulsor","text":"Propulsor(duct_coordinates, centerbody_coordinates, rotorstator_parameters, operating_point, paneling_constants, reference_parameters)\n\nArguments\n\nduct_coordinates::AbstractMatrix : The [z, r] coordinates of the duct geometry beginning at the inner (casing) side trailing edge and proceeding clockwise. Note that the duct geometry absolute radial position does not need to be included here if the autoshiftduct option is selected.\ncenterbody_coordinates::AbstractMatrix : The [z, r] coordinates of the centerbody beginning at the leading edge and ending at the trailing edge. Note that the leading edge is assumed to be placed at a radial distance of 0.0 from the axis of rotation.\noperating_point::OperatingPoint : The operating point values.\npaneling_constants::PanelingConstants : Constants used in re-paneling the geometry.\nrotorstator_parameters::RotorStatorParameters : Rotor (and possibly stator) geometric paramters.\nreference_parameters::ReferenceParameters : Reference Parameters.\n\n\n\n\n\n","category":"type"},{"location":"DuctAPE/tutorial/#Body-Geometry","page":"Getting Started","title":"Body Geometry","text":"","category":"section"},{"location":"DuctAPE/tutorial/","page":"Getting Started","title":"Getting Started","text":"We begin by defining a matrix of coordinates for the duct and another for the centerbody geometries, for example:","category":"page"},{"location":"DuctAPE/tutorial/","page":"Getting Started","title":"Getting Started","text":"duct_coordinates = [\n 0.304466 0.158439\n 0.294972 0.158441\n 0.28113 0.158423\n 0.266505 0.158365\n 0.251898 0.158254\n 0.237332 0.158088\n 0.222751 0.157864\n 0.208123 0.157586\n 0.193399 0.157258\n 0.178507 0.156897\n 0.16349 0.156523\n 0.148679 0.156177\n 0.134222 0.155902\n 0.12 0.155721\n 0.106044 0.155585\n 0.092531 0.155498\n 0.079836 0.155546\n 0.067995 0.155792\n 0.057025 0.156294\n 0.046983 0.157103\n 0.037937 0.158256\n 0.029956 0.159771\n 0.02311 0.161648\n 0.017419 0.163862\n 0.012842 0.166404\n 0.009324 0.169289\n 0.006854 0.172546\n 0.005484 0.176154\n 0.005242 0.180005\n 0.006112 0.184067\n 0.00809 0.188086\n 0.011135 0.192004\n 0.015227 0.19579\n 0.020339 0.199393\n 0.026403 0.202735\n 0.033312 0.205736\n 0.040949 0.208332\n 0.049193 0.210487\n 0.057935 0.212174\n 0.067113 0.21339\n 0.076647 0.214136\n 0.086499 0.214421\n 0.09661 0.214255\n 0.10695 0.213649\n 0.117508 0.212618\n 0.12838 0.211153\n 0.139859 0.209267\n 0.151644 0.207051\n 0.163586 0.204547\n 0.175647 0.201771\n 0.187807 0.198746\n 0.20002 0.19549\n 0.212269 0.192017\n 0.224549 0.188335\n 0.236794 0.18447\n 0.249026 0.180416\n 0.261206 0.176188\n 0.273301 0.171796\n 0.28524 0.16727\n 0.29644 0.162842\n 0.304542 0.159526\n]\nnothing # hide","category":"page"},{"location":"DuctAPE/tutorial/","page":"Getting Started","title":"Getting Started","text":"centerbody_coordinates = [\n 0.0 0.0\n 0.000586 0.005293\n 0.002179 0.010047\n 0.004736 0.014551\n 0.008231 0.018825\n 0.012632 0.022848\n 0.01788 0.026585\n 0.023901 0.030001\n 0.030604 0.033068\n 0.0379 0.035771\n 0.045705 0.038107\n 0.053933 0.040075\n 0.06254 0.04169\n 0.071451 0.042966\n 0.08063 0.043916\n 0.090039 0.044561\n 0.09968 0.044922\n 0.109361 0.044999\n 0.12 0.044952\n 0.135773 0.04495\n 0.151899 0.04493\n 0.16806 0.044913\n 0.184232 0.044898\n 0.200407 0.044882\n 0.21658 0.044866\n 0.232723 0.044847\n 0.248578 0.044839\n 0.262095 0.044564\n 0.274184 0.043576\n 0.285768 0.041795\n 0.296701 0.039168\n 0.306379 0.035928\n]\nnothing # hide","category":"page"},{"location":"DuctAPE/tutorial/","page":"Getting Started","title":"Getting Started","text":"pg = plot(\n duct_coordinates[:, 1],\n duct_coordinates[:, 2];\n aspectratio=1,\n color=1,\n linewidth=2,\n label=\"Duct\",\n xlabel=\"z\",\n ylabel=\"r\",\n legend=:left,\n) # hide\nplot!(\n pg,\n centerbody_coordinates[:, 1],\n centerbody_coordinates[:, 2];\n color=2,\n linewidth=2,\n label=\"Center Body\",\n) # hide","category":"page"},{"location":"DuctAPE/tutorial/","page":"Getting Started","title":"Getting Started","text":"note: Note\nThe body geometry coordinates must be input as columns of z (axial) and r (radial) coordinates, in that order.","category":"page"},{"location":"DuctAPE/tutorial/#Rotor-Geometry","page":"Getting Started","title":"Rotor Geometry","text":"","category":"section"},{"location":"DuctAPE/tutorial/","page":"Getting Started","title":"Getting Started","text":"The next step is to assemble an object of type RotorStatorParameters which contains the geometric information required to define the rotor(s) and their respective blade elements.","category":"page"},{"location":"DuctAPE/tutorial/","page":"Getting Started","title":"Getting Started","text":"DuctAPE.RotorStatorParameters","category":"page"},{"location":"DuctAPE/tutorial/#DuctAPE.RotorStatorParameters-DuctAPE-tutorial","page":"Getting Started","title":"DuctAPE.RotorStatorParameters","text":"RotorStatorParameters(\n B, rotorzloc, r, Rhub, Rtip, chords, twists, tip_gap, airfoils, fliplift\n)\n\nComposite type containing the rotor(s) geometric properties.\n\nNote that the actual struct requires the inputs to be arrays, but there is a constructor function that will take in scalars and automatically build the array-based struct.\n\nArguments\n\nB::AbstractVector{Float} : The number of blades for each rotor. May not be an integer, but usually is.\nrotorzloc::AbstractVector{Float} : Dimensional, axial position of each rotor.\nr::AbstractArray{Float} : Non-dimensional radial locations of each blade element.\nRhub::AbstractVector{Float} : Dimensional hub radius of rotor. (may be changed if it does not match the radial position of the centerbody geometry at the selected rotorzloc.\nRtip::AbstractVector{Float} : Dimensional tip radius of rotor. Is used to determine the radial position of the duct if the autoshiftduct option is selected.\nchords::AbstractArray{Float} : Dimensional chord lengths of the blade elements.\ntwists::AbstractArray{Float} : Blade element angles, in radians.\ntip_gap::AbstractVector{Float} : Currently unused, do not set to anything other than zeros.\nairfoils::AbstractArray{AFType} : Airfoil types describing the airfoil polars for each blade element. Currently only fully tested with C4Blade.DFDCairfoil types.\nfliplift::AbstractVector{Bool} : flag to indicate if the airfoil lift values should be flipped or not.\n\n\n\n\n\n","category":"type"},{"location":"DuctAPE/tutorial/","page":"Getting Started","title":"Getting Started","text":"In this example, we have a single rotor defined as follows.","category":"page"},{"location":"DuctAPE/tutorial/","page":"Getting Started","title":"Getting Started","text":"# number of rotors\nB = 5\n\n# rotor axial location\nrotorzloc = 0.12\n\n# rotor tip radius\nRtip = 0.15572081487373543\n\n# rotor hub radius\nRhub = 0.04495252299071941\n\n# non-dimensional blade element radial stations\nr = [\n 0.050491\n 0.061567\n 0.072644\n 0.083721\n 0.094798\n 0.10587\n 0.11695\n 0.12803\n 0.13911\n 0.15018\n] ./ Rtip\n\n# dimensional chord lengths\nchords = [\n 0.089142\n 0.079785\n 0.0713\n 0.063979\n 0.057777\n 0.052541\n 0.048103\n 0.044316\n 0.041061\n 0.038243\n]\n\n# twist angles (from plane of rotation) in radians\ntwists = [\n 69.012\n 59.142\n 51.825\n 46.272\n 41.952\n 38.509\n 35.699\n 33.354\n 31.349\n 29.596\n] .* pi / 180.0\n\n# DFDC-type airfoil object\nafparams = DuctAPE.c4b.DFDCairfoil(;\n alpha0=0.0,\n clmax=1.5,\n clmin=-1.0,\n dclda=6.28,\n dclda_stall=0.5,\n dcl_stall=0.2,\n cdmin=0.012,\n clcdmin=0.1,\n dcddcl2=0.005,\n cmcon=0.0,\n Re_ref=2e5,\n Re_exp=0.35,\n mcrit=0.7,\n)\n\n# all airfoils are the same\nairfoils = fill(afparams, length(r)) # specify the airfoil array\n\n# assemble rotor parameters\nrotorstator_parameters = dt.RotorStatorParameters(\n [B],\n [rotorzloc],\n r,\n [Rhub],\n [Rtip],\n chords,\n twists,\n [0.0], # currently only zero tip gaps work.\n airfoils,\n [0.0], # can flip the cl lookups on the fly if desired, say, for stator sections\n)\nnothing # hide","category":"page"},{"location":"DuctAPE/tutorial/","page":"Getting Started","title":"Getting Started","text":"plot!(\n pg,\n rotorzloc * ones(length(r)),\n r .* Rtip;\n seriestype=:scatter,\n markersize=3,\n markerstrokewidth=0,\n label=\"Blade Elements\",\n) # hide","category":"page"},{"location":"DuctAPE/tutorial/","page":"Getting Started","title":"Getting Started","text":"note: Airfoils\nAirfoil types for DuctAPE are currently contained in the C4Blade (Cascade Compatible CCBlade) sub-module of DuctAPE which is exported as c4b and also contains the various airfoil evaluation functions used for the blade element lookups. The available airfoil types include all the airfoil types from CCBlade, as well as DFDCairfoil which is an XROTOR-like parametric cascade polar used in DFDC. In addition there are untested cascade types with similar structure to CCBlades airfoil types called DTCascade. Furthermore, there is an experimental actuator disk model implemented via the ADM airfoil type in C4Blade.","category":"page"},{"location":"DuctAPE/tutorial/#Operating-Point","page":"Getting Started","title":"Operating Point","text":"","category":"section"},{"location":"DuctAPE/tutorial/","page":"Getting Started","title":"Getting Started","text":"Next we will assemble the operating point which contains information about the freestream as well as the rotor rotation rate(s).","category":"page"},{"location":"DuctAPE/tutorial/","page":"Getting Started","title":"Getting Started","text":"DuctAPE.OperatingPoint","category":"page"},{"location":"DuctAPE/tutorial/#DuctAPE.OperatingPoint-DuctAPE-tutorial","page":"Getting Started","title":"DuctAPE.OperatingPoint","text":"OperatingPoint(Vinf, rhoinf, muinf, asound, Omega)\n\nPropulsor operating point information.\n\nNote that the actual struct requires the inputs to be arrays, but there is a constructor function that will take in scalars and automatically build the array-based struct.\n\nAlso note that even though each field is required to be a vector, only Omega should have more than one entry, and only then if there are more than one rotor. The purpose behind having vector rather than constant scalar inputs here is for ease of redefinition in an optimization setting when freestream design variables may be present.\n\nArguments\n\nVinf::AbstractVector{Float} : Freestream velocity magnitude (which is only in the axial direction).\nrhoinf::AbstractVector{Float} : Freestream density\nmuinf::AbstractVector{Float} : Freestream viscosity\nasound::AbstractVector{Float} : Freestream speed of sound\nOmega::AbstractVector{Float} : Rotor rototation rate(s)\n\n\n\n\n\n","category":"type"},{"location":"DuctAPE/tutorial/","page":"Getting Started","title":"Getting Started","text":"# Freestream\nVinf = 0.0 # hover condition\nrhoinf = 1.226\nasound = 340.0\nmuinf = 1.78e-5\n\n# Rotation Rate\nRPM = 8000.0\nOmega = RPM * pi / 30 # if using RPM, be sure to convert to rad/s\n\n# utilizing the constructor function to put things in vector types\noperating_point = dt.OperatingPoint(Vinf, rhoinf, muinf, asound, Omega)\nnothing # hide","category":"page"},{"location":"DuctAPE/tutorial/#Paneling-Constants","page":"Getting Started","title":"Paneling Constants","text":"","category":"section"},{"location":"DuctAPE/tutorial/","page":"Getting Started","title":"Getting Started","text":"The PanelingConstants object contains the constants required for DuctAPE to re-panel the provided geometry into a format compatible with the solve structure. The PanelingConstants object is also used to build all of the preallocated caches inside DuctAPE, which can be done up-front if desired. Note that there is some functionality in place for cases when the user wants to keep their own specified geometry, but this functionality should be used with caution and only by users who are certain their provided geometry is in the compatible format. See the Examples for an example.","category":"page"},{"location":"DuctAPE/tutorial/","page":"Getting Started","title":"Getting Started","text":"DuctAPE.PanelingConstants","category":"page"},{"location":"DuctAPE/tutorial/#DuctAPE.PanelingConstants-DuctAPE-tutorial","page":"Getting Started","title":"DuctAPE.PanelingConstants","text":"PanelingConstants(\n nduct_inlet,\n ncenterbody_inlet,\n npanels,\n dte_minus_cbte,\n nwake_sheets,\n wake_length=1.0,\n)\n\nConstants used in re-paneling geometry.\n\nNote that unlike other input structures, this one, in general, does not define fields as vectors. This is because these values should not change throughout an optimization, even if the geometry may change. Otherwise, discontinuities could be experienced.\n\nArguments\n\nnduct_inlet::Int : The number of panels to use for the duct inlet (this number is used for both the casing and nacelle re-paneling)\nncenterbody_inlet::Int : The number of panels to use for the centerbody inlet.\nnpanels::AbstractVector{Int} : A vector containing the number of panels between discrete locations inside the wake. Specifically, the number of panels between the rotors, between the last rotor and the first body trailing edge, between the body trailing edges (if different), and between the last body trailing edge and the end of the wake. The length of this vector should be N+1 (where N is the number of rotors) if the duct and centerbody trailing edges are aligned, and N+2 if not.\ndte_minus_cbte::Float : An indicator concerning the hub and duct trailing edge relative locations. Should be set to -1 if the duct trailing edge axial position minus the centerbody trailing edge axial position is negative, +1 if positive (though any positive or negative number will suffice), and zero if the trailing edges are aligned.\nnwake_sheets::Int : The number of wake sheets to use. Note this will also be setting the number of blade elements to use.\nwake_length::Float=1.0 : Non-dimensional (based on the length from the foremost body leading edge and the aftmost body trailing edge) length of the wake extending behind the aftmost body trailing edge.\n\n\n\n\n\n","category":"type"},{"location":"DuctAPE/tutorial/","page":"Getting Started","title":"Getting Started","text":"# number of panels for the duct inlet\nnduct_inlet = 30\n\n# number of panels for the center body inlet\nncenterbody_inlet = 30\n\n# number of panels from:\n# - rotor to duct trailing edge\n# - duct trailing edge to center body trailing edge\n# - center body trailing edge to end of wake\nnpanels = [30, 1, 30]\n\n# the duct trailing edge is ahead of the centerbody trailing edge.\ndte_minus_cbte = -1.0\n\n# number of wake sheets (one more than blade elements to use)\nnwake_sheets = 11\n\n# non-dimensional wake length aft of rear-most trailing edge\nwake_length = 0.8\n\n# assemble paneling constants\npaneling_constants = dt.PanelingConstants(\n nduct_inlet, ncenterbody_inlet, npanels, dte_minus_cbte, nwake_sheets, wake_length\n)\nnothing # hide","category":"page"},{"location":"DuctAPE/tutorial/#Reference-Parameters","page":"Getting Started","title":"Reference Parameters","text":"","category":"section"},{"location":"DuctAPE/tutorial/","page":"Getting Started","title":"Getting Started","text":"The reference parameters are used in the post-processing non-dimensionalizations.","category":"page"},{"location":"DuctAPE/tutorial/","page":"Getting Started","title":"Getting Started","text":"DuctAPE.ReferenceParameters","category":"page"},{"location":"DuctAPE/tutorial/#DuctAPE.ReferenceParameters-DuctAPE-tutorial","page":"Getting Started","title":"DuctAPE.ReferenceParameters","text":"ReferenceParameters(Vref, Rref)\n\nReference parameters for post-process non-dimensionalization.\n\nNote that the actual struct requires the inputs to be arrays, but there is a constructor function that will take in scalars and automatically build the array-based struct.\n\nArguments\n\nVref::AbstractVector{Float} : Reference velocity.\nRref::AbstractVector{Float} : Reference rotor tip radius.\n\n\n\n\n\n","category":"type"},{"location":"DuctAPE/tutorial/","page":"Getting Started","title":"Getting Started","text":"# reference velocity (close to average axial velocity at rotor in this case)\nVref = 50.0\n\n# reference radius (usually tip radius of rotor)\nRref = Rtip\n\n# assemble reference parameters\nreference_parameters = dt.ReferenceParameters([Vref], [Rref])\nnothing # hide","category":"page"},{"location":"DuctAPE/tutorial/#All-Together","page":"Getting Started","title":"All Together","text":"","category":"section"},{"location":"DuctAPE/tutorial/","page":"Getting Started","title":"Getting Started","text":"We are now posed to construct the Propulsor input type.","category":"page"},{"location":"DuctAPE/tutorial/","page":"Getting Started","title":"Getting Started","text":"# assemble propulsor object\npropulsor = dt.Propulsor(\n duct_coordinates,\n centerbody_coordinates,\n rotorstator_parameters,\n operating_point,\n paneling_constants,\n reference_parameters,\n)\nnothing # hide","category":"page"},{"location":"DuctAPE/tutorial/#Set-Options","page":"Getting Started","title":"Set Options","text":"","category":"section"},{"location":"DuctAPE/tutorial/","page":"Getting Started","title":"Getting Started","text":"The default options should be sufficient for just starting out and are set through the set_options function.","category":"page"},{"location":"DuctAPE/tutorial/","page":"Getting Started","title":"Getting Started","text":"DuctAPE.set_options","category":"page"},{"location":"DuctAPE/tutorial/#DuctAPE.set_options-DuctAPE-tutorial","page":"Getting Started","title":"DuctAPE.set_options","text":"set_options(; kwargs...)\nset_options(multipoint; kwargs...)\n\nSet the options for DuctAPE to use.\n\nNote that the vast majority of the available options are defined through keyword arguments. See the documentation for the various option types for more information.\n\nArguments\n\nmultipoint::AbstractArray{OperatingPoint} : a vector of operating points to use if running a multi-point analysis.\n\n\n\n\n\n","category":"function"},{"location":"DuctAPE/tutorial/","page":"Getting Started","title":"Getting Started","text":"options = dt.set_options()","category":"page"},{"location":"DuctAPE/tutorial/","page":"Getting Started","title":"Getting Started","text":"For more advanced option selection, see the examples and API reference.","category":"page"},{"location":"DuctAPE/tutorial/#Run-a-Single-Analysis","page":"Getting Started","title":"Run a Single Analysis","text":"","category":"section"},{"location":"DuctAPE/tutorial/","page":"Getting Started","title":"Getting Started","text":"With the propulsor input build, and the options selected, we are now ready to run an analysis. This is done simply with the analyze function which dispatches the appropriate analysis, solve, and post-processing functions based on the selected options.","category":"page"},{"location":"DuctAPE/tutorial/","page":"Getting Started","title":"Getting Started","text":"DuctAPE.analyze(::DuctAPE.Propulsor, ::DuctAPE.Options)","category":"page"},{"location":"DuctAPE/tutorial/#DuctAPE.analyze-Tuple{Propulsor, Options}-DuctAPE-tutorial","page":"Getting Started","title":"DuctAPE.analyze","text":"analyze(\n propulsor::Propulsor,\n options::Options=set_options();\n prepost_container_caching=nothing,\n solve_parameter_caching=nothing,\n solve_container_caching=nothing,\n return_inputs=false,\n)\n\nAnalyze propulsor, including preprocessing.\n\nArguments\n\npropulsor::Propulsor : Propulsor input object (see docstring for Propulsor type)\noptions::Options=set_options() : Options object (see set_options and related functions)\n\nKeyword Arguments\n\nprepost_container_caching=nothing : Output of allocate_prepost_container_cache\nsolve_parameter_caching=nothing : Output of allocate_solve_parameter_container_cache\nsolve_container_caching=nothing : Output of allocate_solve_container_cache\nreturn_inputs=false : flag as to whether or not to return the pre-processed inputs\n\nReturns\n\nouts::NamedTuple : Named Tuple of various analysis outputs (see docstring for postprocess for details), note, if linear system decomposition fails, no solve is performed and an empty vector is returned.\nins::NamedTuple : Named Tuple of various pre-processed inputs (e.g. panels and body linear system), will only be returned if return_inputs=true\nconvergence_flag : Flag for successful solve convergence\n\n\n\n\n\n","category":"method"},{"location":"DuctAPE/tutorial/","page":"Getting Started","title":"Getting Started","text":"outs, success_flag = dt.analyze(propulsor, options)\nnothing # hide","category":"page"},{"location":"DuctAPE/tutorial/#Single-Run-Outputs","page":"Getting Started","title":"Single Run Outputs","text":"","category":"section"},{"location":"DuctAPE/tutorial/","page":"Getting Started","title":"Getting Started","text":"There are many outputs contained in the named tuple output from the analyze function (see the post_process() docstring), but some that may be of immediate interest include:","category":"page"},{"location":"DuctAPE/tutorial/","page":"Getting Started","title":"Getting Started","text":"# Total Thrust Coefficient\nouts.totals.CT","category":"page"},{"location":"DuctAPE/tutorial/","page":"Getting Started","title":"Getting Started","text":"# Total Torque Coefficient\nouts.totals.CQ","category":"page"},{"location":"DuctAPE/tutorial/#Run-a-Multi-Point-Analysis","page":"Getting Started","title":"Run a Multi-Point Analysis","text":"","category":"section"},{"location":"DuctAPE/tutorial/","page":"Getting Started","title":"Getting Started","text":"In the case that one wants to run the same geometry at several different operating points, for example: for a range of advance ratios, there is another dispatch of the analyze function that takes in an input, multipoint, that is a vector of operating points.","category":"page"},{"location":"DuctAPE/tutorial/","page":"Getting Started","title":"Getting Started","text":"DuctAPE.analyze(multipoint::AbstractVector{TO},propulsor::Propulsor,options::Options) where TO<:OperatingPoint","category":"page"},{"location":"DuctAPE/tutorial/#DuctAPE.analyze-Union{Tuple{TO}, Tuple{AbstractVector{TO}, Propulsor, Options}} where TO<:OperatingPoint-DuctAPE-tutorial","page":"Getting Started","title":"DuctAPE.analyze","text":"analyze(\n multipoint::AbstractVector{OperatingPoint},\n propulsor::Propulsor,\n options::Options=set_options();\n prepost_container_caching=nothing,\n solve_parameter_caching=nothing,\n solve_container_caching=nothing,\n return_inputs=false,\n)\n\nAnalyze propulsor, including preprocessing, for a set of operating points.\n\nArguments\n\nmultipoint::AbstractVector{OperatingPoint} : Vector of Operating Points at which to analyze the propulsor (note that the operating point within the propulsor input will be overwritten with these)\npropulsor::Propulsor : Propulsor input object\noptions::Options=set_options() : Options object\n\nKeyword Arguments\n\nprepost_container_caching=nothing : Output of allocate_prepost_container_cache\nsolve_parameter_caching=nothing : Output of allocate_solve_parameter_container_cache\nsolve_container_caching=nothing : Output of allocate_solve_container_cache\nreturn_inputs=false : flag as to whether or not to return the pre-processed inputs\n\nReturns\n\nouts::Vector{NamedTuple} : Vector of named tuples of various analysis outputs (see docstring for postprocess for details), note, if linear system decomposition fails, no solve is performed and an empty vector is returned.\nins::NamedTuple : Named Tuple of various pre-processed inputs (e.g. panels and body linear system), will only be returned if return_inputs=true\nconvergence_flag : Flag for successful solve convergence\n\n\n\n\n\n","category":"method"},{"location":"DuctAPE/tutorial/","page":"Getting Started","title":"Getting Started","text":"Running a multi-point analysis on the example geometry given there, it might look something like this:","category":"page"},{"location":"DuctAPE/tutorial/","page":"Getting Started","title":"Getting Started","text":"# - Advance Ratio Range - #\nJs = range(0.0, 2.0; step=0.01)\n\n# - Calculate Vinfs - #\nD = 2.0 * rotorstator_parameters.Rtip[1] # rotor diameter\nn = RPM / 60.0 # rotation rate in revolutions per second\nVinfs = Js * n * D\n\n# - Set Operating Points - #\nops = [deepcopy(operating_point) for i in 1:length(Vinfs)]\nfor (iv, v) in enumerate(Vinfs)\n ops[iv].Vinf[] = v\nend\n\n# - Run Multi-point Analysis - #\nouts_vec, success_flags = DuctAPE.analyze(ops, propulsor, DuctAPE.set_options(ops))\nnothing #hide","category":"page"},{"location":"DuctAPE/tutorial/","page":"Getting Started","title":"Getting Started","text":"There are a few things to note here.","category":"page"},{"location":"DuctAPE/tutorial/","page":"Getting Started","title":"Getting Started","text":"We want to make sure that the operating point objects we put into the input vector are unique instances.\nWe need to use the dispatch of set_options that takes in the operating point vector to set up the right number of things in the background (like convergence flags for each operating point).\nThe outputs of the analysis are vectors of the same outputs for a single analysis.","category":"page"},{"location":"DuctAPE/tutorial/#Multi-point-Outputs","page":"Getting Started","title":"Multi-point Outputs","text":"","category":"section"},{"location":"DuctAPE/tutorial/","page":"Getting Started","title":"Getting Started","text":"For multi-point analysis outputs, which are given as a vector of output objects, we might access and plot things as follows. We also take the opportunity to present some verification against DFDC, showing that DuctAPE matches remarkably well (within 0.5%) of DFDC. We therefore first provide data from DFDC analyses of the above example geometry at various advance ratios.","category":"page"},{"location":"DuctAPE/tutorial/","page":"Getting Started","title":"Getting Started","text":"# Verification Data From DFDC\n\ndfdc_jept = [\n 0.0 0.0 0.64763 0.96692\n 0.1 0.1366 0.64716 0.88394\n 0.2 0.2506 0.6448 0.80785\n 0.3 0.3457 0.64044 0.73801\n 0.4 0.4251 0.63401 0.67382\n 0.5 0.4915 0.62534 0.61468\n 0.6 0.547 0.61428 0.56001\n 0.7 0.5935 0.6006 0.50925\n 0.8 0.6326 0.58411 0.46187\n 0.9 0.6654 0.56452 0.41738\n 1.0 0.693 0.54158 0.37531\n 1.1 0.716 0.51499 0.33522\n 1.2 0.7349 0.48446 0.2967\n 1.3 0.7499 0.44966 0.25937\n 1.4 0.7606 0.41031 0.2229\n 1.5 0.7661 0.36604 0.18694\n 1.6 0.7643 0.31654 0.15121\n 1.7 0.7506 0.26153 0.11547\n 1.8 0.7126 0.20061 0.07941\n 1.9 0.61 0.13355 0.04287\n 2.0 0.1861 0.05993 0.00558\n]\n\ndfdc_J = dfdc_jept[:,1]\ndfdc_eta = dfdc_jept[:,2]\ndfdc_cp = dfdc_jept[:,3]\ndfdc_ct = dfdc_jept[:,4]\nnothing #hide","category":"page"},{"location":"DuctAPE/tutorial/","page":"Getting Started","title":"Getting Started","text":"We can then access the various multi-point analysis outputs however is convenient, we choose a broadcasting approach here:","category":"page"},{"location":"DuctAPE/tutorial/","page":"Getting Started","title":"Getting Started","text":"\n# - extract efficiency, power, and thrust coefficients - #\n# efficiency\neta = (p->p.totals.total_efficiency[1]).(outs_vec)\n# power\ncp = (p->p.totals.CP[1]).(outs_vec)\n# thrust\nct = (p->p.totals.CT[1]).(outs_vec)\nnothing #hide","category":"page"},{"location":"DuctAPE/tutorial/","page":"Getting Started","title":"Getting Started","text":"And then we can plot the data to compare DFDC and DuctAPE.","category":"page"},{"location":"DuctAPE/tutorial/","page":"Getting Started","title":"Getting Started","text":"\n# set up efficiency plot\npe = plot(; xlabel=\"Advance Ratio\", ylabel=\"Efficiency\")\n\n# plot DFDC data\nplot!(\n pe,\n dfdc_J,\n dfdc_eta;\n seriestype=:scatter,\n markersize=5,\n markercolor=plotsgray,\n markerstrokecolor=plotsgray,\n label=\"DFDC\"\n)\n\n# Plot DuctAPE outputs\nplot!(pe, Js, eta; linewidth=2, color=primary, label = \"DuctAPE\")\n\n# setup cp/ct plot\nppt = plot(; xlabel=\"Advance Ratio\")\n\n# plot DFDC data\nplot!(\n ppt,\n dfdc_J,\n dfdc_cp;\n seriestype=:scatter,\n markersize=5,\n markercolor=plotsgray,\n markerstrokecolor=primary,\n markerstrokewidth=2,\n label=\"DFDC Cp\"\n)\nplot!(\n ppt,\n dfdc_J,\n dfdc_ct;\n seriestype=:scatter,\n markersize=5,\n markercolor=plotsgray,\n markerstrokecolor=secondary,\n markerstrokewidth=2,\n label=\"DFDC Ct\"\n)\n\n# plot DuctAPE outputs\nplot!(\n ppt,\n Js,\n cp;\n linewidth=1.5,\n color=primary,\n label=\"DuctAPE Cp\"\n)\nplot!(\n ppt,\n Js,\n ct;\n linewidth=1.5,\n color=secondary,\n label=\"DuctAPE Ct\"\n)\n\nplot(pe, ppt; size=(700,350), layout=(1,2), margin=2mm)","category":"page"},{"location":"DuctAPE/api/api_index/#Index","page":"API Index","title":"Index","text":"","category":"section"},{"location":"DuctAPE/api/api_index/","page":"API Index","title":"API Index","text":"Modules=[DuctAPE]","category":"page"}] }