Пример #1
0
    def __init__(self, name, mesh, verbose=False, **kwargs):
        """Create a Domain.

        Parameters
        ----------
        name : str
            Object name.
        mesh : Mesh
            A mesh defining the domain.
        """
        Domain.__init__(self, name, mesh=mesh, verbose=verbose, **kwargs)

        if len(mesh.descs) > 1:
            msg = 'meshes with several cell kinds are not supported!'
            raise NotImplementedError(msg)

        self.geom_els = geom_els = {}
        for ig, desc in enumerate(mesh.descs):
            gel = GeometryElement(desc)

            if gel.dim > 0:
                # Create geometry elements of dimension - 1.
                gel.create_surface_facet()

            geom_els[desc] = gel

        for gel in six.itervalues(geom_els):
            key = gel.get_interpolation_name()

            gel.poly_space = PolySpace.any_from_args(key, gel, 1)
            gel = gel.surface_facet
            if gel is not None:
                key = gel.get_interpolation_name()
                gel.poly_space = PolySpace.any_from_args(key, gel, 1)

        self.vertex_set_bcs = self.mesh.nodal_bcs

        self.cmesh = self.mesh.cmesh

        # Must be before creating derived connectivities.
        self.fix_element_orientation()

        from sfepy.discrete.fem.geometry_element import create_geometry_elements
        gels = create_geometry_elements()
        self.cmesh.set_local_entities(gels)
        self.cmesh.setup_entities()

        n_nod, dim = self.mesh.coors.shape
        self.shape = Struct(n_nod=n_nod,
                            dim=dim,
                            tdim=self.cmesh.tdim,
                            n_el=self.cmesh.n_el,
                            n_gr=len(self.geom_els))

        self.reset_regions()
        self.clear_surface_groups()
Пример #2
0
    def test_base_functions_delta(self):
        """
        Test :math:`\delta` property of base functions evaluated in the
        reference element nodes.
        """
        from sfepy.base.base import ordered_iteritems
        from sfepy.discrete import PolySpace

        ok = True

        for key, gel in ordered_iteritems(self.gels):
            for order in range(11):
                ps = PolySpace.any_from_args('aux',
                                             gel,
                                             order,
                                             base='lagrange',
                                             force_bubble=False)
                bf = ps.eval_base(ps.node_coors)
                _ok = nm.allclose(nm.eye(ps.n_nod),
                                  bf.squeeze(),
                                  rtol=0.0,
                                  atol=(order + 1) * 1e-14)

                self.report('%s order %d (n_nod: %d): %s' %
                            (key, order, ps.n_nod, _ok))

                if not _ok:
                    import pdb
                    pdb.set_trace()

            ok = ok and _ok

        return ok
Пример #3
0
    def __init__(self, coors, conn, poly_space=None, gel=None, order=1):
        self.coors = coors
        self.conn = conn

        try:
            nm.take(self.coors, self.conn)

        except IndexError:
            output('coordinates shape: %s' % list(coors.shape))
            output('connectivity: min: %d, max: %d' % (conn.min(), conn.max()))
            msg = 'incompatible connectivity and coordinates (see above)'
            raise IndexError(msg)

        self.n_el, self.n_ep = conn.shape
        self.dim = self.coors.shape[1]

        if poly_space is None:
            poly_space = PolySpace.any_from_args(None,
                                                 gel,
                                                 order,
                                                 base='lagrange',
                                                 force_bubble=False)

        self.poly_space = poly_space
        self.indices = slice(None)
Пример #4
0
    def test_partition_of_unity(self):
        from sfepy.linalg import combine
        from sfepy.discrete import Integral, PolySpace

        ok = True
        orders = {'2_3' : 5, '2_4' : 5, '3_4' : 5, '3_8' : 5}
        bases = (
            [ii for ii in combine([['2_4', '3_8'],
                                   ['lagrange', 'serendipity', 'bernstein']]
            )]
            + [ii for ii in combine([['2_3', '3_4'],
                                     ['lagrange', 'bernstein']])]
        )

        for geom, poly_space_base in bases:
            max_order = orders[geom]
            for order in range(max_order + 1):
                if (poly_space_base == 'serendipity') and not (0 < order < 4):
                    continue
                self.report('geometry: %s, base: %s, order: %d'
                            % (geom, poly_space_base, order))

                integral = Integral('i', order=2 * order)
                coors, _ = integral.get_qp(geom)

                ps = PolySpace.any_from_args('ps', self.gels[geom], order,
                                             base=poly_space_base)
                vals = ps.eval_base(coors)
                _ok = nm.allclose(vals.sum(axis=-1), 1, atol=1e-14, rtol=0.0)
                self.report('partition of unity:', _ok)
                ok = ok and _ok

        return ok
