Source code for felupe.element._quad

# -*- 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

from ._base import Element
from ._lagrange import ArbitraryOrderLagrange


[docs] class ConstantQuad(Element): r"""A 2D quadrilateral element formulation with constant shape functions. Notes ----- The quadrilateral element is defined by four points (0-3). [1] The shape function :math:`h` is given in terms of the coordinates :math:`(r,s)`. .. math:: h(r,s) = 1 Examples -------- .. pyvista-plot:: :force_static: >>> import felupe as fem >>> >>> element = fem.ConstantQuad() >>> element.plot().show() References ---------- .. [1] W. Schroeder, K. Martin and B. Lorensen. The Visualization Toolkit, 4th ed. Kitware, 2006. ISBN: 978-1-930934-19-1. """ def __init__(self): self.points = np.array([[-1, -1], [1, -1], [1, 1], [-1, 1]], dtype=float) self.cells = np.arange(len(self.points)).reshape(1, -1) self.cell_type = "quad"
[docs] def function(self, rs): "Return the shape functions at given coordinates (r, s)." return np.ones(1)
[docs] def gradient(self, rs): "Return the gradient of shape functions at given coordinates (r, s)." return np.zeros((1, 2))
[docs] def hessian(self, rs): "Return the hessian of shape functions at given coordinates (r, s)." return np.zeros((1, 2, 2))
[docs] class Quad(Element): r"""A 2D quadrilateral element formulation with linear shape functions. Notes ----- The quadrilateral element is defined by four points (0-3). [1] The shape functions :math:`\boldsymbol{h}` are given in terms of the coordinates :math:`(r,s)`. .. math:: \boldsymbol{h}(r,s) = \frac{1}{4} \begin{bmatrix} (1-r) (1-s) \\ (1+r) (1-s) \\ (1+r) (1+s) \\ (1-r) (1+s) \end{bmatrix} Examples -------- .. pyvista-plot:: :force_static: >>> import felupe as fem >>> >>> element = fem.Quad() >>> element.plot().show() References ---------- .. [1] W. Schroeder, K. Martin and B. Lorensen. The Visualization Toolkit, 4th ed. Kitware, 2006. ISBN: 978-1-930934-19-1. """ def __init__(self): self.points = np.array([[-1, -1], [1, -1], [1, 1], [-1, 1]], dtype=float) self.cells = np.arange(len(self.points)).reshape(1, -1) self.cell_type = "quad"
[docs] def function(self, rs): "Return the shape functions at given coordinates (r, s)." r, s = rs return ( np.array( [ (1 - r) * (1 - s), (1 + r) * (1 - s), (1 + r) * (1 + s), (1 - r) * (1 + s), ] ) * 0.25 )
[docs] def gradient(self, rs): "Return the gradient of shape functions at given coordinates (r, s)." r, s = rs return ( np.array( [ [-(1 - s), -(1 - r)], [(1 - s), -(1 + r)], [(1 + s), (1 + r)], [-(1 + s), (1 - r)], ] ) * 0.25 )
[docs] def hessian(self, rs): "Return the hessian of shape functions at given coordinates (r, s)." r, s = rs return ( np.array( [ [[0, 1], [1, 0]], [[0, -1], [-1, 0]], [[0, 1], [1, 0]], [[0, -1], [-1, 0]], ] ) * 0.25 )
[docs] class QuadraticQuad(Element): r"""A 2D quadrilateral element formulation with quadratic (serendipity) shape functions. Notes ----- The quadratic (serendipity) quadrilateral element is defined by eight points (0-7). [1] The shape functions :math:`\boldsymbol{h}` are given in terms of the coordinates :math:`(r,s)`. Examples -------- .. pyvista-plot:: :force_static: >>> import felupe as fem >>> >>> element = fem.QuadraticQuad() >>> element.plot().show() References ---------- .. [1] W. Schroeder, K. Martin and B. Lorensen. The Visualization Toolkit, 4th ed. Kitware, 2006. ISBN: 978-1-930934-19-1. """ def __init__(self): self.points = np.array( [ [-1, -1], [1, -1], [1, 1], [-1, 1], [0, -1], [1, 0], [0, 1], [-1, 0], ], dtype=float, ) self.cells = np.arange(len(self.points)).reshape(1, -1) self.cell_type = "quad8"
[docs] def function(self, rs): "Return the shape functions at given coordinates (r, s)." r, s = rs ra, sa = self.points.T h = (1 + ra * r) * (1 + sa * s) * (ra * r + sa * s - 1) / 4 h[ra == 0] = (1 - r**2) * (1 + sa[ra == 0] * s) / 2 h[sa == 0] = (1 + ra[sa == 0] * r) * (1 - s**2) / 2 return h
[docs] def gradient(self, rs): "Return the gradient of shape functions at given coordinates (r, s)." r, s = rs ra, sa = self.points.T dhdr = ( ra * (1 + sa * s) * (ra * r + sa * s - 1) / 4 + (1 + ra * r) * (1 + sa * s) * ra / 4 ) dhds = ( sa * (1 + ra * r) * (ra * r + sa * s - 1) / 4 + (1 + ra * r) * (1 + sa * s) * sa / 4 ) dhdr[ra == 0] = -r * (1 + sa[ra == 0] * s) dhds[ra == 0] = (1 - r**2) * sa[ra == 0] / 2 dhdr[sa == 0] = ra[sa == 0] * (1 - s**2) / 2 dhds[sa == 0] = (1 + ra[sa == 0] * r) * -s return np.vstack([dhdr, dhds]).T
[docs] def hessian(self, rs): "Return the hessian of shape functions at given coordinates (r, s)." r, s = rs ra, sa = self.points.T d2hdrdr = ra**2 * (1 + sa * s) / 2 d2hdsds = sa**2 * (1 + ra * r) / 2 d2hdrds = ra * sa * (1 + 2 * ra * r + 2 * sa * s) / 4 d2hdrdr[ra == 0] = -(1 + sa[ra == 0] * s) d2hdsds[sa == 0] = -(1 + ra[sa == 0] * r) d2hdrdr[sa == 0] = 0 d2hdsds[ra == 0] = 0 d2hdrds[ra == 0] = sa[ra == 0] * -r d2hdrds[sa == 0] = ra[sa == 0] * -s return np.array([[d2hdrdr, d2hdrds], [d2hdrds, d2hdsds]]).T
[docs] class BiQuadraticQuad(Element): r"""A 2D quadrilateral element formulation with bi-quadratic shape functions. Notes ----- The bi-quadratic quadrilateral element is defined by nine points (0-8). [1] The shape functions :math:`\boldsymbol{h}` are given in terms of the coordinates :math:`(r,s)`. Examples -------- .. pyvista-plot:: :force_static: >>> import felupe as fem >>> >>> element = fem.BiQuadraticQuad() >>> element.plot().show() References ---------- .. [1] W. Schroeder, K. Martin and B. Lorensen. The Visualization Toolkit, 4th ed. Kitware, 2006. ISBN: 978-1-930934-19-1. """ def __init__(self): self._lagrange = ArbitraryOrderLagrange(order=2, dim=2, permute=False) self._vertices = np.array([0, 2, 8, 6]) self._edges = np.array([1, 5, 7, 3]) self._faces = np.array([4]) self._volume = np.array([], dtype=int) self._permute = np.concatenate( (self._vertices, self._edges, self._faces, self._volume) ) self.points = self._lagrange.points[self._permute] self.cells = np.arange(len(self.points)).reshape(1, -1) self.cell_type = "quad9"
[docs] def function(self, rs): "Return the shape functions at given coordinates (r, s)." return self._lagrange.function(rs)[self._permute]
[docs] def gradient(self, rs): "Return the gradient of shape functions at given coordinates (r, s)." return self._lagrange.gradient(rs)[self._permute, :]