Path: blob/main/src/meshes/surface_interpolant.jl
2055 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# CurvedSurface{RealT<:Real}8#9# Contains the data needed to represent a curve with data points (x,y) as a Lagrange polynomial10# interpolant written in barycentric form at a given set of nodes.11struct CurvedSurface{RealT <: Real}12nodes :: Vector{RealT}13barycentric_weights :: Vector{RealT}14coordinates :: Array{RealT, 2} #[nnodes, ndims]15end1617# evaluate the Gamma curve interpolant at a particular point s and return the (x,y) coordinate18function evaluate_at(s, boundary_curve::CurvedSurface)19@unpack nodes, barycentric_weights, coordinates = boundary_curve2021x_coordinate_at_s_on_boundary_curve = lagrange_interpolation(s, nodes,22view(coordinates, :,231),24barycentric_weights)25y_coordinate_at_s_on_boundary_curve = lagrange_interpolation(s, nodes,26view(coordinates, :,272),28barycentric_weights)2930return x_coordinate_at_s_on_boundary_curve, y_coordinate_at_s_on_boundary_curve31end3233# evaluate the derivative of a Gamma curve interpolant at a particular point s34# and return the (x,y) coordinate35function derivative_at(s, boundary_curve::CurvedSurface)36@unpack nodes, barycentric_weights, coordinates = boundary_curve3738x_coordinate_at_s_on_boundary_curve_prime = lagrange_interpolation_derivative(s,39nodes,40view(coordinates,41:,421),43barycentric_weights)44y_coordinate_at_s_on_boundary_curve_prime = lagrange_interpolation_derivative(s,45nodes,46view(coordinates,47:,482),49barycentric_weights)50return x_coordinate_at_s_on_boundary_curve_prime,51y_coordinate_at_s_on_boundary_curve_prime52end5354# Chebyshev-Gauss-Lobatto nodes and weights for use with curved boundaries55function chebyshev_gauss_lobatto_nodes_weights(n_nodes::Integer)5657# Initialize output58nodes = zeros(n_nodes)59weights = zeros(n_nodes)6061# Get polynomial degree for convenience62N = n_nodes - 16364for j in 1:n_nodes65nodes[j] = -cospi((j - 1) / N)66weights[j] = pi / N67end68weights[1] = 0.5f0 * weights[1]69weights[end] = 0.5f0 * weights[end]7071return nodes, weights72end7374# Calculate Lagrange interpolating polynomial of a function f(x) at a given point x for a given75# node distribution.76function lagrange_interpolation(x, nodes, fvals, wbary)77# Barycentric two formulation of Lagrange interpolant78numerator = zero(eltype(fvals))79denominator = zero(eltype(fvals))8081for j in eachindex(nodes)82# using eps(nodes[j]) instead of eps(x) allows us to use integer83# coordinates for the target location x84if isapprox(x, nodes[j], rtol = eps(nodes[j]))85return fvals[j]86end87t = wbary[j] / (x - nodes[j])88numerator += t * fvals[j]89denominator += t90end9192return numerator / denominator93end9495# Calculate derivative of a Lagrange interpolating polynomial of a function f(x) at a given96# point x for a given node distribution.97function lagrange_interpolation_derivative(x, nodes, fvals, wbary)98at_node = false99numerator = zero(eltype(fvals))100i = 0101102for j in eachindex(nodes)103if isapprox(x, nodes[j])104at_node = true105p = fvals[j]106denominator = -wbary[j]107i = j108end109end110111if at_node112for j in eachindex(nodes)113if j != i114numerator += wbary[j] * (p - fvals[j]) / (x - nodes[j])115end116end117else118denominator = zero(eltype(fvals))119p = lagrange_interpolation(x, nodes, fvals, wbary)120for j in eachindex(nodes)121t = wbary[j] / (x - nodes[j])122numerator += t * (p - fvals[j]) / (x - nodes[j])123denominator += t124end125end126127return numerator / denominator # p_prime128end129end # @muladd130131132