Sorry for the later reply, was actually working on the package I’m using for this answer. I think @juliohm’s approach is probably better suited (esp if you can’t choose the points at which you interpolate), but I figure I’d include this in case it’s helpful to anyone.
I have a package NodesAndModes.jl for high order polynomials and interpolation points on several shapes. A warning: I found a bug in the main branch, so I’m using a branch where I fixed this by making it more “Julian”.
You can get high order interpolation nodes for a Tri() or Tet() domain via
pkg> add NodesAndModes#dev_elem_types
julia> using NodesAndModes
julia> using Plots
julia> x,y = nodes(Tri(),25) # degree 25 interpolation nodes
This gives some “decent” interpolation nodes.
I do the actual interpolation using linear algebra (implicitly defined Lagrange basis functions). If I want to interpolate, say, a version of Runge’s function in 2D
with a degree N=20 interpolant, I can do this using
using NodesAndModes
N = 20 # polynomial degree
x,y = nodes(Tri(),N)
xp,yp = equi_nodes(Tri(),100) # plotting nodes
f(x,y) = 1/(1 + 5*((x+1/3)^2+(y+1/3)^2)) # Runge-ish function
function interp(elem,N,x_eval,y_eval,x,y,f_vals)
coeffs = vandermonde(elem,N,x,y)\f_vals
return vandermonde(elem,N,x_eval,y_eval)*coeffs
end
f_interp = interp(Tri(),N,xp,yp,x,y,f.(x,y))
err = maximum(abs.(f.(xp,yp)-f_interp))
@show err
which gives an error of 0.015041654247017144.
Runge’s function is sort of the worst-case scenario. If you interpolate a smoother function like f(x,y) = sin(pi*x)*sin(pi*y)
, then the error is 1.167277052793736e-9.
A few notes
- if the points at which you want to interpolate are fixed, you can just replace the interpolation
x,y
in the above with your node locations. However, due to the nature of high order interpolation, this can lead to pretty poor results.
- degree N > 25 starts to get iffy since some of the polynomials get really large and roundoff effects come into play. For many “nice” functions, N between 15-20 is more than enough though.
- if your evaluation and interpolation points don’t change between iterations, you can reduce the interpolation procedure to just a matrix-vector product, which should be pretty fast.
Finally, for completeness, the plots were generated using
scatter(xp,yp,f_interp,zcolor=f_interp,msw=0,leg=false,title="Interpolant")
and scatter(xp,yp,f.(xp,yp),zcolor=f.(xp,yp),msw=0,leg=false,title="Exact")