Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Stochastic Galerkin for ODESystem and PDESystem #38

Closed
wants to merge 108 commits into from
Closed
Show file tree
Hide file tree
Changes from 104 commits
Commits
Show all changes
108 commits
Select commit Hold shift + click to select a range
8268244
develop automated polynomial chaos transformations
FHoltorf Jul 20, 2022
413523e
outline of mathematical approach for polynomial models
FHoltorf Sep 21, 2022
5910a04
introduce PCE type and associated utilities
FHoltorf Sep 25, 2022
b5d42d8
forgot to include PCE_utils.jl
FHoltorf Sep 25, 2022
1611efc
symbolic pipeline to apply PCE ansatz to equations + Roadmap
FHoltorf Sep 25, 2022
ee6aa9e
tests for PCE (+ export PCE type)
FHoltorf Sep 25, 2022
0c9a505
extracting PCE expansion coefficients after applying PCE ansatz
FHoltorf Sep 25, 2022
183f3db
test for ansatz application
FHoltorf Sep 25, 2022
01f4f48
introduce utilities to extract the basis indices (perhaps I should ju…
FHoltorf Sep 25, 2022
7453265
test monomial extraction
FHoltorf Sep 25, 2022
bf049ac
evaluating inner products for galerkin projection
FHoltorf Sep 25, 2022
4ad852f
rm OrthoPoly functions -> not compatible with PolyChaos => consider P…
FHoltorf Sep 25, 2022
c9638b2
description of potential pr to PolyChaos
FHoltorf Sep 25, 2022
9380ad0
galerking projection
FHoltorf Sep 25, 2022
d548775
combining everything
FHoltorf Sep 25, 2022
44dccf1
pce for explicit ODEs
FHoltorf Sep 25, 2022
eedee96
forgot to export moment_equations
FHoltorf Sep 25, 2022
2ccb1c2
update potential interfaces agenda
FHoltorf Sep 25, 2022
495022a
test galerking projection
FHoltorf Sep 26, 2022
c85f2b0
rm old file
FHoltorf Sep 26, 2022
750cc94
merge remote master
FHoltorf Sep 26, 2022
4e5d652
restructure PCE tests
FHoltorf Sep 26, 2022
06a0e98
update testing environmnet
FHoltorf Sep 26, 2022
2bc23b8
move dependencies to respective tests for easier bookkepping
FHoltorf Sep 26, 2022
3b7f8a3
bug fix: constant terms were omitted in coefficient extraction and ga…
FHoltorf Sep 26, 2022
9cfb203
tutorial docs
FHoltorf Sep 27, 2022
0a97073
fix naming conflict for SVD in tests
FHoltorf Sep 27, 2022
db21b2f
fix typo in tutorial
FHoltorf Sep 27, 2022
02d20cc
replace allequal call
FHoltorf Sep 27, 2022
ac41583
SciML format
FHoltorf Sep 27, 2022
7ae4754
fix typos in PCE utils
FHoltorf Sep 27, 2022
db13e24
test bump_degree for different OPs + some minor changes
FHoltorf Sep 27, 2022
fcf255f
SciML format
FHoltorf Sep 27, 2022
d4e7ef9
rm recursion coefficient methods as they are not needed in current im…
FHoltorf Sep 28, 2022
d395638
rm recursion coefficient methods as they are not needed in current im…
FHoltorf Sep 28, 2022
7546a75
support for generic orthogonal polynomials
FHoltorf Sep 28, 2022
ceba828
fixed error in coefficient extraction (symbolic constant parts!)
FHoltorf Sep 28, 2022
6fa5101
test for moment equations + more challenging test equation + minor bu…
FHoltorf Sep 28, 2022
06cd417
SciML format
FHoltorf Sep 28, 2022
73d89de
fix bug
FHoltorf Sep 28, 2022
1a10d55
fix apply_ansatz test
FHoltorf Sep 28, 2022
ec500c5
merge master
FHoltorf Oct 13, 2022
9e80090
run SciML formatter
FHoltorf Oct 13, 2022
11504df
include normalization in galerkin_projection
FHoltorf Oct 14, 2022
dad3d67
doc strings
FHoltorf Oct 14, 2022
a6708dd
bug fix
FHoltorf Oct 14, 2022
d378ad4
TensorProductOrthoPoly introduced
FHoltorf Oct 15, 2022
7510399
change code base to TensorProductOrthoPoly
FHoltorf Oct 15, 2022
bdf692e
SciML format
FHoltorf Oct 15, 2022
c8353f8
TensorProductOrthoPoly and ancillary tests + minor adjustments
FHoltorf Oct 16, 2022
32eb581
SciML format
FHoltorf Oct 16, 2022
bcad194
rm field bases_dict
FHoltorf Oct 17, 2022
c65f681
rm sym_to_pc and inverse dict => goal: denser code
FHoltorf Oct 17, 2022
3f9f42f
rename bases => uni_basis, pc_basis => tensor_basis and added some ty…
FHoltorf Oct 17, 2022
8e2773e
SciML format
FHoltorf Oct 17, 2022
7c2ea49
Merge branch 'main' into PolyChaos for easier pr merging.
FHoltorf Oct 17, 2022
d582ccf
adjust tutorial for new field names
FHoltorf Oct 17, 2022
a2ca3d8
SciML format again ...
FHoltorf Oct 17, 2022
3383d42
Fix typo "and" -> "an"
bowenszhu Oct 26, 2022
892b261
Change MTK to fullname in case the abbreviation is unknown for new users
bowenszhu Oct 26, 2022
bf1addb
Change to use `Symbolics.variables` to create an array of symbolic vars
bowenszhu Oct 26, 2022
36652c8
Resolve `independent_variables` deprecated warning
bowenszhu Oct 26, 2022
2ff6379
Generate code of `bump_degree` for AbstractOrthoPoly subtypes
bowenszhu Oct 26, 2022
6b45308
Remove unnecessary import in runtests.jl
bowenszhu Oct 26, 2022
1912a9d
Remove unused type variable
bowenszhu Oct 26, 2022
9eb94f1
Construct `PCE`, `PCEMetadata`
bowenszhu Oct 28, 2022
afba1c8
Merge pull request #16 from bowenszhu/PolyChaos-unused-type-variable
FHoltorf Oct 28, 2022
98763cd
Merge pull request #19 from bowenszhu/PolyChaos-typo-and
FHoltorf Oct 28, 2022
ef9a6a6
Merge pull request #14 from bowenszhu/PolyChaos-get_iv
FHoltorf Oct 28, 2022
6908335
Merge pull request #15 from bowenszhu/PolyChaos-remove-import-test
FHoltorf Oct 28, 2022
96b9082
Merge pull request #17 from bowenszhu/PolyChaos-eval-bump_degree
FHoltorf Oct 28, 2022
f6931d4
Merge pull request #18 from bowenszhu/PolyChaos-create-var
FHoltorf Oct 28, 2022
86b7256
Test `PCE` constructor
bowenszhu Oct 29, 2022
c583ce7
Define `stochastic_galerkin`
bowenszhu Oct 29, 2022
48cfe4a
Split tests into groups
bowenszhu Oct 29, 2022
69bf142
Define `TensorProductOrthoPoly`
bowenszhu Nov 2, 2022
8482586
Compute size of multi-indices
bowenszhu Nov 4, 2022
c4b190d
Add internal docs
bowenszhu Nov 4, 2022
62dee42
Compute multi-indices in graded lexicographic order
bowenszhu Nov 4, 2022
51df08f
Restructure docs
bowenszhu Nov 4, 2022
8d0d0e0
Compute general tensor scalar product for multivariate orthogonal polys
bowenszhu Nov 5, 2022
ab5a64b
Reorganize import and export
bowenszhu Nov 5, 2022
10e3bd3
Revert "Split tests into groups"
bowenszhu Nov 5, 2022
2a6b857
Update PCE docstring
bowenszhu Nov 5, 2022
d64fc09
Update PCE struct, constructor, docstring
bowenszhu Nov 6, 2022
e60bc06
Remove field `uni_basis` from struct `PCE`
bowenszhu Nov 6, 2022
f2b66e0
Remove `computeSP` https://github.com/SciML/PolyChaos.jl/pull/90
bowenszhu Nov 7, 2022
568cbb9
Create new constructor method of `Tensor` https://github.com/SciML/Po…
bowenszhu Nov 7, 2022
69855d1
Update `PCE` docstring
bowenszhu Nov 7, 2022
b56b374
Test `dim` `computeTensorizedSP` constructor of `TensorProductOrthoPoly`
bowenszhu Nov 7, 2022
cdd6a3f
Move `EmptyQuad` check from `computeTensorizedSP` to TPOP constructor
bowenszhu Nov 7, 2022
b989cd6
Fix `PCE` constructor type annotation
bowenszhu Nov 7, 2022
347044b
Record multi-index index of chaos coefficients in symbolic metadata
bowenszhu Nov 7, 2022
33251b1
Merge remote-tracking branch 'FHoltorf/PolyChaos' into Stochastic-Gal…
bowenszhu Nov 8, 2022
eb09133
Add independent variables to `PCE` constructor arguments
bowenszhu Nov 8, 2022
717ec69
Add ansatz and precompute 2d tensor inner product in `PCE` constructor
bowenszhu Nov 8, 2022
c1090c9
Remove `get_independent_vars` tests
bowenszhu Nov 8, 2022
9955e79
Fix `PCE` dispatch types in docs
bowenszhu Nov 8, 2022
f57836c
Fix \vec accents rendering in docs
bowenszhu Nov 8, 2022
c981746
Define `Inner` and its associated operations
bowenszhu Nov 9, 2022
4b2a11d
Rename `Inner` to `BasisProduct`
bowenszhu Nov 9, 2022
d59e01d
Update `^`, add `+` `*` `<ₑ` `symtype` for `BasisProduct`
bowenszhu Nov 9, 2022
33dfe36
Add tests for `BasisProduct`
bowenszhu Nov 9, 2022
ecae9c1
Define `hash` for `BasisProduct`
bowenszhu Nov 9, 2022
4cff573
Change `Term` to concrete `Symbolic` type in `+``*``^` of `BasisProduct`
bowenszhu Nov 21, 2022
b9f97ca
Remove outdated `get_basis_indices` methods
bowenszhu Dec 5, 2022
29cfcae
Remove repeated import
bowenszhu Dec 5, 2022
560b2e6
Input distributions of stochastic parameters via symbolic metadata
bowenszhu Dec 5, 2022
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .github/workflows/CI.yml
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ jobs:
- "1"
- "1.6"
steps:
- uses: actions/checkout@v2
- uses: actions/checkout@v3
- uses: julia-actions/setup-julia@v1
with:
version: ${{ matrix.version }}
Expand Down
6 changes: 4 additions & 2 deletions Project.toml
Original file line number Diff line number Diff line change
Expand Up @@ -4,22 +4,24 @@ authors = ["Bowen S. Zhu <[email protected]> and contributors"]
version = "0.1.1"

[deps]
Combinatorics = "861a8166-3701-5b0c-9a16-15d98fcdc6aa"
DocStringExtensions = "ffbed154-4ef7-542d-bbb7-c09d3a79fcae"
LinearAlgebra = "37e2e46d-f89d-539d-b4ee-838fcccc9c8e"
ModelingToolkit = "961ee093-0014-501f-94e3-6117800e7a78"
PolyChaos = "8d666b04-775d-5f6e-b778-5ac7c70f65a3"
RandomizedLinAlg = "0448d7d9-159c-5637-8537-fd72090fea46"
Setfield = "efcf1570-3423-57d1-acb7-fd33fddbac46"
SparseArrays = "2f01184e-e22b-5df5-ae63-d93ebab69eaf"
SymbolicUtils = "d1185830-fcd6-423d-90d6-eec64667417b"
Symbolics = "0c5d862f-8b57-4792-8d23-62f2024744c7"
TSVD = "9449cd9e-2762-5aa3-a617-5413e99d722e"

[compat]
Combinatorics = "1.0"
DocStringExtensions = "0.8, 0.9"
ModelingToolkit = "8.21"
PolyChaos = "0.2"
RandomizedLinAlg = "0.1"
Setfield = "0.8, 1"
SymbolicUtils = "0.19"
Symbolics = "4.10"
TSVD = "0.4"
julia = "1.6"
2 changes: 2 additions & 0 deletions docs/Project.toml
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,8 @@ LinearAlgebra = "37e2e46d-f89d-539d-b4ee-838fcccc9c8e"
MethodOfLines = "94925ecb-adb7-4558-8ed8-f975c56a0bf4"
ModelingToolkit = "961ee093-0014-501f-94e3-6117800e7a78"
Plots = "91a5bcdd-55d7-5caf-9e0b-520d859cae80"
PolyChaos = "8d666b04-775d-5f6e-b778-5ac7c70f65a3"
Symbolics = "0c5d862f-8b57-4792-8d23-62f2024744c7"

[compat]
Documenter = "0.27"
2 changes: 1 addition & 1 deletion docs/make.jl
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
using Documenter, ModelOrderReduction
using Documenter, ModelOrderReduction, Symbolics, PolyChaos

include("pages.jl")

Expand Down
11 changes: 9 additions & 2 deletions docs/pages.jl
Original file line number Diff line number Diff line change
@@ -1,5 +1,12 @@
pages = [
"Home" => "index.md",
"Functions" => "functions.md",
"Tutorials" => Any["tutorials/deim_FitzHugh-Nagumo.md"],
"Polynomial Chaos Expansion (PCE)" => [
"Introduction" => "pce/pce.md",
"pce/stochastic_galerkin.md",
],
"Discrete Empirical Interpolation Method (DEIM)" => [
"Introduction" => "deim/deim.md",
"deim/deim_FitzHugh-Nagumo.md",
],
"internals.md",
]
5 changes: 5 additions & 0 deletions docs/src/deim/deim.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
# Discrete Empirical Interpolation Method (DEIM)

```@docs
deim
```
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
# Discrete Empirical Interpolation Method (DEIM)
# Example: FitzHugh-Nagumo System

This section illustrates how ModelOrderReduction.jl can be used to build a reduced order
model via Petrov-Galerkin projection using the Proper Orthogonal Decomposition (POD) and
Expand Down
6 changes: 0 additions & 6 deletions docs/src/functions.md

This file was deleted.

6 changes: 6 additions & 0 deletions docs/src/internals.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
# Internal Documentation

```@autodocs
Modules = [ModelOrderReduction]
Public = false
```
6 changes: 6 additions & 0 deletions docs/src/pce/pce.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
# Polynomial Chaos Expansion (PCE)

```@docs
PCE
PCE(::AbstractVector{Num}, ::AbstractVector{Num}, ::AbstractVector{Num}, ::AbstractVector{<:Union{AbstractOrthoPoly, AbstractCanonicalOrthoPoly}})
```
5 changes: 5 additions & 0 deletions docs/src/pce/stochastic_galerkin.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
# Stochastic Galerkin Method (SGM)

```@docs
stochastic_galerkin
```
Binary file added examples/PCE/mean.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added examples/PCE/traces.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
123 changes: 123 additions & 0 deletions examples/PCE/tutorial.jl
Original file line number Diff line number Diff line change
@@ -0,0 +1,123 @@
using ModelOrderReduction, ModelingToolkit, DifferentialEquations,
PolyChaos, Plots, LinearAlgebra

# Reaction system
# k[1](1+θ[1]/2)/k[2]: A + B ⇌ C
# k[3](1+θ[2]/2): C → D
# k[4]: B → D
#
# state: c[1:4] = [A, B, C, D]
# certain parameters: k[1:4]
# uncertain parameters: θ[1:2] ∼ U[-1,1]

@parameters k[1:4], θ[1:2]
@variables t, c(t)[1:4]
D = Differential(t)
reactor = [D(c[1]) ~ -k[1] * (1 + 0.5 * θ[1]) * c[1] * c[2] + k[2] * c[3];
D(c[2]) ~ -k[1] * (1 + 0.5 * θ[1]) * c[1] * c[2] - k[4] * c[2] + k[2] * c[3];
D(c[3]) ~ k[1] * c[1] * c[2] - k[3] * c[3];
D(c[4]) ~ k[3] * (1 + 0.5 * θ[2]) * c[3] + k[4] * c[2]];

@named reactor_model = ODESystem(reactor, t, c, vcat(k, θ))

# 1. choose/generate PCE of the system state
d_pce = 3
pce = PCE(c, [θ[i] => Uniform_11OrthoPoly(d_pce) for i in eachindex(θ)])

# 2. generate moment equations
moment_eqs, pce_eval = moment_equations(reactor_model, pce)

# 3. solve the moment equations
# 3a. find initial moments via Galerkin projection (note that c0 could depend on an uncertain parameter)
c0 = [1.0, 2.0, 0.0, 0.0]
z0 = reduce(vcat, pce_galerkin(c0, pce))

# 3b. solve the initial value problem for the moment equations
moment_prob = ODEProblem(moment_eqs, z0, (0.0, 10.0),
[k[1] => 1.0, k[2] => 0.2, k[3] => 12, k[4] => 0.1])
moment_sol = solve(moment_prob, Tsit5())

# 3c. define a function approximating the parametric solution to the IVP.
pce_sol(t, θ) = pce_eval(moment_sol(t), θ)

# 4. now let's compare to true solution
# take 100 uniform samples
n = 5
θsamples = Iterators.product(range(-1, 1, length = n), range(-1, 1, length = n))
ps = [k[1] => 1.0, k[2] => 0.2, k[3] => 12, k[4] => 0.1, θ[1] => 0.0, θ[2] => 0.0]
pvals = [p[2] for p in ps]
reactor_problem = ODEProblem(reactor_model, c0, (0.0, 10.0), ps)
t_range = range(0.0, 10.0, length = 100)
sols = []
for θval in θsamples
pvals[end - 1] = θval[1]
pvals[end] = θval[2]
_prob = remake(reactor_problem, p = pvals)
push!(sols, Array(solve(_prob, Tsit5(), saveat = t_range)))
end

species = ["A", "B", "C", "D"]
color = [:red, :green, :blue, :orange]
plots = [plot(title = "Species $(species[i])", xlabel = "time", ylabel = "concentration",
legend = false) for i in 1:4]
for sol in sols
for i in 1:4
plot!(plots[i], t_range, sol[i, :], color = color[i])
end
end
for θval in θsamples
pce_predictions = [pce_sol(t, [θval...]) for t in t_range]
for i in 1:4
plot!(plots[i], t_range, [c[i] for c in pce_predictions], color = "black",
linestyle = :dash)
end
end

fig = plot(plots...)
savefig(fig, string(@__DIR__, "/traces.png"))

n = 100
θsamples = Iterators.product(range(-1, 1, length = n), range(-1, 1, length = n))
ps = [k[1] => 1.0, k[2] => 0.2, k[3] => 12, k[4] => 0.1, θ[1] => 0.0, θ[2] => 0.0]
pvals = [p[2] for p in ps]
reactor_problem = ODEProblem(reactor_model, c0, (0.0, 10.0), ps)
t_range = range(0.0, 10.0, length = 100)
sols = []
for θval in θsamples
pvals[end - 1] = θval[1]
pvals[end] = θval[2]
_prob = remake(reactor_problem, p = pvals)
push!(sols, Array(solve(_prob, Tsit5(), saveat = t_range)))
end

mean_solution = mean(sols)
var_solution = mean([sol .^ 2 for sol in sols]) - mean_solution .^ 2

L = length(pce.sym_basis)
mean_PCE = [[moment_sol(t)[((i - 1) * L + 1):(i * L)][1] for i in 1:4] for t in t_range]
var_weightings = computeSP2(pce.tensor_basis)
var_PCE = [[dot(moment_sol(t)[((i - 1) * L + 1):(i * L)] .^ 2, var_weightings) for i in 1:4]
for t in t_range] .- [m .^ 2 for m in mean_PCE]

species = ["A", "B", "C", "D"]
color = [:red, :green, :blue, :orange]
plots = [plot(title = "Species $(species[i])", xlabel = "time", ylabel = "mean",
legend = false) for i in 1:4]

for i in 1:4
plot!(plots[i], t_range, [mean_solution[i, k] for k in axes(mean_solution, 2)],
color = color[i])
plot!(plots[i], t_range, [s[i] for s in mean_PCE], color = "black", linestyle = :dash)
end
fig = plot(plots...)
savefig(fig, string(@__DIR__, "/mean.png"))

plots = [plot(title = "Species $(species[i])", xlabel = "time", ylabel = "variance",
legend = false) for i in 1:4]
for i in 1:4
plot!(plots[i], t_range, [var_solution[i, k] for k in axes(var_solution, 2)],
color = color[i])
plot!(plots[i], t_range, [s[i] for s in var_PCE], color = "black", linestyle = :dash)
end
fig = plot(plots...)
savefig(fig, string(@__DIR__, "/var.png"))
109 changes: 109 additions & 0 deletions examples/PCE/tutorial.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,109 @@
# Polynomial Chaos Expansion for Random ODEs
## Sketch of the Theory
This section reviews the basic concept behind the use of Polynomial Chaos Expansion (PCE) for approximate solution to random ODEs as well as how `ModelOrderReduction` facilitates its use within the SciML ecosystem.

In essence, PCE is nothing more than a function expansion technique for square integrable functions where the basis functions are chosen to be orthogonal polynomials; for a detailed treatment of the mathematical underpinnings the interested reader is referred to Gautschi (2004) [1], for example. For the sake of this tutorial we will remain much more informal and discuss only aspects that are critical for basic use of PCE in computational practice. To that end, we will consider the problem of finding a parametric solution to the following *random* ODE:
```math
\begin{aligned}
\frac{dx}{dt}(p) = f(x,p,t), \quad x(0) = x_0(p)
\end{aligned}
```
where the parameters $p$ are *apriori* only known to follow a given distribution $\mu$. Specifically, we will seek to find an approximation to the solution $x(t,p)$ in the form of a PCE that matches the statistics of the random process $x(t,p)$ with $p \sim \mu$. To that end, we approximate
```math
\begin{aligned}
x(t,p) \approx \hat{x}(t,p) = \sum_{i=0}^L z_i(t) \zeta_i(p)
\end{aligned}
```
where $\zeta_0(p), \dots, \zeta_L(p)$ are mutually orthogonal polynomial with respect to the distribution $\mu$, i.e.,
```math
\begin{aligned}
\left\langle \zeta_i, \zeta_j \right\rangle := \int \zeta_i(p) \zeta_j(p) d\mu(p) = \delta_{ij}
\end{aligned}
```
where $\delta_{ij}$ is the Kronecker delta. These polynomials can be efficiently constructed for many distributions. In particular, they are known analytically for many standard distributions including but not limited to Gaussians, uniform or beta distributions; moreover, they can be approximated numerically for distributions with known smooth densities and even empirically known distributions. For more details, please review the documentation of [PolyChaos.jl](github.com/SciML/PolyChaos.jl) or Gautschi (2004) [1] for instance.

Inserting the PCE-Ansatz $\hat{x}$ into the random ODE of interest yields
```math
\begin{aligned}
\sum_{i=0}^L \frac{dz_i}{dt}(t) \zeta_i(p) = f\left(\sum_{i=0}^L z_i(t) \zeta_i(p), p, t \right), \sum_{i=0}^L z_i(0) \zeta_i(p)
\end{aligned}
```
To derive evolution equations for the coefficients (or *moments*) $z_i$ we simply demand that the residual of the above equations to be orthogonal to the space spanned by $\zeta_0, \dots, \zeta_L$. Orthogonality here shall be understood with respect to the inner product as described above. This is equivalent to demanding minimal expected mismatch when evaluating the above equation for $p \sim \mu$. Mathematically, this condition translates into a set of deterministic ODEs for the moments $z_j$:
```math
\begin{aligned}
\left\langle\sum_{i=0}^L \frac{dz_i}{dt}(t) \zeta_i(p), \zeta_j(p) \right\rangle = \left \langle f\left(\sum_{i=0}^L z_i(t) \zeta_i(p), p, t \right), \sum_{i=0}^L z_i(0) \zeta_i(p), \zeta_j(p) \right\rangle
\end{aligned}
```
and since $\left\langle \zeta_i, \zeta_j\right\rangle = \delta_{ij}$ it follows that
```math
\begin{aligned}
\frac{dz_0}{dt} &= \left \langle f\left(\sum_{i=0}^L z_i(t) \zeta_i(p), p, t \right), \sum_{i=0}^L z_i(0) \zeta_i(p), \zeta_0(p) \right\rangle\\
& \vdots\\
\frac{dz_L}{dt} &= \left \langle f\left(\sum_{i=0}^L z_i(t) \zeta_i(p), p, t \right), \sum_{i=0}^L z_i(0) \zeta_i(p), \zeta_L(p) \right\rangle
\end{aligned}
```
with initial condition
```math
\begin{aligned}
z_i(0) = \left\langle x_0, \zeta_i \right\rangle.
\end{aligned}
```
These equations are referred to as the moment equations and can in principle be solved with any suitable IVP solution technique.

## Example
In this section, we will showcase how `ModelOrderReduction.jl` may be used to apply PCE for the approximate solution of random ODEs as described in the previous section. To that end, we will consider a simple nonlinear reactor in which the following reaction occurs
```math
\begin{aligned}
&A + B \xleftrightharpoons[k_1(1-\frac{\theta_1}{2})]{k_2} C\\
&C \xrightarrow{k_3(1-\frac{\theta_2}{2})} D\\
&B \xrightarrow{k_4} D
\end{aligned}
```
where the rate parameters $\theta_1 \sim U[-1,1]$, $\theta_2 \sim U[-1,1]$ are uncertain. Using [ModelingToolkit.jl]{github.com/SciML/ModelingToolkit.jl} the following code creates the associated model.
```
using ModelOrderReduction, ModelingToolkit, DifferentialEquations, PolyChaos, Plots

@parameters k[1:4], θ[1:2]
@variables t, c(t)[1:4]
D = Differential(t)
reactor = [D(c[1]) ~ -k[1]*(1+0.5*θ[1])*c[1]*c[2] + k[2]*c[3];
D(c[2]) ~ -k[1]*(1+0.5*θ[1])*c[1]*c[2] - k[4]*c[2] + k[2]*c[3];
D(c[3]) ~ k[1]*c[1]*c[2] - k[3]*c[3];
D(c[4]) ~ k[3]*(1+0.5*θ[2])*c[3] + k[4]*c[2]];

@named reactor_model = ODESystem(reactor, t, c, vcat(k, θ))
```

Next, we are going to define the PCE Ansatz with the help of which we are going to approximate the parametric solution. To that end, we heavily rely on [PolyChaos.jl]{github.com/SciML/PolyChaos.jl}. In this example, we choose a PCE of degree 3.
```
d_pce = 3
pce = PCE(c, [θ[i] => Uniform_11OrthoPoly(d_pce) for i in eachindex(θ)])
```

Next, we are constructing the corresponding moment equations via a simple function call of `moment_equations`. This function returns an `ModelingToolkit.ODESystem` describing the deterministic evolution equation of the PCE moments and a function that maps the state of this model via the PCE Ansatz back to the original model state (in this example, the concentration of the different species).
```
moment_eqs, pce_eval = moment_equations(reactor_model, pce)
```

Next, we are solving the evolution equation for the PCE moments. The initial condition for the moments is also obtained via Galerkin projection onto the space spanned by the basis functions in the PCE Ansatz.
```
c0 = [1.0, 2.0, 0.0, 0.0]
z0 = reduce(vcat, pce_galerkin(c0, pce))
moment_prob = ODEProblem(moment_eqs, z0, (0.0, 10.0), [k[1] => 1.0, k[2] => 0.2, k[3] => 12, k[4] => 0.1])
moment_sol = solve(moment_prob, Tsit5())
```

Lastly, we wish to demonstrate that this approximation can be remarkably accurate in practice. The figure below shows the PCE approximation (dashed black lines) compared to the full model for several realization of the uncertain paramters.

![traces](traces.png)

While PCE can even provide a good parametric surrogate model of the true solution of the random ODE, it is really designed to capture the statistics of the solution of the random ODE well. Moreover, any statistics that can be computed in terms of the moments of the states of the random ODE are remarkably cheap to compute from the PCE coefficients/moments alone. The figures below shows an example for the mean and variances of the different species.


![mean](mean.png)
![var](var.png)



## References
Gautschi, Walter. Orthogonal polynomials: computation and approximation. OUP Oxford, 2004.
Binary file added examples/PCE/var.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
3 changes: 0 additions & 3 deletions src/DataReduction/POD.jl
Original file line number Diff line number Diff line change
@@ -1,6 +1,3 @@
using TSVD: tsvd
using RandomizedLinAlg: rsvd

function matricize(VoV::Vector{Vector{T}}) where {T}
reduce(hcat, VoV)
end
Expand Down
22 changes: 15 additions & 7 deletions src/ModelOrderReduction.jl
Original file line number Diff line number Diff line change
@@ -1,23 +1,31 @@
module ModelOrderReduction

using Combinatorics: powerset, combinations
using DocStringExtensions

using Symbolics
using ModelingToolkit
using LinearAlgebra

using ModelingToolkit
using PolyChaos
using RandomizedLinAlg: rsvd
using Setfield
using SparseArrays
using Symbolics
using TSVD: tsvd

include("utils.jl")

include("Types.jl")
include("ErrorHandle.jl")

include("DataReduction/POD.jl")
export SVD, TSVD, RSVD
export POD, reduce!
export POD, reduce!, matricize

using Setfield
include("deim.jl")
export deim

include("pce/pce.jl")
export PCE
include("pce/pce_metadata.jl")
include("pce/stochastic_galerkin.jl")
export stochastic_galerkin

end
Loading