Esempio n. 1
0
    def get_fargs(self,
                  force_pars,
                  normal,
                  anchor,
                  bounds,
                  virtual,
                  state,
                  mode=None,
                  term_mode=None,
                  diff_var=None,
                  **kwargs):
        sg, _ = self.get_mapping(virtual)

        assert_((force_pars >= 0.0).all(),
                'force parameters must be non-negative!')

        force_pars = Term.tile_mat(force_pars, sg.shape[0])

        if self.cp is None:
            self.cp = ContactPlane(anchor, normal, bounds)

        qps = self.get_physical_qps()
        qp_coors = qps.values
        u_qp = self.get(state, 'val').reshape(qp_coors.shape)

        # Deformed QP coordinates.
        coors = u_qp + qp_coors

        force = nm.zeros(coors.shape[0], dtype=nm.float64)

        k, f0, eps, a = self._get_force_pars(force_pars, force.shape)

        # Active points in contact change with displacements!
        ii = self.cp.mask_points(qp_coors)

        if diff_var is None:
            if ii.any():
                d = self.cp.get_distance(coors[ii])
                # Force in the plane normal direction.
                force[ii] = self.smooth_f(d, k[ii], f0[ii], a[ii], eps[ii], 0)

            fmode = 0

        else:
            if ii.any():
                d = self.cp.get_distance(coors[ii])
                # Force in the plane normal direction derivative.
                force[ii] = self.smooth_f(d, k[ii], f0[ii], a[ii], eps[ii], 1)

            fmode = 1

        force.shape = qps.shape[:2] + (1, 1)

        return force, self.cp.normal, sg, fmode
Esempio n. 2
0
def main():
    import os

    import numpy as nm
    import matplotlib.pyplot as plt

    from sfepy.fem import MeshIO
    import sfepy.linalg as la
    from sfepy.mechanics.contact_bodies import (ContactPlane, plot_polygon,
                                                plot_points)

    conf_dir = os.path.dirname(__file__)
    io = MeshIO.any_from_filename(filename_mesh, prefix_dir=conf_dir)
    bb = io.read_bounding_box()
    outline = [vv for vv in la.combine(zip(*bb))]

    ax = plot_points(None, nm.array(outline), 'r*')
    for name in ['cp%d' % ii for ii in range(4)]:
        cpc = materials[name][0]
        cp = ContactPlane(cpc['.a'], cpc['.n'], cpc['.bs'])

        v1, v2 = la.get_perpendiculars(cp.normal)

        ax = plot_polygon(ax, cp.bounds)
        ax = plot_polygon(
            ax, nm.r_[cp.anchor[None, :],
                      cp.anchor[None, :] + cp.normal[None, :]])
        ax = plot_polygon(ax, nm.r_[cp.anchor[None, :],
                                    cp.anchor[None, :] + v1])
        ax = plot_polygon(ax, nm.r_[cp.anchor[None, :],
                                    cp.anchor[None, :] + v2])

    plt.show()
Esempio n. 3
0
    def get_fargs(self, force_pars, normal, anchor, bounds, virtual, state,
                  mode=None, term_mode=None, diff_var=None, **kwargs):
        sg, _ = self.get_mapping(virtual)

        assert_((force_pars >= 0.0).all(),
                'force parameters must be non-negative!')

        if self.cp is None:
            self.cp = ContactPlane(anchor, normal, bounds)

        ig = self.char_fun.ig
        qps = self.get_physical_qps()
        qp_coors = qps.values[ig]
        u_qp = self.get(state, 'val').reshape(qp_coors.shape)

        # Deformed QP coordinates.
        coors = u_qp + qp_coors

        force = nm.zeros(coors.shape[0], dtype=nm.float64)

        k, f0, eps, a = self._get_force_pars(force_pars, force.shape)

        # Active points in contact change with displacements!
        ii = self.cp.mask_points(qp_coors)

        if diff_var is None:
            if ii.any():
                d = self.cp.get_distance(coors[ii])
                # Force in the plane normal direction.
                force[ii] = self.smooth_f(d, k[ii], f0[ii], a[ii], eps[ii], 0)

            fmode = 0

        else:
            if ii.any():
                d = self.cp.get_distance(coors[ii])
                # Force in the plane normal direction derivative.
                force[ii] = self.smooth_f(d, k[ii], f0[ii], a[ii], eps[ii], 1)

            fmode = 1

        force.shape = qps.shape[ig][:2] + (1, 1)

        return force, self.cp.normal, sg, fmode