Пример #5
0
    def test_normals(self):
        """
        Check orientations of surface normals on the reference elements.
        """
        import sfepy
        from sfepy.discrete import Integral, PolySpace
        from sfepy.discrete.fem import Mesh, FEDomain
        from sfepy.discrete.fem.mappings import SurfaceMapping
        from sfepy.linalg import normalize_vectors

        ok = True

        for geom in ['2_3', '2_4', '3_4', '3_8']:
            mesh = Mesh.from_file('meshes/elements/%s_1.mesh' % geom,
                                  prefix_dir=sfepy.data_dir)
            domain = FEDomain('domain', mesh)
            surface = domain.create_region('Surface', 'vertices of surface',
                                           'facet')
            domain.create_surface_group(surface)

            sd = domain.surface_groups[surface.name]

            coors = domain.get_mesh_coors()
            gel = domain.geom_els[geom].surface_facet
            ps = PolySpace.any_from_args('aux', gel, 1)

            mapping = SurfaceMapping(coors, sd.get_connectivity(), ps)

            integral = Integral('i', order=1)
            vals, weights = integral.get_qp(gel.name)

            # Evaluate just in the first quadrature point...
            geo = mapping.get_mapping(vals[:1], weights[:1])

            expected = expected_normals[geom].copy()
            normalize_vectors(expected)

            _ok = nm.allclose(expected,
                              geo.normal[:, 0, :, 0],
                              rtol=0.0,
                              atol=1e-14)
            self.report('%s: %s' % (geom, _ok))

            if not _ok:
                self.report('expected:')
                self.report(expected)
                self.report('actual:')
                self.report(geo.normal[:, 0, :, 0])

            ok = ok and _ok

        return ok
Пример #6
0
 def _create_interpolant(self):
     name = self.gel.name + '_DG_legendre'
     ps = PolySpace.any_from_args(name,
                                  self.gel,
                                  self.approx_order,
                                  base=self.poly_space_base,
                                  force_bubble=False)
     self.poly_space = ps
     # 'legendre_simplex' is created for '1_2'.
     if self.gel.name in ["2_4", "3_8"]:
         self.extended = True
     else:
         self.extended = False
Пример #7
0
def compute_nodal_normals(nodes, region, field, return_imap=False):
    """
    Nodal normals are computed by simple averaging of element normals of
    elements every node is contained in.
    """
    dim = region.dim

    field.domain.create_surface_group(region)
    field.setup_surface_data(region)

    # Custom integral with quadrature points in nodes.
    ps = PolySpace.any_from_args('', field.gel.surface_facet,
                                 field.approx_order)
    qp_coors = ps.node_coors
    # Unit normals -> weights = ones.
    qp_weights = nm.ones(qp_coors.shape[0], dtype=nm.float64)

    integral = Integral('aux', coors=qp_coors, weights=qp_weights)

    normals = nm.zeros((nodes.shape[0], dim), dtype=nm.float64)
    mask = nm.zeros((nodes.max() + 1, ), dtype=nm.int32)
    imap = nm.empty_like(mask)
    imap.fill(nodes.shape[0])  # out-of-range index for normals.
    imap[nodes] = nm.arange(nodes.shape[0], dtype=nm.int32)

    cmap, _ = field.get_mapping(region, integral, 'surface')
    e_normals = cmap.normal[..., 0]

    sd = field.surface_data[region.name]
    econn = sd.get_connectivity()
    mask[econn] += 1

    # normals[imap[econn]] += e_normals
    im = imap[econn]
    for ii, en in enumerate(e_normals):
        normals[im[ii]] += en

    # All nodes must have a normal.
    if not nm.all(mask[nodes] > 0):
        raise ValueError('region %s has not complete faces!' % region.name)

    norm = la.norm_l2_along_axis(normals)[:, nm.newaxis]
    if (norm < 1e-15).any():
        raise ValueError('zero nodal normal! (a node in volume?)')
    normals /= norm

    if return_imap:
        return normals, imap

    else:
        return normals
