Esempio n. 1
0
    def create_mapping(self, kind, ig):
        """
        Create mapping from reference elements to physical elements,
        given the integration kind ('v' or 's').

        This mapping can be used to compute the physical quadrature
        points.

        Returns
        -------
        mapping : VolumeMapping or SurfaceMapping instance
            The requested mapping.
        """
        from sfepy.fem.mappings import VolumeMapping, SurfaceMapping
        from sfepy.fem.fe_surface import FESurface

        coors = self.domain.get_mesh_coors()
        if kind == 's':
            coors = coors[self.all_vertices]

        gel = self.domain.groups[ig].gel
        conn = self.domain.groups[ig].conn

        if kind == 'v':
            cells = self.cells[ig]

            mapping = VolumeMapping(coors, conn[cells], gel=gel)

        elif kind == 's':
            aux = FESurface('aux', self, gel.get_surface_entities(), conn, ig)
            mapping = SurfaceMapping(coors, aux.leconn, gel=gel.surface_facet)

        return mapping
Esempio n. 2
0
def create_mapping(coors, gel, order):
    """
    Create mapping from transformed (in `x-y` plane) element faces to
    reference element faces.

    Parameters
    ----------
    coors : array
        The transformed coordinates of element nodes, shape `(n_el,
        n_ep, dim)`. The function verifies that the all `z` components
        are zero.
    gel : GeometryElement instance
        The geometry element corresponding to the faces.
    order : int
        The polynomial order of the mapping.

    Returns
    -------
    mapping : VolumeMapping instance
        The reference element face mapping.
    """
    # Strip 'z' component (should be 0 now...).
    assert_(nm.allclose(coors[:, :, -1], 0.0, rtol=1e-12, atol=1e-12))
    coors = coors[:, :, :-1].copy()

    # Mapping from transformed element to reference element.
    sh = coors.shape
    seq_coors = coors.reshape((sh[0] * sh[1], sh[2]))
    seq_conn = nm.arange(seq_coors.shape[0], dtype=nm.int32)
    seq_conn.shape = sh[:2]

    mapping = VolumeMapping(seq_coors, seq_conn, gel=gel, order=1)

    return mapping
Esempio n. 3
0
    def test_gradients(self):
        from sfepy.fem.mappings import VolumeMapping

        ok = True
        order = 3

        bads = []
        bad_families = set()
        for (geom, poly_space_base, qp_weights, mesh, ir, ic,
             ap, ps, rrc, crc, vec,
             edofs, fdofs) in _gen_common_data(order, self.gels, self.report):
            conn = mesh.conns[0]
            gel = self.gels[geom]

            geo_ps = ap.interp.get_geom_poly_space('v')
            rmapping = VolumeMapping(mesh.coors, conn[:1],
                                     poly_space=geo_ps)
            rori = ap.ori[:1] if ap.ori is not None else None
            rvg = rmapping.get_mapping(rrc, qp_weights,
                                       poly_space=ps, ori=rori)
            rbfg = rvg.bfg

            cmapping = VolumeMapping(mesh.coors, conn[1:],
                                     poly_space=geo_ps)
            cori = ap.ori[1:] if ap.ori is not None else None
            cvg = cmapping.get_mapping(crc, qp_weights,
                                       poly_space=ps, ori=cori)
            cbfg = cvg.bfg

            dofs = nm.r_[edofs, fdofs]

            res = nm.zeros((2, dofs.shape[0]), dtype=nm.int32)
            res[0, :] = dofs
            for ii, ip in enumerate(dofs):
                vec.fill(0.0)
                vec[ip] = 1.0

                evec = vec[ap.econn]

                rvals = nm.dot(rbfg, evec[0])[0]
                cvals = nm.dot(cbfg, evec[1])[0]

                okx = nm.allclose(rvals[:, 0], cvals[:, 0],
                                  atol=1e-14, rtol=0.0)
                if gel.dim == 2:
                    oky = nm.allclose(rvals[:, 1], -cvals[:, 1],
                                      atol=1e-14, rtol=0.0)
                    _ok = okx and oky

                else:
                    oky = nm.allclose(rvals[:, 1], cvals[:, 1],
                                      atol=1e-14, rtol=0.0)
                    okz = nm.allclose(rvals[:, 2], -cvals[:, 2],
                                      atol=1e-14, rtol=0.0)
                    _ok = okx and oky and okz

                res[1, ii] = _ok
                if not _ok:
                    bads.append([geom, poly_space_base, ir, ic, ip])
                    bad_families.add((geom, poly_space_base))

                ok = ok and _ok

            self.report('results (dofs, status: 1 ok, 0 failure):\n%s' % res)

        if not ok:
            self.report('gradient continuity errors:\n', bads)
            self.report('%d in total!' % len(bads))
            self.report('gradient continuity errors occurred in these'
                        ' spaces:\n', bad_families)

        return ok
