Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
trixi-framework
GitHub Repository: trixi-framework/Trixi.jl
Path: blob/main/src/solvers/dgsem/l2projection.jl
5591 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
# This diagram shows what is meant by "lower", "upper", and "large":
9
# +1 +1
10
# | |
11
# upper | |
12
# | |
13
# -1 |
14
# | large
15
# +1 |
16
# | |
17
# lower | |
18
# | |
19
# -1 -1
20
#
21
# That is, we are only concerned with 2:1 subdivision of a surface/element.
22
23
# Calculate forward projection matrix for discrete L2 projection from large to upper
24
#
25
# Note: This is actually an interpolation.
26
function calc_forward_upper(n_nodes, RealT = Float64)
27
# Calculate nodes, weights, and barycentric weights
28
nodes, _ = gauss_lobatto_nodes_weights(n_nodes, RealT)
29
wbary = barycentric_weights(nodes)
30
31
# Calculate projection matrix (actually: interpolation)
32
operator = zeros(RealT, n_nodes, n_nodes)
33
for j in 1:n_nodes
34
poly = lagrange_interpolating_polynomials(0.5f0 * (nodes[j] + 1), nodes, wbary)
35
for i in 1:n_nodes
36
operator[j, i] = poly[i]
37
end
38
end
39
40
return operator
41
end
42
43
# Calculate forward projection matrix for discrete L2 projection from large to lower
44
#
45
# Note: This is actually an interpolation.
46
function calc_forward_lower(n_nodes, RealT = Float64)
47
# Calculate nodes, weights, and barycentric weights
48
nodes, _ = gauss_lobatto_nodes_weights(n_nodes, RealT)
49
wbary = barycentric_weights(nodes)
50
51
# Calculate projection matrix (actually: interpolation)
52
operator = zeros(RealT, n_nodes, n_nodes)
53
for j in 1:n_nodes
54
poly = lagrange_interpolating_polynomials(0.5f0 * (nodes[j] - 1), nodes, wbary)
55
for i in 1:n_nodes
56
operator[j, i] = poly[i]
57
end
58
end
59
60
return operator
61
end
62
63
# Calculate reverse projection matrix for discrete L2 projection from upper to large (Gauss version)
64
#
65
# Note: To not make the L2 projection exact, first convert to Gauss nodes,
66
# perform projection, and convert back to Gauss-Lobatto.
67
function calc_reverse_upper(n_nodes, ::Val{:gauss}, RealT = Float64)
68
# Calculate nodes, weights, and barycentric weights for Legendre-Gauss
69
gauss_nodes, gauss_weights = gauss_nodes_weights(n_nodes, RealT)
70
gauss_wbary = barycentric_weights(gauss_nodes)
71
72
# Calculate projection matrix (actually: discrete L2 projection with errors)
73
operator = zeros(RealT, n_nodes, n_nodes)
74
for j in 1:n_nodes
75
poly = lagrange_interpolating_polynomials(0.5f0 * (gauss_nodes[j] + 1),
76
gauss_nodes, gauss_wbary)
77
for i in 1:n_nodes
78
operator[i, j] = 0.5f0 * poly[i] * gauss_weights[j] / gauss_weights[i]
79
end
80
end
81
82
# Calculate Vandermondes
83
lobatto_nodes, _ = gauss_lobatto_nodes_weights(n_nodes, RealT)
84
gauss2lobatto = polynomial_interpolation_matrix(gauss_nodes, lobatto_nodes)
85
lobatto2gauss = polynomial_interpolation_matrix(lobatto_nodes, gauss_nodes)
86
87
return gauss2lobatto * operator * lobatto2gauss
88
end
89
90
# Calculate reverse projection matrix for discrete L2 projection from lower to large (Gauss version)
91
#
92
# Note: To not make the L2 projection exact, first convert to Gauss nodes,
93
# perform projection, and convert back to Gauss-Lobatto.
94
function calc_reverse_lower(n_nodes, ::Val{:gauss}, RealT = Float64)
95
# Calculate nodes, weights, and barycentric weights for Legendre-Gauss
96
gauss_nodes, gauss_weights = gauss_nodes_weights(n_nodes, RealT)
97
gauss_wbary = barycentric_weights(gauss_nodes)
98
99
# Calculate projection matrix (actually: discrete L2 projection with errors)
100
operator = zeros(RealT, n_nodes, n_nodes)
101
for j in 1:n_nodes
102
poly = lagrange_interpolating_polynomials(0.5f0 * (gauss_nodes[j] - 1),
103
gauss_nodes, gauss_wbary)
104
for i in 1:n_nodes
105
operator[i, j] = 0.5f0 * poly[i] * gauss_weights[j] / gauss_weights[i]
106
end
107
end
108
109
# Calculate Vandermondes
110
lobatto_nodes, _ = gauss_lobatto_nodes_weights(n_nodes, RealT)
111
gauss2lobatto = polynomial_interpolation_matrix(gauss_nodes, lobatto_nodes)
112
lobatto2gauss = polynomial_interpolation_matrix(lobatto_nodes, gauss_nodes)
113
114
return gauss2lobatto * operator * lobatto2gauss
115
end
116
117
# Calculate reverse projection matrix for discrete L2 projection from upper to large (Gauss-Lobatto
118
# version)
119
function calc_reverse_upper(n_nodes, ::Val{:gauss_lobatto}, RealT = Float64)
120
# Calculate nodes, weights, and barycentric weights
121
nodes, weights = gauss_lobatto_nodes_weights(n_nodes, RealT)
122
wbary = barycentric_weights(nodes)
123
124
# Calculate projection matrix (actually: discrete L2 projection with errors)
125
operator = zeros(RealT, n_nodes, n_nodes)
126
for j in 1:n_nodes
127
poly = lagrange_interpolating_polynomials(0.5f0 * (nodes[j] + 1), nodes, wbary)
128
for i in 1:n_nodes
129
operator[i, j] = 0.5f0 * poly[i] * weights[j] / weights[i]
130
end
131
end
132
133
return operator
134
end
135
136
# Calculate reverse projection matrix for discrete L2 projection from lower to large (Gauss-Lobatto
137
# version)
138
function calc_reverse_lower(n_nodes, ::Val{:gauss_lobatto}, RealT = Float64)
139
# Calculate nodes, weights, and barycentric weights
140
nodes, weights = gauss_lobatto_nodes_weights(n_nodes, RealT)
141
wbary = barycentric_weights(nodes)
142
143
# Calculate projection matrix (actually: discrete L2 projection with errors)
144
operator = zeros(RealT, n_nodes, n_nodes)
145
for j in 1:n_nodes
146
poly = lagrange_interpolating_polynomials(0.5f0 * (nodes[j] - 1), nodes, wbary)
147
for i in 1:n_nodes
148
operator[i, j] = 0.5f0 * poly[i] * weights[j] / weights[i]
149
end
150
end
151
152
return operator
153
end
154
end # @muladd
155
156