Skip to content

Commit b8c0ea8

Browse files
committed
Hand rolled lu
1 parent ec46c4d commit b8c0ea8

1 file changed

Lines changed: 123 additions & 56 deletions

File tree

src/solver.jl

Lines changed: 123 additions & 56 deletions
Original file line numberDiff line numberDiff line change
@@ -141,9 +141,11 @@ sol::VSMSolution = VSMSolution(): The result of calling [solve!](@ref)
141141
relaxation_factor::Float64 = 0.03
142142

143143
# Nonlin solver fields
144-
prob::Union{NonlinearProblem, Nothing} = nothing
145-
nonlin_cache::Union{NonlinearSolveFirstOrder.GeneralizedFirstOrderAlgorithmCache, Nothing} = nothing
146144
atol::Float64 = 1e-5
145+
nonlin_jac::Matrix{Float64} = zeros(P, P)
146+
nonlin_residual::MVector{P, Float64} = zeros(P)
147+
nonlin_residual_perturbed::MVector{P, Float64} = zeros(P)
148+
nonlin_gamma_perturbed::MVector{P, Float64} = zeros(P)
147149

148150
# Damping settings
149151
is_with_artificial_damping::Bool = false
@@ -733,8 +735,54 @@ end
733735
return nothing
734736
end
735737

