Interpolations should be just fine doing this kind of thing. It’s not well documented, but Interpolations (now) does interpolation in the naive way, which IMO is a strength. For example, this is how the internals for linear interpolation in 1d actually work:
julia> using Interpolations
# Build a "weighted adjacent index" for indexing into any array: compute
# 0.2*a[j] + 0.8*a[j+1], with j=3
julia> widx = Interpolations.WeightedAdjIndex(3, (0.2, 0.8))
Interpolations.WeightedAdjIndex{2,Float64}(3, (0.2, 0.8))
julia> r = 1:10
1:10
julia> r[widx] # you can index arbitrary arrays with these weird indexes
3.8000000000000003
# Now do something kinda silly, but it shows you're not constrained in what you can do
julia> widx = Interpolations.WeightedAdjIndex(3, (0.0, 0.0, 0.0, 0.7))
Interpolations.WeightedAdjIndex{4,Float64}(3, (0.0, 0.0, 0.0, 0.7))
julia> r[widx]
4.199999999999999
julia> 0.7*r[6] # the 4 weights apply to positions 3, 4, 5, and 6, hence the r[6]
4.199999999999999
# Try a 2d example
julia> A = reshape(1:20, 4, 5)
4×5 reshape(::UnitRange{Int64}, 4, 5) with eltype Int64:
1 5 9 13 17
2 6 10 14 18
3 7 11 15 19
4 8 12 16 20
# Try indexing the first dimension with an integer and the 2nd with a weighted index
julia> i, j = 2, Interpolations.WeightedAdjIndex(2, (0.3, 0.7))
(2, Interpolations.WeightedAdjIndex{2,Float64}(2, (0.3, 0.7)))
julia> A[i,j]
8.8
julia> 0.3*A[i,2] + 0.7*A[i,3] # see, same as linear interpolation along dimension 2
8.8
# Interpolate in both dimensions, this time trying out the other index type, WeightedArbIndex.
# This type allows the index locations to be arbitrary, rather than incremental. It is used internally to
# implement things like periodic boundary conditions, reflecting boundary conditions, etc.
julia> i = Interpolations.WeightedArbIndex((1, 3), (-0.1, 100.0))
Interpolations.WeightedArbIndex{2,Float64}((1, 3), (-0.1, 100.0))
julia> A[i, j]
979.2199999999999
# Indeed, this is the full 2d interpolation
julia> A[1,2]*(-0.1*0.3) + A[1,3]*(-0.1*0.7) + A[3,2]*(100*0.3) + A[3,3]*(100*0.7)
979.22
As you can see, Interpolations puts all the magic into the index objects, not the arrays. This makes it very flexible. Moreover, if you put stuff inside @inbounds
then the generated code should be very efficient.
Interpolations does include a NoInterp
mode as an exported interface for doing these kinds of things, but the real magic is in the indexes.