Fill an n-dimensional array by interpolating functions that define the boundaries
Given a set of functions bounding a domain (as well as internal contours, if desired), this module fills an ndarray with an n-dimensional mesh. Its primary use is for creating computational grids.
To create a planar mesh in two dimensions, specify functions defining the four edges. Each of the four edges is defined by a function of one variable. The easiest way to remember the sequence is as ordered pairs of opposing edges, the first set with u
ommitted, then v
.
Try it out (click button to edit on codepen) →
var tfi = require('ndarray-transfinite-interpolation');
var zeros = require('ndarray-scratch').zeros;
var edges = [[
v => [0, v],
v => [1, v]
], [
u => [u, 0],
u => [u, 1]
]];
tfi(zeros([11, 11, 2]), edges);
You can perturb the edges with functions:
tfi(zeros([11, 11, 2]), [[
v => [Math.sin(v * Math.PI * 2), v],
v => [1, v]
], [
u => [u, 0],
u => [u, 1]
]]);
Now we can get creative. So far we've defined edges, but you can also define internal curves through which the grid passes.
tfi(zeros([11, 11, 2]), [[
v => [Math.sin(v * Math.PI * 2), v],
v => [0.5, v],
v => [1, v]
], [
u => [u, 0],
u => [u, 1]
]]);
Notice that although we've defined a straight line through the center, the grid on the righthand side is slightly perturbed in the opposite direcdtion. That's because of the Lagrange interpolation. A future version will include the option to use linear interpolation instead.
By passing an additional array of arrays, you can specify the parameter values at which the respective curves are defined:
const edges = [[
v => [0, v],
v => [1, v]
], [
u => [u, 0],
u => [u, 0.2],
u => [u, 1]
]];
const t = [[0, 1], [0, 0.2, 1]]
const A = tfi(zeros([11, 11, 2]), edges, t);
Finally you can pass functions that map [0, 1] ⟶ [0, 1]
or else an ndarray or array of matching length that defines the parameter values at which the respective curves are evaluated:
const edges = [
[v => [0, v], v => [1, v]],
[u => [u, 0], u => [u, 1]]
];
const mapping = [
u => u * u * u,
[0, 0.15, 0.2, 0.35, 0.4, 0.55, 0.6, 0.75, 0.8, 0.95, 1]
];
const A = tfi(zeros([11, 11, 2]), edges, null, mapping);
There's no reason to constrain things to two dimensions. You can interpolate a surface in three dimensions:
So far we've done surfaces in two or three dimensions. To create a volumetric mesh in three dimensions, imagine a cube parameterized by [u, v, w]
, with u ∈ [0, 1]
, v ∈ [0, 1]
, and w ∈ [0, 1]
. Each of the six faces is defined by a two-dimensional function. The input to transfinite interpolation is these functions. The easiest way to conceptualize it is as ordered pairs of opposing faces, the first set with u
ommitted, then v
, then finally with w
ommitted.
var faces = [[
(v, w) => [0, v, w],
(v, w) => [1, v, w]
], [
(u, w) => [u, 0, w],
(u, w) => [u, 1, w]
], [
(u, v) => [u, v, 0],
(u, v) => [u, v, 1]
]];
tfi(zeros([11, 11, 11, 3]), faces);
Get fancy. One thing to watch for is that it's very easy to define curves that don't actually meet where they claim to. If they don't match up, you'll still get a decent result, but it might not be what you expect.
Not yet on npm. Useful, but needs cleanup.
Fill ndarray grid
with an evaluation of the specified grid. Options are:
grid
: An ndarray into which the mesh is evaluatedbounds
: An array of arrays containing for each dimension a list of functions that define the mesh. The trailing dimension ofgrid
is expected to equal the number of dimensions (equal the length of the array) inbounds
. Each function is parameterized from 0 to 1 and is expected to return anArray
with length equal to the trailing dimension ofgrid
.t
: An array of arrays specifying the respective value of the parameter at whichbounds
are defined. See above for illustration.ivars
: Independent variables at which to evaluate the grid intogrid
. These maybe be a function that maps[0, 1] → [0, 1]
or else a one-dimensional array (or ndarray) of length equal to the corresponding dimension ofgrid
. If not specified, the grid is evaluated with uniform spacing from 0 to 1.
- option for linear interpolation (instead of Lagrange interpolation)
- boundary derivative
- lots of tests!
© 2016 Ricky Reusser. MIT License.