738+
@inline function lu_solve_inplace!(
739+
A::AbstractMatrix{Float64},
740+
b::AbstractVector{Float64},
741+
n::Int,
742+
)
743+
@inbounds for k in 1:n
744+
amax = abs(A[k, k])
745+
pivot_row = k
746+
for i in (k + 1):n
747+
v = abs(A[i, k])
748+
if v > amax
749+
amax = v
750+
pivot_row = i
751+
end
752+
end
753+
amax == 0.0 && return false
754+
if pivot_row != k
755+
for j in 1:n
756+
tmp = A[k, j]
757+
A[k, j] = A[pivot_row, j]
758+
A[pivot_row, j] = tmp
759+
end
760+
tmp = b[k]
761+
b[k] = b[pivot_row]
762+
b[pivot_row] = tmp
763+
end
764+
inv_pivot = 1.0 / A[k, k]
765+
for i in (k + 1):n
766+
factor = A[i, k] * inv_pivot
767+
A[i, k] = factor
768+
for j in (k + 1):n
769+
A[i, j] -= factor * A[k, j]
770+
end
771+
b[i] -= factor * b[k]
772+
end
773+
end
774+
@inbounds for k in n:-1:1
775+
s = b[k]
776+
for j in (k + 1):n
777+
s -= A[k, j] * b[j]
778+
end
779+
b[k] = s / A[k, k]
780+
end
781+
return true
782+
end
783+
736784
"""
737-
gamma_loop!(solver::Solver, AIC_x::Matrix{Float64},
785+
gamma_loop!(solver::Solver, AIC_x::Matrix{Float64},
738786
AIC_y::Matrix{Float64}, AIC_z::Matrix{Float64},
739787
panels::Vector{Panel}, relaxation_factor::Float64; log=true)
740788
@@ -778,63 +826,82 @@ function gamma_loop!(
778826
velocity_view_z = @view induced_velocity_all[:, 3]
779827

780828
if solver.solver_type == NONLIN
781-
prob = solver.prob
782-
if isnothing(prob)
783-
function f_nonlin!(d_gamma, gamma, _p)
829+
gamma_iter = solver.lr.gamma_new
830+
residual = solver.nonlin_residual
831+
residual_perturbed = solver.nonlin_residual_perturbed
832+
gamma_perturbed = solver.nonlin_gamma_perturbed
833+
jac = solver.nonlin_jac
834+
relstep = sqrt(eps(Float64))
835+
abstep = sqrt(eps(Float64))
836+
837+
solver.lr.converged = false
838+
for iter in 1:solver.max_iterations
839+
update_gamma_candidate!(
840+
residual, gamma_iter, solver, panels, n_panels,
841+
AIC_x, AIC_y, AIC_z,
842+
velocity_view_x, velocity_view_y, velocity_view_z,
843+
va_array, induced_velocity_all, relative_velocity_array,
844+
y_airf_array, relative_velocity_crossz, v_acrossz_array,
845+
z_airf_array, x_airf_array,
846+
v_normal_array, v_tangential_array,
847+
va_magw_array, cl_dist, chord_array,
848+
)
849+
max_residual = 0.0
850+
@inbounds for i in 1:n_panels
851+
residual[i] -= gamma_iter[i]
852+
a = abs(residual[i])
853+
a > max_residual && (max_residual = a)
854+
end
855+
if max_residual < solver.atol
856+
solver.lr.converged = true
857+
break
858+
end
859+
860+
@inbounds for j in 1:n_panels
861+
for i in 1:n_panels
862+
gamma_perturbed[i] = gamma_iter[i]
863+
end
864+
step = max(abstep, relstep * abs(gamma_iter[j]))
865+
gamma_perturbed[j] += step
784866
update_gamma_candidate!(
785-
solver.lr.gamma_new,
786-
gamma,
787-
solver,
788-
panels,
789-
n_panels,
790-
AIC_x,
791-
AIC_y,
792-
AIC_z,
793-
velocity_view_x,
794-
velocity_view_y,
795-
velocity_view_z,
796-
va_array,
797-
induced_velocity_all,
798-
relative_velocity_array,
799-
y_airf_array,
800-
relative_velocity_crossz,
801-
v_acrossz_array,
802-
z_airf_array,
803-
x_airf_array,
804-
v_normal_array,
805-
v_tangential_array,
806-
va_magw_array,
807-
cl_dist,
808-
chord_array,
867+
residual_perturbed, gamma_perturbed, solver, panels, n_panels,
868+
AIC_x, AIC_y, AIC_z,
869+
velocity_view_x, velocity_view_y, velocity_view_z,
870+
va_array, induced_velocity_all, relative_velocity_array,
871+
y_airf_array, relative_velocity_crossz, v_acrossz_array,
872+
z_airf_array, x_airf_array,
873+
v_normal_array, v_tangential_array,
874+
va_magw_array, cl_dist, chord_array,
809875
)
810-
d_gamma .= solver.lr.gamma_new .- gamma
811-
nothing
876+
inv_step = 1.0 / step
877+
for i in 1:n_panels
878+
residual_perturbed[i] -= gamma_perturbed[i]
879+
jac[i, j] = (residual_perturbed[i] - residual[i]) * inv_step
880+
end
881+
end
882+
883+
lu_solve_inplace!(jac, residual, n_panels) || break
884+
885+
@inbounds for i in 1:n_panels
886+
gamma_iter[i] -= residual[i]
812887
end
813-
prob = NonlinearProblem(f_nonlin!, solver.lr.gamma_new, SciMLBase.NullParameters())
814-
solver.prob = prob
815-
end
816-
prob = prob::NonlinearProblem
817-
818-
nonlin_cache = solver.nonlin_cache
819-
if isnothing(nonlin_cache)
820-
alg = NewtonRaphson(; autodiff=AutoFiniteDiff())
821-
nonlin_cache = SciMLBase.init(
822-
prob,
823-
alg;
824-
abstol = solver.atol,
825-
reltol = solver.rtol,
826-
)
827-
solver.nonlin_cache = nonlin_cache
828-
else
829-
SciMLBase.reinit!(
830-
nonlin_cache, solver.lr.gamma_new;
831-
p=SciMLBase.NullParameters(),
832-
)
833888
end
834-
sol = NonlinearSolve.solve!(nonlin_cache)
835-
gamma .= sol.u
836-
solver.lr.gamma_new .= sol.u
837-
solver.lr.converged = SciMLBase.successful_retcode(sol)
889+
890+
# Refresh side-effect state (alpha_dist, v_a_dist, cl_dist, ...) at the
891+
# converged iterate; the inner FD loop left them set at the last
892+
# perturbed gamma.
893+
update_gamma_candidate!(
894+
residual, gamma_iter, solver, panels, n_panels,
895+
AIC_x, AIC_y, AIC_z,
896+
velocity_view_x, velocity_view_y, velocity_view_z,
897+
va_array, induced_velocity_all, relative_velocity_array,
898+
y_airf_array, relative_velocity_crossz, v_acrossz_array,
899+
z_airf_array, x_airf_array,
900+
v_normal_array, v_tangential_array,
901+
va_magw_array, cl_dist, chord_array,
902+
)
903+
904+
gamma .= gamma_iter
838905
return nothing
839906
end
840907

0 commit comments

Comments
 (0)