Context
KiteModels.jl uses NLsolve.jl to find the steady-state equilibrium of a 4-point kite power system (3D mass-spring network with aerodynamic forces). We'd like to migrate to NonlinearSolve.jl but the current code relies on several NLsolve-specific features.
Current NLsolve usage
The core call pattern is:
using NLsolve
# Manual central finite-difference Jacobian with subnormal flushing
function make_jac(f!, n_vars)
_F1 = zeros(Float64, n_vars)
_F2 = zeros(Float64, n_vars)
_xp = zeros(Float64, n_vars)
_xm = zeros(Float64, n_vars)
threshold = sqrt(floatmin(Float64))
function jac!(J, x)
h_factor = cbrt(eps(Float64))
for j in 1:n_vars
copyto!(_xp, x); copyto!(_xm, x)
h = max(abs(x[j]), one(Float64)) * h_factor
_xp[j] += h; _xm[j] -= h
f!(_F1, _xp); f!(_F2, _xm)
@views J[:, j] .= (_F1 .- _F2) ./ (2h)
end
@. J = ifelse(abs(J) < threshold, zero(Float64), J)
end
return jac!
end
n_unknowns = 20 # 2*(segments + kite_particles - 1) + 2
X00 = zeros(Float64, n_unknowns)
jac! = make_jac(f!, n_unknowns)
results = nlsolve(f!, jac!, X00;
autoscale=true, xtol=4e-7, ftol=4e-7, iterations=200)
if NLsolve.converged(results)
solution = results.zero
end
NLsolve features we depend on
-
Manual Jacobian (jac!): Needed because NLSolversBase >= 7.10 produces subnormal Jacobian entries via DifferentiationInterface, which cause NaN in NLsolve's autoscale (subnormal column norms squared underflow to zero). The manual Jacobian flushes near-zero entries.
-
autoscale=true: Critical for convergence — the system variables have very different scales (positions in meters vs. small perturbations).
-
Separate xtol and ftol: Both set to 4e-7.
-
iterations limit: Set to 200.
-
results.zero and converged(results): Solution extraction and convergence check.
Questions
- What is the equivalent
NonlinearSolve.jl API for this call pattern?
- Does NonlinearSolve handle autoscaling? (I see #425 is open for trust region autoscaling.)
- Does NonlinearSolve's automatic differentiation avoid the subnormal Jacobian issue, or would we still need a manual Jacobian?
- What's the recommended solver algorithm for this kind of problem (20-variable nonlinear system from physics, starting from a reasonable initial guess)?
Self-contained MWE
Below is a complete, self-contained MWE (~960 lines) that reproduces the KiteModels.jl steady-state test without any kite-specific package dependencies. It models a 4-point kite on a segmented tether with aerodynamic forces, spring/damping, and a winch. The nonlinear solve finds particle positions where all accelerations vanish (steady-state equilibrium).
Dependencies: StaticArrays, LinearAlgebra, NLsolve, Dierckx, Test
Click to expand full MWE (mwe_steady_state_kps4.jl)
$(cat /home/crackauc/sandbox/tmp_20260219_005256_56738/mwe_steady_state_kps4.jl)
Running the MWE
] add StaticArrays NLsolve Dierckx
include("mwe_steady_state_kps4.jl")
Expected output (all 15 tests pass):
l=100.0: tether_length=100.92196416459542, pre_tension=1.0003226874576083 ✓
l=200.0: tether_length=202.59541320501268, pre_tension=1.0004541973108771 ✓
l=392.0: tether_length=399.15270436705833, pre_tension=1.0006386343184874 ✓
Test Summary: | Pass Total Time
test_find_steady_state (MWE) | 15 15 15.3s
Environment
- Julia 1.11
- NLsolve v4.5.1
- StaticArrays v1.9.16
Context
KiteModels.jl uses
NLsolve.jlto find the steady-state equilibrium of a 4-point kite power system (3D mass-spring network with aerodynamic forces). We'd like to migrate toNonlinearSolve.jlbut the current code relies on several NLsolve-specific features.Current NLsolve usage
The core call pattern is:
NLsolve features we depend on
Manual Jacobian (
jac!): Needed becauseNLSolversBase >= 7.10produces subnormal Jacobian entries via DifferentiationInterface, which cause NaN in NLsolve's autoscale (subnormal column norms squared underflow to zero). The manual Jacobian flushes near-zero entries.autoscale=true: Critical for convergence — the system variables have very different scales (positions in meters vs. small perturbations).Separate
xtolandftol: Both set to4e-7.iterationslimit: Set to 200.results.zeroandconverged(results): Solution extraction and convergence check.Questions
NonlinearSolve.jlAPI for this call pattern?Self-contained MWE
Below is a complete, self-contained MWE (~960 lines) that reproduces the KiteModels.jl steady-state test without any kite-specific package dependencies. It models a 4-point kite on a segmented tether with aerodynamic forces, spring/damping, and a winch. The nonlinear solve finds particle positions where all accelerations vanish (steady-state equilibrium).
Dependencies:
StaticArrays,LinearAlgebra,NLsolve,Dierckx,TestClick to expand full MWE (mwe_steady_state_kps4.jl)
Running the MWE
Expected output (all 15 tests pass):
Environment