Esempio n. 4
0
File: fea.py Progetto: sdurve/sfepy
    def describe_geometry(self,
                          field,
                          gtype,
                          region,
                          integral=None,
                          return_mapping=False):
        """
        Compute jacobians, element volumes and base function derivatives
        for Volume-type geometries (volume mappings), and jacobians,
        normals and base function derivatives for Surface-type
        geometries (surface mappings).

        Notes
        -----
        - volume mappings can be defined on a part of an element group,
          although the field has to be defined always on the whole group.
        - surface mappings are defined on the surface region
        - surface mappings require field order to be > 0
        """
        domain = field.domain
        group = domain.groups[self.ig]
        coors = domain.get_mesh_coors(actual=True)

        if gtype == 'volume':
            if integral is None:
                from sfepy.fem import Integral
                integral = Integral('i_tmp', 'v', 1)

            qp = self.get_qp('v', integral)

            iels = region.cells[self.ig]

            geo_ps = self.interp.get_geom_poly_space('v')
            ps = self.interp.poly_spaces['v']
            bf = self.get_base('v', 0, integral, iels=iels)

            conn = nm.take(group.conn, iels, axis=0)
            mapping = VolumeMapping(coors, conn, poly_space=geo_ps)
            vg = mapping.get_mapping(qp.vals,
                                     qp.weights,
                                     poly_space=ps,
                                     ori=self.ori)

            out = vg

        elif (gtype == 'surface') or (gtype == 'surface_extra'):
            assert_(field.approx_order > 0)

            if self.ori is not None:
                msg = 'surface integrals do not work yet with the' \
                      ' hierarchical basis!'
                raise ValueError(msg)

            sd = domain.surface_groups[self.ig][region.name]
            esd = self.surface_data[region.name]

            qp = self.get_qp(sd.face_type, integral)

            geo_ps = self.interp.get_geom_poly_space(sd.face_type)
            ps = self.interp.poly_spaces[esd.face_type]
            bf = self.get_base(esd.face_type, 0, integral)

            conn = sd.get_connectivity()

            mapping = SurfaceMapping(coors, conn, poly_space=geo_ps)
            sg = mapping.get_mapping(qp.vals, qp.weights, poly_space=ps)

            if gtype == 'surface_extra':
                sg.alloc_extra_data(self.get_v_data_shape()[2])

                self.create_bqp(region.name, integral)
                qp = self.qp_coors[(integral.name, esd.bkey)]

                v_geo_ps = self.interp.get_geom_poly_space('v')
                bf_bg = v_geo_ps.eval_base(qp.vals, diff=True)
                ebf_bg = self.get_base(esd.bkey, 1, integral)

                sg.evaluate_bfbgm(bf_bg, ebf_bg, coors, sd.fis, group.conn)

            out = sg

        elif gtype == 'point':
            out = mapping = None

        else:
            raise ValueError('unknown geometry type: %s' % gtype)

        if out is not None:
            # Store the integral used.
            out.integral = integral
            out.qp = qp
            out.ps = ps
            # Update base.
            out.bf[:] = bf

        if return_mapping:
            out = (out, mapping)

        return out