Пример #8
0
    def test_hessians(self):
        """
        Test the second partial derivatives of basis functions using finite
        differences.
        """
        from sfepy.linalg import combine
        from sfepy.discrete import Integral, PolySpace

        ok = True
        orders = {'2_3': 3, '2_4': 3, '3_4': 4, '3_8': 3}
        bases = ([
            ii for ii in combine([['2_3', '2_4', '3_4', '3_8'], ['lagrange']])
        ])

        for geom, poly_space_base in bases:
            self.report('geometry: %s, base: %s' % (geom, poly_space_base))
            order = orders[geom]

            integral = Integral('i', order=order)
            coors, _ = integral.get_qp(geom)

            ps = PolySpace.any_from_args('ps',
                                         self.gels[geom],
                                         order,
                                         base=poly_space_base)

            dim = coors.shape[1]
            h1 = nm.zeros((coors.shape[0], dim, dim, ps.n_nod), nm.float64)
            eps = 1e-8
            for ir in range(dim):
                cc = coors.copy()

                cc[:, ir] -= eps
                aux0 = ps.eval_base(cc, diff=1)

                cc[:, ir] += 2 * eps
                aux1 = ps.eval_base(cc, diff=1)

                h1[:, :, ir, :] = 0.5 * (aux1 - aux0) / eps

            h2 = ps.eval_base(coors, diff=2)

            _ok = nm.allclose(h1, h2, rtol=0, atol=50 * eps)
            self.report('hessians: error: %.2e ok: %s' %
                        (nm.abs(h1 - h2).max(), _ok))
            ok = ok and _ok

        return ok
Пример #9
0
def describe_geometry(field, region, integral):
    """
    Describe membrane geometry in a given region.

    Parameters
    ----------
    field : Field instance
        The field defining the FE approximation.
    region : Region instance
        The surface region to describe.
    integral : Integral instance
        The integral defining the quadrature points.

    Returns
    -------
    mtx_t : array
        The transposed transformation matrix :math:`T`, see
        :func:`create_transformation_matrix`.
    membrane_geo : CMapping instance
        The mapping from transformed elements to a reference elements.
    """
    # Coordinates of element vertices.
    sg, _ = field.get_mapping(region, integral, 'surface')
    sd = field.surface_data[region.name]
    coors = field.coors[sd.econn[:, :sg.n_ep]]

    # Coordinate transformation matrix (transposed!).
    mtx_t = create_transformation_matrix(coors)

    # Transform coordinates to the local coordinate system.
    coors_loc = dot_sequences((coors - coors[:, 0:1, :]), mtx_t)

    # Mapping from transformed elements to reference elements.
    gel = field.gel.surface_facet
    vm = create_mapping(coors_loc, gel, 1)

    qp = integral.get_qp(gel.name)
    ps = PolySpace.any_from_args(None, gel, field.approx_order)
    membrane_geo = vm.get_mapping(qp[0], qp[1], poly_space=ps)
    membrane_geo.bf[:] = ps.eval_base(qp[0])

    return mtx_t, membrane_geo
Пример #10
0
    def test_base_functions_values(self):
        """
        Compare base function values and their gradients with correct
        data. Also test that sum of values over all element nodes gives one.
        """
        from sfepy.base.base import ordered_iteritems
        from sfepy.discrete import PolySpace

        ok = True

        for key, val in ordered_iteritems(test_bases):
            gel = self.gels[key[:3]]
            diff = key[-4:] == 'grad'
            order = int(key[5])
            force_bubble = key[6:7] == 'B'

            ps = PolySpace.any_from_args('aux',
                                         gel,
                                         order,
                                         base='lagrange',
                                         force_bubble=force_bubble)
            dim = ps.geometry.dim
            coors = nm.r_[ps.geometry.coors, [[0.2] * dim]]

            bf = ps.eval_base(coors, diff=diff)
            _ok = nm.allclose(val, bf, rtol=0.0, atol=1e-14)
            ## if not _ok:
            ##     nm.set_printoptions(threshold=1000000, linewidth=65)
            ##     print bf.__repr__()

            if not diff:
                _ok = _ok and nm.allclose(
                    bf.sum(axis=2), 1.0, rtol=0.0, atol=1e-14)

            self.report('%s: %s' % (key, _ok))

            ok = ok and _ok

        return ok
Пример #11
0
 def _create_interpolant(self):
     name = '%s_%s_%s_%d' % (self.gel.name, self.space,
                               self.poly_space_base, self.approx_order)
     ps = PolySpace.any_from_args(name, self.gel, self.approx_order,
                                  base='lagrange', force_bubble=False)
     self.poly_space = ps
