From 4558256fc7d25fa769f77138669f6d496878d1ce Mon Sep 17 00:00:00 2001 From: Christopher Rackauckas Date: Tue, 17 Oct 2023 05:43:43 -0400 Subject: [PATCH] Overhaul the documentation --- docs/pages.jl | 8 +- docs/src/basics/NonlinearProblem.md | 2 +- docs/src/basics/NonlinearSolution.md | 2 +- docs/src/basics/TerminationCondition.md | 2 +- docs/src/solvers/BracketingSolvers.md | 2 +- docs/src/solvers/SteadyStateSolvers.md | 2 +- docs/src/tutorials/code_optimization.md | 31 ++++ docs/src/tutorials/getting_started.md | 148 ++++++++++++++++++ docs/src/tutorials/iterator_interface.md | 6 +- .../{advanced.md => large_systems.md} | 2 +- docs/src/tutorials/nonlinear.md | 61 -------- docs/src/tutorials/small_compile.md | 1 + docs/src/tutorials/termination_conditions.md | 1 + 13 files changed, 198 insertions(+), 70 deletions(-) create mode 100644 docs/src/tutorials/code_optimization.md create mode 100644 docs/src/tutorials/getting_started.md rename docs/src/tutorials/{advanced.md => large_systems.md} (99%) delete mode 100644 docs/src/tutorials/nonlinear.md create mode 100644 docs/src/tutorials/small_compile.md create mode 100644 docs/src/tutorials/termination_conditions.md diff --git a/docs/pages.jl b/docs/pages.jl index 9ce5701cf..0ba8c4241 100644 --- a/docs/pages.jl +++ b/docs/pages.jl @@ -1,8 +1,12 @@ # Put in a separate page so it can be used by SciMLDocs.jl pages = ["index.md", - "Tutorials" => Any["tutorials/nonlinear.md", - "tutorials/advanced.md", + "tutorials/getting_started.md" + "Tutorials" => Any[ + "tutorials/code_optimization.md", + "tutorials/large_systems.md", + "tutorials/small_compile.md", + "tutorials/termination_conditions.md", "tutorials/iterator_interface.md"], "Basics" => Any["basics/NonlinearProblem.md", "basics/NonlinearFunctions.md", diff --git a/docs/src/basics/NonlinearProblem.md b/docs/src/basics/NonlinearProblem.md index 8c3ec07ba..11dc09772 100644 --- a/docs/src/basics/NonlinearProblem.md +++ b/docs/src/basics/NonlinearProblem.md @@ -1,4 +1,4 @@ -# Nonlinear Problems +# [Nonlinear Problems](@id problems) ## The Three Types of Nonlinear Problems diff --git a/docs/src/basics/NonlinearSolution.md b/docs/src/basics/NonlinearSolution.md index 65df15e86..da9886a3c 100644 --- a/docs/src/basics/NonlinearSolution.md +++ b/docs/src/basics/NonlinearSolution.md @@ -1,4 +1,4 @@ -# Nonlinear Solutions +# [Nonlinear Solutions](@id solution) ```@docs SciMLBase.NonlinearSolution diff --git a/docs/src/basics/TerminationCondition.md b/docs/src/basics/TerminationCondition.md index e966bb22c..97bec6d32 100644 --- a/docs/src/basics/TerminationCondition.md +++ b/docs/src/basics/TerminationCondition.md @@ -1,4 +1,4 @@ -# Termination Conditions +# [Termination Conditions](@id termination_condition) Provides a API to specify termination conditions for [`NonlinearProblem`](@ref) and [`SteadyStateProblem`](@ref). For details on the various termination modes, i.e., diff --git a/docs/src/solvers/BracketingSolvers.md b/docs/src/solvers/BracketingSolvers.md index 8205fff0f..37184fbfe 100644 --- a/docs/src/solvers/BracketingSolvers.md +++ b/docs/src/solvers/BracketingSolvers.md @@ -1,4 +1,4 @@ -# Interval Rootfinding Methods (Bracketing Solvers) +# [Interval Rootfinding Methods (Bracketing Solvers)](@id bracketing) `solve(prob::IntervalNonlinearProblem,alg;kwargs)` diff --git a/docs/src/solvers/SteadyStateSolvers.md b/docs/src/solvers/SteadyStateSolvers.md index adc1a994a..af7b2bc06 100644 --- a/docs/src/solvers/SteadyStateSolvers.md +++ b/docs/src/solvers/SteadyStateSolvers.md @@ -1,4 +1,4 @@ -# Steady State Solvers +# [Steady State Solvers](@id ss_solvers) `solve(prob::SteadyStateProblem,alg;kwargs)` diff --git a/docs/src/tutorials/code_optimization.md b/docs/src/tutorials/code_optimization.md new file mode 100644 index 000000000..0a20e6a9e --- /dev/null +++ b/docs/src/tutorials/code_optimization.md @@ -0,0 +1,31 @@ +# [Code Optimization for Solving Nonlinear Systems](@id code_optimization) + +## Optimizing Nonlinear Solver Code for Small Systems + +```@example +using NonlinearSolve, StaticArrays + +f(u, p) = u .* u .- p +u0 = @SVector[1.0, 1.0] +p = 2.0 +probN = NonlinearProblem(f, u0, p) +sol = solve(probN, NewtonRaphson(), reltol = 1e-9) +``` + +## Using Jacobian Free Newton Krylov (JNFK) Methods + +If we want to solve the first example, without constructing the entire Jacobian + +```@example +using NonlinearSolve, LinearSolve + +function f!(res, u, p) + @. res = u * u - p +end +u0 = [1.0, 1.0] +p = 2.0 +prob = NonlinearProblem(f!, u0, p) + +linsolve = LinearSolve.KrylovJL_GMRES() +sol = solve(prob, NewtonRaphson(; linsolve), reltol = 1e-9) +``` \ No newline at end of file diff --git a/docs/src/tutorials/getting_started.md b/docs/src/tutorials/getting_started.md new file mode 100644 index 000000000..17eb04711 --- /dev/null +++ b/docs/src/tutorials/getting_started.md @@ -0,0 +1,148 @@ +# Getting Started with Nonlinear Rootfinding in Julia + +NonlinearSolve.jl is a system for solving rootfinding problems, i.e. finding +the value $$u$$ such that $$f(u) = 0$$. In this tutorial we will go through +the basics of NonlinearSolve.jl, demonstrating the core ideas and leading you +to understanding the deeper parts of the documentation. + +## The Three Types of Nonlinear Systems + +There are three types of nonlinear systems: + +1. The "standard nonlinear system", i.e. the `NonlinearProblem`. This is a + system of equations with an initial condition where you want to satisfy + all equations simultaniously. +2. The "interval rootfinding problem", i.e. the `IntervalNonlinearProblem`. + This is the case where you're given an interval `[a,b]` and need to find + where `f(u) = 0` for `u` inside the bounds. +3. The "steady state problem", i.e. find the `u` such that `u' = f(u) = 0`. + While related to (1), it's not entirely the same because there's a uniquely + defined privledged root. +4. The nonlinear least squares problem, which is an overconstrained nonlinear + system (i.e. more equations than states) which might not be satisfiable, i.e. + there may be no `u` such that `f(u) = 0`, and thus we find the `u` which + minimizes `||f(u)||` in the least squares sense. + +For now let's focus on the first two. The other two are covered in later tutorials, +but from the first two we can show the general flow of the NonlinearSolve.jl package. + +## Problem Type 1: Solving Nonlinear Systems of Equations + +A nonlinear system $$f(u) = 0$$ is specified by defining a function `f(u,p)`, +where `p` are the parameters of the system. For example, the following solves +the vector equation $$f(u) = u^2 - p$$ for a vector of equations: + +```@example +using NonlinearSolve + +f(u, p) = u .* u .- p +u0 = [1.0, 1.0] +p = 2.0 +prob = NonlinearProblem(f, u0, p) +sol = solve(prob) +``` + +where `u0` is the initial condition for the rootfinder. Native NonlinearSolve.jl +solvers use the given type of `u0` to determine the type used within the solver +and the return. Note that the parameters `p` can be any type, but most are an +AbstractArray for automatic differentiation. + +### Investigating the Solution + +To investigate the solution, one can look at the elements of the `NonlinearSolution`. +The most important value is `sol.u`: this is the `u` that satisfies `f(u) = 0`. For example: + +```@example +u = sol.u +``` + +```@example +f(u, p) +``` + +This final value, the difference of the solution against zero, can also be found with `sol.resid`: + +```@example +sol.resid +``` + +To know if the solution converged, or why the solution had not converged we can check the return +code (`retcode`): + +```@example +sol.retcode +``` + +There are multiple return codes which can mean the solve was successful, and thus we can use the +general command `SciMLBase.successful_retcode` to check whether the solution process exited as +intended: + +```@exmaple +SciMLBase.successful_retcode(sol) +``` + +If we're curious about what it took to solve this equation, then you're in luck because all of the +details can be found in `sol.stats`: + +```@example +sol.stats +``` + +For more information on `NonlinearSolution`s, see the [`NonlinearSolution` manual page](@ref solution). + +### Interacting with the Solver Options + +While `sol = solve(prob)` worked for our case here, in many situations you may need to interact more +deeply with how the solving process is done. First things first, you can specify the solver using the +positional arguments. For example, let's set the solver to `TrustRegion()`: + +```@example +solve(prob, TrustRegion()) +``` + +For a complete list of solver choices, see [the nonlinear system solvers page](@ref nonlinearsystemsolvers). + +Next we can modify the tolerances. Here let's set some really low tolerances to force a tight solution: + +```@example +solve(prob, TrustRegion(), reltol=1e-12, abstol=1e-12) +``` + +There are many more options for doing this configuring. Specifically for handling termination conditions, +see the [Termination Conditions](@ref termination_condition) page for more details. And for more details on +all of the available keyword arguments, see the [solver options](@ref solver_options) page. + +## Problem Type 2: Solving Interval Rootfinding Problems with Bracketing Methods + +For scalar rootfinding problems, bracketing methods exist in NonlinearSolve. The difference with bracketing +methods is that with bracketing methods, instead of giving a `u0` initial condition, you pass a `uspan (a,b)` +bracket in which the zero is expected to live. For example: + +```@example +using NonlinearSolve +f(u, p) = u * u - 2.0 +uspan = (1.0, 2.0) # brackets +prob_int = IntervalNonlinearProblem(f, uspan) +sol = solve(prob_int) +``` + +All of the same option handling from before works just as before, now just with different solver choices +(see the [bracketing solvers](@ref bracketing) page for more details). For example, let's set the solver +to `ITP()` and set a high absolute tolerance: + +```@example +sol = solve(prob_int, ITP(), abstol = 0.01) +``` + +## Going Beyond the Basics: How to use the Documentation + +Congrats, you now know how to use the basics of NonlinearSolve.jl! However, there is so much more to +see. Next check out: + +- [Some code optimization tricks to know about with NonlinearSolve.jl](@ref code_optimization) +- [An iterator interface which lets you step through the solving process step by step](@ref iterator) +- [How to handle large systems of equations efficiently](@ref large_systems) +- [Ways to use NonlinearSolve.jl that is faster to startup and can statically compile](@ref fast_startup) +- [More detailed termination conditions](@ref termination_conditions_tutorial) + +And also check out the rest of the manual. \ No newline at end of file diff --git a/docs/src/tutorials/iterator_interface.md b/docs/src/tutorials/iterator_interface.md index a7232fa25..640fb5f02 100644 --- a/docs/src/tutorials/iterator_interface.md +++ b/docs/src/tutorials/iterator_interface.md @@ -1,4 +1,8 @@ -# Nonlinear Solver Iterator Interface +# [Nonlinear Solver Iterator Interface](@id iterator) + +!!! warn + + This iterator interface will be expanded with a `step!` function soon! There is an iterator form of the nonlinear solver which mirrors the DiffEq integrator interface: diff --git a/docs/src/tutorials/advanced.md b/docs/src/tutorials/large_systems.md similarity index 99% rename from docs/src/tutorials/advanced.md rename to docs/src/tutorials/large_systems.md index 01a337e12..43c7f6cd6 100644 --- a/docs/src/tutorials/advanced.md +++ b/docs/src/tutorials/large_systems.md @@ -1,4 +1,4 @@ -# Solving Large Ill-Conditioned Nonlinear Systems with NonlinearSolve.jl +# [Solving Large Ill-Conditioned Nonlinear Systems with NonlinearSolve.jl](@id large_systems) This tutorial is for getting into the extra features of using NonlinearSolve.jl. Solving ill-conditioned nonlinear systems requires specializing the linear solver on properties of the Jacobian in order to cut down on the ``\mathcal{O}(n^3)`` linear solve and the ``\mathcal{O}(n^2)`` back-solves. This tutorial is designed to explain the advanced usage of NonlinearSolve.jl by solving the steady state stiff Brusselator partial differential equation (BRUSS) using NonlinearSolve.jl. diff --git a/docs/src/tutorials/nonlinear.md b/docs/src/tutorials/nonlinear.md deleted file mode 100644 index 2a1ced12f..000000000 --- a/docs/src/tutorials/nonlinear.md +++ /dev/null @@ -1,61 +0,0 @@ -# Solving Nonlinear Systems - -A nonlinear system $$f(u) = 0$$ is specified by defining a function `f(u,p)`, -where `p` are the parameters of the system. For example, the following solves -the vector equation $$f(u) = u^2 - p$$ for a vector of equations: - -```@example -using NonlinearSolve, StaticArrays - -f(u, p) = u .* u .- p -u0 = @SVector[1.0, 1.0] -p = 2.0 -probN = NonlinearProblem(f, u0, p) -sol = solve(probN, NewtonRaphson(), reltol = 1e-9) -``` - -where `u0` is the initial condition for the rootfinder. Native NonlinearSolve.jl -solvers use the given type of `u0` to determine the type used within the solver -and the return. Note that the parameters `p` can be any type, but most are an -AbstractArray for automatic differentiation. - -## Using Bracketing Methods - -For scalar rootfinding problems, bracketing methods exist in `SimpleNonlinearSolve`. In this case, one passes -a bracket instead of an initial condition, for example: - -```@example -using SimpleNonlinearSolve -f(u, p) = u * u - 2.0 -uspan = (1.0, 2.0) # brackets -probB = IntervalNonlinearProblem(f, uspan) -sol = solve(probB, ITP()) -``` - -The user can also set a tolerance that suits the application. - -```@example -using SimpleNonlinearSolve -f(u, p) = u * u - 2.0 -uspan = (1.0, 2.0) # brackets -probB = IntervalNonlinearProblem(f, uspan) -sol = solve(probB, ITP(), abstol = 0.01) -``` - -## Using Jacobian Free Newton Krylov (JNFK) Methods - -If we want to solve the first example, without constructing the entire Jacobian - -```@example -using NonlinearSolve, LinearSolve - -function f!(res, u, p) - @. res = u * u - p -end -u0 = [1.0, 1.0] -p = 2.0 -probN = NonlinearProblem(f!, u0, p) - -linsolve = LinearSolve.KrylovJL_GMRES() -sol = solve(probN, NewtonRaphson(; linsolve), reltol = 1e-9) -``` diff --git a/docs/src/tutorials/small_compile.md b/docs/src/tutorials/small_compile.md new file mode 100644 index 000000000..31208f146 --- /dev/null +++ b/docs/src/tutorials/small_compile.md @@ -0,0 +1 @@ +# Faster Startup and and Static Compilation \ No newline at end of file diff --git a/docs/src/tutorials/termination_conditions.md b/docs/src/tutorials/termination_conditions.md new file mode 100644 index 000000000..909f0cd34 --- /dev/null +++ b/docs/src/tutorials/termination_conditions.md @@ -0,0 +1 @@ +# [More Detailed Termination Conditions](@id termination_conditions_tutorial) \ No newline at end of file