Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
trixi-framework
GitHub Repository: trixi-framework/Trixi.jl
Path: blob/main/src/semidiscretization/semidiscretization_hyperbolic.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
SemidiscretizationHyperbolic
10
11
A struct containing everything needed to describe a spatial semidiscretization
12
of a hyperbolic conservation law.
13
"""
14
mutable struct SemidiscretizationHyperbolic{Mesh, Equations, InitialCondition,
15
BoundaryConditions,
16
SourceTerms, Solver, Cache} <:
17
AbstractSemidiscretization
18
mesh::Mesh
19
equations::Equations
20
21
# This guy is a bit messy since we abuse it as some kind of "exact solution"
22
# although this doesn't really exist...
23
const initial_condition::InitialCondition
24
25
const boundary_conditions::BoundaryConditions
26
const source_terms::SourceTerms
27
const solver::Solver
28
cache::Cache
29
performance_counter::PerformanceCounter
30
end
31
# We assume some properties of the fields of the semidiscretization, e.g.,
32
# the `equations` and the `mesh` should have the same dimension. We check these
33
# properties in the outer constructor defined below. While we could ensure
34
# them even better in an inner constructor, we do not use this approach to
35
# simplify the integration with Adapt.jl for GPU usage, see
36
# https://github.com/trixi-framework/Trixi.jl/pull/2677#issuecomment-3591789921
37
38
"""
39
SemidiscretizationHyperbolic(mesh, equations, initial_condition, solver;
40
source_terms=nothing,
41
boundary_conditions,
42
RealT=real(solver),
43
uEltype=RealT)
44
45
Construct a semidiscretization of a hyperbolic PDE.
46
47
Boundary conditions must be provided explicitly either as a `NamedTuple` or as a
48
single boundary condition that gets applied to all boundaries.
49
"""
50
function SemidiscretizationHyperbolic(mesh, equations, initial_condition, solver;
51
source_terms = nothing,
52
boundary_conditions,
53
# `RealT` is used as real type for node locations etc.
54
# while `uEltype` is used as element type of solutions etc.
55
RealT = real(solver), uEltype = RealT)
56
@assert ndims(mesh) == ndims(equations)
57
58
cache = create_cache(mesh, equations, solver, RealT, uEltype)
59
_boundary_conditions = digest_boundary_conditions(boundary_conditions, mesh, solver,
60
cache)
61
62
check_periodicity_mesh_boundary_conditions(mesh, _boundary_conditions)
63
64
performance_counter = PerformanceCounter()
65
66
return SemidiscretizationHyperbolic{typeof(mesh), typeof(equations),
67
typeof(initial_condition),
68
typeof(_boundary_conditions),
69
typeof(source_terms),
70
typeof(solver), typeof(cache)}(mesh, equations,
71
initial_condition,
72
_boundary_conditions,
73
source_terms,
74
solver, cache,
75
performance_counter)
76
end
77
78
# @eval due to @muladd
79
@eval Adapt.@adapt_structure(SemidiscretizationHyperbolic)
80
81
# Create a new semidiscretization but change some parameters compared to the input.
82
# `Base.similar` follows a related concept but would require us to `copy` the `mesh`,
83
# which would impact the performance. Instead, `SciMLBase.remake` has exactly the
84
# semantics we want to use here. In particular, it allows us to re-use mutable parts,
85
# e.g. `remake(semi).mesh === semi.mesh`.
86
function remake(semi::SemidiscretizationHyperbolic; uEltype = real(semi.solver),
87
mesh = semi.mesh,
88
equations = semi.equations,
89
initial_condition = semi.initial_condition,
90
solver = semi.solver,
91
source_terms = semi.source_terms,
92
boundary_conditions = semi.boundary_conditions)
93
# TODO: Which parts do we want to `remake`? At least the solver needs some
94
# special care if shock-capturing volume integrals are used (because of
95
# the indicators and their own caches...).
96
return SemidiscretizationHyperbolic(mesh, equations, initial_condition, solver;
97
source_terms, boundary_conditions, uEltype)
98
end
99
100
# general fallback
101
function digest_boundary_conditions(boundary_conditions, mesh, solver, cache)
102
return boundary_conditions
103
end
104
105
# general fallback
106
function digest_boundary_conditions(boundary_conditions::BoundaryConditionPeriodic,
107
mesh, solver, cache)
108
return boundary_conditions
109
end
110
111
# resolve ambiguities with definitions below
112
function digest_boundary_conditions(boundary_conditions::BoundaryConditionPeriodic,
113
mesh::Union{TreeMesh{1}, StructuredMesh{1}}, solver,
114
cache)
115
return boundary_conditions
116
end
117
118
function digest_boundary_conditions(boundary_conditions::BoundaryConditionPeriodic,
119
mesh::Union{TreeMesh{2}, StructuredMesh{2}},
120
solver, cache)
121
return boundary_conditions
122
end
123
124
function digest_boundary_conditions(boundary_conditions::BoundaryConditionPeriodic,
125
mesh::Union{TreeMesh{3}, StructuredMesh{3}},
126
solver, cache)
127
return boundary_conditions
128
end
129
130
function digest_boundary_conditions(boundary_conditions::BoundaryConditionPeriodic,
131
mesh::Union{P4estMesh{2}, UnstructuredMesh2D,
132
T8codeMesh{2}},
133
solver, cache)
134
return boundary_conditions
135
end
136
137
function digest_boundary_conditions(boundary_conditions::BoundaryConditionPeriodic,
138
mesh::Union{P4estMesh{3}, T8codeMesh{3}},
139
solver, cache)
140
return boundary_conditions
141
end
142
143
# allow passing a single BC that get converted into a tuple of BCs
144
# on (mapped) hypercube domains
145
function digest_boundary_conditions(boundary_conditions,
146
mesh::Union{TreeMesh{1}, StructuredMesh{1}}, solver,
147
cache)
148
return (; x_neg = boundary_conditions, x_pos = boundary_conditions)
149
end
150
151
function digest_boundary_conditions(boundary_conditions,
152
mesh::Union{TreeMesh{2}, StructuredMesh{2}}, solver,
153
cache)
154
return (; x_neg = boundary_conditions, x_pos = boundary_conditions,
155
y_neg = boundary_conditions, y_pos = boundary_conditions)
156
end
157
158
function digest_boundary_conditions(boundary_conditions,
159
mesh::Union{TreeMesh{3}, StructuredMesh{3}}, solver,
160
cache)
161
return (; x_neg = boundary_conditions, x_pos = boundary_conditions,
162
y_neg = boundary_conditions, y_pos = boundary_conditions,
163
z_neg = boundary_conditions, z_pos = boundary_conditions)
164
end
165
166
# allow passing named tuples of BCs constructed in an arbitrary order
167
# on (mapped) hypercube domains
168
function digest_boundary_conditions(boundary_conditions::NamedTuple{Keys, ValueTypes},
169
mesh::Union{TreeMesh{1}, StructuredMesh{1}}, solver,
170
cache) where {Keys, ValueTypes <: NTuple{2, Any}}
171
@unpack x_neg, x_pos = boundary_conditions
172
return (; x_neg, x_pos)
173
end
174
175
function digest_boundary_conditions(boundary_conditions::NamedTuple{Keys, ValueTypes},
176
mesh::Union{TreeMesh{2}, StructuredMesh{2}}, solver,
177
cache) where {Keys, ValueTypes <: NTuple{4, Any}}
178
@unpack x_neg, x_pos, y_neg, y_pos = boundary_conditions
179
return (; x_neg, x_pos, y_neg, y_pos)
180
end
181
182
function digest_boundary_conditions(boundary_conditions::NamedTuple{Keys, ValueTypes},
183
mesh::Union{TreeMesh{3}, StructuredMesh{3}}, solver,
184
cache) where {Keys, ValueTypes <: NTuple{6, Any}}
185
@unpack x_neg, x_pos, y_neg, y_pos, z_neg, z_pos = boundary_conditions
186
return (; x_neg, x_pos, y_neg, y_pos, z_neg, z_pos)
187
end
188
189
# If a NamedTuple is passed with not the same number of BCs, ensure that the keys are correct.
190
# For periodic boundary parts, the keys can be missing and get filled with `boundary_condition_periodic`.
191
function digest_boundary_conditions(boundary_conditions::NamedTuple,
192
mesh::Union{TreeMesh{1}, StructuredMesh{1}}, solver,
193
cache)
194
x_neg, x_pos = get_periodicity_boundary_conditions_x(boundary_conditions, mesh)
195
return (; x_neg, x_pos)
196
end
197
198
function digest_boundary_conditions(boundary_conditions::NamedTuple,
199
mesh::Union{TreeMesh{2}, StructuredMesh{2}}, solver,
200
cache)
201
x_neg, x_pos = get_periodicity_boundary_conditions_x(boundary_conditions, mesh)
202
y_neg, y_pos = get_periodicity_boundary_conditions_y(boundary_conditions, mesh)
203
return (; x_neg, x_pos, y_neg, y_pos)
204
end
205
206
function digest_boundary_conditions(boundary_conditions::NamedTuple,
207
mesh::Union{TreeMesh{3}, StructuredMesh{3}}, solver,
208
cache)
209
x_neg, x_pos = get_periodicity_boundary_conditions_x(boundary_conditions, mesh)
210
y_neg, y_pos = get_periodicity_boundary_conditions_y(boundary_conditions, mesh)
211
z_neg, z_pos = get_periodicity_boundary_conditions_z(boundary_conditions, mesh)
212
return (; x_neg, x_pos, y_neg, y_pos, z_neg, z_pos)
213
end
214
215
# Allow NamedTuple for P4estMesh, UnstructuredMesh2D, and T8codeMesh
216
# define in two functions to resolve ambiguities
217
function digest_boundary_conditions(boundary_conditions::NamedTuple,
218
mesh::Union{P4estMesh{2}, P4estMeshView{2},
219
UnstructuredMesh2D,
220
T8codeMesh{2}},
221
solver, cache)
222
return UnstructuredSortedBoundaryTypes(boundary_conditions, cache)
223
end
224
225
function digest_boundary_conditions(boundary_conditions::NamedTuple,
226
mesh::Union{P4estMesh{3}, T8codeMesh{3}},
227
solver, cache)
228
return UnstructuredSortedBoundaryTypes(boundary_conditions, cache)
229
end
230
231
function digest_boundary_conditions(boundary_conditions::UnstructuredSortedBoundaryTypes,
232
mesh::Union{P4estMesh{2}, P4estMeshView{2},
233
UnstructuredMesh2D,
234
T8codeMesh{2}},
235
solver, cache)
236
return boundary_conditions
237
end
238
239
function digest_boundary_conditions(boundary_conditions::UnstructuredSortedBoundaryTypes,
240
mesh::Union{P4estMesh{3}, T8codeMesh{3}},
241
solver, cache)
242
return boundary_conditions
243
end
244
245
# allow passing a single BC that get converted into a named tuple of BCs
246
# on (mapped) hypercube domains
247
function digest_boundary_conditions(boundary_conditions,
248
mesh::Union{P4estMesh{2}, P4estMeshView{2},
249
UnstructuredMesh2D,
250
T8codeMesh{2}},
251
solver, cache)
252
bcs = (; x_neg = boundary_conditions, x_pos = boundary_conditions,
253
y_neg = boundary_conditions, y_pos = boundary_conditions)
254
return UnstructuredSortedBoundaryTypes(bcs, cache)
255
end
256
257
function digest_boundary_conditions(boundary_conditions,
258
mesh::Union{P4estMesh{3}, T8codeMesh{3}},
259
solver, cache)
260
bcs = (; x_neg = boundary_conditions, x_pos = boundary_conditions,
261
y_neg = boundary_conditions, y_pos = boundary_conditions,
262
z_neg = boundary_conditions, z_pos = boundary_conditions)
263
return UnstructuredSortedBoundaryTypes(bcs, cache)
264
end
265
266
# add methods for every dimension to resolve ambiguities
267
function digest_boundary_conditions(boundary_conditions::AbstractArray,
268
mesh::Union{TreeMesh{1}, StructuredMesh{1}},
269
solver, cache)
270
throw(ArgumentError("Please use a named tuple instead of an (abstract) array to supply multiple boundary conditions (to improve performance)."))
271
end
272
273
function digest_boundary_conditions(boundary_conditions::AbstractArray,
274
mesh::Union{TreeMesh{2}, StructuredMesh{2}},
275
solver, cache)
276
throw(ArgumentError("Please use a named tuple instead of an (abstract) array to supply multiple boundary conditions (to improve performance)."))
277
end
278
279
function digest_boundary_conditions(boundary_conditions::AbstractArray,
280
mesh::Union{TreeMesh{3}, StructuredMesh{3}},
281
solver, cache)
282
throw(ArgumentError("Please use a named tuple instead of an (abstract) array to supply multiple boundary conditions (to improve performance)."))
283
end
284
285
function digest_boundary_conditions(boundary_conditions::Tuple,
286
mesh::Union{TreeMesh{1}, StructuredMesh{1}},
287
solver, cache)
288
throw(ArgumentError("Please use a named tuple instead of a tuple to supply multiple boundary conditions."))
289
end
290
291
function digest_boundary_conditions(boundary_conditions::Tuple,
292
mesh::Union{TreeMesh{2}, StructuredMesh{2}},
293
solver, cache)
294
throw(ArgumentError("Please use a named tuple instead of a tuple to supply multiple boundary conditions."))
295
end
296
297
function digest_boundary_conditions(boundary_conditions::Tuple,
298
mesh::Union{TreeMesh{3}, StructuredMesh{3}},
299
solver, cache)
300
throw(ArgumentError("Please use a named tuple instead of a tuple to supply multiple boundary conditions."))
301
end
302
303
function get_periodicity_boundary_conditions_x(boundary_conditions, mesh)
304
if isperiodic(mesh, 1)
305
if :x_neg in keys(boundary_conditions) &&
306
boundary_conditions.x_neg != boundary_condition_periodic ||
307
:x_pos in keys(boundary_conditions) &&
308
boundary_conditions.x_pos != boundary_condition_periodic
309
throw(ArgumentError("For periodic mesh non-periodic boundary conditions in x-direction are supplied."))
310
end
311
x_neg = x_pos = boundary_condition_periodic
312
else
313
required = (:x_neg, :x_pos)
314
if !all(in(keys(boundary_conditions)), required)
315
throw(ArgumentError("NamedTuple of boundary conditions for 1-dimensional (non-periodic) mesh must have keys $(required), got $(keys(boundary_conditions))"))
316
end
317
@unpack x_neg, x_pos = boundary_conditions
318
end
319
return x_neg, x_pos
320
end
321
322
function get_periodicity_boundary_conditions_y(boundary_conditions, mesh)
323
if isperiodic(mesh, 2)
324
if :y_neg in keys(boundary_conditions) &&
325
boundary_conditions.y_neg != boundary_condition_periodic ||
326
:y_pos in keys(boundary_conditions) &&
327
boundary_conditions.y_pos != boundary_condition_periodic
328
throw(ArgumentError("For periodic mesh non-periodic boundary conditions in y-direction are supplied."))
329
end
330
y_neg = y_pos = boundary_condition_periodic
331
else
332
required = (:y_neg, :y_pos)
333
if !all(in(keys(boundary_conditions)), required)
334
throw(ArgumentError("NamedTuple of boundary conditions for 2-dimensional (non-periodic) mesh must have keys $(required), got $(keys(boundary_conditions))"))
335
end
336
@unpack y_neg, y_pos = boundary_conditions
337
end
338
return y_neg, y_pos
339
end
340
341
function get_periodicity_boundary_conditions_z(boundary_conditions, mesh)
342
if isperiodic(mesh, 3)
343
if :z_neg in keys(boundary_conditions) &&
344
boundary_conditions.z_neg != boundary_condition_periodic ||
345
:z_pos in keys(boundary_conditions) &&
346
boundary_conditions.z_pos != boundary_condition_periodic
347
throw(ArgumentError("For periodic mesh non-periodic boundary conditions in z-direction are supplied."))
348
end
349
z_neg = z_pos = boundary_condition_periodic
350
else
351
required = (:z_neg, :z_pos)
352
if !all(in(keys(boundary_conditions)), required)
353
throw(ArgumentError("NamedTuple of boundary conditions for 3-dimensional (non-periodic) mesh must have keys $(required), got $(keys(boundary_conditions))"))
354
end
355
@unpack z_neg, z_pos = boundary_conditions
356
end
357
return z_neg, z_pos
358
end
359
360
# No checks for these meshes yet available
361
function check_periodicity_mesh_boundary_conditions(mesh::Union{P4estMesh,
362
P4estMeshView,
363
UnstructuredMesh2D,
364
T8codeMesh,
365
DGMultiMesh},
366
boundary_conditions)
367
return nothing
368
end
369
370
function check_periodicity_mesh_boundary_conditions(mesh::Union{TreeMesh,
371
StructuredMesh,
372
StructuredMeshView},
373
boundary_conditions::BoundaryConditionPeriodic)
374
if !isperiodic(mesh)
375
throw(ArgumentError("Periodic boundary condition supplied for non-periodic mesh."))
376
end
377
return nothing
378
end
379
380
function check_periodicity_mesh_boundary_conditions_x(mesh, x_neg, x_pos)
381
if isperiodic(mesh, 1) &&
382
(x_neg != boundary_condition_periodic ||
383
x_pos != boundary_condition_periodic)
384
throw(ArgumentError("For periodic mesh non-periodic boundary conditions in x-direction are supplied."))
385
end
386
if !isperiodic(mesh, 1) &&
387
(x_neg == boundary_condition_periodic ||
388
x_pos == boundary_condition_periodic)
389
throw(ArgumentError("For non-periodic mesh periodic boundary conditions in x-direction are supplied."))
390
end
391
return nothing
392
end
393
394
function check_periodicity_mesh_boundary_conditions_y(mesh, y_neg, y_pos)
395
if isperiodic(mesh, 2) &&
396
(y_neg != boundary_condition_periodic ||
397
y_pos != boundary_condition_periodic)
398
throw(ArgumentError("For periodic mesh non-periodic boundary conditions in y-direction are supplied."))
399
end
400
if !isperiodic(mesh, 2) &&
401
(y_neg == boundary_condition_periodic ||
402
y_pos == boundary_condition_periodic)
403
throw(ArgumentError("For non-periodic mesh periodic boundary conditions in y-direction are supplied."))
404
end
405
return nothing
406
end
407
408
function check_periodicity_mesh_boundary_conditions_z(mesh, z_neg, z_pos)
409
if isperiodic(mesh, 3) &&
410
(z_neg != boundary_condition_periodic ||
411
z_pos != boundary_condition_periodic)
412
throw(ArgumentError("For periodic mesh non-periodic boundary conditions in z-direction are supplied."))
413
end
414
if !isperiodic(mesh, 3) &&
415
(z_neg == boundary_condition_periodic ||
416
z_pos == boundary_condition_periodic)
417
throw(ArgumentError("For non-periodic mesh periodic boundary conditions in z-direction are supplied."))
418
end
419
return nothing
420
end
421
422
function check_periodicity_mesh_boundary_conditions(mesh::Union{TreeMesh{1},
423
StructuredMesh{1}},
424
boundary_conditions::NamedTuple)
425
return check_periodicity_mesh_boundary_conditions_x(mesh, boundary_conditions.x_neg,
426
boundary_conditions.x_pos)
427
end
428
429
function check_periodicity_mesh_boundary_conditions(mesh::Union{TreeMesh{2},
430
StructuredMesh{2},
431
StructuredMeshView{2}},
432
boundary_conditions::NamedTuple)
433
check_periodicity_mesh_boundary_conditions_x(mesh, boundary_conditions.x_neg,
434
boundary_conditions.x_pos)
435
return check_periodicity_mesh_boundary_conditions_y(mesh, boundary_conditions.y_neg,
436
boundary_conditions.y_pos)
437
end
438
439
function check_periodicity_mesh_boundary_conditions(mesh::Union{TreeMesh{3},
440
StructuredMesh{3}},
441
boundary_conditions::NamedTuple)
442
check_periodicity_mesh_boundary_conditions_x(mesh, boundary_conditions.x_neg,
443
boundary_conditions.x_pos)
444
check_periodicity_mesh_boundary_conditions_y(mesh, boundary_conditions.y_neg,
445
boundary_conditions.y_pos)
446
return check_periodicity_mesh_boundary_conditions_z(mesh, boundary_conditions.z_neg,
447
boundary_conditions.z_pos)
448
end
449
450
function Base.show(io::IO, semi::SemidiscretizationHyperbolic)
451
@nospecialize semi # reduce precompilation time
452
453
print(io, "SemidiscretizationHyperbolic(")
454
print(io, semi.mesh)
455
print(io, ", ", semi.equations)
456
print(io, ", ", semi.initial_condition)
457
print(io, ", ", semi.boundary_conditions)
458
print(io, ", ", semi.source_terms)
459
print(io, ", ", semi.solver)
460
print(io, ", cache(")
461
for (idx, key) in enumerate(keys(semi.cache))
462
idx > 1 && print(io, " ")
463
print(io, key)
464
end
465
print(io, "))")
466
return nothing
467
end
468
469
function Base.show(io::IO, ::MIME"text/plain", semi::SemidiscretizationHyperbolic)
470
@nospecialize semi # reduce precompilation time
471
472
if get(io, :compact, false)
473
show(io, semi)
474
else
475
summary_header(io, "SemidiscretizationHyperbolic")
476
summary_line(io, "#spatial dimensions", ndims(semi.equations))
477
summary_line(io, "mesh", semi.mesh)
478
summary_line(io, "equations", semi.equations |> typeof |> nameof)
479
summary_line(io, "initial condition", semi.initial_condition)
480
481
print_boundary_conditions(io, semi)
482
483
summary_line(io, "source terms", semi.source_terms)
484
summary_line(io, "solver", semi.solver |> typeof |> nameof)
485
summary_line(io, "total #DOFs per field", ndofsglobal(semi))
486
summary_footer(io)
487
end
488
end
489
490
# type alias for dispatch in printing of boundary conditions
491
#! format: off
492
const SemiHypMeshBCSolver{Mesh, BoundaryConditions, Solver} =
493
SemidiscretizationHyperbolic{Mesh,
494
Equations,
495
InitialCondition,
496
BoundaryConditions,
497
SourceTerms,
498
Solver} where {Equations,
499
InitialCondition,
500
SourceTerms}
501
#! format: on
502
503
# generic fallback: print the type of semi.boundary_condition.
504
function print_boundary_conditions(io, semi::SemiHypMeshBCSolver)
505
return summary_line(io, "boundary conditions", typeof(semi.boundary_conditions))
506
end
507
508
function print_boundary_conditions(io,
509
semi::SemiHypMeshBCSolver{<:Any,
510
<:UnstructuredSortedBoundaryTypes})
511
@unpack boundary_conditions = semi.boundary_conditions
512
summary_line(io, "boundary conditions", length(boundary_conditions))
513
for (boundary_name, boundary_condition) in pairs(boundary_conditions)
514
summary_line(increment_indent(io), boundary_name, typeof(boundary_condition))
515
end
516
end
517
518
function print_boundary_conditions(io, semi::SemiHypMeshBCSolver{<:Any, <:NamedTuple})
519
@unpack boundary_conditions = semi
520
summary_line(io, "boundary conditions", length(boundary_conditions))
521
bc_names = keys(boundary_conditions)
522
for (i, bc_name) in enumerate(bc_names)
523
summary_line(increment_indent(io), String(bc_name),
524
typeof(boundary_conditions[i]))
525
end
526
end
527
528
function print_boundary_conditions(io,
529
semi::SemiHypMeshBCSolver{<:Union{TreeMesh,
530
StructuredMesh},
531
<:Union{NamedTuple,
532
AbstractArray}})
533
summary_line(io, "boundary conditions", 2 * ndims(semi))
534
bcs = semi.boundary_conditions
535
536
summary_line(increment_indent(io), "negative x", bcs.x_neg)
537
summary_line(increment_indent(io), "positive x", bcs.x_pos)
538
if ndims(semi) > 1
539
summary_line(increment_indent(io), "negative y", bcs.y_neg)
540
summary_line(increment_indent(io), "positive y", bcs.y_pos)
541
end
542
if ndims(semi) > 2
543
summary_line(increment_indent(io), "negative z", bcs.z_neg)
544
summary_line(increment_indent(io), "positive z", bcs.z_pos)
545
end
546
end
547
548
@inline Base.ndims(semi::SemidiscretizationHyperbolic) = ndims(semi.mesh)
549
550
@inline nvariables(semi::SemidiscretizationHyperbolic) = nvariables(semi.equations)
551
552
@inline Base.real(semi::SemidiscretizationHyperbolic) = real(semi.solver)
553
554
@inline function mesh_equations_solver_cache(semi::SemidiscretizationHyperbolic)
555
@unpack mesh, equations, solver, cache = semi
556
return mesh, equations, solver, cache
557
end
558
559
function calc_error_norms(func, u_ode, t, analyzer, semi::SemidiscretizationHyperbolic,
560
cache_analysis)
561
@unpack mesh, equations, initial_condition, solver, cache = semi
562
u = wrap_array(u_ode, mesh, equations, solver, cache)
563
564
return calc_error_norms(func, u, t, analyzer, mesh, equations, initial_condition,
565
solver,
566
cache, cache_analysis)
567
end
568
569
function compute_coefficients(t, semi::SemidiscretizationHyperbolic)
570
# Call `compute_coefficients` in `src/semidiscretization/semidiscretization.jl`
571
return compute_coefficients(semi.initial_condition, t, semi)
572
end
573
574
function compute_coefficients!(u_ode, t, semi::SemidiscretizationHyperbolic)
575
return compute_coefficients!(u_ode, semi.initial_condition, t, semi)
576
end
577
578
function rhs!(du_ode, u_ode, semi::SemidiscretizationHyperbolic, t)
579
@unpack mesh, equations, boundary_conditions, source_terms, solver, cache = semi
580
581
u = wrap_array(u_ode, mesh, equations, solver, cache)
582
du = wrap_array(du_ode, mesh, equations, solver, cache)
583
backend = trixi_backend(u)
584
585
# TODO: Taal decide, do we need to pass the mesh?
586
time_start = time_ns()
587
@trixi_timeit_ext backend timer() "rhs!" rhs!(du, u, t, mesh, equations,
588
boundary_conditions, source_terms,
589
solver, cache)
590
runtime = time_ns() - time_start
591
put!(semi.performance_counter, runtime)
592
593
return nothing
594
end
595
end # @muladd
596
597