Skip to content

Commit 4fdc654

Browse files
SKopeczranocha
andauthored
Sk/update basic examples and docstrings (#96)
* Updated basic examples * Edited doc strings for MPRK and SSPMPRK schemes * Started tutorial for linear advection * spell check * documenter latex * extended tutorial * Update docs/make.jl Co-authored-by: Hendrik Ranocha <[email protected]> * Update docs/src/linear_advection.md Co-authored-by: Hendrik Ranocha <[email protected]> * Update docs/src/linear_advection.md Co-authored-by: Hendrik Ranocha <[email protected]> * Update docs/src/linear_advection.md Co-authored-by: Hendrik Ranocha <[email protected]> * Updated Project.toml and improved tutorial for linear advection * N=1000 in linear advection tutorial * Update docs/src/linear_advection.md Co-authored-by: Hendrik Ranocha <[email protected]> * Update docs/src/linear_advection.md Co-authored-by: Hendrik Ranocha <[email protected]> * Update docs/src/linear_advection.md Co-authored-by: Hendrik Ranocha <[email protected]> * Update docs/src/linear_advection.md Co-authored-by: Hendrik Ranocha <[email protected]> * Added plot labels --------- Co-authored-by: Hendrik Ranocha <[email protected]>
1 parent 2389d44 commit 4fdc654

File tree

6 files changed

+179
-24
lines changed

6 files changed

+179
-24
lines changed

docs/Project.toml

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,14 @@
11
[deps]
2+
BenchmarkTools = "6e4b80f9-dd63-53aa-95a3-0cdb28fa8baf"
23
Documenter = "e30172f5-a6a5-5a46-863b-614d45cd2de4"
34
OrdinaryDiffEq = "1dea7af3-3e70-54e6-95c3-0bf5283fa5ed"
45
Plots = "91a5bcdd-55d7-5caf-9e0b-520d859cae80"
6+
PositiveIntegrators = "d1b20bf0-b083-4985-a874-dc5121669aa5"
7+
SparseArrays = "2f01184e-e22b-5df5-ae63-d93ebab69eaf"
58

69
[compat]
10+
BenchmarkTools = "1"
711
Documenter = "1"
8-
OrdinaryDiffEq = "6"
12+
OrdinaryDiffEq = "6.59"
913
Plots = "1"
14+
SparseArrays = "1.7"

docs/make.jl

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -73,6 +73,9 @@ makedocs(modules = [PositiveIntegrators],
7373
# Explicitly specify documentation structure
7474
pages = [
7575
"Home" => "index.md",
76+
"Tutorials" => [
77+
"Linear Advection" => "linear_advection.md",
78+
],
7679
"API reference" => "api_reference.md",
7780
"Contributing" => "contributing.md",
7881
"Code of conduct" => "code_of_conduct.md",

docs/src/index.md

Lines changed: 8 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -78,8 +78,8 @@ To solve this PDS together with initial values ``u_1(0)=u_2(0)=2`` on the time d
7878
```@example LotkaVolterra
7979
using PositiveIntegrators # load PDSProblem
8080
81-
P(u, p, t) = [2*u[1] 0.0; u[1]*u[2] 0.0] # Production matrix
82-
d(u, p, t) = [0.0; u[2]] # Destruction vector
81+
P(u, p, t) = [2*u[1] 0; u[1]*u[2] 0] # Production matrix
82+
d(u, p, t) = [0; u[2]] # Destruction vector
8383
8484
u0 = [2.0; 2.0] # initial values
8585
tspan = (0.0, 10.0) # time span
@@ -88,12 +88,10 @@ tspan = (0.0, 10.0) # time span
8888
prob = PDSProblem(P, d, u0, tspan)
8989
nothing #hide
9090
```
91-
Now that the problem has been created, we can solve it with any of the methods of [OrdinaryDiffEq.jl](https://docs.sciml.ai/OrdinaryDiffEq/stable/). Here we use the method `Tsit5()`. Please note that [PositiveIntegrators.jl](https://github.com/SKopecz/PositiveIntegrators.jl) currently only provides methods for positive and conservative PDS, see below.
91+
Now that the problem has been created, we can solve it with any method of [PositiveIntegrators.jl](https://github.com/SKopecz/PositiveIntegrators.jl). In the following, we use the method `MPRK22(1.0)`. In addition, we could also use any method provided by [OrdinaryDiffEq.jl](https://docs.sciml.ai/OrdinaryDiffEq/stable/), but these might possibly generate negative approximations.
9292

9393
```@example LotkaVolterra
94-
using OrdinaryDiffEq #load Tsit5
95-
96-
sol = solve(prob, Tsit5())
94+
sol = solve(prob, MPRK22(1.0))
9795
nothing # hide
9896
```
9997
Finally, we can use [Plots.jl](https://docs.juliaplots.org/stable/) to visualize the solution.
@@ -119,7 +117,6 @@ This shows that the sum of the state variables of a conservative PDS remains con
119117
\sum_{i=1}^N y_i(t) = \sum_{i=1}^N y_i(0)
120118
```
121119
for all times ``t>0``.
122-
Moreover, a conservative PDS is completely defined by the square matrix ``\mathbf P=(p_{ij})_{i,j=1,\dots,N}``. There is no need to store an additional vector of destruction terms since ``d_{ij} = p_{ji}`` for all ``i,j=1,\dots,N``.
123120

124121
One specific example of a conservative PDS is the SIR model
125122
```math
@@ -165,7 +162,7 @@ tspan = (0.0, 100.0); # time span
165162
prob = ConservativePDSProblem(P, u0, tspan)
166163
nothing # hide
167164
```
168-
Since the SIR model is not only conservative but also positive, we can use any MPRK scheme from [PositiveIntegrators.jl](https://github.com/SKopecz/PositiveIntegrators.jl) to solve it. Here we use `MPRK22(1.0)`.
165+
Since the SIR model is not only conservative but also positive, we can use any scheme from [PositiveIntegrators.jl](https://github.com/SKopecz/PositiveIntegrators.jl) to solve it. Here we use `MPRK22(1.0)`.
169166
Please note that any method from [OrdinaryDiffEq.jl](https://docs.sciml.ai/OrdinaryDiffEq/stable/) can be used as well, but might possibly generate negative approximations.
170167

171168
```@example SIR
@@ -176,9 +173,10 @@ Finally, we can use [Plots.jl](https://docs.juliaplots.org/stable/) to visualize
176173
```@example SIR
177174
using Plots
178175
179-
plot(sol, legend=:right)
176+
plot(sol, label = ["S" "I" "R"], legend=:right)
177+
plot!(sol, idxs = ((t, S, I, R) -> (t, S + I + R), 0, 1, 2, 3), label = "S+I+R") #Plot S+I+R over time.
180178
```
181-
179+
We see that there is always a nonnegative number of people in each compartment, while the population ``S+I+R`` remains constant over time.
182180

183181
## Referencing
184182

docs/src/linear_advection.md

Lines changed: 130 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,130 @@
1+
# Tutorial: Solution of the linear advection equation
2+
3+
This tutorial is about the efficient solution of production-destruction systems (PDS) with a large number of differential equations.
4+
We will explore several ways to represent such large systems and assess their efficiency.
5+
6+
## Definition of the production-destruction system
7+
8+
One example of the occurrence of a PDS with a large number of equations is the space discretization of a partial differential equation. In this tutorial we want to solve the linear advection equation
9+
10+
```math
11+
\partial_t u(t,x)=-a\partial_x u(t,x),\quad u(0,x)=u_0(x)
12+
```
13+
14+
with ``a>0``, ``t≥ 0``, ``x\in[0,1]`` and periodic boundary conditions. To keep things as simple as possible, we
15+
discretize the space domain as ``0=x_0<x_1\dots <x_{N-1}<x_N=1`` with ``x_i = i Δ x`` for ``i=0,\dots,N`` and ``Δx=1/N``. An upwind discretization of the spatial derivative yields the ODE system
16+
17+
```math
18+
\begin{aligned}
19+
&\partial_t u_1(t) =-\frac{a}{Δx}\bigl(u_1(t)-u_{N}(t)\bigr),\\
20+
&\partial_t u_i(t) =-\frac{a}{Δx}\bigl(u_i(t)-u_{i-1}(t)\bigr),\quad i=2,\dots,N,
21+
\end{aligned}
22+
```
23+
24+
where ``u_i(t)`` is an approximation of ``u(t,x_i)`` for ``i=1,\dots, N``.
25+
This system can also be written as ``\partial_t \mathbf u(t)=\mathbf A\mathbf u(t)`` with ``\mathbf u(t)=(u_1(t),\dots,u_N(t))`` and
26+
27+
```math
28+
\mathbf A= \frac{a}{Δ x}\begin{bmatrix}-1&0&\dots&0&1\\1&-1&\ddots&&0\\0&\ddots&\ddots&\ddots&\vdots\\ \vdots&\ddots&\ddots&\ddots&0\\0&\dots&0&1&-1\end{bmatrix}.
29+
```
30+
31+
In particular the matrix ``\mathbf A`` shows that there is a single production term and a single destruction term per equation.
32+
Furthermore, the system is conservative as ``\mathbf A`` has column sum zero.
33+
To be precise, the production matrix ``\mathbf P = (p_{i,j})`` of this conservative PDS is given by
34+
35+
```math
36+
\begin{aligned}
37+
&p_{1,N}(t,\mathbf u(t)) = \frac{a}{Δ x}u_N(t),\\
38+
&p_{i,i-1}(t,\mathbf u(t)) = \frac{a}{Δ x}u_{i-1}(t),\quad i=2,\dots,N.
39+
\end{aligned}
40+
```
41+
42+
Since the PDS is conservative, we have ``d_{i,j}=p_{j,i}`` and the system is fully determined by the production matrix ``\mathbf P``.
43+
44+
## Solution of the production-destruction system
45+
46+
Now we are ready to define a `ConservativePDSProblem` and to solve this problem with a method of [PositiveIntegrators.jl](https://github.com/SKopecz/PositiveIntegrators.jl) or [OrdinaryDiffEq.jl](https://docs.sciml.ai/OrdinaryDiffEq/stable/). In the following we use ``a=1``, ``N=1000`` and the time domain ``t\in[0,1]``. Moreover, we choose the step function
47+
48+
```math
49+
u_0(x)=\begin{cases}1, & 0.4 ≤ x ≤ 0.6,\\ 0,& \text{elsewhere}\end{cases}
50+
```
51+
52+
as initial condition. Due to the periodic boundary conditions and the transport velocity ``a=1``, the solution at time ``t=1`` is identical to the initial distribution, i.e. ``u(1,x) = u_0(x)``.
53+
54+
```@example LinearAdvection
55+
N = 1000 # number of subintervals
56+
dx = 1/N # mesh width
57+
x = LinRange(dx, 1.0, N) # discretization points x_1,...,x_N = x_0
58+
u0 = @. 0.0 + (0.4 ≤ x ≤ 0.6) * 1.0 # initial solution
59+
tspan = (0.0, 1.0) # time domain
60+
61+
nothing #hide
62+
```
63+
64+
As mentioned above, we will try different approaches to solve this PDS and compare their efficiency. These are
65+
1. an in-place implementation with a dense matrix,
66+
2. an in-place implementation with a sparse matrix.
67+
68+
### Standard in-place implementation
69+
70+
```@example LinearAdvection
71+
using PositiveIntegrators # load ConservativePDSProblem
72+
73+
function lin_adv_P!(P, u, p, t)
74+
P .= 0.0
75+
N = length(u)
76+
dx = 1 / N
77+
P[1, N] = u[N] / dx
78+
for i in 2:N
79+
P[i, i - 1] = u[i - 1] / dx
80+
end
81+
return nothing
82+
end
83+
84+
prob = ConservativePDSProblem(lin_adv_P!, u0, tspan) # create the PDS
85+
86+
sol = solve(prob, MPRK43I(1.0, 0.5); save_everystep = false)
87+
88+
nothing #hide
89+
```
90+
91+
```@example LinearAdvection
92+
using Plots
93+
94+
plot(x, u0; label = "u0", xguide = "x", yguide = "u")
95+
plot!(x, last(sol.u); label = "u")
96+
```
97+
98+
### Using sparse matrices
99+
100+
TODO: Some text
101+
102+
```@example LinearAdvection
103+
using SparseArrays
104+
p_prototype = spdiagm(-1 => ones(eltype(u0), N - 1),
105+
N - 1 => ones(eltype(u0), 1))
106+
prob_sparse = ConservativePDSProblem(lin_adv_P!, u0, tspan; p_prototype=p_prototype)
107+
108+
sol_sparse = solve(prob_sparse, MPRK43I(1.0, 0.5); save_everystep = false)
109+
110+
nothing #hide
111+
```
112+
113+
```@example LinearAdvection
114+
plot(x,u0; label = "u0", xguide = "x", yguide = "u")
115+
plot!(x, last(sol_sparse.u); label = "u")
116+
```
117+
118+
### Performance comparison
119+
120+
Finally, we use [BenchmarkTools.jl](https://github.com/JuliaCI/BenchmarkTools.jl)
121+
to compare the performance of the different implementations.
122+
123+
```@example LinearAdvection
124+
using BenchmarkTools
125+
@benchmark solve(prob, MPRK43I(1.0, 0.5); save_everystep = false)
126+
```
127+
128+
```@example LinearAdvection
129+
@benchmark solve(prob_sparse, MPRK43I(1.0, 0.5); save_everystep = false)
130+
```

src/mprk.jl

Lines changed: 24 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -122,13 +122,14 @@ The first-order modified Patankar-Euler algorithm for production-destruction sys
122122
first-order accurate, unconditionally positivity-preserving, and
123123
linearly implicit.
124124
125-
The scheme was introduced by Burchard et al for conservative production-destruction systems.
125+
The scheme was introduced by Burchard et al. for conservative production-destruction systems.
126126
For nonconservative production–destruction systems we use the straight forward extension
127127
128-
``u_i^{n+1} = u_i^n + Δt \\sum_{j, j≠i} \\biggl(p_{ij}^n \\frac{u_j^{n+1}}{u_j^n}-d_{ij}^n \\frac{u_i^{n+1}}{u_i^n}\\biggr) + {\\Delta}t p_{ii}^n - Δt d_{ii}^n\\frac{u_i^{n+1}}{u_i^n}``.
128+
``u_i^{n+1} = u_i^n + Δt \\sum_{j, j≠i} \\biggl(p_{ij}^n \\frac{u_j^{n+1}}{u_j^n}-d_{ij}^n \\frac{u_i^{n+1}}{u_i^n}\\biggr) + {\\Delta}t p_{ii}^n - Δt d_{ii}^n\\frac{u_i^{n+1}}{u_i^n}``,
129129
130-
The modified Patankar-Euler method requires the special structure of a
131-
[`PDSProblem`](@ref) or a [`ConservativePDSProblem`](@ref).
130+
where ``p_{ij}^n = p_{ij}(t^n,\\mathbf u^n)`` and ``d_{ij}^n = d_{ij}(t^n,\\mathbf u^n)``.
131+
132+
The modified Patankar-Euler method requires the special structure of a [`PDSProblem`](@ref) or a [`ConservativePDSProblem`](@ref).
132133
133134
You can optionally choose the linear solver to be used by passing an
134135
algorithm from [LinearSolve.jl](https://github.com/SciML/LinearSolve.jl)
@@ -137,6 +138,8 @@ You can also choose the parameter `small_constant` which is added to all Patanka
137138
to avoid divisions by zero. You can pass a value explicitly, otherwise `small_constant` is set to
138139
`floatmin` of the floating point type used.
139140
141+
The current implementation only supports fixed time steps.
142+
140143
## References
141144
142145
- Hans Burchard, Eric Deleersnijder, and Andreas Meister.
@@ -329,14 +332,18 @@ end
329332
MPRK22(α; [linsolve = ..., small_constant = ...])
330333
331334
A family of second-order modified Patankar-Runge-Kutta algorithms for
332-
production-destruction systems. Each member of this family is an one-step, two-stage method which is
335+
production-destruction systems. Each member of this family is an adaptive, one-step, two-stage method which is
333336
second-order accurate, unconditionally positivity-preserving, and linearly
334-
implicit. The parameter `α` is described by Kopecz and Meister (2018) and
337+
implicit. In this implementation the stage-values are conservative as well.
338+
The parameter `α` is described by Kopecz and Meister (2018) and
335339
studied by Izgin, Kopecz and Meister (2022) as well as
336-
Torlo, Öffner and Ranocha (2022).
340+
Torlo, Öffner and Ranocha (2022).
341+
342+
This method supports adaptive time stepping, using the Patankar-weight denominators
343+
``σ_i``, see Kopecz and Meister (2018), as first order approximations to estimate the error.
337344
338345
The scheme was introduced by Kopecz and Meister for conservative production-destruction systems.
339-
For nonconservative production–destruction systems we use the straight forward extension
346+
For nonconservative production–destruction systems we use a straight forward extension
340347
analogous to [`MPE`](@ref).
341348
342349
This modified Patankar-Runge-Kutta method requires the special structure of a
@@ -712,12 +719,15 @@ end
712719
713720
A family of third-order modified Patankar-Runge-Kutta schemes for
714721
production-destruction systems, which is based on the two-parameter family of third order explicit Runge--Kutta schemes.
715-
Each member of this family is a one-step method with four-stages which is
722+
Each member of this family is an adaptive, one-step method with four-stages which is
716723
third-order accurate, unconditionally positivity-preserving, conservative and linearly
717724
implicit. In this implementation the stage-values are conservative as well.
718725
The parameters `α` and `β` must be chosen such that the Runge--Kutta coefficients are nonnegative,
719726
see Kopecz and Meister (2018) for details.
720727
728+
These methods support adaptive time stepping, using the Patankar-weight denominators
729+
``σ_i``, see Kopecz and Meister (2018), as second order approximations to estimate the error.
730+
721731
The scheme was introduced by Kopecz and Meister for conservative production-destruction systems.
722732
For nonconservative production–destruction systems we use the straight forward extension
723733
analogous to [`MPE`](@ref).
@@ -809,15 +819,18 @@ end
809819
"""
810820
MPRK43II(γ; [linsolve = ..., small_constant = ...])
811821
812-
A family of third-order modified Patankar-Runge-Kutta schemes for (conservative)
822+
A family of third-order modified Patankar-Runge-Kutta schemes for
813823
production-destruction systems, which is based on the one-parameter family of third order explicit Runge--Kutta schemes with
814824
non-negative Runge--Kutta coefficients.
815-
Each member of this family is a one-step method with four stages which is
825+
Each member of this family is an adaptive, one-step method with four stages which is
816826
third-order accurate, unconditionally positivity-preserving, conservative and linearly
817827
implicit. In this implementation the stage-values are conservative as well. The parameter `γ` must satisfy
818828
`3/8 ≤ γ ≤ 3/4`.
819829
Further details are given in Kopecz and Meister (2018).
820830
831+
This method supports adaptive time stepping, using the Patankar-weight denominators
832+
``σ_i``, see Kopecz and Meister (2018), as second order approximations to estimate the error.
833+
821834
The scheme was introduced by Kopecz and Meister for conservative production-destruction systems.
822835
For nonconservative production–destruction systems we use the straight forward extension
823836
analogous to [`MPE`](@ref).

src/sspmprk.jl

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,14 +3,18 @@
33
SSPMPRK22(α, β; [linsolve = ..., small_constant = ...])
44
55
A family of second-order modified Patankar-Runge-Kutta algorithms for
6-
production-destruction systems. Each member of this family is a one-step, two-stage method which is
6+
production-destruction systems. Each member of this family is an adaptive, one-step, two-stage method which is
77
second-order accurate, unconditionally positivity-preserving, and linearly
88
implicit. The parameters `α` and `β` are described by Huang and Shu (2019) and
99
studied by Huang, Izgin, Kopecz, Meister and Shu (2023).
1010
The difference to [`MPRK22`](@ref) is that this method is based on the SSP formulation of
1111
an explicit second-order Runge-Kutta method. This family of schemes contains the [`MPRK22`](@ref) family,
1212
where `MPRK22(α) = SSMPRK22(0, α)` applies.
1313
14+
This method supports adaptive time stepping, using the first order approximations
15+
``(σ_i - u_i^n) / τ + u_i^n`` with ``τ=1+(α_{21}β_{10}^2)/(β_{20}+β_{21})``,
16+
see (2.7) in Huang and Shu (2019), to estimate the error.
17+
1418
The scheme was introduced by Huang and Shu for conservative production-destruction systems.
1519
For nonconservative production–destruction systems we use the straight forward extension
1620
analogous to [`MPE`](@ref).
@@ -408,7 +412,7 @@ end
408412
SSPMPRK43([linsolve = ..., small_constant = ...])
409413
410414
A third-order modified Patankar-Runge-Kutta algorithm for
411-
production-destruction systems. This scheme is a one-step, two-stage method which is
415+
production-destruction systems. This scheme is a one-step, four-stage method which is
412416
third-order accurate, unconditionally positivity-preserving, and linearly
413417
implicit. The scheme is described by Huang, Zhao and Shu (2019) and
414418
studied by Huang, Izgin, Kopecz, Meister and Shu (2023).
@@ -429,6 +433,8 @@ You can also choose the parameter `small_constant` which is added to all Patanka
429433
to avoid divisions by zero. You can pass a value explicitly, otherwise `small_constant` is set to
430434
`floatmin` of the floating point type used.
431435
436+
The current implementation only supports fixed time steps.
437+
432438
## References
433439
434440
- Juntao Huang, Weifeng Zhao and Chi-Wang Shu.

0 commit comments

Comments
 (0)