Esempio n. 5
0
    def test_gradients(self):
        from sfepy.fem.mappings import VolumeMapping

        ok = True
        orders = {'2_3' : 3, '2_4' : 3, '3_4' : 4, '3_8' : 3}

        bads = []
        bad_families = set()
        for (geom, poly_space_base, qp_weights, mesh, ir, ic,
             ap, ps, rrc, rcell, crc, ccell, vec,
             edofs, fdofs) in _gen_common_data(orders, self.gels, self.report):
            conn = mesh.conns[0]
            gel = self.gels[geom]

            geo_ps = ap.interp.get_geom_poly_space('v')
            rmapping = VolumeMapping(mesh.coors, conn[rcell:rcell+1],
                                     poly_space=geo_ps)
            rori = ap.ori[:1] if ap.ori is not None else None
            rvg = rmapping.get_mapping(rrc, qp_weights,
                                       poly_space=ps, ori=rori)
            rbfg = rvg.bfg

            cmapping = VolumeMapping(mesh.coors, conn[ccell:ccell+1],
                                     poly_space=geo_ps)
            cori = ap.ori[1:] if ap.ori is not None else None
            cvg = cmapping.get_mapping(crc, qp_weights,
                                       poly_space=ps, ori=cori)
            cbfg = cvg.bfg

            dofs = nm.r_[edofs, fdofs]

            res = nm.zeros((2, dofs.shape[0]), dtype=nm.int32)
            res[0, :] = dofs
            for ii, ip in enumerate(dofs):
                vec.fill(0.0)
                vec[ip] = 1.0

                evec = vec[ap.econn]

                rvals = nm.dot(rbfg, evec[rcell])[0]
                cvals = nm.dot(cbfg, evec[ccell])[0]

                okx = nm.allclose(rvals[:, 0], cvals[:, 0],
                                  atol=1e-12, rtol=0.0)
                if gel.dim == 2:
                    oky = nm.allclose(rvals[:, 1], -cvals[:, 1],
                                      atol=1e-12, rtol=0.0)
                    _ok = okx and oky

                else:
                    oky = nm.allclose(rvals[:, 1], cvals[:, 1],
                                      atol=1e-12, rtol=0.0)
                    okz = nm.allclose(rvals[:, 2], -cvals[:, 2],
                                      atol=1e-12, rtol=0.0)
                    _ok = okx and oky and okz

                res[1, ii] = _ok
                if not _ok:
                    bads.append([geom, poly_space_base, ir, ic, ip])
                    bad_families.add((geom, poly_space_base))

                ok = ok and _ok

            self.report('results (dofs, status: 1 ok, 0 failure):\n%s' % res)

        if not ok:
            self.report('gradient continuity errors:\n', bads)
            self.report('%d in total!' % len(bads))
            self.report('gradient continuity errors occurred in these'
                        ' spaces:\n', bad_families)

        return ok
