Skip to content
Open
Show file tree
Hide file tree
Changes from 45 commits
Commits
Show all changes
105 commits
Select commit Hold shift + click to select a range
c364bc4
Use SciMLOperators for IMEX with linear part
DanielDoehring Nov 27, 2025
ebd5b2f
test
DanielDoehring Nov 27, 2025
47dd6a2
bf
DanielDoehring Nov 27, 2025
2b4678b
Merge branch 'main' into MatrixOperatorIMEX
DanielDoehring Nov 27, 2025
d467843
cp
DanielDoehring Nov 27, 2025
9c3ba03
Merge branch 'MatrixOperatorIMEX' of github.com:DanielDoehring/Trixi.…
DanielDoehring Nov 27, 2025
cf59962
compat
DanielDoehring Nov 27, 2025
ecbf0d3
sciml base
DanielDoehring Nov 27, 2025
ac63659
cp
DanielDoehring Nov 27, 2025
7fe1660
cp
DanielDoehring Nov 27, 2025
bac340c
cp
DanielDoehring Nov 27, 2025
61d375f
revert
DanielDoehring Nov 27, 2025
3ef1310
f
DanielDoehring Nov 27, 2025
be88afe
cp
DanielDoehring Nov 27, 2025
83b2dad
cp
DanielDoehring Nov 27, 2025
236c5f8
cp
DanielDoehring Nov 27, 2025
9120892
cp
DanielDoehring Nov 27, 2025
4db9379
cp
DanielDoehring Nov 27, 2025
2ced411
cp
DanielDoehring Nov 27, 2025
006eb6b
Apply suggestions from code review
DanielDoehring Nov 27, 2025
885644f
Update test/Project.toml
DanielDoehring Nov 27, 2025
3897d6c
restrict sciml compact bounds
DanielDoehring Nov 27, 2025
376e451
relieve
DanielDoehring Nov 27, 2025
5bfc670
v
DanielDoehring Nov 27, 2025
66d8cfc
up
DanielDoehring Nov 27, 2025
5da16ce
up
DanielDoehring Nov 27, 2025
33748a3
up
DanielDoehring Nov 27, 2025
585e95d
rev
DanielDoehring Nov 27, 2025
042b1df
1
DanielDoehring Nov 27, 2025
5e1c5e2
cp
DanielDoehring Nov 27, 2025
d41294f
add base explicitly
DanielDoehring Nov 28, 2025
ad10cfd
Update src/semidiscretization/semidiscretization_hyperbolic_parabolic.jl
DanielDoehring Nov 28, 2025
d5cf05c
rev
DanielDoehring Nov 30, 2025
6646b37
rev
DanielDoehring Nov 30, 2025
d92804c
compat
DanielDoehring Nov 30, 2025
02d6fb5
Merge branch 'MatrixOperatorIMEX' of github.com:DanielDoehring/Trixi.…
DanielDoehring Nov 30, 2025
2c78429
Merge branch 'main' into MatrixOperatorIMEX
DanielDoehring Nov 30, 2025
b903d31
rm
DanielDoehring Nov 30, 2025
c3fe575
Merge branch 'MatrixOperatorIMEX' of github.com:DanielDoehring/Trixi.…
DanielDoehring Nov 30, 2025
8917be3
rev
DanielDoehring Nov 30, 2025
5f4d595
cp
DanielDoehring Nov 30, 2025
f391536
rev
DanielDoehring Nov 30, 2025
5392ac1
cp
DanielDoehring Nov 30, 2025
46123e1
up
DanielDoehring Nov 30, 2025
68602a0
Update examples/tree_2d_dgsem/elixir_advection_diffusion_imex_operato…
DanielDoehring Dec 1, 2025
6e0264b
Update examples/tree_2d_dgsem/elixir_advection_diffusion_imex_operato…
DanielDoehring Dec 1, 2025
dfbe22e
Merge branch 'main' into MatrixOperatorIMEX
DanielDoehring Dec 1, 2025
4c10ef5
Merge branch 'main' into MatrixOperatorIMEX
DanielDoehring Dec 2, 2025
d01ac3f
Update test/Project.toml
DanielDoehring Dec 3, 2025
a73c0f1
Merge branch 'main' into MatrixOperatorIMEX
DanielDoehring Dec 3, 2025
446f643
Merge branch 'main' into MatrixOperatorIMEX
DanielDoehring Dec 3, 2025
fb9c973
reduce changes
DanielDoehring Dec 4, 2025
0c2229f
Merge branch 'MatrixOperatorIMEX' of github.com:DanielDoehring/Trixi.…
DanielDoehring Dec 4, 2025
96360a3
try
DanielDoehring Dec 4, 2025
b0f1342
bump rat
DanielDoehring Dec 4, 2025
462d5a8
bump
DanielDoehring Dec 4, 2025
11fa94e
fix
DanielDoehring Dec 4, 2025
ed58b54
bump
DanielDoehring Dec 4, 2025
24a2e43
sbp
DanielDoehring Dec 4, 2025
46c74f4
cb
DanielDoehring Dec 4, 2025
1171f1f
dg
DanielDoehring Dec 4, 2025
6bbd558
hdf5
DanielDoehring Dec 4, 2025
7be2b94
8
DanielDoehring Dec 4, 2025
b9765be
lv
DanielDoehring Dec 4, 2025
69ce7c3
pref
DanielDoehring Dec 4, 2025
94d5c16
up
DanielDoehring Dec 4, 2025
7686ec5
up
DanielDoehring Dec 4, 2025
814bcff
cm
DanielDoehring Dec 4, 2025
107fa72
DS
DanielDoehring Dec 4, 2025
be86246
adt
DanielDoehring Dec 4, 2025
6220f4b
static
DanielDoehring Dec 4, 2025
c03ff9b
mk
DanielDoehring Dec 4, 2025
d92bc16
ka
DanielDoehring Dec 4, 2025
88ecc02
FA
DanielDoehring Dec 4, 2025
60d5531
p
DanielDoehring Dec 4, 2025
4787762
mpi
DanielDoehring Dec 4, 2025
5e873ad
doc
DanielDoehring Dec 4, 2025
dc63b53
Update src/equations/equations_parabolic.jl
DanielDoehring Dec 4, 2025
4a7b9ae
Merge branch 'main' into MatrixOperatorIMEX
DanielDoehring Dec 4, 2025
bee8a9b
Merge branch 'main' into MatrixOperatorIMEX
DanielDoehring Dec 4, 2025
58fa6b4
Merge branch 'main' into MatrixOperatorIMEX
DanielDoehring Dec 4, 2025
30859e0
Merge branch 'main' into MatrixOperatorIMEX
DanielDoehring Dec 6, 2025
3da48f3
Update src/Trixi.jl
DanielDoehring Dec 6, 2025
54e87f3
be precise
DanielDoehring Dec 6, 2025
73fb5fa
rwrite
DanielDoehring Dec 6, 2025
afe59d1
adapt
DanielDoehring Dec 6, 2025
00f525f
Update src/semidiscretization/semidiscretization_hyperbolic_parabolic.jl
DanielDoehring Dec 6, 2025
439e8da
fmt
DanielDoehring Dec 6, 2025
e4dce4a
Merge branch 'MatrixOperatorIMEX' of https://github.com/DanielDoehrin…
DanielDoehring Dec 6, 2025
4c7ca5e
Apply suggestions from code review
DanielDoehring Dec 7, 2025
775db13
revert
DanielDoehring Dec 7, 2025
9036f62
Merge branch 'MatrixOperatorIMEX' of https://github.com/DanielDoehrin…
DanielDoehring Dec 7, 2025
5057d40
Update Project.toml
DanielDoehring Dec 7, 2025
3d6bd2a
Update test/Project.toml
DanielDoehring Dec 7, 2025
6f714e2
core
DanielDoehring Dec 7, 2025
0a71bf4
Merge branch 'MatrixOperatorIMEX' of https://github.com/DanielDoehrin…
DanielDoehring Dec 7, 2025
2d4e9a3
bump
DanielDoehring Dec 7, 2025
0934c06
bump
DanielDoehring Dec 7, 2025
34f904e
base
DanielDoehring Dec 7, 2025
b4eb001
bp
DanielDoehring Dec 7, 2025
8251d4f
up
DanielDoehring Dec 7, 2025
d0ec119
bump
DanielDoehring Dec 7, 2025
7afb8e3
try
DanielDoehring Dec 7, 2025
7f9e250
bump
DanielDoehring Dec 7, 2025
a0b2027
fix
DanielDoehring Dec 7, 2025
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
80 changes: 40 additions & 40 deletions Project.toml
Original file line number Diff line number Diff line change
Expand Up @@ -69,58 +69,58 @@ TrixiNLsolveExt = "NLsolve"
TrixiSparseConnectivityTracerExt = "SparseConnectivityTracer"