Esempio n. 4
0
class ContactPlaneTerm(Term):
    r"""
    Small deformation elastic contact plane term with penetration penalty.

    The plane is given by an anchor point :math:`\ul{A}` and a normal
    :math:`\ul{n}`. The contact occurs in points that orthogonally project onto
    the plane into a polygon given by orthogonal projections of boundary points
    :math:`\{\ul{B}_i\}`, :math:`i = 1, \dots, N_B` on the plane. In such
    points, a penetration distance :math:`d(\ul{u}) = (\ul{X} + \ul{u} -
    \ul{A}, \ul{n})` is computed, and a force :math:`f(d(\ul{u})) \ul{n}` is
    applied. The force depends on the non-negative parameters :math:`k`
    (stiffness) and :math:`f_0` (force at zero penetration):

    - If :math:`f_0 = 0`:

      .. math::

         f(d) = 0 \mbox{ for } d \leq 0 \;, \\
         f(d) = k d \mbox{ for } d > 0 \;.

    - If :math:`f_0 > 0`:

      .. math::

         f(d) = 0 \mbox{ for } d \leq -\frac{2 r_0}{k} \;, \\
         f(d) = \frac{k^2}{4 r_0} d^2 + k d + r_0
         \mbox{ for } -\frac{2 r_0}{k} < d \leq 0 \;, \\
         f(d) = k d + f_0 \mbox{ for } d > 0 \;.

      In this case the dependence :math:`f(d)` is smooth, and a (small) force
      is applied even for (small) negative penetrations: :math:`-\frac{2
      r_0}{k} < d \leq 0`.

    :Definition:

    .. math::
        \int_{\Gamma} \ul{v} \cdot f(d(\ul{u})) \ul{n}

    :Arguments:
        - material_f : :math:`[k, f_0]`
        - material_n : :math:`\ul{n}` (special)
        - material_a : :math:`\ul{A}` (special)
        - material_b : :math:`\{\ul{B}_i\}`, :math:`i = 1, \dots, N_B` (special)
        - virtual    : :math:`\ul{v}`
        - state      : :math:`\ul{u}`
    """
    name = 'dw_contact_plane'
    arg_types = ('material_f', 'material_n', 'material_a', 'material_b',
                 'virtual', 'state')
    arg_shapes = {'material_f' : '1, 2', 'material_n' : '.: D',
                  'material_a' : '.: D', 'material_b' : '.: N, D',
                  'virtual' : ('D', 'state'), 'state' : 'D'}
    geometries = ['3_4', '3_8']
    integration = 'surface'

    def __init__(self, *args, **kwargs):
        Term.__init__(self, *args, **kwargs)

        self.cp = None

    @staticmethod
    def function(out, force, normal, geo, fmode):
        bf = geo.bf[0]
        nbf = bf * normal[None, :, None]
        nbf.shape = (bf.shape[0], bf.shape[2] * normal.shape[0])

        if fmode == 0:
            out_qp = force * nbf[None, :, :, None]

        else:
            nbf2 = nbf[:, :, None] * nbf[:, None, :]
            out_qp = force * nbf2[None, :, :, :]

        status = geo.integrate(out, nm.ascontiguousarray(out_qp))

        return status

    @staticmethod
    def smooth_f(d, k, f0, a, eps, diff):
        ii = nm.where((d > eps) & (d <= 0.0))[0]

        if not diff:
            out = nm.where(d > 0.0, k * d + f0, 0.0)
            if len(ii):
                di = d[ii]
                out[ii] = a[ii] * di**2 + k[ii] * di + f0[ii]

        else:
            out = nm.where(d > 0.0, k, 0.0)
            if len(ii):
                out[ii] = 2 * a[ii] * d[ii] + k[ii]

        return out

    @staticmethod
    def _get_force_pars(force_pars, shape):
        k = force_pars[..., 0]
        f0 = force_pars[..., 1]
        k.shape = f0.shape = shape

        ir = f0 >= 1e-14
        eps = nm.where(ir, - 2.0 * f0 / k, 0.0)
        a = nm.zeros_like(eps)
        a[ir] = k[ir]**2 / (4.0 * f0[ir])

        return k, f0, eps, a

    def get_fargs(self, force_pars, normal, anchor, bounds, virtual, state,
                  mode=None, term_mode=None, diff_var=None, **kwargs):
        sg, _ = self.get_mapping(virtual)

        assert_((force_pars >= 0.0).all(),
                'force parameters must be non-negative!')

        if self.cp is None:
            self.cp = ContactPlane(anchor, normal, bounds)

        ig = self.char_fun.ig
        qps = self.get_physical_qps()
        qp_coors = qps.values[ig]
        u_qp = self.get(state, 'val').reshape(qp_coors.shape)

        # Deformed QP coordinates.
        coors = u_qp + qp_coors

        force = nm.zeros(coors.shape[0], dtype=nm.float64)

        k, f0, eps, a = self._get_force_pars(force_pars, force.shape)

        # Active points in contact change with displacements!
        ii = self.cp.mask_points(qp_coors)

        if diff_var is None:
            if ii.any():
                d = self.cp.get_distance(coors[ii])
                # Force in the plane normal direction.
                force[ii] = self.smooth_f(d, k[ii], f0[ii], a[ii], eps[ii], 0)

            fmode = 0

        else:
            if ii.any():
                d = self.cp.get_distance(coors[ii])
                # Force in the plane normal direction derivative.
                force[ii] = self.smooth_f(d, k[ii], f0[ii], a[ii], eps[ii], 1)

            fmode = 1

        force.shape = qps.shape[ig][:2] + (1, 1)

        return force, self.cp.normal, sg, fmode