Esempio n. 6
0
    def describe_dual_surface(self, surface):
        n_fa, n_edge = surface.n_fa, self.sgel.n_edge

        mesh_coors = self.mesh_coors

        # Face centres.
        fcoors = mesh_coors[surface.econn]
        centre_coors = nm.dot(self.bf.squeeze(), fcoors)

        surface_coors = mesh_coors[surface.nodes]

        dual_coors = nm.r_[surface_coors, centre_coors]
        coor_offset = surface.nodes.shape[0]

        # Normals in primary mesh nodes.
        nodal_normals = compute_nodal_normals(surface.nodes, self.region,
                                              self.field)

        ee = surface.leconn[:, self.sgel.edges].copy()
        edges_per_face = ee.copy()
        sh = edges_per_face.shape
        ee.shape = edges_per_face.shape = (sh[0] * sh[1], sh[2])
        edges_per_face.sort(axis=1)

        eo = nm.empty((sh[0] * sh[1], ), dtype=nm.object)
        eo[:] = [tuple(ii) for ii in edges_per_face]

        ueo, e_sort, e_id = unique(eo, return_index=True, return_inverse=True)
        ueo = edges_per_face[e_sort]

        # edge centre, edge point 1, face centre, edge point 2
        conn = nm.empty((n_edge * n_fa, 4), dtype=nm.int32)
        conn[:, 0] = e_id
        conn[:, 1] = ee[:, 0]
        conn[:,2] = nm.repeat(nm.arange(n_fa, dtype=nm.int32), n_edge) \
                    + coor_offset
        conn[:, 3] = ee[:, 1]

        # face centre, edge point 2, edge point 1
        tri_conn = nm.ascontiguousarray(conn[:, [2, 1, 3]])

        # Ensure orientation - outward normal.
        cc = dual_coors[tri_conn]
        v1 = cc[:, 1] - cc[:, 0]
        v2 = cc[:, 2] - cc[:, 0]

        normals = nm.cross(v1, v2)
        nn = nodal_normals[surface.leconn].sum(axis=1).repeat(n_edge, 0)
        centre_normals = (1.0 / surface.n_fp) * nn
        centre_normals /= la.norm_l2_along_axis(centre_normals)[:, None]
        dot = nm.sum(normals * centre_normals, axis=1)

        assert_((dot > 0.0).all())

        # Prepare mapping from reference triangle e_R to a
        # triangle within reference face e_D.
        gel = self.gel.surface_facet
        ref_coors = gel.coors
        ref_centre = nm.dot(self.bf.squeeze(), ref_coors)
        cc = nm.r_[ref_coors, ref_centre[None, :]]
        rconn = nm.empty((n_edge, 3), dtype=nm.int32)
        rconn[:, 0] = gel.n_vertex
        rconn[:, 1] = gel.edges[:, 0]
        rconn[:, 2] = gel.edges[:, 1]

        map_er_ed = VolumeMapping(cc, rconn, gel=gel)

        # Prepare mapping from reference triangle e_R to a
        # physical triangle e.
        map_er_e = SurfaceMapping(dual_coors, tri_conn, gel=gel)

        # Compute triangle basis (edge) vectors.
        nn = surface.nodes[ueo]
        edge_coors = mesh_coors[nn]

        edge_centre_coors = 0.5 * edge_coors.sum(axis=1)

        edge_normals = 0.5 * nodal_normals[ueo].sum(axis=1)

        edge_normals /= la.norm_l2_along_axis(edge_normals)[:, None]

        nn = surface.nodes[ueo]
        edge_dirs = edge_coors[:, 1] - edge_coors[:, 0]
        edge_dirs /= la.norm_l2_along_axis(edge_dirs)[:, None]

        edge_ortho = nm.cross(edge_normals, edge_dirs)
        edge_ortho /= la.norm_l2_along_axis(edge_ortho)[:, None]

        # Primary face - dual sub-faces map.
        # i-th row: indices to conn corresponding to sub-faces of i-th face.
        face_map = nm.arange(n_fa * n_edge, dtype=nm.int32)
        face_map.shape = (n_fa, n_edge)

        # The actual connectivity for assembling (unique nodes per master
        # faces).
        asm_conn = e_id[face_map]

        n_nod = ueo.shape[0]  # One node per unique edge.
        n_components = self.dim - 1

        dual_surface = Struct(name='dual_surface_description',
                              dim=self.dim,
                              n_dual_fa=conn.shape[0],
                              n_dual_fp=self.dim,
                              n_fa=n_fa,
                              n_edge=n_edge,
                              n_nod=n_nod,
                              n_components=n_components,
                              n_dof=n_nod * n_components,
                              dual_coors=dual_coors,
                              coor_offset=coor_offset,
                              e_sort=e_sort,
                              conn=conn,
                              tri_conn=tri_conn,
                              map_er_e=map_er_e,
                              map_er_ed=map_er_ed,
                              face_map=face_map,
                              asm_conn=asm_conn,
                              nodal_normals=nodal_normals,
                              edge_centre_coors=edge_centre_coors,
                              edge_normals=edge_normals,
                              edge_dirs=edge_dirs,
                              edge_ortho=edge_ortho)

        return dual_surface
