Path: blob/main/src/solvers/dgsem/l2projection.jl
5591 views
# By default, Julia/LLVM does not use fused multiply-add operations (FMAs).1# Since these FMAs can increase the performance of many numerical algorithms,2# we need to opt-in explicitly.3# See https://ranocha.de/blog/Optimizing_EC_Trixi for further details.4@muladd begin5#! format: noindent67# This diagram shows what is meant by "lower", "upper", and "large":8# +1 +19# | |10# upper | |11# | |12# -1 |13# | large14# +1 |15# | |16# lower | |17# | |18# -1 -119#20# That is, we are only concerned with 2:1 subdivision of a surface/element.2122# Calculate forward projection matrix for discrete L2 projection from large to upper23#24# Note: This is actually an interpolation.25function calc_forward_upper(n_nodes, RealT = Float64)26# Calculate nodes, weights, and barycentric weights27nodes, _ = gauss_lobatto_nodes_weights(n_nodes, RealT)28wbary = barycentric_weights(nodes)2930# Calculate projection matrix (actually: interpolation)31operator = zeros(RealT, n_nodes, n_nodes)32for j in 1:n_nodes33poly = lagrange_interpolating_polynomials(0.5f0 * (nodes[j] + 1), nodes, wbary)34for i in 1:n_nodes35operator[j, i] = poly[i]36end37end3839return operator40end4142# Calculate forward projection matrix for discrete L2 projection from large to lower43#44# Note: This is actually an interpolation.45function calc_forward_lower(n_nodes, RealT = Float64)46# Calculate nodes, weights, and barycentric weights47nodes, _ = gauss_lobatto_nodes_weights(n_nodes, RealT)48wbary = barycentric_weights(nodes)4950# Calculate projection matrix (actually: interpolation)51operator = zeros(RealT, n_nodes, n_nodes)52for j in 1:n_nodes53poly = lagrange_interpolating_polynomials(0.5f0 * (nodes[j] - 1), nodes, wbary)54for i in 1:n_nodes55operator[j, i] = poly[i]56end57end5859return operator60end6162# Calculate reverse projection matrix for discrete L2 projection from upper to large (Gauss version)63#64# Note: To not make the L2 projection exact, first convert to Gauss nodes,65# perform projection, and convert back to Gauss-Lobatto.66function calc_reverse_upper(n_nodes, ::Val{:gauss}, RealT = Float64)67# Calculate nodes, weights, and barycentric weights for Legendre-Gauss68gauss_nodes, gauss_weights = gauss_nodes_weights(n_nodes, RealT)69gauss_wbary = barycentric_weights(gauss_nodes)7071# Calculate projection matrix (actually: discrete L2 projection with errors)72operator = zeros(RealT, n_nodes, n_nodes)73for j in 1:n_nodes74poly = lagrange_interpolating_polynomials(0.5f0 * (gauss_nodes[j] + 1),75gauss_nodes, gauss_wbary)76for i in 1:n_nodes77operator[i, j] = 0.5f0 * poly[i] * gauss_weights[j] / gauss_weights[i]78end79end8081# Calculate Vandermondes82lobatto_nodes, _ = gauss_lobatto_nodes_weights(n_nodes, RealT)83gauss2lobatto = polynomial_interpolation_matrix(gauss_nodes, lobatto_nodes)84lobatto2gauss = polynomial_interpolation_matrix(lobatto_nodes, gauss_nodes)8586return gauss2lobatto * operator * lobatto2gauss87end8889# Calculate reverse projection matrix for discrete L2 projection from lower to large (Gauss version)90#91# Note: To not make the L2 projection exact, first convert to Gauss nodes,92# perform projection, and convert back to Gauss-Lobatto.93function calc_reverse_lower(n_nodes, ::Val{:gauss}, RealT = Float64)94# Calculate nodes, weights, and barycentric weights for Legendre-Gauss95gauss_nodes, gauss_weights = gauss_nodes_weights(n_nodes, RealT)96gauss_wbary = barycentric_weights(gauss_nodes)9798# Calculate projection matrix (actually: discrete L2 projection with errors)99operator = zeros(RealT, n_nodes, n_nodes)100for j in 1:n_nodes101poly = lagrange_interpolating_polynomials(0.5f0 * (gauss_nodes[j] - 1),102gauss_nodes, gauss_wbary)103for i in 1:n_nodes104operator[i, j] = 0.5f0 * poly[i] * gauss_weights[j] / gauss_weights[i]105end106end107108# Calculate Vandermondes109lobatto_nodes, _ = gauss_lobatto_nodes_weights(n_nodes, RealT)110gauss2lobatto = polynomial_interpolation_matrix(gauss_nodes, lobatto_nodes)111lobatto2gauss = polynomial_interpolation_matrix(lobatto_nodes, gauss_nodes)112113return gauss2lobatto * operator * lobatto2gauss114end115116# Calculate reverse projection matrix for discrete L2 projection from upper to large (Gauss-Lobatto117# version)118function calc_reverse_upper(n_nodes, ::Val{:gauss_lobatto}, RealT = Float64)119# Calculate nodes, weights, and barycentric weights120nodes, weights = gauss_lobatto_nodes_weights(n_nodes, RealT)121wbary = barycentric_weights(nodes)122123# Calculate projection matrix (actually: discrete L2 projection with errors)124operator = zeros(RealT, n_nodes, n_nodes)125for j in 1:n_nodes126poly = lagrange_interpolating_polynomials(0.5f0 * (nodes[j] + 1), nodes, wbary)127for i in 1:n_nodes128operator[i, j] = 0.5f0 * poly[i] * weights[j] / weights[i]129end130end131132return operator133end134135# Calculate reverse projection matrix for discrete L2 projection from lower to large (Gauss-Lobatto136# version)137function calc_reverse_lower(n_nodes, ::Val{:gauss_lobatto}, RealT = Float64)138# Calculate nodes, weights, and barycentric weights139nodes, weights = gauss_lobatto_nodes_weights(n_nodes, RealT)140wbary = barycentric_weights(nodes)141142# Calculate projection matrix (actually: discrete L2 projection with errors)143operator = zeros(RealT, n_nodes, n_nodes)144for j in 1:n_nodes145poly = lagrange_interpolating_polynomials(0.5f0 * (nodes[j] - 1), nodes, wbary)146for i in 1:n_nodes147operator[i, j] = 0.5f0 * poly[i] * weights[j] / weights[i]148end149end150151return operator152end153end # @muladd154155156