Esempio n. 5
0
class ContactPlaneTerm(Term):
    r"""
    Small deformation elastic contact plane term with penetration penalty.

    The plane is given by an anchor point :math:`\ul{A}` and a normal
    :math:`\ul{n}`. The contact occurs in points that orthogonally project onto
    the plane into a polygon given by orthogonal projections of boundary points
    :math:`\{\ul{B}_i\}`, :math:`i = 1, \dots, N_B` on the plane. In such
    points, a penetration distance :math:`d(\ul{u}) = (\ul{X} + \ul{u} -
    \ul{A}, \ul{n})` is computed, and a force :math:`f(d(\ul{u})) \ul{n}` is
    applied. The force depends on the non-negative parameters :math:`k`
    (stiffness) and :math:`f_0` (force at zero penetration):

    - If :math:`f_0 = 0`:

      .. math::

         f(d) = 0 \mbox{ for } d \leq 0 \;, \\
         f(d) = k d \mbox{ for } d > 0 \;.

    - If :math:`f_0 > 0`:

      .. math::

         f(d) = 0 \mbox{ for } d \leq -\frac{2 r_0}{k} \;, \\
         f(d) = \frac{k^2}{4 r_0} d^2 + k d + r_0
         \mbox{ for } -\frac{2 r_0}{k} < d \leq 0 \;, \\
         f(d) = k d + f_0 \mbox{ for } d > 0 \;.

      In this case the dependence :math:`f(d)` is smooth, and a (small) force
      is applied even for (small) negative penetrations: :math:`-\frac{2
      r_0}{k} < d \leq 0`.

    :Definition:

    .. math::
        \int_{\Gamma} \ul{v} \cdot f(d(\ul{u})) \ul{n}

    :Arguments:
        - material_f : :math:`[k, f_0]`
        - material_n : :math:`\ul{n}` (special)
        - material_a : :math:`\ul{A}` (special)
        - material_b : :math:`\{\ul{B}_i\}`, :math:`i = 1, \dots, N_B` (special)
        - virtual    : :math:`\ul{v}`
        - state      : :math:`\ul{u}`
    """
    name = 'dw_contact_plane'
    arg_types = ('material_f', 'material_n', 'material_a', 'material_b',
                 'virtual', 'state')
    arg_shapes = {
        'material_f': '1, 2',
        'material_n': '.: D',
        'material_a': '.: D',
        'material_b': '.: N, D',
        'virtual': ('D', 'state'),
        'state': 'D'
    }
    geometries = ['3_4', '3_8']
    integration = 'surface'

    def __init__(self, *args, **kwargs):
        Term.__init__(self, *args, **kwargs)

        self.cp = None

    @staticmethod
    def function(out, force, normal, geo, fmode):
        bf = geo.bf[0]
        nbf = bf * normal[None, :, None]
        nbf.shape = (bf.shape[0], bf.shape[2] * normal.shape[0])

        if fmode == 0:
            out_qp = force * nbf[None, :, :, None]

        else:
            nbf2 = nbf[:, :, None] * nbf[:, None, :]
            out_qp = force * nbf2[None, :, :, :]

        status = geo.integrate(out, nm.ascontiguousarray(out_qp))

        return status

    @staticmethod
    def smooth_f(d, k, f0, a, eps, diff):
        ii = nm.where((d > eps) & (d <= 0.0))[0]

        if not diff:
            out = nm.where(d > 0.0, k * d + f0, 0.0)
            if len(ii):
                di = d[ii]
                out[ii] = a[ii] * di**2 + k[ii] * di + f0[ii]

        else:
            out = nm.where(d > 0.0, k, 0.0)
            if len(ii):
                out[ii] = 2 * a[ii] * d[ii] + k[ii]

        return out

    @staticmethod
    def _get_force_pars(force_pars, shape):
        k = force_pars[..., 0]
        f0 = force_pars[..., 1]
        k.shape = f0.shape = shape

        ir = f0 >= 1e-14
        eps = nm.where(ir, -2.0 * f0 / k, 0.0)
        a = nm.zeros_like(eps)
        a[ir] = k[ir]**2 / (4.0 * f0[ir])

        return k, f0, eps, a

    def get_fargs(self,
                  force_pars,
                  normal,
                  anchor,
                  bounds,
                  virtual,
                  state,
                  mode=None,
                  term_mode=None,
                  diff_var=None,
                  **kwargs):
        sg, _ = self.get_mapping(virtual)

        assert_((force_pars >= 0.0).all(),
                'force parameters must be non-negative!')

        if self.cp is None:
            self.cp = ContactPlane(anchor, normal, bounds)

        ig = self.char_fun.ig
        qps = self.get_physical_qps()
        qp_coors = qps.values[ig]
        u_qp = self.get(state, 'val').reshape(qp_coors.shape)

        # Deformed QP coordinates.
        coors = u_qp + qp_coors

        force = nm.zeros(coors.shape[0], dtype=nm.float64)

        k, f0, eps, a = self._get_force_pars(force_pars, force.shape)

        # Active points in contact change with displacements!
        ii = self.cp.mask_points(qp_coors)

        if diff_var is None:
            if ii.any():
                d = self.cp.get_distance(coors[ii])
                # Force in the plane normal direction.
                force[ii] = self.smooth_f(d, k[ii], f0[ii], a[ii], eps[ii], 0)

            fmode = 0

        else:
            if ii.any():
                d = self.cp.get_distance(coors[ii])
                # Force in the plane normal direction derivative.
                force[ii] = self.smooth_f(d, k[ii], f0[ii], a[ii], eps[ii], 1)

            fmode = 1

        force.shape = qps.shape[ig][:2] + (1, 1)

        return force, self.cp.normal, sg, fmode