[compat]
Accessors = "0.1.36"
Adapt = "4"
CUDA = "5.8"
CodeTracking = "1.0.5, 2, 3"
ConstructionBase = "1.5"
Accessors = "0.1.42"
Adapt = "4.4"
CUDA = "5.9"
CodeTracking = "2.0.2"
ConstructionBase = "1.6"
Convex = "0.16"
DataStructures = "0.18.15, 0.19"
DelimitedFiles = "1"
DiffEqBase = "6.155.2"
DiffEqCallbacks = "2.35, 3, 4"
DataStructures = "0.19.3"
DelimitedFiles = "1.9.1"
DiffEqBase = "6.192"
DiffEqCallbacks = "4.10.1"
Downloads = "1.6"
ECOS = "1.1.2"
EllipsisNotation = "1.0"
FillArrays = "1.9"
ForwardDiff = "0.10.36, 1"
HDF5 = "0.16.10, 0.17"
KernelAbstractions = "0.9.36"
EllipsisNotation = "1.8"
FillArrays = "1.15"
ForwardDiff = "1.3"
HDF5 = "0.17.2"
KernelAbstractions = "0.9.39"
LinearAlgebra = "1"
LinearMaps = "2.7, 3.0"
LoopVectorization = "0.12.171"
MPI = "0.20.6"
Makie = "0.21, 0.22, 0.23, 0.24"
LinearMaps = "3.11.4"
LoopVectorization = "0.12.173"
MPI = "0.20.23"
Makie = "0.24.7"
MuladdMacro = "0.2.4"
NLsolve = "4.5.1"
Octavian = "0.3.28"
OffsetArrays = "1.13"
P4est = "0.4.12"
Polyester = "=0.7.16, 0.7.18"
PrecompileTools = "1.2"
Preferences = "1.4"
Octavian = "0.3.29"
OffsetArrays = "1.17"
P4est = "0.4.13"
Polyester = "0.7.18"
PrecompileTools = "1.2.1"
Preferences = "1.5"
Printf = "1"
RecipesBase = "1.3.4"
RecursiveArrayTools = "3.31.1"
Reexport = "1.2"
Requires = "1.3"
SciMLBase = "2.67.0"
RecursiveArrayTools = "3.39"
Reexport = "1.2.2"
Requires = "1.3.1"
SciMLBase = "2.127"
SimpleUnPack = "1.1"
SparseArrays = "1"
SparseArrays = "1.10"
SparseConnectivityTracer = "1.0.1"
StableRNGs = "1.0.2"
StartUpDG = "1.1.5"
Static = "1.1.1"
StaticArrayInterface = "1.5.1"
StaticArrays = "1.9"
StableRNGs = "1.0.4"
StartUpDG = "1.3.3"
Static = "1.3.1"
StaticArrayInterface = "1.8"
StaticArrays = "1.9.15"
StrideArrays = "0.1.29"
StructArrays = "0.6.20, 0.7"
SummationByPartsOperators = "0.5.52"
StructArrays = "0.7.2"
SummationByPartsOperators = "0.5.86"
T8code = "0.7.4"
TimerOutputs = "0.5.25"
Triangulate = "2.2, 3"
TimerOutputs = "0.5.29"
Triangulate = "3"
TriplotBase = "0.1"
TriplotRecipes = "0.1"
TrixiBase = "0.1.6"
TriplotRecipes = "0.1.2"
TrixiBase = "0.1.8"
UUIDs = "1.6"
julia = "1.10"
74 changes: 74 additions & 0 deletions examples/tree_2d_dgsem/elixir_advection_diffusion_imex_operator.jl
Original file line number Diff line number Diff line change
@@ -0,0 +1,74 @@
using OrdinaryDiffEqSDIRK
using SciMLBase, SciMLOperators, SparseArrays
using Trixi