Esempio n. 7
0
    def describe_geometry(self, field, gtype, region, integral=None,
                          return_mapping=False):
        """
        Compute jacobians, element volumes and base function derivatives
        for Volume-type geometries (volume mappings), and jacobians,
        normals and base function derivatives for Surface-type
        geometries (surface mappings).

        Notes
        -----
        - volume mappings can be defined on a part of an element group,
          although the field has to be defined always on the whole group.
        - surface mappings are defined on the surface region
        - surface mappings require field order to be > 0
        """
        domain = field.domain
        group = domain.groups[self.ig]
        coors = domain.get_mesh_coors(actual=True)

        if gtype == 'volume':
            if integral is None:
                from sfepy.fem import Integral
                integral = Integral('i_tmp', 'v', 1)

            qp = self.get_qp('v', integral)

            iels = region.cells[self.ig]

            geo_ps = self.interp.get_geom_poly_space('v')
            ps = self.interp.poly_spaces['v']
            bf = self.get_base('v', 0, integral, iels=iels)

            conn = nm.take(group.conn, iels, axis=0)
            mapping = VolumeMapping(coors, conn, poly_space=geo_ps)
            vg = mapping.get_mapping(qp.vals, qp.weights, poly_space=ps,
                                     ori=self.ori)

            out = vg

        elif (gtype == 'surface') or (gtype == 'surface_extra'):
            assert_(field.approx_order > 0)

            if self.ori is not None:
                msg = 'surface integrals do not work yet with the' \
                      ' hierarchical basis!'
                raise ValueError(msg)

            sd = domain.surface_groups[self.ig][region.name]
            esd = self.surface_data[region.name]

            qp = self.get_qp(sd.face_type, integral)

            geo_ps = self.interp.get_geom_poly_space(sd.face_type)
            ps = self.interp.poly_spaces[esd.face_type]
            bf = self.get_base(esd.face_type, 0, integral)

            conn = sd.get_connectivity()

            mapping = SurfaceMapping(coors, conn, poly_space=geo_ps)
            sg = mapping.get_mapping(qp.vals, qp.weights, poly_space=ps)

            if gtype == 'surface_extra':
                sg.alloc_extra_data(self.get_v_data_shape()[2])

                self.create_bqp(region.name, integral)
                qp = self.qp_coors[(integral.name, esd.bkey)]

                v_geo_ps = self.interp.get_geom_poly_space('v')
                bf_bg = v_geo_ps.eval_base(qp.vals, diff=True)
                ebf_bg = self.get_base(esd.bkey, 1, integral)

                sg.evaluate_bfbgm(bf_bg, ebf_bg, coors, sd.fis, group.conn)

            out =  sg

        elif gtype == 'point':
            out = mapping = None

        else:
            raise ValueError('unknown geometry type: %s' % gtype)

        if out is not None:
            # Store the integral used.
            out.integral = integral
            out.qp = qp
            out.ps = ps
            # Update base.
            out.bf[:] = bf

        if return_mapping:
            out = (out, mapping)

        return out
Esempio n. 8
0
    def describe_geometry(self, field, gtype, region, integral=None, coors=None):
        """Compute jacobians, element volumes and base function derivatives
        for Volume-type geometries, and jacobians, normals and base function
        derivatives for Surface-type geometries.
        """
        if coors is None:
            coors = field.aps.coors

        if gtype == 'volume':
            if integral is None:
                from sfepy.fem import Integral
                dim = field.domain.shape.dim
                quad_name = 'gauss_o1_d%d' % dim
                integral = Integral('i_tmp', 'v', quad_name)

            qp = self.get_qp('v', integral)

            mapping = VolumeMapping(coors, self.econn,
                                    poly_space=self.interp.poly_spaces['v'])

            try:
                vg = mapping.get_mapping(qp.vals, qp.weights)

            except ValueError: # Constant bubble.
                domain = self.region.domain
                group = domain.groups[self.ig]
                coors = domain.get_mesh_coors()

                ps = self.interp.gel.interp.poly_spaces['v']
                mapping = VolumeMapping(coors, group.conn, poly_space=ps)

                vg = mapping.get_mapping(qp.vals, qp.weights)

            out = vg

        elif (gtype == 'surface') or (gtype == 'surface_extra'):
            sd = self.surface_data[region.name]
            qp = self.get_qp(sd.face_type, integral)

            if not self.is_surface:
                ps = self.interp.poly_spaces[sd.face_type]

            else:
                ps = self.interp.poly_spaces['v']

            mapping = SurfaceMapping(coors, sd.econn, poly_space=ps)

            sg = mapping.get_mapping(qp.vals, qp.weights)

            if gtype == 'surface_extra':
                sg.alloc_extra_data( self.get_v_data_shape()[2] )

                self.create_bqp( region.name, integral )
                bf_bg = self.get_base(sd.bkey, 1, integral)
                sg.evaluate_bfbgm( bf_bg, coors, sd.fis, self.econn )

            out =  sg

        elif gtype == 'point':
            out = None

        else:
            raise ValueError('unknown geometry type: %s' % gtype)

        if out is not None:
            # Store the integral used.
            out.integral = integral

        return out