Source code for felupe.mesh._interpolate

# -*- coding: utf-8 -*-
"""
This file is part of FElupe.

FElupe is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.

FElupe is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
GNU General Public License for more details.

You should have received a copy of the GNU General Public License
along with FElupe.  If not, see <http://www.gnu.org/licenses/>.
"""

import numpy as np


[docs] def interpolate_line(mesh, xi, axis=None, Interpolator=None, **kwargs): r"""Return an interpolated line mesh from an existing line mesh with provided interpolation points on a given axis. Parameters ---------- mesh : Mesh A :class:`~felupe.Mesh` with cell-type ``line``. xi : ndarray Points at which to interpolate data. If axis is None, a normalized curve- progress must be provided (:math:`0 \le \xi \le 1`). axis : int or None, optional The axis of the points at which the data will be interpolated. If None, a normalized curve-progress is used. Default is None. Interpolator : callable or None, optional An interpolator class (default is :class:`scipy.interpolate.PchipInterpolator`). **kwargs : dict, optional Optional keyword arguments are passed to the Interpolator. Returns ------- Mesh A new line mesh with interpolated points. The attribute ``points_derivative`` holds the derivatives of the independent variable w.r.t. the dependent variable(s). Examples -------- .. pyvista-plot:: :context: :force_static: >>> import felupe as fem >>> import numpy as np >>> from scipy.interpolate import CubicSpline >>> >>> mesh = fem.mesh.Line(b=1.0, n=5).expand(n=1) >>> t = mesh.x.copy() >>> mesh.points[:, 0] = np.sin(2 * np.pi * t) >>> mesh.points[:, 1] = np.cos(2 * np.pi * t) >>> >>> mesh_new = fem.mesh.interpolate_line( ... mesh, xi=np.linspace(0, 1), Interpolator=CubicSpline, bc_type="periodic" ... ) >>> >>> mesh_new.plot( ... plotter=mesh.plot(style="points", color="red", point_size=15), ... color="black", ... ).show() """ if Interpolator is None: from scipy.interpolate import PchipInterpolator as Interpolator if axis is None: # progress-based interpolation distances = np.linalg.norm(np.diff(mesh.points, axis=0), axis=1) progress = np.insert(np.cumsum(distances), 0, 0) progress /= progress.max() spline = Interpolator(progress, mesh.points, **kwargs) points_new = spline(xi) cells_new = np.repeat(np.arange(len(xi)), 2)[1:-1].reshape(-1, 2) mesh_new = type(mesh)(points_new, cells_new, cell_type="line") mesh_new.points_derivative = spline.derivative()(xi) else: # independent- and dependent-variables # line connectivity # concatenate the first point of each cell and the last point of the last cell line = np.concatenate([mesh.cells[:, :-1].ravel(), mesh.cells[-1, -1:]]) # independent spline variable points = mesh.points[line, axis] ascending = np.argsort(points) # dependent spline variable(s) mask = np.ones(mesh.dim, dtype=bool) mask[axis] = False axes = np.arange(mesh.dim) values = mesh.points[line.reshape(-1, 1), axes[mask]] # create a spline spline = Interpolator(points[ascending], values[ascending], **kwargs) # evaluation points for the independent spline variable points_new = np.zeros((len(xi), mesh.dim)) points_new[:, axis] = xi points_new[:, axes[mask]] = spline(xi) cells_new = np.repeat(np.arange(len(xi)), 2)[1:-1].reshape(-1, 2) mesh_new = type(mesh)(points_new, cells_new, cell_type="line") mesh_new.points_derivative = np.zeros_like(mesh_new.points) mesh_new.points_derivative[:, axes[mask]] = spline.derivative()(xi) return mesh_new