###############################################################################
# semidiscretization of the linear advection-diffusion equation

advection_velocity = (1.5, 1.0)
equations = LinearScalarAdvectionEquation2D(advection_velocity)
diffusivity() = 5.0e-1
equations_parabolic = LaplaceDiffusion2D(diffusivity(), equations)

solver = DGSEM(polydeg = 3, surface_flux = flux_lax_friedrichs)

coordinates_min = (-1.0, -1.0)
coordinates_max = (1.0, 1.0)

mesh = TreeMesh(coordinates_min, coordinates_max,
initial_refinement_level = 4,
periodicity = true,
n_cells_max = 30_000)

function initial_condition_diffusive_convergence_test(x, t,
equation::LinearScalarAdvectionEquation2D)
# Store translated coordinate for easy use of exact solution
RealT = eltype(x)
x_trans = x - equation.advection_velocity * t

nu = diffusivity()
c = 1
A = 0.5f0
L = 2
f = 1.0f0 / L
omega = 2 * convert(RealT, pi) * f
scalar = c + A * sin(omega * sum(x_trans)) * exp(-2 * nu * omega^2 * t)
return SVector(scalar)
end
initial_condition = initial_condition_diffusive_convergence_test

semi = SemidiscretizationHyperbolicParabolic(mesh,
(equations, equations_parabolic),
initial_condition, solver)

