Skip to content

Commit 09d81e3

Browse files
Improve multidimensional matrix operators (#330)
* improve multidimensional matrix operators * format * Apply suggestions from code review Co-authored-by: Hendrik Ranocha <[email protected]> * remove kron specialization again --------- Co-authored-by: Hendrik Ranocha <[email protected]>
1 parent 14664f7 commit 09d81e3

6 files changed

+140
-2
lines changed

src/SummationByPartsOperators.jl

+3-1
Original file line numberDiff line numberDiff line change
@@ -152,7 +152,8 @@ export FilterCallback, ConstantFilter, ExponentialFilter
152152
export SafeMode, FastMode, ThreadedMode
153153
export derivative_order, accuracy_order, source_of_coefficients, grid, semidiscretize
154154
export mass_matrix, mass_matrix_boundary
155-
export integrate, integrate_boundary, restrict_boundary,
155+
export integrate, integrate_boundary,
156+
restrict_interior, restrict_boundary,
156157
left_boundary_weight, right_boundary_weight,
157158
scale_by_mass_matrix!, scale_by_inverse_mass_matrix!,
158159
derivative_left, derivative_right,
@@ -165,6 +166,7 @@ export periodic_central_derivative_operator, periodic_derivative_operator,
165166
fourier_derivative_operator,
166167
legendre_derivative_operator, legendre_second_derivative_operator,
167168
upwind_operators, function_space_operator, tensor_product_operator_2D
169+
export normals, boundary_indices
168170
export UniformMesh1D, UniformPeriodicMesh1D
169171
export couple_continuously, couple_discontinuously
170172
export mul!

src/general_operators.jl

+9
Original file line numberDiff line numberDiff line change
@@ -304,6 +304,15 @@ restrict_boundary(u, D::AbstractNonperiodicDerivativeOperator) = u[[begin, end]]
304304

305305
restrict_boundary(u, D::AbstractPeriodicDerivativeOperator) = eltype(u)[]
306306

307+
"""
308+
restrict_interior(u, D::AbstractDerivativeOperator)
309+
310+
Restrict the coefficients `u` to the interior nodes of the derivative operator `D`.
311+
"""
312+
restrict_interior(u, D::AbstractNonperiodicDerivativeOperator) = u[(begin + 1):(end - 1)]
313+
314+
restrict_interior(u, D::AbstractPeriodicDerivativeOperator) = u
315+
307316
"""
308317
mass_matrix_boundary(D::AbstractDerivativeOperator)
309318

src/multidimensional_matrix_operators.jl

+18
Original file line numberDiff line numberDiff line change
@@ -74,10 +74,28 @@ Base.ndims(::AbstractMultidimensionalMatrixDerivativeOperator{Dim}) where {Dim}
7474
Base.getindex(D::AbstractMultidimensionalMatrixDerivativeOperator, i::Int) = D.Ds[i]
7575
Base.eltype(::AbstractMultidimensionalMatrixDerivativeOperator{Dim, T}) where {Dim, T} = T
7676

77+
"""
78+
normals(D::MultidimensionalMatrixDerivativeOperator)
79+
80+
Return the normal vectors of the boundary nodes of a [`MultidimensionalMatrixDerivativeOperator`](@ref) `D`.
81+
"""
82+
normals(D::AbstractMultidimensionalMatrixDerivativeOperator) = D.normals
83+
84+
"""
85+
boundary_indices(D::MultidimensionalMatrixDerivativeOperator)
86+
87+
Return the indices of the boundary nodes of a [`MultidimensionalMatrixDerivativeOperator`](@ref) `D`.
88+
"""
89+
boundary_indices(D::AbstractMultidimensionalMatrixDerivativeOperator) = D.boundary_indices
90+
7791
function restrict_boundary(u, D::AbstractMultidimensionalMatrixDerivativeOperator)
7892
u[D.boundary_indices]
7993
end
8094

95+
function restrict_interior(u, D::AbstractMultidimensionalMatrixDerivativeOperator)
96+
u[setdiff(eachindex(u), D.boundary_indices)]
97+
end
98+
8199
"""
82100
integrate_boundary([func = identity,] u, D::MultidimensionalMatrixDerivativeOperator, dim)
83101

test/SBP_operators_test.jl

+39
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,9 @@ for source in D_test_list, T in (Float32, Float64)
4545
# SBP property
4646
M = mass_matrix(D)
4747
@test M * Matrix(D) + Matrix(D)' * M mass_matrix_boundary(D)
48+
49+
@test restrict_interior(x2, D) x2[(begin + 1):(end - 1)]
50+
@test restrict_boundary(x2, D) [xmin^2, xmax^2]
4851
# interior and boundary
4952
mul!(res, D, x0)
5053
@test all(i -> abs(res[i]) < 1000 * eps(T), eachindex(res))
@@ -112,6 +115,9 @@ for source in D_test_list, T in (Float32, Float64)
112115
# SBP property
113116
M = mass_matrix(D)
114117
@test M * Matrix(D) + Matrix(D)' * M mass_matrix_boundary(D)
118+
119+
@test restrict_interior(x2, D) x2[(begin + 1):(end - 1)]
120+
@test restrict_boundary(x2, D) [xmin^2, xmax^2]
115121
# interior and boundary
116122
mul!(res, D, x0)
117123
@test all(i -> abs(res[i]) < 1000 * eps(T), eachindex(res))
@@ -189,6 +195,9 @@ for source in D_test_list, T in (Float32, Float64)
189195
# SBP property
190196
M = mass_matrix(D)
191197
@test M * Matrix(D) + Matrix(D)' * M mass_matrix_boundary(D)
198+
199+
@test restrict_interior(x2, D) x2[(begin + 1):(end - 1)]
200+
@test restrict_boundary(x2, D) [xmin^2, xmax^2]
192201
# interior and boundary
193202
mul!(res, D, x0)
194203
@test all(i -> abs(res[i]) < 1000 * eps(T), eachindex(res))
@@ -276,6 +285,9 @@ for source in D_test_list, T in (Float32, Float64)
276285
# SBP property
277286
M = mass_matrix(D)
278287
@test M * Matrix(D) + Matrix(D)' * M mass_matrix_boundary(D)
288+
289+
@test restrict_interior(x2, D) x2[(begin + 1):(end - 1)]
290+
@test restrict_boundary(x2, D) [xmin^2, xmax^2]
279291
# interior and boundary
280292
mul!(res, D, x0)
281293
@test all(i -> abs(res[i]) < 16000 * eps(T), eachindex(res))
@@ -438,6 +450,9 @@ for source in D_test_list, T in (Float32, Float64)
438450
dL = derivative_left(D, Val{1}())
439451
dR = derivative_right(D, Val{1}())
440452
@test M * Matrix(D) - Matrix(D)' * M eR * dR' - eL * dL' - dR * eR' + dL * eL'
453+
454+
@test restrict_interior(x2, D) x2[(begin + 1):(end - 1)]
455+
@test restrict_boundary(x2, D) [xmin^2, xmax^2]
441456
# interior and boundary
442457
mul!(res, D, x0)
443458
@test all(i -> abs(res[i]) < 2000 * eps(T), eachindex(res))
@@ -509,6 +524,9 @@ for source in D_test_list, T in (Float32, Float64)
509524
dL = derivative_left(D, Val{1}())
510525
dR = derivative_right(D, Val{1}())
511526
@test M * Matrix(D) - Matrix(D)' * M eR * dR' - eL * dL' - dR * eR' + dL * eL'
527+
528+
@test restrict_interior(x2, D) x2[(begin + 1):(end - 1)]
529+
@test restrict_boundary(x2, D) [xmin^2, xmax^2]
512530
# interior and boundary
513531
mul!(res, D, x0)
514532
@test all(i -> abs(res[i]) < 10000 * eps(T), eachindex(res))
@@ -587,6 +605,9 @@ for source in D_test_list, T in (Float32, Float64)
587605
dL = derivative_left(D, Val{1}())
588606
dR = derivative_right(D, Val{1}())
589607
@test M * Matrix(D) - Matrix(D)' * M eR * dR' - eL * dL' - dR * eR' + dL * eL'
608+
609+
@test restrict_interior(x2, D) x2[(begin + 1):(end - 1)]
610+
@test restrict_boundary(x2, D) [xmin^2, xmax^2]
590611
# interior and boundary
591612
mul!(res, D, x0)
592613
@test all(i -> abs(res[i]) < 10000 * eps(T), eachindex(res))
@@ -669,6 +690,9 @@ end
669690
@test derivative_order(D) == der_order
670691
@test accuracy_order(D) == acc_order
671692
@test issymmetric(D) == false
693+
694+
@test restrict_interior(x2, D) x2[(begin + 1):(end - 1)]
695+
@test restrict_boundary(x2, D) [xmin^2, xmax^2]
672696
# interior and boundary
673697
mul!(res, D, x0)
674698
@test all(i -> abs(res[i]) < eps(T), eachindex(res))
@@ -730,6 +754,9 @@ end
730754
@test derivative_order(D) == der_order
731755
@test accuracy_order(D) == acc_order
732756
@test issymmetric(D) == false
757+
758+
@test restrict_interior(x2, D) x2[(begin + 1):(end - 1)]
759+
@test restrict_boundary(x2, D) [xmin^2, xmax^2]
733760
# interior and boundary
734761
mul!(res, D, x0)
735762
@test all(i -> abs(res[i]) < 100_000 * eps(T), eachindex(res))
@@ -800,6 +827,9 @@ end
800827
@test derivative_order(D) == der_order
801828
@test accuracy_order(D) == acc_order
802829
@test issymmetric(D) == false
830+
831+
@test restrict_interior(x2, D) x2[(begin + 1):(end - 1)]
832+
@test restrict_boundary(x2, D) [xmin^2, xmax^2]
803833
# interior and boundary
804834
mul!(res, D, x0)
805835
@test all(i -> abs(res[i]) < 1_000_000 * eps(T), eachindex(res))
@@ -884,6 +914,9 @@ end
884914
@test derivative_order(D) == der_order
885915
@test accuracy_order(D) == acc_order
886916
@test issymmetric(D) == false
917+
918+
@test restrict_interior(x2, D) x2[(begin + 1):(end - 1)]
919+
@test restrict_boundary(x2, D) [xmin^2, xmax^2]
887920
# interior and boundary
888921
mul!(res, D, x0)
889922
@test all(i -> abs(res[i]) < 10 * eps(T) / D.Δx^4, eachindex(res))
@@ -953,6 +986,9 @@ end
953986
@test derivative_order(D) == der_order
954987
@test accuracy_order(D) == acc_order
955988
@test issymmetric(D) == false
989+
990+
@test restrict_interior(x2, D) x2[(begin + 1):(end - 1)]
991+
@test restrict_boundary(x2, D) [xmin^2, xmax^2]
956992
# interior and boundary
957993
mul!(res, D, x0)
958994
@test all(i -> abs(res[i]) < 50_000_000 * eps(T), eachindex(res))
@@ -1033,6 +1069,9 @@ end
10331069
@test derivative_order(D) == der_order
10341070
@test accuracy_order(D) == acc_order
10351071
@test issymmetric(D) == false
1072+
1073+
@test restrict_interior(x2, D) x2[(begin + 1):(end - 1)]
1074+
@test restrict_boundary(x2, D) [xmin^2, xmax^2]
10361075
# interior and boundary
10371076
mul!(res, D, x0)
10381077
@test all(i -> abs(res[i]) < 50_000_000 * eps(T), eachindex(res))

test/multidimensional_matrix_operators_test.jl

+19-1
Original file line numberDiff line numberDiff line change
@@ -121,8 +121,21 @@ end
121121
end
122122
@test eltype(D_t) == eltype(D_1) == eltype(D_2) == T
123123
@test real(D_t) == real(D_1) == real(D_2) == T
124+
@test normals(D_t) == D_t.normals
125+
@test boundary_indices(D_t) == D_t.boundary_indices
124126

125-
@test length(grid(D_t)) == N_x * N_y
127+
nodes = grid(D_t)
128+
@test length(nodes) == N_x * N_y
129+
u = sin.(first.(nodes) .^ 2) .* cospi.(last.(nodes))
130+
u_reference = copy(u)
131+
132+
SummationByPartsOperators.scale_by_mass_matrix!(u, D_t)
133+
SummationByPartsOperators.scale_by_inverse_mass_matrix!(u, D_t)
134+
@test u u_reference
135+
@test length(restrict_interior(u, D_t)) == (N_x - 2) * (N_y - 2)
136+
@test length(restrict_boundary(u, D_t)) == 2 * (N_x + N_y)
137+
138+
# derivative operators
126139
M = mass_matrix(D_t)
127140
D_x = D_t[1]
128141
@test D_x isa SparseMatrixCSC
@@ -148,6 +161,11 @@ end
148161
@test B_x Diagonal(kron(B_1D_1, M_1D_2))
149162
@test B_y Diagonal(kron(M_1D_1, B_1D_2))
150163

164+
# integrals
165+
@test integrate(abs2, u, D_t) sum(M * abs2.(u))
166+
@test integrate_boundary(abs2, u, D_t, 1) sum(B_x * abs2.(u))
167+
@test integrate_boundary(abs2, u, D_t, 2) sum(B_y * abs2.(u))
168+
151169
# accuracy test
152170
x = grid(D_t)
153171
x0 = ones(N_x * N_y)

0 commit comments

Comments
 (0)