From 223c0fc5c4e049ce52806103a20c1a204efdcdd5 Mon Sep 17 00:00:00 2001 From: Torkel Date: Tue, 28 May 2024 18:30:16 -0400 Subject: [PATCH] update references in simulation files --- .../model_simulation/ensemble_simulations.md | 13 +++++--- .../ode_simulation_performance.md | 23 +++++++------ .../simulation_introduction.md | 32 +++++++++---------- .../model_simulation/simulation_plotting.md | 2 +- .../simulation_structure_interfacing.md | 8 ++--- 5 files changed, 40 insertions(+), 38 deletions(-) diff --git a/docs/src/model_simulation/ensemble_simulations.md b/docs/src/model_simulation/ensemble_simulations.md index 47689b7050..b0731bf628 100644 --- a/docs/src/model_simulation/ensemble_simulations.md +++ b/docs/src/model_simulation/ensemble_simulations.md @@ -3,10 +3,10 @@ In many contexts, a single model is re-simulated under similar conditions. Examp - Performing Monte Carlo simulations of a stochastic model to gain insight in its behaviour. - Scanning a model's behaviour for different parameter values and/or initial conditions. -While this can be handled using `for` loops, it is typically better to first create an `EnsembleProblem`, and then perform an ensemble simulation. Advantages include a more concise interface and the option for [automatic simulation parallelisation](@ref ref). Here we provide a short tutorial on how to perform parallel ensemble simulations, with a more extensive documentation being available [here](@ref https://docs.sciml.ai/DiffEqDocs/stable/features/ensemble/). +While this can be handled using `for` loops, it is typically better to first create an `EnsembleProblem`, and then perform an ensemble simulation. Advantages include a more concise interface and the option for [automatic simulation parallelisation](@ref ode_simulation_performance_parallelisation). Here we provide a short tutorial on how to perform parallel ensemble simulations, with a more extensive documentation being available [here](https://docs.sciml.ai/DiffEqDocs/stable/features/ensemble/). ## [Monte Carlo simulations using unmodified conditions](@id ensemble_simulations_monte_carlo) -We will first consider Monte Carlo simulations where the simulation conditions are identical in-between simulations. First, we declare a [simple self-activation loop](@ref ref) model +We will first consider Monte Carlo simulations where the simulation conditions are identical in-between simulations. First, we declare a [simple self-activation loop](@ref basic_CRN_library_self_activation) model ```@example ensemble using Catalyst sa_model = @reaction_network begin @@ -19,6 +19,7 @@ ps = [:v0 => 0.1, :v => 2.5, :K => 40.0, :n => 4.0, :deg => 0.01] ``` We wish to simulate it as an SDE. Rather than performing a single simulation, however, we want to perform multiple ones. Here, we first create a normal `SDEProblem`, and use it as the single input to a `EnsembleProblem` (`EnsembleProblem` are created similarly for ODE and jump simulations, but the `ODEProblem` or `JumpProblem` is used instead). ```@example ensemble +using StochasticDiffEq sprob = SDEProblem(sa_model, u0, tspan, ps) eprob = EnsembleProblem(sprob) nothing # hide @@ -30,9 +31,10 @@ nothing # hide ``` Finally, we can use our ensemble simulation solution as input to `plot` (just like normal simulations): ```@example ensemble +using Plots plot(sols; la = 0.5) ``` -Here, each simulation is displayed as an individual trajectory. We also use the [`la` plotting option](@ref ref) to reduce the transparency of each individual line, improving the plot visual. +Here, each simulation is displayed as an individual trajectory. We also use the [`la` plotting option](@ref simulation_plotting_options) to reduce the transparency of each individual line, improving the plot visual. Various convenience functions are available for analysing and plotting ensemble simulations (a full list can be found [here]). Here, we use these to first create an `EnsembleSummary` (retrieving each simulation's value at time points `0.0, 1.0, 2.0, ... 1000.0`). Next, we use this as an input to the `plot` command, which automatically plots the mean $X$ activity across the ensemble, while also displaying the 5% and 95% quantiles as the shaded area: ```@example ensemble @@ -45,7 +47,8 @@ Previously, we assumed that each simulation used the same initial conditions and Here, we first create an `ODEProblem` of our previous self-activation loop: ```@example ensemble -oprob = ODEProblem(sa_model, u0, tspan, p) +using OrdinaryDiffEq +oprob = ODEProblem(sa_model, u0, tspan, ps) nothing # hide ``` Next, we wish to simulate the model for a range of initial conditions of $X$`. To do this we create a problem function, which takes the following arguments: @@ -53,7 +56,7 @@ Next, we wish to simulate the model for a range of initial conditions of $X$`. T - `i`: The number of this specific Monte Carlo iteration in the interval `1:trajectories`. - `repeat`: The iteration of the repeat of the simulation. Typically `1`, but potentially higher if [the simulation re-running option](https://docs.sciml.ai/DiffEqDocs/stable/features/ensemble/#Building-a-Problem) is used. -Here we will use the following problem function (utilising [remake](@ref ref)), which will provide a uniform range of initial concentrations of $X$: +Here we will use the following problem function (utilising [remake](@ref simulation_structure_interfacing_problems_remake)), which will provide a uniform range of initial concentrations of $X$: ```@example ensemble function prob_func(prob, i, repeat) remake(prob; u0 = [:X => i * 5.0]) diff --git a/docs/src/model_simulation/ode_simulation_performance.md b/docs/src/model_simulation/ode_simulation_performance.md index 86c50123d5..9eaf4d4018 100644 --- a/docs/src/model_simulation/ode_simulation_performance.md +++ b/docs/src/model_simulation/ode_simulation_performance.md @@ -13,7 +13,7 @@ Generally, this short checklist provides a quick guide for dealing with ODE perf ## [Regarding stiff and non-stiff problems and solvers](@id ode_simulation_performance_stiffness) Generally, ODE problems can be categorised into [*stiff ODEs* and *non-stiff ODEs*](https://en.wikipedia.org/wiki/Stiff_equation). This categorisation is important due to stiff ODEs requiring specialised solvers. A common cause of failure to simulate an ODE is the use of a non-stiff solver for a stiff problem. There is no exact way to determine whether a given ODE is stiff or not, however, systems with several different time scales (e.g. a CRN with both slow and fast reactions) typically generate stiff ODEs. -Here we simulate the (stiff) [Brusselator](@ref ref) model using the `Tsit5` solver (which is designed for non-stiff ODEs): +Here we simulate the (stiff) [Brusselator](@ref basic_CRN_library_brusselator) model using the `Tsit5` solver (which is designed for non-stiff ODEs): ```@example ode_simulation_performance_1 using Catalyst, OrdinaryDiffEq, Plots @@ -52,7 +52,7 @@ Finally, we should note that stiffness is not tied to the model equations only. ## [ODE solver selection](@id ode_simulation_performance_solvers) -OrdinaryDiffEq implements an unusually large number of ODE solvers, with the performance of the simulation heavily depending on which one is chosen. These are provided as the second argument to the `solve` command, e.g. here we use the `Tsit5` solver to simulate a simple [birth-death process](@ref ref): +OrdinaryDiffEq implements an unusually large number of ODE solvers, with the performance of the simulation heavily depending on which one is chosen. These are provided as the second argument to the `solve` command, e.g. here we use the `Tsit5` solver to simulate a simple [birth-death process](@ref basic_CRN_library_bd): ```@example ode_simulation_performance_2 using Catalyst, OrdinaryDiffEq @@ -123,7 +123,7 @@ nothing # hide ### [Using a sparse Jacobian](@id ode_simulation_performance_sparse_jacobian) For a system with $n$ variables, the Jacobian will be an $n\times n$ matrix. This means that, as $n$ becomes large, the Jacobian can become *very* large, potentially causing a significant strain on memory. In these cases, most Jacobian entries are typically $0$. This means that a [*sparse*](https://en.wikipedia.org/wiki/Sparse_matrix) Jacobian (rather than a *dense* one, which is the default) can be advantageous. To designate sparse Jacobian usage, simply provide the `sparse = true` option when constructing an `ODEProblem`: ```@example ode_simulation_performance_3 -oprob = ODEProblem(brusselator, u0, tspan, p; sparse = true) +oprob = ODEProblem(brusselator, u0, tspan, ps; sparse = true) nothing # hide ``` @@ -172,10 +172,10 @@ Generally, the use of preconditioners is only recommended for advanced users who ## [Parallelisation on CPUs and GPUs](@id ode_simulation_performance_parallelisation) Whenever an ODE is simulated a large number of times (e.g. when investigating its behaviour for different parameter values), the best way to improve performance is to [parallelise the simulation over multiple processing units](https://en.wikipedia.org/wiki/Parallel_computing). Indeed, an advantage of the Julia programming language is that it was designed after the advent of parallel computing, making it well-suited for this task. Roughly, parallelisation can be divided into parallelisation on [CPUs](https://en.wikipedia.org/wiki/Central_processing_unit) and on [GPUs](https://en.wikipedia.org/wiki/General-purpose_computing_on_graphics_processing_units). CPU parallelisation is most straightforward, while GPU parallelisation requires specialised ODE solvers (which Catalyst have access to). -Both CPU and GPU parallelisation require first building an `EnsembleProblem` (which defines the simulations you wish to perform) and then supplying this with the correct parallelisation options. These have [previously been introduced in Catalyst's documentation](@ref ref) (but in the context of convenient bundling of similar simulations, rather than to improve performance), with a more throughout description being found in [OrdinaryDiffEq's documentation](https://docs.sciml.ai/DiffEqDocs/stable/features/ensemble/#ensemble). Finally, a general documentation of parallel computing in Julia is available [here](https://docs.julialang.org/en/v1/manual/parallel-computing/). +Both CPU and GPU parallelisation require first building an `EnsembleProblem` (which defines the simulations you wish to perform) and then supplying this with the correct parallelisation options. `EnsembleProblem`s have [previously been introduced in Catalyst's documentation](@ref ensemble_simulations) (but in the context of convenient bundling of similar simulations, rather than to improve performance), with a more throughout description being found in [OrdinaryDiffEq's documentation](https://docs.sciml.ai/DiffEqDocs/stable/features/ensemble/#ensemble). Finally, a general documentation of parallel computing in Julia is available [here](https://docs.julialang.org/en/v1/manual/parallel-computing/). ### [CPU parallelisation](@id ode_simulation_performance_parallelisation_CPU) -For this example (and the one for GPUs), we will consider a modified [Michaelis-Menten enzyme kinetics model](@ref ref), which describes an enzyme ($E$) that converts a substrate ($S$) to a product ($P$): +For this example (and the one for GPUs), we will consider a modified [Michaelis-Menten enzyme kinetics model](@ref basic_CRN_library_mm), which describes an enzyme ($E$) that converts a substrate ($S$) to a product ($P$): ```@example ode_simulation_performance_4 using Catalyst mm_model = @reaction_network begin @@ -186,12 +186,12 @@ mm_model = @reaction_network begin end ``` The model can be simulated, showing how $P$ is produced from $S$: -```@example ode_simulation_performance_3 +```@example ode_simulation_performance_4 using OrdinaryDiffEq, Plots u0 = [:S => 1.0, :E => 1.0, :SE => 0.0, :P => 0.0] tspan = (0.0, 50.0) -p = [:kB => 1.0, :kD => 0.1, :kP => 0.5, :d => 0.1] -oprob = ODEProblem(mm_model, u0, tspan, p) +ps = [:kB => 1.0, :kD => 0.1, :kP => 0.5, :d => 0.1] +oprob = ODEProblem(mm_model, u0, tspan, ps) sol = solve(oprob, Tsit5()) plot(sol) ``` @@ -208,7 +208,7 @@ Here, `prob_func` takes 3 arguments: and output the `ODEProblem` simulated in the i'th simulation. -Let us assume that we wish to simulate our model 100 times, for $kP = 0.01, 0.02, ..., 0.99, 1.0$. We define our `prob_func` using [`remake`](@ref ref): +Let us assume that we wish to simulate our model 100 times, for $kP = 0.01, 0.02, ..., 0.99, 1.0$. We define our `prob_func` using [`remake`](@ref simulation_structure_interfacing_problems_remake): ```@example ode_simulation_performance_4 function prob_func(prob, i, repeat) return remake(prob; p = [:kP => 0.01*i]) @@ -240,12 +240,12 @@ esol = solve(eprob, Tsit5(), EnsembleDistributed(); trajectories=100) nothing # hide ``` To utilise multiple processes, you must first give Julia access to these. You can check how many processes are available using the `nprocs` (which requires the [Distributed.jl](https://github.com/JuliaLang/Distributed.jl) package): -```julia +```@example ode_simulation_performance_4 using Distributed nprocs() ``` Next, more processes can be added using `addprocs`. E.g. here we add an additional 4 processes: -```julia +```@example ode_simulation_performance_4 addprocs(4) nothing # hide ``` @@ -309,7 +309,6 @@ Generally, it is recommended to use `EnsembleGPUArray` for large models (that ha ```julia esol1 = solve(eprob, Tsit5(), EnsembleGPUArray(CUDA.CUDABackend()); trajectories = 10000) esol2 = solve(eprob, GPUTsit5(), EnsembleGPUKernel(CUDA.CUDABackend()); trajectories = 10000) -nothing # hide ``` Note that we have to provide the `CUDA.CUDABackend()` argument to our ensemble algorithms (to designate our GPU backend, in this case, CUDA). diff --git a/docs/src/model_simulation/simulation_introduction.md b/docs/src/model_simulation/simulation_introduction.md index 113b0fa7b4..ed3056c616 100644 --- a/docs/src/model_simulation/simulation_introduction.md +++ b/docs/src/model_simulation/simulation_introduction.md @@ -1,7 +1,7 @@ # [Model Simulation Introduction](@id simulation_intro) Catalyst's core functionality is the creation of *chemical reaction network* (CRN) models that can be simulated using ODE, SDE, and jump simulations. How such simulations are carried out has already been described in [Catalyst's introduction](@ref introduction_to_catalyst). This page provides a deeper introduction, giving some additional background and introducing various simulation-related options. -Here we will focus on the basics, with other sections of the simulation documentation describing various specialised features, or giving advice on performance. Anyone who plans on using Catalyst's simulation functionality extensively is recommended to also read the documentation on [solution plotting](@ref ref), and on how to [interact with simulation problems, integrators, and solutions](@ref ref). Anyone with an application for which performance is critical should consider reading the corresponding page on performance advice for [ODEs](@ref ref), [SDEs](@ref ref), or [jump simulations](@ref ref). +Here we will focus on the basics, with other sections of the simulation documentation describing various specialised features, or giving advice on performance. Anyone who plans on using Catalyst's simulation functionality extensively is recommended to also read the documentation on [solution plotting](@ref simulation_plotting), and on how to [interact with simulation problems, integrators, and solutions](@ref simulation_structure_interfacing). Anyone with an application for which performance is critical should consider reading the corresponding page on performance advice for [ODEs](@ref ode_simulation_performance), [SDEs](@ref ref), or [jump simulations](@ref ref). ### [Background to CRN simulations](@id simulation_intro_theory) This section provides some brief theory on CRN simulations. For details on how to carry out these simulations in actual code, please skip to the following sections. @@ -40,9 +40,9 @@ These three different approaches are summed up in the following table: Example simulation methods - [Euler](https://en.wikipedia.org/wiki/Euler_method#:~:text=The%20Euler%20method%20is%20a,proportional%20to%20the%20step%20size.), [Runge-Kutta](https://en.wikipedia.org/wiki/Runge%E2%80%93Kutta_methods) - [Euler-Maruyama](https://en.wikipedia.org/wiki/Euler%E2%80%93Maruyama_method), [Milstein](https://en.wikipedia.org/wiki/Milstein_method) - [Gillespie](https://en.wikipedia.org/wiki/Gillespie_algorithm), [Sorting direct](https://pubmed.ncbi.nlm.nih.gov/16321569/) + Euler, Runge-Kutta + Euler-Maruyama, Milstein + Gillespie, Sorting direct Species units @@ -70,18 +70,18 @@ These three different approaches are summed up in the following table: Simulation package - [OrdinaryDiffEq.jl](https://github.com/SciML/OrdinaryDiffEq.jl) - [StochasticDiffEq.jl](https://github.com/SciML/StochasticDiffEq.jl) - [JumpProcesses.jl](https://github.com/SciML/JumpProcesses.jl) + OrdinaryDiffEq.jl + StochasticDiffEq.jl + JumpProcesses.jl ``` ## [Performing (ODE) simulations](@id simulation_intro_ODEs) -The following section gives a (more throughout than [previous]) introduction of how to simulate Catalyst models. This is exemplified using ODE simulations (some ODE-specific options will also be discussed). Later on, we will describe options specific to [SDE](@ref ref) and [jump](@ref ref) simulations. All ODE simulations are performed using the [OrdinaryDiffEq.jl](https://github.com/SciML/OrdinaryDiffEq.jl) package, which full documentation can be found [here](https://docs.sciml.ai/OrdinaryDiffEq/stable/). A dedicated section giving advice on how to optimise ODE simulation performance can be found [here](@ref ref) +The following section gives a (more throughout than [previous]) introduction of how to simulate Catalyst models. This is exemplified using ODE simulations (some ODE-specific options will also be discussed). Later on, we will describe things specific to [SDE](@ref simulation_intro_SDEs) and [jump](@ref simulation_intro_jumps) simulations. All ODE simulations are performed using the [OrdinaryDiffEq.jl](https://github.com/SciML/OrdinaryDiffEq.jl) package, which full documentation can be found [here](https://docs.sciml.ai/OrdinaryDiffEq/stable/). A dedicated section giving advice on how to optimise ODE simulation performance can be found [here](@ref ode_simulation_performance) -To perform any simulation, we must first define our model, as well as the simulation's initial conditions, time span, and parameter values. Here we will use a simple [two-state model](@ref ref): +To perform any simulation, we must first define our model, as well as the simulation's initial conditions, time span, and parameter values. Here we will use a simple [two-state model](@ref basic_CRN_library_two_states): ```@example simulation_intro_ode using Catalyst two_state_model = @reaction_network begin @@ -108,7 +108,7 @@ Finally, the result can be plotted using the [Plots.jl](https://github.com/Julia using Plots plot(sol) ``` -More information on how to interact with solution structures is provided [here](@ref simulation_structure_interfacing) and on how to plot them [here](@ref ref). +More information on how to interact with solution structures is provided [here](@ref simulation_structure_interfacing) and on how to plot them [here](@ref simulation_plotting). Some additional considerations: - If a model without parameters has been declared, only the first three arguments must be provided to `ODEProblem`. @@ -122,7 +122,7 @@ While good defaults are generally selected, OrdinaryDiffEq enables the user to c sol = solve(oprob, Rodas5P()) nothing # hide ``` -A full list of available solvers is provided [here](https://docs.sciml.ai/DiffEqDocs/stable/solvers/ode_solve/), and a discussion on optimal solver choices [here](@ref ref). +A full list of available solvers is provided [here](https://docs.sciml.ai/DiffEqDocs/stable/solvers/ode_solve/), and a discussion on optimal solver choices [here](@ref ode_simulation_performance_solvers). Additional options can be provided as keyword arguments. E.g. the `adaptive` arguments determine whether adaptive time-stepping is used (for algorithms that permit this). This defaults to `true`, but can be disabled using ```@example simulation_intro_ode @@ -160,7 +160,7 @@ nothing # hide The forms used for `u0` and `ps` does not need to be the same (but can e.g. be a vector and a tuple). !!! note - It [is possible](@ref ref) to designate specific types for parameters. When this is done, the tuple form for providing parameter values should be preferred. + It is possible to [designate specific types for parameters](@ref dsl_advanced_options_parameter_types). When this is done, the tuple form for providing parameter values should be preferred. Throughout Catalyst's documentation, we typically provide the time span as a tuple. However, if the first time point is `0.0` (which is typically the case), this can be omitted. Here, we supply only the simulation endpoint to our `ODEProblem`: ```@example simulation_intro_ode @@ -193,7 +193,7 @@ we can see that while this simulation (unlike the ODE ones) exhibits some fluctu Unlike for ODE and jump simulations, there are no good heuristics for automatically selecting suitable SDE solvers. Hence, for SDE simulations a solver must be provided. `STrapezoid` will work for a large number of cases. When this is not the case, however, please check the list of [available SDE solvers](https://docs.sciml.ai/DiffEqDocs/stable/solvers/sde_solve/) for a suitable alternative (making sure to select one compatible with non-diagonal noise and the [Ito interpretation]https://en.wikipedia.org/wiki/It%C3%B4_calculus). ### [Common SDE simulation pitfalls](@id simulation_intro_SDEs_pitfalls) -Next, let us reduce species amounts (using [`remake`](@ref ref)), thereby also increasing the relative amount of noise, we encounter a problem when the model is simulated: +Next, let us reduce species amounts (using [`remake`](@ref simulation_structure_interfacing_problems_remake)), thereby also increasing the relative amount of noise, we encounter a problem when the model is simulated: ```@example simulation_intro_sde sprob = remake(sprob; u0 = [:X1 => 0.33, :X2 => 0.66]) sol = solve(sprob, STrapezoid()) @@ -209,7 +209,7 @@ sol = solve(sprob, STrapezoid()) sol = solve(sprob, STrapezoid(); seed = 12345) # hide plot(sol) ``` -Again, the simulation is aborted. This time, however, species concentrations are relatively large, so the CLE might still hold. What has happened this time is that the accuracy of the simulations has not reached its desired threshold. This can be deal with [by reducing simulation tolerances](@ref ref): +Again, the simulation is aborted. This time, however, species concentrations are relatively large, so the CLE might still hold. What has happened this time is that the accuracy of the simulations has not reached its desired threshold. This can be deal with [by reducing simulation tolerances](@ref ode_simulation_performance_error): ```@example simulation_intro_sde sol = solve(sprob, STrapezoid(), abstol = 1e-1, reltol = 1e-1) sol = solve(sprob, STrapezoid(); seed = 12345, abstol = 1e-1, reltol = 1e-1) # hide @@ -255,9 +255,9 @@ plot(sol) ``` !!! note - Above, Catalyst is unable to infer that $η$ is a parameter from the `@default_noise_scaling η` option only. Hence, `@parameters η` is used to explicitly declare $η$ to be a parameter (as discussed in more detail [here](@ref ref)). + Above, Catalyst is unable to infer that $η$ is a parameter from the `@default_noise_scaling η` option only. Hence, `@parameters η` is used to explicitly declare $η$ to be a parameter (as discussed in more detail [here](@ref dsl_advanced_options_declaring_species_and_parameters)). -It is possible to designate specific noise scaling terms for individual reactions through the `noise_scaling` [reaction metadata](@ref ref). Here, CLE noise terms associated with a specific reaction are multiplied by that reaction's noise scaling term. Here we use this to turn off the noise in the $X1 \to X2$ reaction: +It is possible to designate specific noise scaling terms for individual reactions through the `noise_scaling` [reaction metadata](@ref dsl_advanced_options_reaction_metadata). Here, CLE noise terms associated with a specific reaction are multiplied by that reaction's noise scaling term. Here we use this to turn off the noise in the $X1 \to X2$ reaction: ```@example simulation_intro_sde two_state_model = @reaction_network begin k1, X1 <--> X2, [noise_scaling = 0.0] diff --git a/docs/src/model_simulation/simulation_plotting.md b/docs/src/model_simulation/simulation_plotting.md index 25cbec54ee..4594ed692c 100644 --- a/docs/src/model_simulation/simulation_plotting.md +++ b/docs/src/model_simulation/simulation_plotting.md @@ -5,7 +5,7 @@ Catalyst uses the [Plots.jl](https://github.com/JuliaPlots/Plots.jl) package for [Makie.jl](https://github.com/MakieOrg/Makie.jl) is a popular alternative to the Plots.jl package. While it is not used within Catalyst's documentation, it is worth considering (especially for users interested in interactivity, or increased control over their plots). ## [Common plotting options](@id simulation_plotting_options) -Let us consider the oscillating [Brusselator](@ref ref) model. We have previously shown how model simulation solutions can be plotted using the `plot` function. Here we plot an ODE simulation from the [Brusselator](@ref ref) model: +Let us consider the oscillating [Brusselator](@ref basic_CRN_library_brusselator) model. We have previously shown how model simulation solutions can be plotted using the `plot` function. Here we plot an ODE simulation from the Brusselator: ```@example simulation_plotting using Catalyst, OrdinaryDiffEq, Plots diff --git a/docs/src/model_simulation/simulation_structure_interfacing.md b/docs/src/model_simulation/simulation_structure_interfacing.md index a993841262..f34d6b9808 100644 --- a/docs/src/model_simulation/simulation_structure_interfacing.md +++ b/docs/src/model_simulation/simulation_structure_interfacing.md @@ -5,7 +5,7 @@ Generally, when we have a structure `simulation_struct` and want to interface wi ## [Interfacing problem objects](@id simulation_structure_interfacing_problems) -We begin by demonstrating how we can interface with problem objects. First, we create an `ODEProblem` representation of a [chemical cross-coupling model](@ref ref) (where a catalyst, $C$, couples two substrates, $S₁$ and $S₂$, to form a product, $P$). +We begin by demonstrating how we can interface with problem objects. First, we create an `ODEProblem` representation of a [chemical cross-coupling model](@ref basic_CRN_library_cc) (where a catalyst, $C$, couples two substrates, $S₁$ and $S₂$, to form a product, $P$). ```@example structure_indexing using Catalyst cc_system = @reaction_network begin @@ -53,7 +53,7 @@ oprob[[:S₁, :S₂]] Generally, when updating problems, it is often better to use the [`remake` function](@ref simulation_structure_interfacing_problems_remake) (especially when several values are updated). !!! warn - Indexing *should not* be used not modify `JumpProblem`s. Here, [remake](@ref ref) should be used exclusively. + Indexing *should not* be used not modify `JumpProblem`s. Here, [remake](@ref simulation_structure_interfacing_problems_remake) should be used exclusively. A problem's time span can be accessed through the `tspan` field: ```@example structure_indexing @@ -162,7 +162,7 @@ get_S(oprob) ``` ## [Interfacing using symbolic representations](@id simulation_structure_interfacing_symbolic_representation) -As [previously described](@ref ref), when e.g. [programmatic modelling is used](@ref ref), species and parameters can be represented as *symbolic variables*. These can be used to index a problem, just like symbol-based representations can. Here we create a simple [two-state model](@ref ref) programmatically, and use its symbolic variables to check, and update, an initial condition: +As [previously described](@ref ref), when e.g. [programmatic modelling is used](@ref ref), species and parameters can be represented as *symbolic variables*. These can be used to index a problem, just like symbol-based representations can. Here we create a simple [two-state model](@ref rbasic_CRN_library_two_statesef) programmatically, and use its symbolic variables to check, and update, an initial condition: ```@example structure_indexing_symbolic_variables using Catalyst t = default_t() @@ -195,7 +195,7 @@ Just like symbolic variables can be used to directly interface with a structure, oprob[two_state_model.X1 + two_state_model.X2] ``` This can be used to form symbolic expressions using model quantities when a model has been created using the DSL (as an alternative to [@unpack] -(@ref ref)). Alternatively, [creating an observable](@ref ref), and then interface using its `Symbol` representation, is also possible. +(@ref ref)). Alternatively, [creating an observable](@ref dsl_advanced_options_observables), and then interface using its `Symbol` representation, is also possible. !!! warn With interfacing with a simulating structure using symbolic variables stored in a `ReactionSystem` model, ensure that the [model is complete](@ref ref). \ No newline at end of file