###############################################################################
# ODE setup

tspan = (0.0, 0.5)
ode = semidiscretize(semi, tspan) # For accessing the initial condition u0 only

D_map, _ = linear_structure_parabolic(semi)
# Cannot directly construct `MatrixOperator` from `LinearMap`, need detour via sparse matrix
opD = MatrixOperator(sparse(D_map))

split_func = SplitFunction(opD, Trixi.rhs!)
ode_operator = SplitODEProblem{true}(split_func, ode.u0, tspan, semi)

###############################################################################
# Callbacks

summary_callback = SummaryCallback()

analysis_interval = 1000
analysis_callback = AnalysisCallback(semi, interval = analysis_interval)

alive_callback = AliveCallback(analysis_interval = analysis_interval)

callbacks = CallbackSet(summary_callback, analysis_callback, alive_callback)

###############################################################################
# run the simulation

sol = solve(ode_operator, KenCarp4();
adaptive = false, dt = 1e-2,
ode_default_options()..., callback = callbacks)
2 changes: 1 addition & 1 deletion src/Trixi.jl
Original file line number Diff line number Diff line change
Expand Up @@ -320,7 +320,7 @@ export ode_norm, ode_unstable_check

export convergence_test,
jacobian_fd, jacobian_ad_forward, jacobian_ad_forward_parabolic,
linear_structure
linear_structure, linear_structure_parabolic

export DGMulti, DGMultiBasis, estimate_dt, DGMultiMesh, GaussSBP

Expand Down
4 changes: 3 additions & 1 deletion src/semidiscretization/semidiscretization.jl
Original file line number Diff line number Diff line change
Expand Up @@ -245,7 +245,8 @@ and a vector `b`:
```math
\\partial_t u(t) = A u(t) - b.
```
Works only for linear equations, i.e., equations with `have_constant_speed(equations) == True()`.
Works only for linear equations, i.e.,
equations which `have_constant_speed(equations) == True()`.

