|
| 1 | +# [Finding Steady States using NonlinearSolve.jl](@id nonlinear_solve) |
| 2 | + |
| 3 | +We have previously described how `ReactionSystem` steady states can be found through [homotopy continuation](@ref homotopy_continuation). Catalyst also supports the creation of `NonlinearProblems` corresponding to `ODEProblems` with all left-hand side derivatives set to 0. These can be solved using the variety of nonlinear equation-solving algorithms implemented by [NonlinearSolve.jl](https://github.com/SciML/NonlinearSolve.jl), with the solutions corresponding to system steady states. Generally, using this approach is advantageous when: |
| 4 | +- Only a single steady state solution is sought. |
| 5 | +- The nonlinear system produced by the model does not correspond to a multivariate, rational, polynomial (homotopy continuation cannot be applied to these systems). Examples include models with non-integer hill coefficients or stoichiometric constants. |
| 6 | + |
| 7 | +However, if all (or multiple) steady states are sought, using homotopy continuation is better. |
| 8 | + |
| 9 | +This tutorial describes how to create `NonlinearProblem`s from Catalyst's `ReactionSystemn`s, and how to solve them using NonlinearSolve. More extensive descriptions of available solvers and options can be found in [NonlinearSolve's documentation](https://docs.sciml.ai/NonlinearSolve/stable/). If you use this in your research, please [cite the NonlinearSolve.jl](@ref nonlinear_solve_citation) and [Catalyst.jl](@ref catalyst_citation) publications. |
| 10 | + |
| 11 | +## Basic example |
| 12 | +Let us consider a simple dimerisation network, where a protein ($P$) can exist in a monomer and a dimer form. The protein is produced at a constant rate from its mRNA, which is also produced at a constant rate. |
| 13 | +```@example nonlinear_solve1 |
| 14 | +using Catalyst |
| 15 | +dimer_production = @reaction_network begin |
| 16 | + pₘ, 0 --> mRNA |
| 17 | + pₚ, mRNA --> mRNA + P |
| 18 | + (k₁, k₂), 2P <--> P₂ |
| 19 | + d, (mRNA, P, P₂) --> 0 |
| 20 | +end |
| 21 | +``` |
| 22 | +This system corresponds to the following ODE: |
| 23 | +```math |
| 24 | +\begin{aligned} |
| 25 | +\frac{dmRNA}{dt} &= pₘ - d \cdot mRNA \\ |
| 26 | +\frac{dP}{dt} &= pₚ \cdot mRNA - k₁ \cdot P + 2k₂ \cdot P₂ - d \cdot P \\ |
| 27 | +\frac{dP₂}{dt} &= k₁ \cdot P + 2k₂ \cdot P₂ \\ |
| 28 | +\end{aligned} |
| 29 | +``` |
| 30 | +To find its steady states we need to solve: |
| 31 | +```math |
| 32 | +\begin{aligned} |
| 33 | +0 &= pₘ - d \cdot mRNA \\ |
| 34 | +0 &= pₚ \cdot mRNA - k₁ \cdot P + 2k₂ \cdot P₂ - d \cdot P \\ |
| 35 | +0 &= k₁ \cdot P + 2k₂ \cdot P₂ \\ |
| 36 | +\end{aligned} |
| 37 | +``` |
| 38 | + |
| 39 | +To solve this problem, we must first designate our parameter values, and also make an initial guess of the solution. Generally, for problems with a single solution (like this one), most arbitrary guesses will work fine (the exception typically being [systems with conservation laws](@ref nonlinear_solve_conservation_laws)). Using these, we can create the `NonlinearProblem` that we wish to solve. |
| 40 | +```@example nonlinear_solve1 |
| 41 | +p = [:pₘ => 0.5, :pₚ => 2.0, :k₁ => 5.0, :k₂ => 1.0, :d => 1.0] |
| 42 | +u_guess = [:mRNA => 1.0, :P => 1.0, :P₂ => 1.0] |
| 43 | +nl_prob = NonlinearProblem(dimer_production, u_guess, p) |
| 44 | +``` |
| 45 | +Finally, we can solve it using the `solve` command, returning the steady state solution: |
| 46 | +```@example nonlinear_solve1 |
| 47 | +using NonlinearSolve |
| 48 | +sol = solve(nl_prob) |
| 49 | +``` |
| 50 | + |
| 51 | +NonlinearSolve provides [a wide range of potential solvers](https://docs.sciml.ai/NonlinearSolve/stable/solvers/NonlinearSystemSolvers/). If we wish to designate one, it can be supplied as a second argument to `solve`. Here, we use the Newton Trust Region method, and then check that the solution is equal to the previous one. |
| 52 | +```@example nonlinear_solve1 |
| 53 | +sol_ntr = solve(nl_prob, TrustRegion()) |
| 54 | +sol ≈ sol_ntr |
| 55 | +``` |
| 56 | + |
| 57 | +## [Finding steady states through ODE simulations](@id nonlinear_solve_ode_simulation_based) |
| 58 | +The `NonlinearProblem`s generated by Catalyst corresponds to ODEs. A common method of solving these is to simulate the ODE from an initial condition until a steady state is reached. NonlinearSolve supports this through the `DynamicSS` method. To use it, an appropriate ODE solver (and any options you wish it to use) must also be supplied (with [a large number being available](https://docs.sciml.ai/DiffEqDocs/stable/solvers/ode_solve/)). Here, we will use the `Tsit5` ODE solver to find the steady states of our dimerisation system. |
| 59 | +```@example nonlinear_solve1 |
| 60 | +using OrdinaryDiffEq, SteadyStateDiffEq |
| 61 | +solve(nl_prob, DynamicSS(Tsit5())) |
| 62 | +``` |
| 63 | +Here, we had to import [OrdinaryDiffEq.jl](https://github.com/SciML/OrdinaryDiffEq.jl) (to use `Tsit5`) and [SteadyStateDiffEq.jl](https://github.com/SciML/SteadyStateDiffEq.jl) (to use `DynamicSS`). |
| 64 | + |
| 65 | +Like previously, the found steady state is unaffected by the initial `u` guess. However, when [finding the steady states of systems with conservation laws](@ref nonlinear_solve_conservation_laws) it is important to select a `u` guess that corresponds to the initial condition for the ODE model for which a steady state is sought. |
| 66 | + |
| 67 | + |
| 68 | +## [Systems with conservation laws](@id nonlinear_solve_conservation_laws) |
| 69 | +As described in the section on homotopy continuation, when finding the steady states of systems with conservation laws, [additional considerations have to be taken](homotopy_continuation_conservation_laws). E.g. consider the following two-state system: |
| 70 | +```@example nonlinear_solve2 |
| 71 | +using Catalyst, NonlinearSolve # hide |
| 72 | +two_state_model = @reaction_network begin |
| 73 | + (k1,k2), X1 <--> X2 |
| 74 | +end |
| 75 | +``` |
| 76 | +It has an infinite number of steady states. To make steady state finding possible, information of the system's conserved quantities (here $C=X1+X2$) must be provided. Since these can be computed from system initial conditions (`u0`, i.e. those provided when performing ODE simulations), designating an `u0` is often the best way. There are two ways to do this. First, one can perform [ODE simulation-based steady state finding](@ref nonlinear_solve_ode_simulation_based), using the initial condition as the initial `u` guess. Alternatively, any conserved quantities can be eliminated when the `NonlinearProblem` is created. This feature is supported by Catalyst's [conservation law finding and elimination feature](@ref network_analysis_deficiency). |
| 77 | + |
| 78 | +To eliminate conservation laws we simply provide the `remove_conserved = true` argument to `NonlinearProblem`: |
| 79 | +```@example nonlinear_solve2 |
| 80 | +p = [:k1 => 2.0, :k2 => 3.0] |
| 81 | +u_guess = [:X1 => 3.0, :X2 => 1.0] |
| 82 | +nl_prob = NonlinearProblem(two_state_model, u_guess, p; remove_conserved = true) |
| 83 | +nothing # hide |
| 84 | +``` |
| 85 | +here it is important that the quantities used in `u_guess` correspond to the conserved quantities we wish to use. E.g. here the conserved quantity $X1 + X2= 3.0 + 1.0 = 4$ holds for the initial condition, and will hence also hold in the calculated steady-state as well. We can now find the steady states using `solve` like before: |
| 86 | +```@example nonlinear_solve2 |
| 87 | +sol = solve(nl_prob) |
| 88 | +``` |
| 89 | +We note that the output only provides a single value. The reason is that the actual system solved only contains a single equation (the other being eliminated with the conserved quantity). To find the values of $X1$ and $X2$ we can [directly query the solution object for these species' values, using the species themselves as inputs](@ref simulation_structure_interfacing_solutions): |
| 90 | +```@example nonlinear_solve2 |
| 91 | +@unpack X1, X2 = two_state_model |
| 92 | +sol[X1] |
| 93 | +``` |
| 94 | +```@example nonlinear_solve2 |
| 95 | +sol[X2] |
| 96 | +``` |
| 97 | + |
| 98 | +--- |
| 99 | +## [Citations](@id nonlinear_solve_citation) |
| 100 | +If you use this functionality in your research, [in addition to Catalyst](@ref catalyst_citation), please cite the following papers to support the authors of the NonlinearSolve.jl package: |
| 101 | +``` |
| 102 | +A NonlinearSolve. jl-related publication is in preparation, once it is available, its details will be added here. |
| 103 | +``` |
0 commit comments