Пример #12
0
def main():
    parser = ArgumentParser(description=__doc__)
    parser.add_argument('--version', action='version', version='%(prog)s')
    parser.add_argument('-b',
                        '--basis',
                        metavar='name',
                        action='store',
                        dest='basis',
                        default='lagrange',
                        help=helps['basis'])
    parser.add_argument('-d',
                        '--derivative',
                        metavar='d',
                        type=int,
                        action='store',
                        dest='derivative',
                        default=0,
                        help=helps['derivative'])
    parser.add_argument('-n',
                        '--max-order',
                        metavar='order',
                        type=int,
                        action='store',
                        dest='max_order',
                        default=2,
                        help=helps['max_order'])
    parser.add_argument('-g',
                        '--geometry',
                        metavar='name',
                        action='store',
                        dest='geometry',
                        default='2_4',
                        help=helps['geometry'])
    parser.add_argument('-m',
                        '--mesh',
                        metavar='mesh',
                        action='store',
                        dest='mesh',
                        default=None,
                        help=helps['mesh'])
    parser.add_argument('--permutations',
                        metavar='permutations',
                        action='store',
                        dest='permutations',
                        default=None,
                        help=helps['permutations'])
    parser.add_argument('--dofs',
                        metavar='dofs',
                        action='store',
                        dest='dofs',
                        default=None,
                        help=helps['dofs'])
    parser.add_argument('-l',
                        '--lin-options',
                        metavar='options',
                        action='store',
                        dest='lin_options',
                        default='min_level=2,max_level=5,eps=1e-3',
                        help=helps['lin_options'])
    parser.add_argument('--plot-dofs',
                        action='store_true',
                        dest='plot_dofs',
                        default=False,
                        help=helps['plot_dofs'])
    parser.add_argument('output_dir')
    options = parser.parse_args()

    output_dir = options.output_dir

    output('polynomial space:', options.basis)
    output('max. order:', options.max_order)

    lin = Struct(kind='adaptive', min_level=2, max_level=5, eps=1e-3)
    for opt in options.lin_options.split(','):
        key, val = opt.split('=')
        setattr(lin, key, eval(val))

    if options.mesh is None:
        dim, n_ep = int(options.geometry[0]), int(options.geometry[2])
        output('reference element geometry:')
        output('  dimension: %d, vertices: %d' % (dim, n_ep))

        gel = GeometryElement(options.geometry)
        gps = PolySpace.any_from_args(None, gel, 1, base=options.basis)
        ps = PolySpace.any_from_args(None,
                                     gel,
                                     options.max_order,
                                     base=options.basis)

        n_digit, _format = get_print_info(ps.n_nod, fill='0')
        name_template = os.path.join(output_dir, 'bf_%s.vtk' % _format)
        for ip in get_dofs(options.dofs, ps.n_nod):
            output('shape function %d...' % ip)

            def eval_dofs(iels, rx):
                if options.derivative == 0:
                    bf = ps.eval_base(rx).squeeze()
                    rvals = bf[None, :, ip:ip + 1]

                else:
                    bfg = ps.eval_base(rx, diff=True)
                    rvals = bfg[None, ..., ip]

                return rvals

            def eval_coors(iels, rx):
                bf = gps.eval_base(rx).squeeze()
                coors = nm.dot(bf, gel.coors)[None, ...]
                return coors

            (level, coors, conn, vdofs,
             mat_ids) = create_output(eval_dofs,
                                      eval_coors,
                                      1,
                                      ps,
                                      min_level=lin.min_level,
                                      max_level=lin.max_level,
                                      eps=lin.eps)
            out = {
                'bf':
                Struct(name='output_data',
                       mode='vertex',
                       data=vdofs,
                       var_name='bf',
                       dofs=None)
            }

            mesh = Mesh.from_data('bf_mesh', coors, None, [conn], [mat_ids],
                                  [options.geometry])

            name = name_template % ip
            ensure_path(name)
            mesh.write(name, out=out)

            output('...done (%s)' % name)

    else:
        mesh = Mesh.from_file(options.mesh)
        output('mesh geometry:')
        output('  dimension: %d, vertices: %d, elements: %d' %
               (mesh.dim, mesh.n_nod, mesh.n_el))

        if options.permutations:
            if options.permutations == 'all':
                from sfepy.linalg import cycle
                gel = GeometryElement(mesh.descs[0])
                n_perms = gel.get_conn_permutations().shape[0]
                all_permutations = [ii for ii in cycle(mesh.n_el * [n_perms])]

            else:
                all_permutations = [
                    int(ii) for ii in options.permutations.split(',')
                ]
                all_permutations = nm.array(all_permutations)
                np = len(all_permutations)
                all_permutations.shape = (np // mesh.n_el, mesh.n_el)

            output('using connectivity permutations:\n', all_permutations)

        else:
            all_permutations = [None]

        for ip, permutations in enumerate(all_permutations):
            if permutations is None:
                suffix = ''

            else:
                suffix = '_' + '_'.join('%d' % ii for ii in permutations)

            save_basis_on_mesh(mesh, options, output_dir, lin, permutations,
                               suffix)