Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
trixi-framework
GitHub Repository: trixi-framework/Trixi.jl
Path: blob/main/src/semidiscretization/semidiscretization_parabolic.jl
5586 views
1
# By default, Julia/LLVM does not use fused multiply-add operations (FMAs).
2
# Since these FMAs can increase the performance of many numerical algorithms,
3
# we need to opt-in explicitly.
4
# See https://ranocha.de/blog/Optimizing_EC_Trixi for further details.
5
@muladd begin
6
#! format: noindent
7
8
"""
9
SemidiscretizationParabolic
10
11
A struct containing everything needed to describe a spatial semidiscretization of a purely
12
parabolic PDE.
13
"""
14
mutable struct SemidiscretizationParabolic{Mesh, Equations, InitialCondition,
15
BoundaryConditions, SourceTerms,
16
Solver, SolverParabolic,
17
Cache, CacheParabolic} <:
18
AbstractSemidiscretization
19
mesh::Mesh
20
equations::Equations
21
22
const initial_condition::InitialCondition
23
24
const boundary_conditions::BoundaryConditions
25
const source_terms::SourceTerms
26
27
const solver::Solver
28
const solver_parabolic::SolverParabolic
29
30
cache::Cache
31
cache_parabolic::CacheParabolic
32
33
performance_counter::PerformanceCounter
34
end
35
36
"""
37
SemidiscretizationParabolic(mesh, equations, initial_condition, solver;
38
solver_parabolic=default_parabolic_solver(),
39
source_terms=nothing,
40
boundary_conditions,
41
RealT=real(solver),
42
uEltype=RealT)
43
44
Construct a semidiscretization of a purely parabolic PDE.
45
46
Boundary conditions must be provided explicitly either as a `NamedTuple` or as a
47
single boundary condition that gets applied to all boundaries.
48
"""
49
function SemidiscretizationParabolic(mesh, equations::AbstractEquationsParabolic,
50
initial_condition, solver;
51
solver_parabolic = default_parabolic_solver(),
52
source_terms = nothing,
53
boundary_conditions,
54
# `RealT` is used as real type for node locations etc.
55
# while `uEltype` is used as element type of solutions etc.
56
RealT = real(solver), uEltype = RealT)
57
@assert ndims(mesh) == ndims(equations)
58
59
cache = create_cache(mesh, equations, solver, RealT, uEltype)
60
_boundary_conditions = digest_boundary_conditions(boundary_conditions, mesh, solver,
61
cache)
62
check_periodicity_mesh_boundary_conditions(mesh, _boundary_conditions)
63
64
cache_parabolic = create_cache_parabolic(mesh, equations, solver,
65
nelements(solver, cache), uEltype)
66
67
performance_counter = PerformanceCounter()
68
69
return SemidiscretizationParabolic{typeof(mesh), typeof(equations),
70
typeof(initial_condition),
71
typeof(_boundary_conditions),
72
typeof(source_terms),
73
typeof(solver),
74
typeof(solver_parabolic),
75
typeof(cache),
76
typeof(cache_parabolic)}(mesh, equations,
77
initial_condition,
78
_boundary_conditions,
79
source_terms,
80
solver,
81
solver_parabolic,
82
cache,
83
cache_parabolic,
84
performance_counter)
85
end
86
87
# @eval due to @muladd
88
@eval Adapt.@adapt_structure(SemidiscretizationParabolic)
89
90
# Create a new semidiscretization but change some parameters compared to the input.
91
function remake(semi::SemidiscretizationParabolic; uEltype = real(semi.solver),
92
mesh = semi.mesh,
93
equations = semi.equations,
94
initial_condition = semi.initial_condition,
95
solver = semi.solver,
96
solver_parabolic = semi.solver_parabolic,
97
source_terms = semi.source_terms,
98
boundary_conditions = semi.boundary_conditions)
99
return SemidiscretizationParabolic(mesh, equations, initial_condition, solver;
100
solver_parabolic = solver_parabolic,
101
source_terms = source_terms,
102
boundary_conditions = boundary_conditions,
103
uEltype = uEltype)
104
end
105
106
function Base.show(io::IO, semi::SemidiscretizationParabolic)
107
@nospecialize semi # reduce precompilation time
108
109
print(io, "SemidiscretizationParabolic(")
110
print(io, semi.mesh)
111
print(io, ", ", semi.equations)
112
print(io, ", ", semi.initial_condition)
113
print(io, ", ", semi.boundary_conditions)
114
print(io, ", ", semi.source_terms)
115
print(io, ", ", semi.solver)
116
print(io, ", ", semi.solver_parabolic)
117
print(io, ", cache(")
118
for (idx, key) in enumerate(keys(semi.cache))
119
idx > 1 && print(io, " ")
120
print(io, key)
121
end
122
print(io, "))")
123
return nothing
124
end
125
126
function Base.show(io::IO, ::MIME"text/plain", semi::SemidiscretizationParabolic)
127
@nospecialize semi # reduce precompilation time
128
129
if get(io, :compact, false)
130
show(io, semi)
131
else
132
summary_header(io, "SemidiscretizationParabolic")
133
summary_line(io, "#spatial dimensions", ndims(semi.equations))
134
summary_line(io, "mesh", semi.mesh)
135
summary_line(io, "equations", semi.equations |> typeof |> nameof)
136
summary_line(io, "initial condition", semi.initial_condition)
137
summary_line(io, "source terms", semi.source_terms)
138
summary_line(io, "solver", semi.solver |> typeof |> nameof)
139
summary_line(io, "parabolic solver", semi.solver_parabolic |> typeof |> nameof)
140
summary_line(io, "total #DOFs per field", ndofsglobal(semi))
141
summary_footer(io)
142
end
143
end
144
145
@inline Base.ndims(semi::SemidiscretizationParabolic) = ndims(semi.mesh)
146
147
@inline function nvariables(semi::SemidiscretizationParabolic)
148
return nvariables(semi.equations)
149
end
150
151
@inline Base.real(semi::SemidiscretizationParabolic) = real(semi.solver)
152
153
@inline function mesh_equations_solver_cache(semi::SemidiscretizationParabolic)
154
@unpack mesh, equations, solver, cache = semi
155
return mesh, equations, solver, cache
156
end
157
158
function calc_error_norms(func, u_ode, t, analyzer,
159
semi::SemidiscretizationParabolic, cache_analysis)
160
@unpack mesh, equations, initial_condition, solver, cache = semi
161
u = wrap_array(u_ode, mesh, equations, solver, cache)
162
163
return calc_error_norms(func, u, t, analyzer, mesh, equations, initial_condition,
164
solver, cache, cache_analysis)
165
end
166
167
function compute_coefficients(t, semi::SemidiscretizationParabolic)
168
return compute_coefficients(semi.initial_condition, t, semi)
169
end
170
171
function compute_coefficients!(u_ode, t, semi::SemidiscretizationParabolic)
172
return compute_coefficients!(u_ode, semi.initial_condition, t, semi)
173
end
174
175
# Required for storing `extra_node_variables` in the `SaveSolutionCallback`.
176
# Not to be confused with `get_node_vars` which returns the variables of the simulated equation.
177
function get_node_variables!(node_variables, u_ode,
178
semi::SemidiscretizationParabolic)
179
return get_node_variables!(node_variables, u_ode,
180
mesh_equations_solver_cache(semi)...,
181
semi.cache_parabolic)
182
end
183
184
"""
185
linear_structure(semi::SemidiscretizationParabolic;
186
t0 = zero(real(semi)))
187
188
Wraps the right-hand side operator of the parabolic semidiscretization `semi`
189
at time `t0` as an affine-linear operator given by a linear operator `A`
190
and a vector `b`:
191
```math
192
\\partial_t u(t) = A u(t) - b.
193
```
194
Works only for equations for which `have_constant_diffusivity(equations) == True()`.
195
As in [`linear_structure(semi::AbstractSemidiscretization)`](@ref), returns `A` and `b`,
196
with `A` represented as a matrix-free `LinearMap`.
197
"""
198
function linear_structure(semi::SemidiscretizationParabolic;
199
t0 = zero(real(semi)))
200
if have_constant_diffusivity(semi.equations) == False()
201
throw(ArgumentError("`linear_structure` expects equations with constant diffusive terms."))
202
end
203
204
apply_rhs! = function (dest, src)
205
return rhs_parabolic!(dest, src, semi, t0)
206
end
207
208
return _linear_structure_from_rhs(semi, apply_rhs!)
209
end
210
211
# For a purely parabolic semidiscretization, the right-hand side is `rhs_parabolic!`
212
# instead of the default `rhs!`.
213
@inline default_rhs(::SemidiscretizationParabolic) = rhs_parabolic!
214
215
function rhs_parabolic!(du_ode, u_ode, semi::SemidiscretizationParabolic, t)
216
@unpack mesh, equations, boundary_conditions, source_terms, solver, solver_parabolic, cache, cache_parabolic = semi
217
218
u = wrap_array(u_ode, mesh, equations, solver, cache)
219
du = wrap_array(du_ode, mesh, equations, solver, cache)
220
backend = trixi_backend(u)
221
222
time_start = time_ns()
223
@trixi_timeit_ext backend timer() "parabolic rhs!" rhs_parabolic!(du, u, t, mesh,
224
equations,
225
boundary_conditions,
226
source_terms,
227
solver,
228
solver_parabolic,
229
cache,
230
cache_parabolic)
231
runtime = time_ns() - time_start
232
put!(semi.performance_counter, runtime)
233
234
return nothing
235
end
236
end # @muladd
237
238