Repository: SciML/Catalyst.jl
Pull request #1229: Changes from doc readthrough
Author: login: TorkelE
Created: 2025-04-12T12:54:50Z | Merged: 2025-04-12T13:48:48Z

Variou misc minor changes.


Diff:
diff --git a/README.md b/README.md
index 0f7ecb1932..9e206a705c 100644
--- a/README.md
+++ b/README.md
@@ -81,7 +81,7 @@ be found in its corresponding research paper, [Catalyst: Fast and flexible model
 - [OrdinaryDiffEq.jl](https://github.com/SciML/OrdinaryDiffEq.jl) Can be used to numerically solver generated reaction rate equation ODE models.
 - [StochasticDiffEq.jl](https://github.com/SciML/StochasticDiffEq.jl) can be used to numerically solve generated Chemical Langevin Equation SDE models.
 - [JumpProcesses.jl](https://github.com/SciML/JumpProcesses.jl) can be used to numerically sample generated Stochastic Chemical Kinetics Jump Process models.
-- Support for [parallelization of all simulations](https://docs.sciml.ai/Catalyst/stable/model_simulation/ode_simulation_performance/#ode_simulation_performance_parallelisation), including parallelization of [ODE simulations on GPUs](https://docs.sciml.ai/Catalyst/stable/model_simulation/ode_simulation_performance/#ode_simulation_performance_parallelisation_GPU) using [DiffEqGPU.jl](https://github.com/SciML/DiffEqGPU.jl).
+- Support for [parallelization of all simulations](https://docs.sciml.ai/Catalyst/stable/model_simulation/ode_simulation_performance/#ode_simulation_performance_parallelisation), including parallelization of [ODE](https://docs.sciml.ai/Catalyst/stable/model_simulation/ode_simulation_performance/#ode_simulation_performance_parallelisation_GPU) and [SDE](https://docs.sciml.ai/Catalyst/stable/model_simulation/sde_simulation_performance/#sde_simulation_performance_parallelisation_GPU) simulations on GPUs using [DiffEqGPU.jl](https://github.com/SciML/DiffEqGPU.jl).
 - [Latexify](https://korsbo.github.io/Latexify.jl/stable/) can be used to [generate LaTeX expressions](https://docs.sciml.ai/Catalyst/stable/model_creation/model_visualisation/#visualisation_latex) corresponding to generated mathematical models or the underlying set of reactions.
 - [Graphviz](https://graphviz.org/) can be used to generate and [visualize reaction network graphs](https://docs.sciml.ai/Catalyst/stable/model_creation/model_visualisation/#visualisation_graphs) (reusing the Graphviz interface created in [Catlab.jl](https://algebraicjulia.github.io/Catlab.jl/stable/)).
 - Model steady states can be [computed through homotopy continuation](https://docs.sciml.ai/Catalyst/stable/steady_state_functionality/homotopy_continuation/) using [HomotopyContinuation.jl](https://github.com/JuliaHomotopyContinuation/HomotopyContinuation.jl) (which can find *all* steady states of systems with multiple ones), by [forward ODE simulations](https://docs.sciml.ai/Catalyst/stable/steady_state_functionality/nonlinear_solve/#steady_state_solving_simulation) using [SteadyStateDiffEq.jl](https://github.com/SciML/SteadyStateDiffEq.jl), or by [numerically solving steady-state nonlinear equations](https://docs.sciml.ai/Catalyst/stable/steady_state_functionality/nonlinear_solve/#steady_state_solving_nonlinear) using [NonlinearSolve.jl](https://github.com/SciML/NonlinearSolve.jl).
diff --git a/docs/src/index.md b/docs/src/index.md
index 226270e2e0..35ec62b9e6 100644
--- a/docs/src/index.md
+++ b/docs/src/index.md
@@ -29,17 +29,17 @@ etc).
 - Models can be [coupled with events](@ref constraint_equations_events) that affect the system and its state during simulations.
 - By leveraging ModelingToolkit, users have a variety of options for generating optimized system representations to use in solvers. These include construction of [dense or sparse Jacobians](@ref ode_simulation_performance_sparse_jacobian), [multithreading or parallelization of generated derivative functions](@ref ode_simulation_performance_parallelisation), [automatic classification of reactions into optimized jump types for Gillespie type simulations](https://docs.sciml.ai/JumpProcesses/stable/jump_types/#jump_types), [automatic construction of dependency graphs for jump systems](https://docs.sciml.ai/JumpProcesses/stable/jump_types/#Jump-Aggregators-Requiring-Dependency-Graphs), and more.
 - [Symbolics.jl](https://github.com/JuliaSymbolics/Symbolics.jl) symbolic expressions and Julia `Expr`s can be obtained for all rate laws and functions determining the deterministic and stochastic terms within resulting ODE, SDE, or jump models.
-- [Steady states](@ref homotopy_continuation) can be computed for model ODE representations.
+- [Steady states](@ref homotopy_continuation) (and their [stabilities](@ref steady_state_stability)) can be computed for model ODE representations.
 
 #### [Features of Catalyst composing with other packages](@id doc_index_features_composed)
 - [OrdinaryDiffEq.jl](https://github.com/SciML/OrdinaryDiffEq.jl) Can be used to numerically solve generated reaction rate equation ODE models.
 - [StochasticDiffEq.jl](https://github.com/SciML/StochasticDiffEq.jl) can be used to numerically solve generated Chemical Langevin Equation SDE models.
 - [JumpProcesses.jl](https://github.com/SciML/JumpProcesses.jl) can be used to numerically sample generated Stochastic Chemical Kinetics Jump Process models.
-- Support for [parallelization of all simulations](@ref ode_simulation_performance_parallelisation), including parallelization of [ODE simulations on GPUs](@ref ode_simulation_performance_parallelisation_GPU) using [DiffEqGPU.jl](https://github.com/SciML/DiffEqGPU.jl).
+- Support for [parallelization of all simulations](@ref ode_simulation_performance_parallelisation), including parallelization of [ODE](@ref ode_simulation_performance_parallelisation_GPU) and [SDE](@ref sde_simulation_performance_parallelisation_GPU) simulations on GPUs using [DiffEqGPU.jl](https://github.com/SciML/DiffEqGPU.jl).
 - [Latexify](https://korsbo.github.io/Latexify.jl/stable/) can be used to [generate LaTeX expressions](@ref visualisation_latex) corresponding to generated mathematical models or the underlying set of reactions.
 - [GraphMakie](https://docs.makie.org/stable/) recipes are provided that can be used to generate and [visualize reaction network graphs](@ref visualisation_graphs) 
-- Model steady states can be [computed through homotopy continuation](@ref homotopy_continuation) using [HomotopyContinuation.jl](https://github.com/JuliaHomotopyContinuation/HomotopyContinuation.jl) (which can find *all* steady states of systems with multiple ones), by [forward ODE simulations](@ref steady_state_solving_simulation) using [SteadyStateDiffEq.jl)](https://github.com/SciML/SteadyStateDiffEq.jl), or by [numerically solving steady-state nonlinear equations](@ref steady_state_solving_nonlinear) using [NonlinearSolve.jl](https://github.com/SciML/NonlinearSolve.jl).
-[BifurcationKit.jl](https://github.com/bifurcationkit/BifurcationKit.jl) can be used to compute bifurcation diagrams of model steady states (including finding periodic orbits).
+- Model steady states can be [computed through homotopy continuation](@ref homotopy_continuation) using [HomotopyContinuation.jl](https://github.com/JuliaHomotopyContinuation/HomotopyContinuation.jl) (which can find *all* steady states of systems with multiple ones), by [forward ODE simulations](@ref steady_state_solving_simulation) using [SteadyStateDiffEq.jl](https://github.com/SciML/SteadyStateDiffEq.jl), or by [numerically solving steady-state nonlinear equations](@ref steady_state_solving_nonlinear) using [NonlinearSolve.jl](https://github.com/SciML/NonlinearSolve.jl).
+- [BifurcationKit.jl](https://github.com/bifurcationkit/BifurcationKit.jl) can be used to compute bifurcation diagrams of model steady states (including finding periodic orbits).
 - [DynamicalSystems.jl](https://github.com/JuliaDynamics/DynamicalSystems.jl) can be used to compute model [basins of attraction](@ref dynamical_systems_basins_of_attraction), [Lyapunov spectrums](@ref dynamical_systems_lyapunov_exponents), and other dynamical system properties.
 - [Optimization.jl](https://github.com/SciML/Optimization.jl), [DiffEqParamEstim.jl](https://github.com/SciML/DiffEqParamEstim.jl), and [PEtab.jl](https://github.com/sebapersson/PEtab.jl) can all be used to [fit model parameters to data](https://sebapersson.github.io/PEtab.jl/stable/Define_in_julia/).
 - [GlobalSensitivity.jl](https://github.com/SciML/GlobalSensitivity.jl) can be used to perform [global sensitivity analysis](@ref global_sensitivity_analysis) of model behaviors.
diff --git a/docs/src/inverse_problems/structural_identifiability.md b/docs/src/inverse_problems/structural_identifiability.md
index 0a8e7a93a7..48a15df07b 100644
--- a/docs/src/inverse_problems/structural_identifiability.md
+++ b/docs/src/inverse_problems/structural_identifiability.md
@@ -1,6 +1,4 @@
 # [Structural Identifiability Analysis](@id structural_identifiability)
-!!! note
-    Due to recent changes in upstream packages, this Catalyst feature is currently broken on Catalyst v14.
 
 During parameter fitting, parameter values are inferred from data. Parameter identifiability refers to whether inferring parameter values for a given model is mathematically feasible. Ideally, parameter fitting should always be accompanied with an identifiability analysis of the problem. 
 
@@ -34,7 +32,7 @@ Global identifiability can be assessed using the `assess_identifiability` functi
 - Unidentifiable.
   
 To it, we provide our `ReactionSystem` model and a list of quantities that we are able to measure. Here, we consider a Goodwind oscillator (a simple 3-component model, where the three species $M$, $E$, and $P$ are produced and degraded, which may exhibit oscillations)[^2]. Let us say that we are able to measure the concentration of $M$, we then designate this using the `measured_quantities` argument. We can now assess identifiability in the following way:
-```julia
+```@example structural_identifiability
 using Catalyst, Logging, StructuralIdentifiability
 gwo = @reaction_network begin
     (pₘ/(1+P), dₘ), 0 <--> M
@@ -46,14 +44,14 @@ assess_identifiability(gwo; measured_quantities = [:M], loglevel = Logging.Error
 From the output, we find that `E(t)`, `pₑ`, and `pₚ` (the trajectory of $E$, and the production rates of $E$ and $P$, respectively) are non-identifiable. Next, `dₑ` and `dₚ` (the degradation rates of $E$ and $P$, respectively) are locally identifiable. Finally, `P(t)`, `M(t)`, `pₘ`, and `dₘ` (the trajectories of `P` and `M`, and the production and degradation rate of `M`, respectively) are all globally identifiable. We note that we also imported the Logging.jl package, and provided the `loglevel = Logging.Error` input argument. StructuralIdentifiability functions generally provide a large number of output messages. Hence, we will use this argument (which requires the Logging package) throughout this tutorial to decrease the amount of printed text.
 
 Next, we also assess identifiability in the case where we can measure all three species concentrations:
-```julia
+```@example structural_identifiability
 assess_identifiability(gwo; measured_quantities = [:M, :P, :E], loglevel = Logging.Error)
 ```
 in which case all species trajectories and parameters become identifiable.
 
 ### [Indicating known parameters](@id structural_identifiability_gi_known_ps)
 In the previous case we assumed that all parameters are unknown, however, this is not necessarily true. If there are parameters with known values, we can supply these using the `known_p` argument. Providing this additional information might also make other, previously unidentifiable, parameters identifiable. Let us consider the previous example, where we measure the concentration of $M$ only, but now assume we also know the production rate of $E$ ($pₑ$):
-```julia
+```@example structural_identifiability
 assess_identifiability(gwo; measured_quantities = [:M], known_p = [:pₑ], loglevel = Logging.Error)
 ```
 Not only does this turn the previously non-identifiable `pₑ` (globally) identifiable (which is obvious, given that its value is now known), but this additional information improve identifiability for several other network components.
@@ -62,14 +60,14 @@ To, in a similar manner, indicate that certain initial conditions are known is a
 
 ### [Providing non-trivial measured quantities](@id structural_identifiability_gi_nontrivial_mq)
 Sometimes, ones may not have measurements of species, but rather some combinations of species (or possibly parameters). To account for this, `measured_quantities` accepts any algebraic expression (and not just single species). To form such expressions, species and parameters have to first be `@unpack`'ed from the model. Say that we have a model where an enzyme ($E$) is converted between an active and inactive form, which in turns activates the production of a product, $P$:
-```julia
+```@example structural_identifiability
 rs = @reaction_network begin
     (kA,kD), Eᵢ <--> Eₐ
     (Eₐ, d), 0 <-->P
 end
 ```
 If we can measure the total amount of $E$ ($=Eᵢ+Eₐ$), as well as the amount of $P$, we can use the following to assess identifiability:
-```julia
+```@example structural_identifiability
 @unpack Eᵢ, Eₐ = rs
 assess_identifiability(rs; measured_quantities = [Eᵢ + Eₐ, :P], loglevel = Logging.Error)
 nothing # hide
@@ -77,7 +75,7 @@ nothing # hide
 
 ### [Assessing identifiability for specified quantities only](@id structural_identifiability_gi_ftc)
 By default, StructuralIdentifiability assesses identifiability for all parameters and variables. It is, however, possible to designate precisely which quantities you want to check using the `funcs_to_check` option. This both includes selecting a smaller subset of parameters and variables to check, or defining customised expressions. Let us consider the Goodwind from previously, and say that we would like to check whether the production parameters ($pₘ$, $pₑ$, and $pₚ$) and the total amount of the three species ($P + M + E$) are identifiable quantities. Here, we would first unpack these (allowing us to form algebraic expressions) and then use the following code:
-```julia
+```@example structural_identifiability
 @unpack pₘ, pₑ, pₚ, M, E, P = gwo
 assess_identifiability(gwo; measured_quantities = [:M], funcs_to_check = [pₘ, pₑ, pₚ, M + E + P], loglevel = Logging.Error)
 nothing # hide
@@ -85,7 +83,7 @@ nothing # hide
 
 ### [Probability of correctness](@id structural_identifiability_gi_probs)
 The identifiability methods used can, in theory, produce erroneous results. However, it is possible to adjust the lower bound for the probability of correctness using the argument `prob_threshold` (by default set to `0.99`, that is, at least a $99\%$ chance of correctness). We can e.g. increase the bound through:
-```julia
+```@example structural_identifiability
 assess_identifiability(gwo; measured_quantities=[:M], prob_threshold = 0.999, loglevel = Logging.Error)
 nothing # hide
 ```
@@ -93,14 +91,14 @@ giving a minimum bound of $99.9\%$ chance of correctness. In practise, the bound
 
 ## [Local identifiability analysis](@id structural_identifiability_lit)
 Local identifiability can be assessed through the `assess_local_identifiability` function. While this is already determined by `assess_identifiability`, assessing local identifiability only has the advantage that it is easier to compute. Hence, there might be models where global identifiability analysis fails (or takes a prohibitively long time), where instead `assess_local_identifiability` can be used. This function takes the same inputs as `assess_identifiability` and returns, for each quantity, `true` if it is locally identifiable (or `false` if it is not). Here, for the Goodwind oscillator, we assesses it for local identifiability only:
-```julia
+```@example structural_identifiability
 assess_local_identifiability(gwo; measured_quantities = [:M], loglevel = Logging.Error)
 ```
 We note that the results are consistent with those produced by `assess_identifiability` (with globally or locally identifiable quantities here all being assessed as at least locally identifiable).
 
 ## [Finding identifiable functions](@id structural_identifiability_identifiabile_funcs)
 Finally, StructuralIdentifiability provides the `find_identifiable_functions` function. Rather than determining the identifiability of each parameter and unknown of the model, it finds a set of identifiable functions, such as any other identifiable expression of the model can be generated by these. Let us again consider the Goodwind oscillator, using the `find_identifiable_functions` function we find that identifiability can be reduced to five globally identifiable expressions:
-```julia
+```@example structural_identifiability
 find_identifiable_functions(gwo; measured_quantities = [:M], loglevel = Logging.Error)
 ```
 Again, these results are consistent with those produced by `assess_identifiability`. There, `pₑ` and `pₚ` where found to be globally identifiable. Here, they correspond directly to identifiable expressions. The remaining four parameters (`pₘ`, `dₘ`, `dₑ`, and `dₚ`) occur as part of more complicated composite expressions.
@@ -109,19 +107,19 @@ Again, these results are consistent with those produced by `assess_identifiabili
 
 ## [Creating StructuralIdentifiability compatible ODE models from Catalyst `ReactionSystem`s](@id structural_identifiability_si_odes)
 While the functionality described above covers the vast majority of analysis that user might want to perform, the StructuralIdentifiability package supports several additional features. While these does not have inherent Catalyst support, we do provide the `make_si_ode` function to simplify their use. Similar to the previous functions, it takes a `ReactionSystem`, lists of measured quantities, and known parameter values. The output is a [ODE of the standard form supported by StructuralIdentifiability](https://docs.sciml.ai/StructuralIdentifiability/stable/tutorials/creating_ode/#Defining-the-model-using-@ODEmodel-macro). It can be created using the following syntax:
-```julia
+```@example structural_identifiability
 si_ode = make_si_ode(gwo; measured_quantities = [:M])
 nothing # hide
 ```
 and then used as input to various StructuralIdentifiability functions. In the following example we use StructuralIdentifiability's `print_for_DAISY` function, printing the model as an expression that can be used by the [DAISY](https://daisy.dei.unipd.it/) software for identifiability analysis[^3].
-```julia
+```@example structural_identifiability
 print_for_DAISY(si_ode)
 nothing # hide
 ```
 
 ## [Notes on systems with conservation laws](@id structural_identifiability_conslaws)
 Several reaction network models, such as
-```julia
+```@example structural_identifiability
 using Catalyst, Logging, StructuralIdentifiability # hide
 rs = @reaction_network begin
     (k1,k2), X1 <--> X2
@@ -132,7 +130,7 @@ contain [conservation laws](@ref conservation_laws) (in this case $Γ = X1 + X2$
 ## [Systems with exponent parameters](@id structural_identifiability_exp_params)
 Structural identifiability cannot currently be applied to systems with parameters (or species) in exponents. E.g. this
 ```julia
-rn = @reaction_network begin
+rn_si_impossible = @reaction_network begin
     (hill(X,v,K,n),d), 0 <--> X
 end
 assess_identifiability(rn; measured_quantities = [:X])
diff --git a/docs/src/model_creation/dsl_advanced.md b/docs/src/model_creation/dsl_advanced.md
index b03b22d4c2..3aeb468132 100644
--- a/docs/src/model_creation/dsl_advanced.md
+++ b/docs/src/model_creation/dsl_advanced.md
@@ -302,8 +302,9 @@ The following cases in which the DSL would normally infer variables will all thr
 - Occurrence of an undeclared species in a reaction, as in the example above.
 - Occurrence of an undeclared parameter in a reaction rate expression, as in the reaction line `k*n, A --> B`.
 - Occurrence of an undeclared parameter in the stoichiometry of a species, as in the reaction line `k, n*A --> B`.
-- Occurrence of an undeclared differential variable on the LHS of a coupled differential equation, as in `A` in `@equations D(A) ~ A^2`.
-- Occurrence of an undeclared [observable](@ref dsl_advanced_options_observables) in an `@observables` expression, such as `@observables X1 ~ A + B`.
+- Occurrence of an undeclared variable in coupled differential or algebraic equation, as in `A` in `@equations D(A) ~ 1 - A^2`.
+- Occurrence of an undeclared differential variables in coupled differential equation, as in `A` in `@equations D(A) ~ 1 - A^2`.
+- Occurrence of an undeclared [observable](@ref dsl_advanced_options_observables) in an `@observables` expression, such as `@observables Xtot ~ X1 + X2`.
 
 ## [Naming reaction networks](@id dsl_advanced_options_naming)
 Each reaction network model has a name. It can be accessed using the `nameof` function. By default, some generic name is used:
@@ -574,7 +575,7 @@ nothing # hide
 !!! note
     When using interpolation, expressions like `2$spec` won't work; the multiplication symbol must be explicitly included like `2*$spec`.
 
-## [Creating individual reaction using the `@reaction` macro](@id dsl_advanced_options_reaction_macro)
+## [Creating individual reactions using the `@reaction` macro](@id dsl_advanced_options_reaction_macro)
 Catalyst exports a macro `@reaction`, which can be used to generate a singular [`Reaction`](@ref) object of the same type which is stored within the [`ReactionSystem`](@ref) structure (which in turn can be generated by `@reaction_network`). Generally, `@reaction` follows [identical rules to those of `@reaction_network`](@ref dsl_description_reactions) for writing and interpreting reactions (however, bi-directional reactions are not permitted). E.g. here we create a simple dimerisation reaction:
 ```@example dsl_advanced_reaction_macro
 using Catalyst # hide
diff --git a/docs/src/model_creation/dsl_basics.md b/docs/src/model_creation/dsl_basics.md
index 043e92de82..5ea700aff1 100644
--- a/docs/src/model_creation/dsl_basics.md
+++ b/docs/src/model_creation/dsl_basics.md
@@ -190,7 +190,7 @@ However, like for the above model, bundling reactions too zealously can reduce (
 
 The one exception to reaction bundling is that we do not permit the user to provide multiple rates but only set one set each for the substrates and products. I.e.
 ```julia
-rn = @reaction_network begin
+rn_erroneous = @reaction_network begin
     (k1,k2), X --> Y
 end
 ```
diff --git a/docs/src/model_creation/functional_parameters.md b/docs/src/model_creation/functional_parameters.md
index 805c96601e..4ee317036a 100644
--- a/docs/src/model_creation/functional_parameters.md
+++ b/docs/src/model_creation/functional_parameters.md
@@ -9,7 +9,7 @@ Let us first consider an easy, quick-start example (the next section will discus
 using Catalyst, DataInterpolations, Plots
 t = default_t()
 tend = 10.0
-ts = collect(0.0:0.01:tend)
+ts = collect(0.0:0.05:tend)
 spline = LinearInterpolation((2 .+ ts) ./ (1 .+ ts), ts)
 @parameters (pIn::typeof(spline))(..)
 plot(spline)
diff --git a/docs/src/model_creation/model_file_loading_and_export.md b/docs/src/model_creation/model_file_loading_and_export.md
index 9884dd2afc..223e839fb4 100644
--- a/docs/src/model_creation/model_file_loading_and_export.md
+++ b/docs/src/model_creation/model_file_loading_and_export.md
@@ -56,7 +56,7 @@ end
 
 In addition to transferring models between Julia sessions, the `save_reactionsystem` function can also be used or print a model to a text file where you can easily inspect its components.
 
-## [Loading and Saving arbitrary Julia variables using Serialization.jl](@id model_file_import_export_julia_serialisation)
+## [Loading and saving arbitrary Julia variables using Serialization.jl](@id model_file_import_export_julia_serialisation)
 Julia provides a general and lightweight interface for loading and saving Julia structures to and from files that it can be good to be aware of. It is called [Serialization.jl](https://docs.julialang.org/en/v1/stdlib/Serialization/) and provides two functions, `serialize` and `deserialize`. The first allows us to write a Julia structure to a file. E.g. if we wish to save a parameter set associated with our model, we can use
 ```@example file_handling_2
 using Serialization
diff --git a/docs/src/model_creation/model_visualisation.md b/docs/src/model_creation/model_visualisation.md
index 7555929944..bd30a40f3c 100644
--- a/docs/src/model_creation/model_visualisation.md
+++ b/docs/src/model_creation/model_visualisation.md
@@ -36,7 +36,7 @@ If you wish to copy the output to your [clipboard](https://en.wikipedia.org/wiki
     For a model to be nicely displayed you have to use an IDE that actually supports this (such as a [notebook](https://jupyter.org/)). Other environments (such as [the Julia REPL](https://docs.julialang.org/en/v1/stdlib/REPL/)) will simply return the full LaTeX code which would generate the desired expression. 
 
 ## [Displaying model networks](@id visualisation_graphs)
-Catalyst uses `GraphMakie` to display representations of chemical reaction networks, including the complex graph and the species-reaction graph (which is similar to the [Petri net](https://en.wikipedia.org/wiki/Petri_net) representation). To get started, import Catalyst, GraphMakie, and NetworkLayout to load the `CatalystGraphMakieExtension` extension, and then load a Makie backend (`CairoMakie` is a good lightweight choice).
+Catalyst uses [GraphMakie.jl](https://github.com/MakieOrg/GraphMakie.jl) to display representations of chemical reaction networks, including the complex graph and the species-reaction graph (which is similar to the [Petri net](https://en.wikipedia.org/wiki/Petri_net) representation). To get started, import Catalyst, GraphMakie, and NetworkLayout to load the `CatalystGraphMakieExtension` extension, and then load a Makie backend ([`CairoMakie`](https://github.com/MakieOrg/Makie.jl) is a good lightweight choice). Here, while Catalyst primarily uses [Plots.jl](https://github.com/JuliaPlots/Plots.jl) for plotting, [Makie](https://github.com/MakieOrg/Makie.jl) is used for displaying network graphs. Makie can also be used for plotting more generally (and is also a preferred option for some).
 
 ```@example visualisation_graphs
 using Catalyst, GraphMakie, NetworkLayout
diff --git a/docs/src/model_creation/reactionsystem_content_accessing.md b/docs/src/model_creation/reactionsystem_content_accessing.md
index ef684a3992..fd0bb3bec3 100644
--- a/docs/src/model_creation/reactionsystem_content_accessing.md
+++ b/docs/src/model_creation/reactionsystem_content_accessing.md
@@ -2,7 +2,7 @@
 Catalyst is based around the creation, analysis, and simulation of chemical reaction network models. Catalyst stores these models in [`ReactionSystem`](@ref) structures. This page describes some basic functions for accessing the content of these structures. This includes retrieving lists of species, parameters, or reactions that a model consists of. An extensive list of relevant functions for working with `ReactionSystem` models can be found in Catalyst's [API](@ref api).
 
 !!! warning
-    Generally, a field of a Julia structure can be accessed through `struct.fieldname`. E.g. a simulation's time vector can be retrieved using `simulation.t`. While Catalyst `ReactionSystem`s are structures, one should *never* access their fields using this approach, but rather using the accessor functions described below and in the [API](@ref api_accessor_functions) (direct accessing of fields can yield unexpected behaviours). E.g. to retrieve the species of a `ReactionsSystem` `rs`, use `Catalyst.get_species(rs)`, *not* `rs.species`. The reason is that, as shown [below](@ref model_accessing_symbolic_variables), Catalyst (and more generally any [ModelingToolkit]https://github.com/SciML/ModelingToolkit.jl system types) reserves this type of accessing for accessing symbolic variables stored in the system. I.e. `rs.X` refers to the `X` symbolic variable, not a field in `rs` named "X".
+    Generally, a field of a Julia structure can be accessed through `struct.fieldname`. E.g. a simulation's time vector can be retrieved using `simulation.t`. While Catalyst `ReactionSystem`s are structures, one should *never* access their fields using this approach, but rather using the accessor functions described below and in the [API](@ref api_accessor_functions) (direct accessing of fields can yield unexpected behaviours). E.g. to retrieve the species of a `ReactionsSystem` called `rs`, use `Catalyst.get_species(rs)`, *not* `rs.species`. The reason is that, as shown [below](@ref model_accessing_symbolic_variables), Catalyst (and more generally any [ModelingToolkit](https://github.com/SciML/ModelingToolkit.jl) system types) reserves this type of accessing for accessing symbolic variables stored in the system. I.e. `rs.X` refers to the `X` symbolic variable, not a field in `rs` named "X".
 
 ## [Direct accessing of symbolic model parameter and species](@id model_accessing_symbolic_variables)
 Previously we have described how the parameters and species that Catalyst models contain are represented using so-called [*symbolic variables*](@ref introduction_to_catalyst) (and how these enable the forming of [*symbolic expressions*](@ref introduction_to_catalyst)). We have described how, during [programmatic modelling](@ref programmatic_CRN_construction), the user has [direct access to these](@ref programmatic_CRN_construction) and how this can be [taken advantage of](@ref programmatic_CRN_construction). We have also described how, during [DSL-based modelling](@ref dsl_description), the need for symbolic representation can be circumvented by [using `@unpack`](@ref dsl_advanced_options_symbolics_and_DSL_unpack) or by [creating an observable](@ref dsl_advanced_options_observables). However, sometimes, it is easier to *directly access a symbolic variable through the model itself*, something which we will describe here.
diff --git a/src/reactionsystem_serialisation/serialisation_support.jl b/src/reactionsystem_serialisation/serialisation_support.jl
index fd552074e8..bb6e7305ed 100644
--- a/src/reactionsystem_serialisation/serialisation_support.jl
+++ b/src/reactionsystem_serialisation/serialisation_support.jl
@@ -75,7 +75,7 @@ function expression_2_string(expr;
     return repr(strip_called_expr)
 end
 
-# Converts a vector of symbolics (e.g. the species or parameter vectors) to a string vector. Strips 
+# Converts a vector of symbolics (e.g. the species or parameter vectors) to a string vector. Strips
 # any calls (e.g. X(t) becomes X). E.g. a species vector [X, Y, Z] is converted to "[X, Y, Z]".
 function syms_2_strings(syms)
     strip_called_syms = [strip_call(Symbolics.unwrap(sym)) for sym in syms]
@@ -188,11 +188,11 @@ end
 
 ### Symbolics Metadata Handling ###
 
-# For a Symbolic, retrieve all metadata that needs to be added to its declaration. Certain metadata 
+# For a Symbolic, retrieve all metadata that needs to be added to its declaration. Certain metadata
 # (such as default values and whether a variable is a species or not) are skipped (these are stored
 # in the `SKIPPED_METADATA` constant).
 # Because it is impossible to retrieve the keyword used to declare individual metadata from the
-# metadata entry, these must be stored manually (in `RECOGNISED_METADATA`). If one of these are 
+# metadata entry, these must be stored manually (in `RECOGNISED_METADATA`). If one of these are
 # encountered, a warning is thrown and it is skipped (we could also throw an error). I have asked
 # Shashi, and he claims there is not alternative (general) solution.
 function get_metadata_to_declare(sym)
@@ -205,7 +205,7 @@ function get_metadata_to_declare(sym)
     return metadata_keys
 end
 
-# Converts a given metadata into the string used to declare it. 
+# Converts a given metadata into the string used to declare it.
 function metadata_2_string(sym, metadata)
     return RECOGNISED_METADATA[metadata] * " = " * x_2_string(sym.metadata[metadata])
 end
@@ -232,12 +232,16 @@ const RECOGNISED_METADATA = Dict([Catalyst.ParameterConstantSpecies => "isconsta
                                   ModelingToolkit.TimeDomain => "timedomain"])
 
 # List of metadata that does not need to be explicitly declared to be added (or which is handled separately).
-const SKIPPED_METADATA = [ModelingToolkit.MTKVariableTypeCtx, Symbolics.VariableSource,
-    Symbolics.VariableDefaultValue, Catalyst.VariableSpecies]
+const SKIPPED_METADATA = [
+    Catalyst.VariableSpecies,
+    ModelingToolkit.MTKVariableTypeCtx,
+    ModelingToolkit.SymScope,
+    Symbolics.VariableDefaultValue,
+    Symbolics.VariableSource]
 
 ### Generic Expression Handling ###
 
-# Potentially strips the call for a symbolics. E.g. X(t) becomes X (but p remains p). This is used 
+# Potentially strips the call for a symbolics. E.g. X(t) becomes X (but p remains p). This is used
 # when variables are written to files, as in code they are used without the call part.
 function strip_call(sym)
     return iscall(sym) ? Sym{Real}(Symbolics.getname(sym)) : sym


Reviews:
user: login: TorkelE
state: COMMENTED
author_association: MEMBER
submitted_at: 2025-04-12T12:56:18Z
user: login: TorkelE
state: COMMENTED
author_association: MEMBER
submitted_at: 2025-04-12T12:57:36Z
user: login: isaacsas
body: LGTM, but please visually check the SI doc page examples work before merging. 
state: APPROVED
author_association: MEMBER
submitted_at: 2025-04-12T13:03:07Z

Review comments:
diff_hunk: @@ -2,7 +2,7 @@
 Catalyst is based around the creation, analysis, and simulation of chemical reaction network models. Catalyst stores these models in [`ReactionSystem`](@ref) structures. This page describes some basic functions for accessing the content of these structures. This includes retrieving lists of species, parameters, or reactions that a model consists of. An extensive list of relevant functions for working with `ReactionSystem` models can be found in Catalyst's [API](@ref api).
 
 !!! warning
-    Generally, a field of a Julia structure can be accessed through `struct.fieldname`. E.g. a simulation's time vector can be retrieved using `simulation.t`. While Catalyst `ReactionSystem`s are structures, one should *never* access their fields using this approach, but rather using the accessor functions described below and in the [API](@ref api_accessor_functions) (direct accessing of fields can yield unexpected behaviours). E.g. to retrieve the species of a `ReactionsSystem` `rs`, use `Catalyst.get_species(rs)`, *not* `rs.species`. The reason is that, as shown [below](@ref model_accessing_symbolic_variables), Catalyst (and more generally any [ModelingToolkit]https://github.com/SciML/ModelingToolkit.jl system types) reserves this type of accessing for accessing symbolic variables stored in the system. I.e. `rs.X` refers to the `X` symbolic variable, not a field in `rs` named "X".
+    Generally, a field of a Julia structure can be accessed through `struct.fieldname`. E.g. a simulation's time vector can be retrieved using `simulation.t`. While Catalyst `ReactionSystem`s are structures, one should *never* access their fields using this approach, but rather using the accessor functions described below and in the [API](@ref api_accessor_functions) (direct accessing of fields can yield unexpected behaviours). E.g. to retrieve the species of a `ReactionsSystem` called `rs`, use `Catalyst.get_species(rs)`, *not* `rs.species`. The reason is that, as shown [below](@ref model_accessing_symbolic_variables), Catalyst (and more generally any [ModelingToolkit](https://github.com/SciML/ModelingToolkit.jl) system types) reserves this type of accessing for accessing symbolic variables stored in the system. I.e. `rs.X` refers to the `X` symbolic variable, not a field in `rs` named "X".
path: docs/src/model_creation/reactionsystem_content_accessing.md
user: login: TorkelE
body: having two code blocks next to each other caused them to merge and look bad, so need to put a word inetween.
created_at: 2025-04-12T12:56:17Z
author_association: MEMBER
diff_hunk: @@ -232,12 +232,16 @@ const RECOGNISED_METADATA = Dict([Catalyst.ParameterConstantSpecies => "isconsta
                                   ModelingToolkit.TimeDomain => "timedomain"])
 
 # List of metadata that does not need to be explicitly declared to be added (or which is handled separately).
-const SKIPPED_METADATA = [ModelingToolkit.MTKVariableTypeCtx, Symbolics.VariableSource,
-    Symbolics.VariableDefaultValue, Catalyst.VariableSpecies]
+const SKIPPED_METADATA = [
+    Catalyst.VariableSpecies,
+    ModelingToolkit.MTKVariableTypeCtx,
+    ModelingToolkit.SymScope,
+    Symbolics.VariableDefaultValue,
+    Symbolics.VariableSource]
path: src/reactionsystem_serialisation/serialisation_support.jl
user: login: TorkelE
body: Added the `ModelingToolkit.SymScope` metadata.
created_at: 2025-04-12T12:57:36Z
author_association: MEMBER

PR comments:
user: login: TorkelE
created_at: 2025-04-12T13:08:05Z
body: yes, will check that
author_association: MEMBER
user: login: TorkelE
created_at: 2025-04-12T13:48:45Z
body: SI tutoril looks good, merging.
author_association: MEMBER