3D example – scalar field¶
As soon as a 3-dimensional field is interpolated, visualization is not straightforward anymore. They typically occur in mechanics as for example in stress, strain or displacement fields. While the former fields are represented by higher order tensors, this example interpolates a scalar, random field using clamped and natural boundary conditions in each dimension. The extension to tensor fields is achieved by employing a multidimensional spline interpolation for each field coordinate.
Preparation¶
The 3-dimensional example is constructed in a unit cube domain and uses the following boundary conditions:
# shape of the data -> number of points in each dimension
shape = (11, 11, 11)
# ranges of the data -> [min, max] for each dimension
ranges = [
[0, 1],
[0, 1],
[0, 1],
]
# interval tuple for each dimension -> (min, max, number of points) for each dimension
interval = tuple((ranges[i][0], ranges[i][1], shape[i]) for i in range(len(shape)))
# boundary conditions for each dimension -> (first condition, second condition) for each dimension
bc = (
("first_derivative", "second_derivative"),
("first_derivative", "second_derivative"),
("first_derivative", "second_derivative"),
)
# boundary conditions values for each dimension -> (first condition value, second condition value) for each dimension
# for "not-a-knot" and "periodic" boundary conditions, the values are not used
bc_value = (
(-1.0, 1.0),
(1.0, 2.0),
(-1.0, -3.0),
)
The values are arbitrarily chosen, yet, different from each other to verify that they are applied in the correct dimension. The data preparation and spline evaluation is analog to the quickstart case.
Boundary condition verification¶
The imposed boundary conditions are verified by inspecting each of the six sides of the unit cube and plotting the first and second derivative as specified. The code for preparing the \(x\)-direction plots reads
d_vals = dvals[:, 0].reshape(x_spline_eval_grid.shape)
dd_vals = ddvals[:, 0, 0].reshape(x_spline_eval_grid.shape)
ax1.plot_surface(
y_spline_eval_grid[0, :, :], # all y values at x = 0 (first index = 0)
z_spline_eval_grid[0, :, :], # all z values at x = 0 (first index = 0)
d_vals[0, :, :], # first order partial derivative w.r.t. x at x = 0
color = "blue")
ax1.plot_surface(
y_spline_eval_grid[-1, :, :], # all y values at x = 1 (first index = -1)
z_spline_eval_grid[-1, :, :], # all z values at x = 1 (first index = -1)
dd_vals[-1, :, :], # second order partial derivative w.r.t. x at x = 1
color = "red")
The remaining sides are inspected similarly. The following image shows surface plots for \(x=0\) (blue) and \(x=1\) (red) of the partial derivatives. A comparison to the specified values above shows that all values are met.
Volumetric swipe¶
A volumetric comparison of the spline evaluation to the original sample data is achieved as follows. The spline is evaluated on a \(101^3\) grid, while the samples are given on a \(11^3\) grid. Since the grid numbers include start and end point, every 10th point on the evaluation grid shares the same location as a original sample. The code snipped reads as follows:
if not i % 10:
assert(np.allclose(vals[::10, ::10, i*step], dummy_data_orig[:,:,cnt]))
cnt += 1
Since it is placed inside a loop which exports 101 slices, the assertion is not done at once for 3-dimensional data but every 10th iteration for a 2-dimensional slice.
Finally, each slice along the \(z\)-direction can be exported and compiled inside a single gif. The following animation shows the volumetric spline interpolation slice by slice.