This has the benefit of greatly reduced memory consumption compared to constructing
the full system matrix explicitly, as done for instance in
Expand All @@ -268,6 +269,7 @@ function linear_structure(semi::AbstractSemidiscretization;
u_ode .= zero(eltype(u_ode))
rhs!(du_ode, u_ode, semi, t0)
b = -du_ode

# Create a copy of `b` used internally to extract the linear part of `semi`.
# This is necessary to get everything correct when the user updates the
# returned vector `b`.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -388,7 +388,8 @@ and a vector `b`:
```math
\\partial_t u(t) = A u(t) - b.
```
Works only for linear equations, i.e., equations with `have_constant_speed(equations) == True()`.
Works only for linear equations, i.e.,
equations which `have_constant_speed(equations) == True()`.

This has the benefit of greatly reduced memory consumption compared to constructing
the full system matrix explicitly, as done for instance in
Expand Down Expand Up @@ -451,6 +452,70 @@ function _jacobian_ad_forward(semi::SemidiscretizationHyperbolicParabolic, t0, u
return J
end

"""
linear_structure_parabolic(semi::SemidiscretizationHyperbolicParabolic;
t0 = zero(real(semi)))

Wraps the **parabolic part** right-hand side operator of the hyperbolic-parabolic semidiscretization `semi`
at time `t0` as an affine-linear operator given by a linear operator `A`
and a vector `b`:
```math
\\partial_t u(t) = A u(t) - b.
```
Works only for linear parabolic equations, i.e.,
equations which `have_constant_diffusivity(equations_parabolic) == True()`.

This has the benefit of greatly reduced memory consumption compared to constructing
the full system matrix explicitly, as done for instance in
[`jacobian_ad_forward_parabolic`](@ref).

The returned linear operator `A` is a matrix-free representation which can be
supplied to iterative solvers from, e.g., [Krylov.jl](https://github.com/JuliaSmoothOptimizers/Krylov.jl).

It is also possible to use this to construct a sparse matrix without the detour of constructing
first the full Jacobian by calling
```julia
using SparseArrays
A_map, b = linear_structure_parabolic(semi, t0 = t0)
A_sparse = sparse(A_map)
```
which can then be further used to construct for instance a
[`MatrixOperator`](https://docs.sciml.ai/SciMLOperators/stable/tutorials/getting_started/#Simplest-Operator:-MatrixOperator)
from [SciMLOperators.jl](https://docs.sciml.ai/SciMLOperators/stable/).
This is especially useful for IMEX schemes where the parabolic part is implicitly,
and for a `MatrixOperator` only factorized once.
"""
function linear_structure_parabolic(semi::SemidiscretizationHyperbolicParabolic;
t0 = zero(real(semi)))
if have_constant_diffusivity(semi.equations_parabolic) == False()
throw(ArgumentError("`linear_structure_parabolic` expects equations with constant diffusive terms."))
end

# allocate memory
u_ode = allocate_coefficients(mesh_equations_solver_cache(semi)...)
du_ode = similar(u_ode)

# get the parabolic right hand side from boundary conditions and optional source terms
u_ode .= zero(eltype(u_ode))
rhs_parabolic!(du_ode, u_ode, semi, t0)
b = -du_ode

# Create a copy of `b` used internally to extract the linear part of `semi`.
# This is necessary to get everything correct when the user updates the
# returned vector `b`.
b_tmp = copy(b)

# wrap the linear operator
A = LinearMap(length(u_ode), ismutating = true) do dest, src
rhs_parabolic!(dest, src, semi, t0)

@. dest += b_tmp
return dest
end

return A, b
end

"""
jacobian_ad_forward_parabolic(semi::SemidiscretizationHyperbolicParabolic;
t0 = zero(real(semi)),
Expand Down
62 changes: 33 additions & 29 deletions test/Project.toml
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,8 @@ Plots = "91a5bcdd-55d7-5caf-9e0b-520d859cae80"
Printf = "de0858da-6303-5e67-8744-51eddeeeb8d7"
Quadmath = "be4d8f0f-7fa4-5f49-b795-2f01399ab2dd"
Random = "9a3f8284-a2c9-5f02-9a11-845980a1fd5c"
SciMLBase = "0bca4576-84f4-4d90-8ffe-ffa030f20462"
SciMLOperators = "c0aeaf25-5076-4817-a8d5-81caf7dfa961"
SparseArrays = "2f01184e-e22b-5df5-ae63-d93ebab69eaf"
SparseConnectivityTracer = "9f842d2f-2579-4b1d-911e-f412cf18a3f5"
SparseMatrixColorings = "0a514795-09f3-496d-8182-132a7b665d35"
Expand All @@ -38,40 +40,42 @@ Test = "8dfed614-e22c-5e08-85e1-65c5234f0b40"
TrixiTest = "0a316866-cbd0-4425-8bcb-08103b2c1f26"

[compat]
ADTypes = "1.11"
Adapt = "4"
Aqua = "0.8"
CUDA = "5.8"
CairoMakie = "0.12, 0.13, 0.14, 0.15"
ADTypes = "1.20"
Adapt = "4.4"
Aqua = "0.8.14"
CUDA = "5.9"
CairoMakie = "0.15.7"
Convex = "0.16"
DelimitedFiles = "1"
DoubleFloats = "1.4.0"
Downloads = "1"
DelimitedFiles = "1.9.1"
DoubleFloats = "1.5"
Downloads = "1.6"
ECOS = "1.1.2"
ExplicitImports = "1.0.1"
FiniteDiff = "2.27.0"
ForwardDiff = "0.10.36, 1"
Krylov = "0.9.10, 0.10"
ExplicitImports = "1.14"
FiniteDiff = "2.29"
ForwardDiff = "1.3"
Krylov = "0.10.3"
LinearAlgebra = "1"
LinearSolve = "2.36.1, 3"
MPI = "0.20.6"
LinearSolve = "3.48"
MPI = "0.20.23"
NLsolve = "4.5.1"
OrdinaryDiffEqBDF = "1.1"
OrdinaryDiffEqCore = "1.6"
OrdinaryDiffEqFeagin = "1"
OrdinaryDiffEqHighOrderRK = "1.1"
OrdinaryDiffEqLowOrderRK = "1.2"
OrdinaryDiffEqLowStorageRK = "1.2"
OrdinaryDiffEqSDIRK = "1.1"
OrdinaryDiffEqSSPRK = "1.2"
OrdinaryDiffEqTsit5 = "1.1"
Plots = "1.26"
OrdinaryDiffEqBDF = "1.10.1"
OrdinaryDiffEqCore = "1.36"
OrdinaryDiffEqFeagin = "1.4"
OrdinaryDiffEqHighOrderRK = "1.5"
OrdinaryDiffEqLowOrderRK = "1.6"
OrdinaryDiffEqLowStorageRK = "1.7"
OrdinaryDiffEqSDIRK = "1.7"
OrdinaryDiffEqSSPRK = "1.7"
OrdinaryDiffEqTsit5 = "1.5"
Plots = "1.41.2"
Printf = "1"
Quadmath = "0.5.10"
Quadmath = "0.5.13"
Random = "1"
SparseArrays = "1"
SciMLBase = "2.127.0"
SciMLOperators = "1.13.0"
SparseArrays = "1.10"
SparseConnectivityTracer = "1.0.1"
SparseMatrixColorings = "0.4.21"
StableRNGs = "1.0.2"
SparseMatrixColorings = "0.4.23"
StableRNGs = "1.0.4"
Test = "1"
TrixiTest = "0.1.4"
TrixiTest = "0.1.5"
9 changes: 9 additions & 0 deletions test/test_parabolic_2d.jl
Original file line number Diff line number Diff line change
Expand Up @@ -253,6 +253,15 @@ end
@test_allocations(Trixi.rhs!, semi, sol, 1000)
end

@trixi_testset "TreeMesh2D: elixir_advection_diffusion_imex_operator.jl" begin
@test_trixi_include(joinpath(EXAMPLES_DIR, "tree_2d_dgsem",
"elixir_advection_diffusion_imex_operator.jl"),
l2=[7.542670562162156e-8], linf=[3.972014046560446e-7])
# Ensure that we do not have excessive memory allocations
# (e.g., from type instabilities)
@test_allocations(Trixi.rhs!, semi, sol, 1000)
end

@trixi_testset "TreeMesh2D: elixir_advection_diffusion_nonperiodic.jl (LDG)" begin
@test_trixi_include(joinpath(EXAMPLES_DIR, "tree_2d_dgsem",
"elixir_advection_diffusion_nonperiodic.jl"),
Expand Down
Loading