Пример #1
0
 def reset_regions(self):
     """
     Reset the list of regions associated with the domain.
     """
     self.regions = OneTypeList(Region)
     self._region_stack = []
     self._bnf = create_bnf(self._region_stack)
Пример #2
0
    def from_conf(conf,
                  variables,
                  regions,
                  materials,
                  integrals,
                  user=None,
                  verbose=True):

        objs = OneTypeList(Equation)

        conf = copy(conf)

        ii = 0
        for name, desc in conf.iteritems():
            if verbose:
                output('equation "%s":' % name)
                output(desc)
            eq = Equation.from_desc(name,
                                    desc,
                                    variables,
                                    regions,
                                    materials,
                                    integrals,
                                    user=user)
            objs.append(eq)
            ii += 1

        obj = Equations(objs)

        return obj
Пример #3
0
    def from_conf(conf):
        objs = OneTypeList(Function)
        for key, fc in conf.iteritems():
            fun = Function(name=fc.name, function=fc.function, is_constant=False, extra_args={})
            objs.append(fun)

        obj = Functions(objs)
        return obj
Пример #4
0
    def from_conf(conf):
        objs = OneTypeList(Function)
        for key, fc in conf.iteritems():
            fun = Function(name = fc.name,
                           function = fc.function,
                           is_constant = False,
                           extra_args = {})
            objs.append(fun)

        obj = Functions(objs)
        return obj
Пример #5
0
    def from_file_hdf5(filename, var_names):
        """TODO: do not read entire file, provide data on demand."""
        io = HDF5MeshIO(filename)
        ts = TimeStepper(*io.read_time_stepper())
        steps = nm.arange(ts.n_step, dtype=nm.int32)

        ths = io.read_variables_time_history(var_names, ts)

        objs = OneTypeList(History)
        for name, th in ths.iteritems():
            hist = History(name, steps=steps, times=ts.times, th=th)
            objs.append(hist)

        obj = Histories(objs, dt=ts.dt, name=' '.join(var_names))
        return obj
Пример #6
0
    def from_conf(conf, functions, wanted=None):
        """
        Construct Materials instance from configuration.
        """
        if wanted is None:
            wanted = conf.keys()

        objs = OneTypeList(Material)
        for key, mc in conf.iteritems():
            if key not in wanted: continue

            mat = Material.from_conf(mc, functions)
            objs.append(mat)

        obj = Materials(objs)
        return obj
Пример #7
0
    def from_conf(conf, functions, wanted=None):
        """
        Construct Materials instance from configuration.
        """
        if wanted is None:
            wanted = list(conf.keys())

        objs = OneTypeList(Material)
        for key, mc in six.iteritems(conf):
            if key not in wanted: continue

            mat = Material.from_conf(mc, functions)
            objs.append(mat)

        obj = Materials(objs)
        return obj
Пример #8
0
 def reset_regions(self):
     """
     Reset the list of regions associated with the domain.
     """
     self.regions = OneTypeList(Region)
     self._region_stack = []
     self._bnf = create_bnf(self._region_stack)
Пример #9
0
    def from_conf(conf):
        objs = OneTypeList(Integral)

        for desc in conf.itervalues():
            if hasattr(desc, 'vals'):
                aux = Integral(desc.name,
                               coors=desc.vals,
                               weights=desc.weights)

            else:
                aux = Integral(desc.name, order=desc.order)

            objs.append(aux)

        obj = Integrals(objs)
        return obj
Пример #10
0
    def from_conf(conf):
        objs = OneTypeList(Integral)

        for desc in conf.itervalues():
            if hasattr(desc, 'vals'):
                aux = Integral(desc.name,
                               coors=desc.vals,
                               weights=desc.weights)

            else:
                aux = Integral(desc.name,
                               order=desc.order)

            objs.append(aux)

        obj = Integrals(objs)
        return obj
Пример #11
0
 def semideep_copy(self):
     """Copy materials, while external data (e.g. region) remain shared."""
     others = copy(self)
     others.update(OneTypeList(Material))
     for mat in self:
         other = mat.copy(name=mat.name)
         other.reset()
         others.append(other)
     return others
Пример #12
0
    def from_file_hdf5( filename, var_names ):
        """TODO: do not read entire file, provide data on demand."""
        io = HDF5MeshIO( filename )
        ts = TimeStepper( *io.read_time_stepper() )
        steps = nm.arange( ts.n_step, dtype = nm.int32 )

        ths = io.read_variables_time_history( var_names, ts )

        objs = OneTypeList( History )
        for name, th in six.iteritems(ths):
            hist = History( name,
                            steps = steps,
                            times = ts.times,
                            th = th )
            objs.append( hist )
            
        obj = Histories( objs, dt = ts.dt,
                         name = ' '.join( var_names ) )
        return obj
Пример #13
0
    def from_conf(conf, variables, regions, materials, integrals,
                  user=None, verbose=True):

        objs = OneTypeList(Equation)

        conf = copy(conf)

        ii = 0
        for name, desc in conf.iteritems():
            if verbose:
                output('equation "%s":' %  name)
                output(desc)
            eq = Equation.from_desc(name, desc, variables, regions,
                                    materials, integrals, user=user)
            objs.append(eq)
            ii += 1

        obj = Equations(objs)

        return obj
Пример #14
0
def read_spline_box_hdf5(filename):
    if not pt.isHDF5File(filename):
        raise ValueError, 'not a HDF5 file! (%s)' % filename

    fd = pt.openFile(filename, mode='r')
    boxes = fd.listNodes('/box')
    n_box = len(boxes)
    dim = len(fd.listNodes(boxes[0].ax))

    sp_boxes = SplineBoxes(dim=dim,
                           n_box=n_box,
                           n_vertex=0,
                           spbs=OneTypeList(SplineBox))
    for box in boxes:
        spb = SplineBox()
        sp_boxes.spbs.append(spb)

        spb.ib = int(box._v_name)
        spb.cpi = nm.asarray(box.cpi.read()) - 1
        spb.gpi = nm.asarray(box.gpi.read()) - 1
        spb.cxyz = nm.asarray(box.cxyz.read()).transpose()
        spb.cxyz0 = spb.cxyz.copy()
        spb.ax = []
        for axi in fd.listNodes(box.ax):
            spb.ax.append(nm.asarray(axi.bsc.read()))

        sp_boxes.n_vertex = max(sp_boxes.n_vertex, nm.amax(spb.gpi) + 1)
        print nm.amin(spb.gpi), nm.amax(spb.gpi)

        ##
        # Fix cpi by rebuilding :).
        off = 0
        n0, n1, n2 = spb.cpi.shape
        aux = nm.arange(n0 * n1).reshape(n1, n0).transpose()
        for ii in xrange(n2):
            spb.cpi[:, :, ii] = aux + off
            off += n0 * n1

    fd.close()

    for perm in cycle([n_box] * 2):
        if perm[0] == perm[1]: continue
        gpi1 = sp_boxes.spbs[perm[0]].gpi
        gpi2 = sp_boxes.spbs[perm[1]].gpi
        assert_(len(nm.intersect1d(gpi1, gpi2)) == 0)

    return sp_boxes
Пример #15
0
class Domain(Struct):
    """
    Domain is divided into groups, whose purpose is to have homogeneous
    data shapes."""
    def __init__(self, name, mesh, verbose=False):
        """Create a Domain.

        Parameters
        ----------
        name : str
            Object name.
        mesh : Mesh
            A mesh defining the domain.
        """
        geom_els = {}
        for ig, desc in enumerate(mesh.descs):
            gel = GeometryElement(desc)
            # Create geometry elements of dimension - 1.
            gel.create_surface_facet()

            geom_els[desc] = gel

        interps = {}
        for gel in geom_els.itervalues():
            key = gel.get_interpolation_name()

            gel.interp = interps.setdefault(key, fea.Interpolant(key, gel))
            gel = gel.surface_facet
            if gel is not None:
                key = gel.get_interpolation_name()
                gel.interp = interps.setdefault(key, fea.Interpolant(key, gel))

        Struct.__init__(self,
                        name=name,
                        mesh=mesh,
                        geom_els=geom_els,
                        geom_interps=interps)
        self.mat_ids_to_i_gs = {}
        for ig, mat_id in enumerate(mesh.mat_ids):
            self.mat_ids_to_i_gs[mat_id[0]] = ig

        self.setup_groups()
        self.fix_element_orientation()
        self.setup_facets(verbose=verbose)
        self.reset_regions()
        self.clear_surface_groups()

    def setup_groups(self):

        n_nod, dim = self.mesh.coors.shape
        self.shape = Struct(n_gr=len(self.mesh.conns),
                            n_el=0,
                            n_nod=n_nod,
                            dim=dim)
        self.groups = {}
        for ii in range(self.shape.n_gr):
            gel = self.geom_els[self.mesh.descs[ii]]  # Shortcut.
            conn = self.mesh.conns[ii]
            vertices = nm.unique(conn)

            n_vertex = vertices.shape[0]
            n_el, n_ep = conn.shape
            n_edge = gel.n_edge
            n_edge_total = n_edge * n_el

            if gel.dim == 3:
                n_face = gel.n_face
                n_face_total = n_face * n_el
            else:
                n_face = n_face_total = 0

            shape = Struct(n_vertex=n_vertex,
                           n_el=n_el,
                           n_ep=n_ep,
                           n_edge=n_edge,
                           n_edge_total=n_edge_total,
                           n_face=n_face,
                           n_face_total=n_face_total,
                           dim=self.mesh.dims[ii])

            self.groups[ii] = Struct(ig=ii,
                                     vertices=vertices,
                                     conn=conn,
                                     gel=gel,
                                     shape=shape)
            self.shape.n_el += n_el

    ##
    # c: 22.11.2007, r: 25.03.2008
    def iter_groups(self, igs=None):
        if igs is None:
            for ig in xrange(self.shape.n_gr):  # sorted by ig.
                yield self.groups[ig]
        else:
            for ig in igs:
                yield ig, self.groups[ig]

    ##
    # c: 25.03.2008, r: 25.03.2008
    def get_cell_offsets(self):
        offs = {}
        off = 0
        for group in self.iter_groups():
            ig = group.ig
            offs[ig] = off
            off += group.shape.n_el
        return offs

    def get_mesh_coors(self, actual=False):
        """
        Return the coordinates of the underlying mesh vertices.
        """
        if actual and hasattr(self.mesh, 'coors_act'):
            return self.mesh.coors_act
        else:
            return self.mesh.coors

    def get_mesh_bounding_box(self):
        """
        Return the bounding box of the underlying mesh. 

        Returns
        -------
        bbox : ndarray (2, dim)
            The bounding box with min. values in the first row and max. values
            in the second row.
        """
        return self.mesh.get_bounding_box()

    def get_diameter(self):
        """
        Return the diameter of the domain.

        Notes
        -----
        The diameter corresponds to the Friedrichs constant.
        """
        bbox = self.get_mesh_bounding_box()
        return (bbox[1, :] - bbox[0, :]).max()

    def get_conns(self):
        """
        Return the element connectivity groups of the underlying mesh.
        """
        return self.mesh.conns

    def fix_element_orientation(self):
        """
        Ensure element nodes ordering giving positive element volume.

        The groups with elements of lower dimension than the space dimension
        are skipped.
        """
        from extmods.mesh import orient_elements

        coors = self.mesh.coors
        for ii, group in self.groups.iteritems():
            if group.shape.dim < self.shape.dim: continue

            ori, conn = group.gel.orientation, group.conn

            itry = 0
            while itry < 2:
                flag = -nm.ones(conn.shape[0], dtype=nm.int32)

                # Changes orientation if it is wrong according to swap*!
                # Changes are indicated by positive flag.
                orient_elements(flag, conn, coors, ori.roots, ori.vecs,
                                ori.swap_from, ori.swap_to)

                if nm.alltrue(flag == 0):
                    if itry > 0: output('...corrected')
                    itry = -1
                    break

                output(
                    'warning: bad element orientation, trying to correct...')
                itry += 1

            if itry == 2 and flag[0] != -1:
                raise RuntimeError('elements cannot be oriented! (%d, %s)' %
                                   (ii, self.mesh.descs[ii]))
            elif flag[0] == -1:
                output('warning: element orienation not checked')

    def has_faces(self):
        return sum([group.shape.n_face for group in self.iter_groups()]) > 0

    def setup_facets(self,
                     create_edges=True,
                     create_faces=True,
                     verbose=False):
        """
        Setup the edges and faces (in 3D) of domain elements.
        """
        kinds = ['edges', 'faces']

        is_face = self.has_faces()
        create = [create_edges, create_faces and is_face]

        for ii, kind in enumerate(kinds):
            if create[ii]:
                if verbose:
                    output('setting up domain %s...' % kind)

                tt = time.clock()
                obj = Facets.from_domain(self, kind)
                obj.sort_and_orient()
                obj.setup_unique()
                obj.setup_neighbours()

                # 'ed' or 'fa'
                setattr(self, kind[:2], obj)

                if verbose:
                    output('...done in %.2f s' % (time.clock() - tt))

        if not is_face:
            self.fa = None

    def get_facets(self, force_faces=False):
        """
        Return edge and face descriptions.
        """
        if force_faces and not self.fa:
            return self.ed, self.ed

        else:
            return self.ed, self.fa

    def reset_regions(self):
        """Reset the list of regions associated with the domain."""
        self.regions = OneTypeList(Region)
        self._region_stack = []
        self._bnf = create_bnf(self._region_stack)

    def create_region(self,
                      name,
                      select,
                      flags=None,
                      check_parents=True,
                      functions=None,
                      add_to_regions=True):
        """Region factory constructor. Append the new region to
        self.regions list."""
        if flags is None:
            flags = {}

        if check_parents:
            parents = get_parents(select)
            for p in parents:
                if p not in [region.name for region in self.regions]:
                    msg = 'parent region %s of %s not found!' % (p, name)
                    raise ValueError(msg)

        stack = self._region_stack
        try:
            self._bnf.parseString(select)
        except ParseException:
            print 'parsing failed:', select
            raise

        region = visit_stack(
            stack, region_op, region_leaf(self, self.regions, select,
                                          functions))
        region.name = name

        forbid = flags.get('forbid', None)
        if forbid:
            fb = re.compile('^group +\d+(\s+\d+)*$').match(forbid)
            if fb:
                groups = forbid[5:].strip().split()
                forbid = [int(ii) for ii in groups]
            else:
                raise ValueError('bad forbid! (%s)' % forbid)
            forbidden_igs = [self.mat_ids_to_i_gs[mat_id] for mat_id in forbid]
            region.delete_groups(forbidden_igs)

        region.switch_cells(flags.get('can_cells', True))

        region.complete_description(self.ed, self.fa)

        if add_to_regions:
            self.regions.append(region)

        return region

    def create_regions(self, region_defs, functions=None):
        output('creating regions...')
        tt = time.clock()

        self.reset_regions()

        ##
        # Sort region definitions by dependencies.
        graph, name_to_sort_name = get_dependency_graph(region_defs)
        sorted_regions = sort_by_dependency(graph)
        ##         print sorted_regions

        ##
        # Define regions.
        for name in sorted_regions:
            sort_name = name_to_sort_name[name]
            rdef = region_defs[sort_name]

            region = self.create_region(name,
                                        rdef.select,
                                        flags=rdef,
                                        check_parents=False,
                                        functions=functions)
            output(' ', region.name)

        output('...done in %.2f s' % (time.clock() - tt))

        return self.regions

    ##
    # 31.07.2007, c
    def get_element_diameters(self, ig, cells, vg, mode, square=True):
        group = self.groups[ig]
        diameters = nm.empty((len(cells), 1, 1, 1), dtype=nm.float64)
        if vg is None:
            diameters.fill(1.0)
        else:
            vg.get_element_diameters(diameters, group.gel.edges,
                                     self.get_mesh_coors().copy(), group.conn,
                                     cells, mode)
        if square:
            out = diameters.squeeze()
        else:
            out = nm.sqrt(diameters.squeeze())

        return out

    ##
    # 29.08.2007, re-c from 00.01.18, r: 26.03.2008
    def surface_faces(self):

        if not self.fa:
            print "no faces defined!"
            raise ValueError

        fa = self.fa
        flag = fa.mark_surface_facets()

        surf_faces = []
        itri = nm.where(flag == 3)[0]
        if itri.size:
            surf_faces.append(fa.facets[itri, :3])
        itet = nm.where(flag == 4)[0]
        if itet.size:
            surf_faces.append(fa.facets[itet, :4])

        isurf = nm.where(flag >= 1)[0]
        if isurf.size:
            lst = fa.indices[isurf]

        return lst, surf_faces

    def clear_surface_groups(self):
        """
        Remove surface group data.
        """
        self.surface_groups = {}

    def create_surface_group(self, region):
        """
        Create a new surface group corresponding to `region` if it does
        not exist yet.

        Notes
        -----
        Surface groups define surface facet connectivity that is needed
        for :class:`sfepy.fem.mappings.SurfaceMapping`.
        """
        for ig in region.igs:
            groups = self.surface_groups.setdefault(ig, {})
            if region.name not in groups:
                region.select_cells_of_surface(reset=False)

                group = self.groups[ig]
                gel_faces = group.gel.get_surface_entities()

                name = 'surface_group_%s_%d' % (region.name, ig)
                surface_group = FESurface(name, region, gel_faces, group.conn,
                                          ig)

                groups[region.name] = surface_group

    def refine(self):
        """
        Uniformly refine the domain mesh.

        Returns
        -------
        domain : Domain instance
            The new domain with the refined mesh.

        Notes
        -----
        Works only for meshes with single element type! Does not
        preserve node groups!
        """

        names = set()
        for group in self.groups.itervalues():
            names.add(group.gel.name)

        if len(names) != 1:
            msg = 'refine() works only for meshes with single element type!'
            raise NotImplementedError(msg)

        el_type = names.pop()
        if el_type == '2_3':
            mesh = refine_2_3(self.mesh, self.ed)

        elif el_type == '2_4':
            mesh = refine_2_4(self.mesh, self.ed)

        elif el_type == '3_4':
            mesh = refine_3_4(self.mesh, self.ed)

        elif el_type == '3_8':
            mesh = refine_3_8(self.mesh, self.ed, self.fa)

        else:
            msg = 'unsupported element type! (%s)' % el_type
            raise NotImplementedError(msg)

        domain = Domain(self.name + '_r', mesh)

        return domain
Пример #16
0
class Domain( Struct ):
    """
    Domain is divided into groups, whose purpose is to have homogeneous
    data shapes."""

    def __init__(self, name, mesh, verbose=False):
        """Create a Domain.

        Parameters
        ----------
        name : str
            Object name.
        mesh : Mesh
            A mesh defining the domain.
        """
        geom_els = {}
        for ig, desc in enumerate(mesh.descs):
            gel = GeometryElement(desc)
            # Create geometry elements of dimension - 1.
            gel.create_surface_facet()

            geom_els[desc] = gel

        interps = {}
        for gel in geom_els.itervalues():
            key = gel.get_interpolation_name()

            gel.interp = interps.setdefault(key,
                                            fea.Interpolant(key, gel))
            gel = gel.surface_facet
            if gel is not None:
                key = gel.get_interpolation_name()
                gel.interp = interps.setdefault(key,
                                                fea.Interpolant(key, gel))

        Struct.__init__(self,
                        name = name,
                        mesh = mesh,
                        geom_els = geom_els,
                        geom_interps = interps)
        self.mat_ids_to_i_gs = {}
        for ig, mat_id in enumerate( mesh.mat_ids ):
            self.mat_ids_to_i_gs[mat_id[0]] = ig

        self.setup_groups()
        self.fix_element_orientation()
        self.setup_facets(verbose=verbose)
        self.reset_regions()
        self.clear_surface_groups()

    def setup_groups( self ):

        n_nod, dim = self.mesh.coors.shape
        self.shape = Struct( n_gr = len( self.mesh.conns ), n_el = 0,
                             n_nod = n_nod, dim = dim )
        self.groups = {}
        for ii in range( self.shape.n_gr ):
            gel = self.geom_els[self.mesh.descs[ii]] # Shortcut.
            conn = self.mesh.conns[ii]
            vertices = nm.unique( conn )

            n_vertex = vertices.shape[0]
            n_el, n_ep = conn.shape
            n_edge = gel.n_edge           
            n_edge_total = n_edge * n_el

            if gel.dim == 3:
                n_face = gel.n_face
                n_face_total = n_face * n_el
            else:
                n_face = n_face_total = 0

            shape = Struct(n_vertex=n_vertex, n_el=n_el, n_ep=n_ep,
                           n_edge=n_edge, n_edge_total=n_edge_total,
                           n_face=n_face, n_face_total=n_face_total,
                           dim=self.mesh.dims[ii])

            self.groups[ii] = Struct( ig = ii,
                                      vertices = vertices,
                                      conn = conn,
                                      gel = gel,
                                      shape = shape )
            self.shape.n_el += n_el

    ##
    # c: 22.11.2007, r: 25.03.2008
    def iter_groups( self, igs = None ):
        if igs is None:
            for ig in xrange( self.shape.n_gr ): # sorted by ig.
                yield self.groups[ig]
        else:
            for ig in igs:
                yield ig, self.groups[ig]

    ##
    # c: 25.03.2008, r: 25.03.2008
    def get_cell_offsets( self ):
        offs = {}
        off = 0
        for group in self.iter_groups():
            ig = group.ig
            offs[ig] = off
            off += group.shape.n_el
        return offs

    def get_mesh_coors(self, actual=False):
        """
        Return the coordinates of the underlying mesh vertices.
        """
        if actual and hasattr(self.mesh, 'coors_act'):
            return self.mesh.coors_act
        else:
            return self.mesh.coors

    def get_mesh_bounding_box(self):
        """
        Return the bounding box of the underlying mesh. 

        Returns
        -------
        bbox : ndarray (2, dim)
            The bounding box with min. values in the first row and max. values
            in the second row.
        """
        return self.mesh.get_bounding_box()

    def get_diameter(self):
        """
        Return the diameter of the domain.

        Notes
        -----
        The diameter corresponds to the Friedrichs constant.
        """
        bbox = self.get_mesh_bounding_box()
        return (bbox[1,:] - bbox[0,:]).max()

    def get_conns(self):
        """
        Return the element connectivity groups of the underlying mesh.
        """
        return self.mesh.conns

    def fix_element_orientation(self):
        """
        Ensure element nodes ordering giving positive element volume.

        The groups with elements of lower dimension than the space dimension
        are skipped.
        """
        from extmods.mesh import orient_elements

        coors = self.mesh.coors
        for ii, group in self.groups.iteritems():
            if group.shape.dim < self.shape.dim: continue

            ori, conn = group.gel.orientation, group.conn

            itry = 0
            while itry < 2:
                flag = -nm.ones(conn.shape[0], dtype=nm.int32)

                # Changes orientation if it is wrong according to swap*!
                # Changes are indicated by positive flag.
                orient_elements(flag, conn, coors,
                                ori.roots, ori.vecs,
                                ori.swap_from, ori.swap_to)

                if nm.alltrue( flag == 0 ):
                    if itry > 0: output('...corrected')
                    itry = -1
                    break

                output('warning: bad element orientation, trying to correct...')
                itry += 1

            if itry == 2 and flag[0] != -1:
                raise RuntimeError('elements cannot be oriented! (%d, %s)'
                                   % (ii, self.mesh.descs[ii]))
            elif flag[0] == -1:
                output('warning: element orienation not checked')

    def has_faces( self ):
        return sum( [group.shape.n_face
                     for group in self.iter_groups()] ) > 0

    def setup_facets(self, create_edges=True, create_faces=True,
                     verbose=False):
        """
        Setup the edges and faces (in 3D) of domain elements.
        """
        kinds = ['edges', 'faces']

        is_face = self.has_faces()
        create = [create_edges, create_faces and is_face]

        for ii, kind in enumerate(kinds):
            if create[ii]:
                if verbose:
                    output('setting up domain %s...' % kind)

                tt = time.clock()
                obj = Facets.from_domain(self, kind)
                obj.sort_and_orient()
                obj.setup_unique()
                obj.setup_neighbours()

                # 'ed' or 'fa'
                setattr(self, kind[:2], obj)

                if verbose:
                    output('...done in %.2f s' % (time.clock() - tt))

        if not is_face:
            self.fa = None

    def get_facets(self, force_faces=False):
        """
        Return edge and face descriptions.
        """
        if force_faces and not self.fa:
            return self.ed, self.ed

        else:
            return self.ed, self.fa

    def reset_regions(self):
        """Reset the list of regions associated with the domain."""
        self.regions = OneTypeList(Region)
        self._region_stack = []
        self._bnf = create_bnf(self._region_stack)

    def create_region(self, name, select, flags=None, check_parents=True,
                      functions=None, add_to_regions=True):
        """Region factory constructor. Append the new region to
        self.regions list."""
        if flags is None:
            flags = {}

        if check_parents:
            parents = get_parents(select)
            for p in parents:
                if p not in [region.name for region in self.regions]:
                    msg = 'parent region %s of %s not found!' % (p, name)
                    raise ValueError(msg)

        stack = self._region_stack
        try:
            self._bnf.parseString(select)
        except ParseException:
            print 'parsing failed:', select
            raise

        region = visit_stack(stack, region_op,
                             region_leaf(self, self.regions, select,
                                         functions))
        region.name = name

        forbid = flags.get('forbid', None)
        if forbid:
            fb = re.compile('^group +\d+(\s+\d+)*$').match(forbid)
            if fb:
                groups = forbid[5:].strip().split()
                forbid = [int( ii ) for ii in groups]
            else:
                raise ValueError('bad forbid! (%s)' % forbid)
            forbidden_igs = [self.mat_ids_to_i_gs[mat_id] for mat_id in forbid]
            region.delete_groups(forbidden_igs)

        region.switch_cells(flags.get('can_cells', True))
            
        region.complete_description(self.ed, self.fa)

        if add_to_regions:
            self.regions.append(region)

        return region
            
    def create_regions(self, region_defs, functions=None):
        output( 'creating regions...' )
        tt = time.clock()

        self.reset_regions()

        ##
        # Sort region definitions by dependencies.
        graph, name_to_sort_name = get_dependency_graph(region_defs)
        sorted_regions = sort_by_dependency(graph)
##         print sorted_regions
        
        ##
        # Define regions.
        for name in sorted_regions:
            sort_name = name_to_sort_name[name]
            rdef = region_defs[sort_name]

            region = self.create_region(name, rdef.select,
                                        flags=rdef,
                                        check_parents=False,
                                        functions=functions)
            output(' ', region.name)

        output( '...done in %.2f s' % (time.clock() - tt) )

        return self.regions

    ##
    # 31.07.2007, c
    def get_element_diameters( self, ig, cells, vg, mode, square = True ):
        group = self.groups[ig]
        diameters = nm.empty( (len( cells ), 1, 1, 1), dtype = nm.float64 )
        if vg is None:
            diameters.fill( 1.0 )
        else:
            vg.get_element_diameters( diameters, group.gel.edges,
                                    self.get_mesh_coors().copy(), group.conn,
                                    cells, mode )
        if square:
            out = diameters.squeeze()
        else:
            out = nm.sqrt( diameters.squeeze() )

        return out
            
    ##
    # 29.08.2007, re-c from 00.01.18, r: 26.03.2008
    def surface_faces( self ):

        if not self.fa:
            print "no faces defined!"
            raise ValueError

        fa = self.fa
        flag = fa.mark_surface_facets()

        surf_faces = []
        itri = nm.where(flag == 3)[0]
        if itri.size:
            surf_faces.append( fa.facets[itri,:3] )
        itet = nm.where(flag == 4)[0]
        if itet.size:
            surf_faces.append( fa.facets[itet,:4] )

        isurf = nm.where( flag >= 1 )[0]
        if isurf.size:
            lst = fa.indices[isurf]

        return lst, surf_faces

    def clear_surface_groups(self):
        """
        Remove surface group data.
        """
        self.surface_groups = {}

    def create_surface_group(self, region):
        """
        Create a new surface group corresponding to `region` if it does
        not exist yet.

        Notes
        -----
        Surface groups define surface facet connectivity that is needed
        for :class:`sfepy.fem.mappings.SurfaceMapping`.
        """
        for ig in region.igs:
            groups = self.surface_groups.setdefault(ig, {})
            if region.name not in groups:
                region.select_cells_of_surface(reset=False)

                group = self.groups[ig]
                gel_faces = group.gel.get_surface_entities()

                name = 'surface_group_%s_%d' % (region.name, ig)
                surface_group = FESurface(name, region, gel_faces,
                                          group.conn, ig)

                groups[region.name] = surface_group

    def refine(self):
        """
        Uniformly refine the domain mesh.

        Returns
        -------
        domain : Domain instance
            The new domain with the refined mesh.

        Notes
        -----
        Works only for meshes with single element type! Does not
        preserve node groups!
        """

        names = set()
        for group in self.groups.itervalues():
            names.add(group.gel.name)

        if len(names) != 1:
            msg = 'refine() works only for meshes with single element type!'
            raise NotImplementedError(msg)

        el_type = names.pop()
        if el_type == '2_3':
            mesh = refine_2_3(self.mesh, self.ed)

        elif el_type == '2_4':
            mesh = refine_2_4(self.mesh, self.ed)

        elif el_type == '3_4':
            mesh = refine_3_4(self.mesh, self.ed)

        elif el_type == '3_8':
            mesh = refine_3_8(self.mesh, self.ed, self.fa)

        else:
            msg = 'unsupported element type! (%s)' % el_type
            raise NotImplementedError(msg)

        domain = Domain(self.name + '_r', mesh)

        return domain
Пример #17
0
class Domain(Struct):

    def __init__(self, name, mesh=None, nurbs=None, bmesh=None, regions=None,
                 verbose=False):
        Struct.__init__(self, name=name, mesh=mesh, nurbs=nurbs, bmesh=bmesh,
                        regions=regions, verbose=verbose)

    def get_centroids(self, dim):
        """
        Return the coordinates of centroids of mesh entities with dimension
        `dim`.
        """
        return self.cmesh.get_centroids(dim)

    def has_faces(self):
        return self.shape.tdim == 3

    def reset_regions(self):
        """
        Reset the list of regions associated with the domain.
        """
        self.regions = OneTypeList(Region)
        self._region_stack = []
        self._bnf = create_bnf(self._region_stack)

    def create_region(self, name, select, kind='cell', parent=None,
                      check_parents=True, functions=None, add_to_regions=True,
                      allow_empty=False):
        """
        Region factory constructor. Append the new region to
        self.regions list.
        """
        if check_parents:
            parents = get_parents(select)
            for p in parents:
                if p not in [region.name for region in self.regions]:
                    msg = 'parent region %s of %s not found!' % (p, name)
                    raise ValueError(msg)

        stack = self._region_stack
        try:
            self._bnf.parseString(select)
        except ParseException:
            print 'parsing failed:', select
            raise

        region = visit_stack(stack, region_op,
                             region_leaf(self, self.regions, select, functions))
        region.name = name
        region.definition = select
        region.set_kind(kind)
        region.finalize(allow_empty=allow_empty)
        region.parent = parent
        region.update_shape()

        if add_to_regions:
            self.regions.append(region)

        return region

    def create_regions(self, region_defs, functions=None):
        output('creating regions...')
        tt = time.clock()

        self.reset_regions()

        ##
        # Sort region definitions by dependencies.
        graph, name_to_sort_name = get_dependency_graph(region_defs)
        sorted_regions = sort_by_dependency(graph)

        ##
        # Define regions.
        for name in sorted_regions:
            sort_name = name_to_sort_name[name]
            rdef = region_defs[sort_name]

            region = self.create_region(name, rdef.select,
                                        kind=rdef.get('kind', 'cell'),
                                        parent=rdef.get('parent', None),
                                        check_parents=False,
                                        functions=functions)
            output(' ', region.name)

        output('...done in %.2f s' % (time.clock() - tt))

        return self.regions

    def save_regions(self, filename, region_names=None):
        """
        Save regions as individual meshes.

        Parameters
        ----------
        filename : str
            The output filename.
        region_names : list, optional
            If given, only the listed regions are saved.
        """
        import os

        if region_names is None:
            region_names = self.regions.get_names()

        trunk, suffix = os.path.splitext(filename)

        output('saving regions...')
        for name in region_names:
            region = self.regions[name]
            output(name)
            aux = self.mesh.from_region(region, self.mesh)
            aux.write('%s_%s%s' % (trunk, region.name, suffix),
                      io='auto')
        output('...done')

    def save_regions_as_groups(self, filename, region_names=None):
        """
        Save regions in a single mesh but mark them by using different
        element/node group numbers.

        If regions overlap, the result is undetermined, with exception of the
        whole domain region, which is marked by group id 0.

        Region masks are also saved as scalar point data for output formats
        that support this.

        Parameters
        ----------
        filename : str
            The output filename.
        region_names : list, optional
            If given, only the listed regions are saved.
        """

        output('saving regions as groups...')
        aux = self.mesh.copy()
        n_ig = c_ig = 0
        n_nod = self.shape.n_nod

        # The whole domain region should go first.
        names = (region_names if region_names is not None
                 else self.regions.get_names())
        for name in names:
            region = self.regions[name]
            if region.vertices.shape[0] == n_nod:
                names.remove(region.name)
                names = [region.name] + names
                break

        out = {}
        for name in names:
            region = self.regions[name]
            output(region.name)

            aux.cmesh.vertex_groups[region.vertices] = n_ig
            n_ig += 1

            mask = nm.zeros((n_nod, 1), dtype=nm.float64)
            mask[region.vertices] = 1.0
            out[name] = Struct(name='region', mode='vertex', data=mask,
                               var_name=name, dofs=None)

            if region.has_cells():
                ii = region.get_cells()
                aux.cmesh.cell_groups[ii] = c_ig
                c_ig += 1

        aux.write(filename, io='auto', out=out)
        output('...done')
Пример #18
0
class Domain(Struct):
    """
    Domain is divided into groups, whose purpose is to have homogeneous
    data shapes.
    """
    def __init__(self, name, mesh, verbose=False):
        """Create a Domain.

        Parameters
        ----------
        name : str
            Object name.
        mesh : Mesh
            A mesh defining the domain.
        """
        geom_els = {}
        for ig, desc in enumerate(mesh.descs):
            gel = GeometryElement(desc)
            # Create geometry elements of dimension - 1.
            gel.create_surface_facet()

            geom_els[desc] = gel

        interps = {}
        for gel in geom_els.itervalues():
            key = gel.get_interpolation_name()

            gel.interp = interps.setdefault(key, fea.Interpolant(key, gel))
            gel = gel.surface_facet
            if gel is not None:
                key = gel.get_interpolation_name()
                gel.interp = interps.setdefault(key, fea.Interpolant(key, gel))

        Struct.__init__(self,
                        name=name,
                        mesh=mesh,
                        geom_els=geom_els,
                        geom_interps=interps)

        self.mat_ids_to_i_gs = {}
        for ig, mat_id in enumerate(mesh.mat_ids):
            self.mat_ids_to_i_gs[mat_id[0]] = ig

        self.setup_groups()
        self.fix_element_orientation()
        self.reset_regions()
        self.clear_surface_groups()

        from sfepy.fem.geometry_element import create_geometry_elements
        from sfepy.fem.extmods.cmesh import CMesh
        self.cmesh = CMesh.from_mesh(mesh)
        gels = create_geometry_elements()
        self.cmesh.set_local_entities(gels)
        self.cmesh.setup_entities()

        self.shape.tdim = self.cmesh.tdim

    def setup_groups(self):
        n_nod, dim = self.mesh.coors.shape
        self.shape = Struct(n_gr=len(self.mesh.conns),
                            n_el=0,
                            n_nod=n_nod,
                            dim=dim)
        self.groups = {}
        for ii in range(self.shape.n_gr):
            gel = self.geom_els[self.mesh.descs[ii]]  # Shortcut.
            conn = self.mesh.conns[ii]
            vertices = nm.unique(conn)

            n_vertex = vertices.shape[0]
            n_el, n_ep = conn.shape
            n_edge = gel.n_edge
            n_edge_total = n_edge * n_el

            if gel.dim == 3:
                n_face = gel.n_face
                n_face_total = n_face * n_el
            else:
                n_face = n_face_total = 0

            shape = Struct(n_vertex=n_vertex,
                           n_el=n_el,
                           n_ep=n_ep,
                           n_edge=n_edge,
                           n_edge_total=n_edge_total,
                           n_face=n_face,
                           n_face_total=n_face_total,
                           dim=self.mesh.dims[ii])

            self.groups[ii] = Struct(ig=ii,
                                     vertices=vertices,
                                     conn=conn,
                                     gel=gel,
                                     shape=shape)
            self.shape.n_el += n_el

    def iter_groups(self, igs=None):
        if igs is None:
            for ig in xrange(self.shape.n_gr):  # sorted by ig.
                yield self.groups[ig]
        else:
            for ig in igs:
                yield ig, self.groups[ig]

    def get_cell_offsets(self):
        offs = {}
        off = 0
        for group in self.iter_groups():
            ig = group.ig
            offs[ig] = off
            off += group.shape.n_el
        return offs

    def get_mesh_coors(self, actual=False):
        """
        Return the coordinates of the underlying mesh vertices.
        """
        if actual and hasattr(self.mesh, 'coors_act'):
            return self.mesh.coors_act
        else:
            return self.mesh.coors

    def get_centroids(self, dim):
        """
        Return the coordinates of centroids of mesh entities with dimension
        `dim`.
        """
        return self.cmesh.get_centroids(dim)

    def get_mesh_bounding_box(self):
        """
        Return the bounding box of the underlying mesh.

        Returns
        -------
        bbox : ndarray (2, dim)
            The bounding box with min. values in the first row and max. values
            in the second row.
        """
        return self.mesh.get_bounding_box()

    def get_diameter(self):
        """
        Return the diameter of the domain.

        Notes
        -----
        The diameter corresponds to the Friedrichs constant.
        """
        bbox = self.get_mesh_bounding_box()
        return (bbox[1, :] - bbox[0, :]).max()

    def get_conns(self):
        """
        Return the element connectivity groups of the underlying mesh.
        """
        return self.mesh.conns

    def fix_element_orientation(self):
        """
        Ensure element nodes ordering giving positive element volume.

        The groups with elements of lower dimension than the space dimension
        are skipped.
        """
        from extmods.cmesh import orient_elements

        coors = self.mesh.coors
        for ii, group in self.groups.iteritems():
            if group.shape.dim < self.shape.dim: continue

            ori, conn = group.gel.orientation, group.conn

            itry = 0
            while itry < 2:
                flag = -nm.ones(conn.shape[0], dtype=nm.int32)

                # Changes orientation if it is wrong according to swap*!
                # Changes are indicated by positive flag.
                orient_elements(flag, conn, coors, ori.roots, ori.vecs,
                                ori.swap_from, ori.swap_to)

                if nm.alltrue(flag == 0):
                    if itry > 0: output('...corrected')
                    itry = -1
                    break

                output(
                    'warning: bad element orientation, trying to correct...')
                itry += 1

            if itry == 2 and flag[0] != -1:
                raise RuntimeError('elements cannot be oriented! (%d, %s)' %
                                   (ii, self.mesh.descs[ii]))
            elif flag[0] == -1:
                output('warning: element orienation not checked')

    def has_faces(self):
        return sum([group.shape.n_face for group in self.iter_groups()]) > 0

    def reset_regions(self):
        """
        Reset the list of regions associated with the domain.
        """
        self.regions = OneTypeList(Region)
        self._region_stack = []
        self._bnf = create_bnf(self._region_stack)

    def create_region(self,
                      name,
                      select,
                      kind='cell',
                      parent=None,
                      check_parents=True,
                      functions=None,
                      add_to_regions=True):
        """
        Region factory constructor. Append the new region to
        self.regions list.
        """
        if check_parents:
            parents = get_parents(select)
            for p in parents:
                if p not in [region.name for region in self.regions]:
                    msg = 'parent region %s of %s not found!' % (p, name)
                    raise ValueError(msg)

        stack = self._region_stack
        try:
            self._bnf.parseString(select)
        except ParseException:
            print 'parsing failed:', select
            raise

        region = visit_stack(
            stack, region_op, region_leaf(self, self.regions, select,
                                          functions))
        region.name = name
        region.definition = select
        region.set_kind(kind)
        region.parent = parent
        region.update_shape()

        if add_to_regions:
            self.regions.append(region)

        return region

    def create_regions(self, region_defs, functions=None):
        output('creating regions...')
        tt = time.clock()

        self.reset_regions()

        ##
        # Sort region definitions by dependencies.
        graph, name_to_sort_name = get_dependency_graph(region_defs)
        sorted_regions = sort_by_dependency(graph)

        ##
        # Define regions.
        for name in sorted_regions:
            sort_name = name_to_sort_name[name]
            rdef = region_defs[sort_name]

            region = self.create_region(name,
                                        rdef.select,
                                        kind=rdef.get('kind', 'cell'),
                                        parent=rdef.get('parent', None),
                                        check_parents=False,
                                        functions=functions)
            output(' ', region.name)

        output('...done in %.2f s' % (time.clock() - tt))

        return self.regions

    def save_regions(self, filename, region_names=None):
        """
        Save regions as individual meshes.

        Parameters
        ----------
        filename : str
            The output filename.
        region_names : list, optional
            If given, only the listed regions are saved.
        """
        import os

        if region_names is None:
            region_names = self.regions.get_names()

        trunk, suffix = os.path.splitext(filename)

        output('saving regions...')
        for name in region_names:
            region = self.regions[name]
            output(name)
            aux = self.mesh.from_region(region, self.mesh)
            aux.write('%s_%s%s' % (trunk, region.name, suffix), io='auto')
        output('...done')

    def save_regions_as_groups(self, filename, region_names=None):
        """
        Save regions in a single mesh but mark them by using different
        element/node group numbers.

        If regions overlap, the result is undetermined, with exception of the
        whole domain region, which is marked by group id 0.

        Region masks are also saved as scalar point data for output formats
        that support this.

        Parameters
        ----------
        filename : str
            The output filename.
        region_names : list, optional
            If given, only the listed regions are saved.
        """

        output('saving regions as groups...')
        aux = self.mesh.copy()
        n_ig = c_ig = 0
        n_nod = self.shape.n_nod

        # The whole domain region should go first.
        names = (region_names
                 if region_names is not None else self.regions.get_names())
        for name in names:
            region = self.regions[name]
            if region.vertices.shape[0] == n_nod:
                names.remove(region.name)
                names = [region.name] + names
                break

        out = {}
        for name in names:
            region = self.regions[name]
            output(region.name)

            aux.ngroups[region.vertices] = n_ig
            n_ig += 1

            mask = nm.zeros((n_nod, 1), dtype=nm.float64)
            mask[region.vertices] = 1.0
            out[name] = Struct(name='region',
                               mode='vertex',
                               data=mask,
                               var_name=name,
                               dofs=None)

            if region.has_cells():
                for ig in region.igs:
                    ii = region.get_cells(ig)
                    aux.mat_ids[ig][ii] = c_ig
                    c_ig += 1

        aux.write(filename, io='auto', out=out)
        output('...done')

    def get_element_diameters(self, ig, cells, vg, mode, square=True):
        group = self.groups[ig]
        diameters = nm.empty((len(cells), 1, 1, 1), dtype=nm.float64)
        if vg is None:
            diameters.fill(1.0)
        else:
            vg.get_element_diameters(diameters, group.gel.edges,
                                     self.get_mesh_coors().copy(), group.conn,
                                     cells.astype(nm.int32), mode)
        if square:
            out = diameters.squeeze()
        else:
            out = nm.sqrt(diameters.squeeze())

        return out

    def clear_surface_groups(self):
        """
        Remove surface group data.
        """
        self.surface_groups = {}

    def create_surface_group(self, region):
        """
        Create a new surface group corresponding to `region` if it does
        not exist yet.

        Notes
        -----
        Surface groups define surface facet connectivity that is needed
        for :class:`sfepy.fem.mappings.SurfaceMapping`.
        """
        for ig in region.igs:
            groups = self.surface_groups.setdefault(ig, {})
            if region.name not in groups:
                group = self.groups[ig]
                gel_faces = group.gel.get_surface_entities()

                name = 'surface_group_%s_%d' % (region.name, ig)
                surface_group = FESurface(name, region, gel_faces, group.conn,
                                          ig)

                groups[region.name] = surface_group

    def refine(self):
        """
        Uniformly refine the domain mesh.

        Returns
        -------
        domain : Domain instance
            The new domain with the refined mesh.

        Notes
        -----
        Works only for meshes with single element type! Does not
        preserve node groups!
        """

        names = set()
        for group in self.groups.itervalues():
            names.add(group.gel.name)

        if len(names) != 1:
            msg = 'refine() works only for meshes with single element type!'
            raise NotImplementedError(msg)

        el_type = names.pop()
        if el_type == '2_3':
            mesh = refine_2_3(self.mesh, self.cmesh)

        elif el_type == '2_4':
            mesh = refine_2_4(self.mesh, self.cmesh)

        elif el_type == '3_4':
            mesh = refine_3_4(self.mesh, self.cmesh)

        elif el_type == '3_8':
            mesh = refine_3_8(self.mesh, self.cmesh)

        else:
            msg = 'unsupported element type! (%s)' % el_type
            raise NotImplementedError(msg)

        domain = Domain(self.name + '_r', mesh)

        return domain
Пример #19
0
class Domain(Struct):
    def __init__(self,
                 name,
                 mesh=None,
                 nurbs=None,
                 bmesh=None,
                 regions=None,
                 verbose=False):
        Struct.__init__(self,
                        name=name,
                        mesh=mesh,
                        nurbs=nurbs,
                        bmesh=bmesh,
                        regions=regions,
                        verbose=verbose)

    def get_centroids(self, dim):
        """
        Return the coordinates of centroids of mesh entities with dimension
        `dim`.
        """
        return self.cmesh.get_centroids(dim)

    def has_faces(self):
        return self.shape.tdim == 3

    def reset_regions(self):
        """
        Reset the list of regions associated with the domain.
        """
        self.regions = OneTypeList(Region)
        self._region_stack = []
        self._bnf = create_bnf(self._region_stack)

    def create_region(self,
                      name,
                      select,
                      kind='cell',
                      parent=None,
                      check_parents=True,
                      functions=None,
                      add_to_regions=True,
                      allow_empty=False):
        """
        Region factory constructor. Append the new region to
        self.regions list.
        """
        if check_parents:
            parents = get_parents(select)
            for p in parents:
                if p not in [region.name for region in self.regions]:
                    msg = 'parent region %s of %s not found!' % (p, name)
                    raise ValueError(msg)

        stack = self._region_stack
        try:
            self._bnf.parseString(select)
        except ParseException:
            print('parsing failed:', select)
            raise

        region = visit_stack(
            stack, region_op, region_leaf(self, self.regions, select,
                                          functions))
        region.name = name
        region.definition = select
        region.set_kind(kind)
        region.finalize(allow_empty=allow_empty)
        region.parent = parent
        region.update_shape()

        if add_to_regions:
            self.regions.append(region)

        return region

    def create_regions(self, region_defs, functions=None):
        output('creating regions...')
        tt = time.clock()

        self.reset_regions()

        ##
        # Sort region definitions by dependencies.
        graph, name_to_sort_name = get_dependency_graph(region_defs)
        sorted_regions = sort_by_dependency(graph)

        ##
        # Define regions.
        for name in sorted_regions:
            sort_name = name_to_sort_name[name]
            rdef = region_defs[sort_name]

            region = self.create_region(name,
                                        rdef.select,
                                        kind=rdef.get('kind', 'cell'),
                                        parent=rdef.get('parent', None),
                                        check_parents=False,
                                        functions=functions)
            output(' ', region.name)

        output('...done in %.2f s' % (time.clock() - tt))

        return self.regions

    def save_regions(self, filename, region_names=None):
        """
        Save regions as individual meshes.

        Parameters
        ----------
        filename : str
            The output filename.
        region_names : list, optional
            If given, only the listed regions are saved.
        """
        import os

        if region_names is None:
            region_names = self.regions.get_names()

        trunk, suffix = os.path.splitext(filename)

        output('saving regions...')
        for name in region_names:
            region = self.regions[name]
            output(name)
            aux = self.mesh.from_region(region, self.mesh)
            aux.write('%s_%s%s' % (trunk, region.name, suffix), io='auto')
        output('...done')

    def save_regions_as_groups(self, filename, region_names=None):
        """
        Save regions in a single mesh but mark them by using different
        element/node group numbers.

        If regions overlap, the result is undetermined, with exception of the
        whole domain region, which is marked by group id 0.

        Region masks are also saved as scalar point data for output formats
        that support this.

        Parameters
        ----------
        filename : str
            The output filename.
        region_names : list, optional
            If given, only the listed regions are saved.
        """

        output('saving regions as groups...')
        aux = self.mesh.copy()
        n_ig = c_ig = 0
        n_nod = self.shape.n_nod

        # The whole domain region should go first.
        names = (region_names
                 if region_names is not None else self.regions.get_names())
        for name in names:
            region = self.regions[name]
            if region.vertices.shape[0] == n_nod:
                names.remove(region.name)
                names = [region.name] + names
                break

        out = {}
        for name in names:
            region = self.regions[name]
            output(region.name)

            aux.cmesh.vertex_groups[region.vertices] = n_ig
            n_ig += 1

            mask = nm.zeros((n_nod, 1), dtype=nm.float64)
            mask[region.vertices] = 1.0
            out[name] = Struct(name='region',
                               mode='vertex',
                               data=mask,
                               var_name=name,
                               dofs=None)

            if region.has_cells():
                ii = region.get_cells()
                aux.cmesh.cell_groups[ii] = c_ig
                c_ig += 1

        aux.write(filename, io='auto', out=out)
        output('...done')
Пример #20
0
def create_evaluable(expression, fields, materials, variables, integrals,
                     regions=None,
                     ebcs=None, epbcs=None, lcbcs=None, ts=None, functions=None,
                     auto_init=False, mode='eval', extra_args=None,
                     verbose=True, kwargs=None):
    """
    Create evaluable object (equations and corresponding variables)
    from the `expression` string.

    Parameters
    ----------
    expression : str
        The expression to evaluate.
    fields : dict
        The dictionary of fields used in `variables`.
    materials : Materials instance
        The materials used in the expression.
    variables : Variables instance
        The variables used in the expression.
    integrals : Integrals instance
        The integrals to be used.
    regions : Region instance or list of Region instances
        The region(s) to be used. If not given, the regions defined
        within the fields domain are used.
    ebcs : Conditions instance, optional
        The essential (Dirichlet) boundary conditions for 'weak'
        mode.
    epbcs : Conditions instance, optional
        The periodic boundary conditions for 'weak'
        mode.
    lcbcs : Conditions instance, optional
        The linear combination boundary conditions for 'weak'
        mode.
    ts : TimeStepper instance, optional
        The time stepper.
    functions : Functions instance, optional
        The user functions for boundary conditions, materials
        etc.
    auto_init : bool
        Set values of all variables to all zeros.
    mode : one of 'eval', 'el_avg', 'qp', 'weak'
        The evaluation mode - 'weak' means the finite element
        assembling, 'qp' requests the values in quadrature points,
        'el_avg' element averages and 'eval' means integration over
        each term region.
    extra_args : dict, optional
        Extra arguments to be passed to terms in the expression.
    verbose : bool
        If False, reduce verbosity.
    kwargs : dict, optional
        The variables (dictionary of (variable name) : (Variable
        instance)) to be used in the expression.

    Returns
    -------
    equation : Equation instance
        The equation that is ready to be evaluated.
    variables : Variables instance
        The variables used in the equation.
    """
    if kwargs is None:
        kwargs = {}

    if regions is not None:
        if isinstance(regions, Region):
            regions = [regions]

        regions = OneTypeList(Region, regions)

    else:
        regions = fields[fields.keys()[0]].domain.regions

    # Create temporary variables.
    aux_vars = Variables(variables)

    if extra_args is None:
        extra_args = kwargs

    else:
        extra_args = copy(extra_args)
        extra_args.update(kwargs)

    if ts is not None:
        extra_args.update({'ts' : ts})

    equations = Equations.from_conf({'tmp' : expression},
                                    aux_vars, regions, materials, integrals,
                                    user=extra_args, verbose=verbose)
    equations.collect_conn_info()

    # The true variables used in the expression.
    variables = equations.variables
    if auto_init:
        for var in variables:
            var.init_data(step=0)

    if mode == 'weak':
        equations.time_update(ts, ebcs, epbcs, lcbcs, functions,
                              verbose=verbose)

    else:
        setup_extra_data(equations.conn_info)

    return equations, variables
Пример #21
0
class Domain(Struct):
    """
    Domain is divided into groups, whose purpose is to have homogeneous
    data shapes.
    """

    def __init__(self, name, mesh, verbose=False):
        """Create a Domain.

        Parameters
        ----------
        name : str
            Object name.
        mesh : Mesh
            A mesh defining the domain.
        """
        geom_els = {}
        for ig, desc in enumerate(mesh.descs):
            gel = GeometryElement(desc)
            # Create geometry elements of dimension - 1.
            gel.create_surface_facet()

            geom_els[desc] = gel

        interps = {}
        for gel in geom_els.itervalues():
            key = gel.get_interpolation_name()

            gel.interp = interps.setdefault(key, fea.Interpolant(key, gel))
            gel = gel.surface_facet
            if gel is not None:
                key = gel.get_interpolation_name()
                gel.interp = interps.setdefault(key, fea.Interpolant(key, gel))

        Struct.__init__(self, name=name, mesh=mesh, geom_els=geom_els,
                        geom_interps=interps)

        self.mat_ids_to_i_gs = {}
        for ig, mat_id in enumerate(mesh.mat_ids):
            self.mat_ids_to_i_gs[mat_id[0]] = ig

        self.setup_groups()
        self.fix_element_orientation()
        self.reset_regions()
        self.clear_surface_groups()

        from sfepy.fem.geometry_element import create_geometry_elements
        from sfepy.fem.extmods.cmesh import CMesh
        self.cmesh = CMesh.from_mesh(mesh)
        gels = create_geometry_elements()
        self.cmesh.set_local_entities(gels)
        self.cmesh.setup_entities()

        self.shape.tdim = self.cmesh.tdim

    def setup_groups(self):
        n_nod, dim = self.mesh.coors.shape
        self.shape = Struct(n_gr=len(self.mesh.conns), n_el=0,
                            n_nod=n_nod, dim=dim)
        self.groups = {}
        for ii in range(self.shape.n_gr):
            gel = self.geom_els[self.mesh.descs[ii]] # Shortcut.
            conn = self.mesh.conns[ii]
            vertices = nm.unique(conn)

            n_vertex = vertices.shape[0]
            n_el, n_ep = conn.shape
            n_edge = gel.n_edge
            n_edge_total = n_edge * n_el

            if gel.dim == 3:
                n_face = gel.n_face
                n_face_total = n_face * n_el
            else:
                n_face = n_face_total = 0

            shape = Struct(n_vertex=n_vertex, n_el=n_el, n_ep=n_ep,
                           n_edge=n_edge, n_edge_total=n_edge_total,
                           n_face=n_face, n_face_total=n_face_total,
                           dim=self.mesh.dims[ii])

            self.groups[ii] = Struct(ig=ii, vertices=vertices, conn=conn,
                                      gel=gel, shape=shape)
            self.shape.n_el += n_el

    def iter_groups(self, igs=None):
        if igs is None:
            for ig in xrange(self.shape.n_gr): # sorted by ig.
                yield self.groups[ig]
        else:
            for ig in igs:
                yield ig, self.groups[ig]

    def get_cell_offsets(self):
        offs = {}
        off = 0
        for group in self.iter_groups():
            ig = group.ig
            offs[ig] = off
            off += group.shape.n_el
        return offs

    def get_mesh_coors(self, actual=False):
        """
        Return the coordinates of the underlying mesh vertices.
        """
        if actual and hasattr(self.mesh, 'coors_act'):
            return self.mesh.coors_act
        else:
            return self.mesh.coors

    def get_centroids(self, dim):
        """
        Return the coordinates of centroids of mesh entities with dimension
        `dim`.
        """
        return self.cmesh.get_centroids(dim)

    def get_mesh_bounding_box(self):
        """
        Return the bounding box of the underlying mesh.

        Returns
        -------
        bbox : ndarray (2, dim)
            The bounding box with min. values in the first row and max. values
            in the second row.
        """
        return self.mesh.get_bounding_box()

    def get_diameter(self):
        """
        Return the diameter of the domain.

        Notes
        -----
        The diameter corresponds to the Friedrichs constant.
        """
        bbox = self.get_mesh_bounding_box()
        return (bbox[1,:] - bbox[0,:]).max()

    def get_conns(self):
        """
        Return the element connectivity groups of the underlying mesh.
        """
        return self.mesh.conns

    def fix_element_orientation(self):
        """
        Ensure element nodes ordering giving positive element volume.

        The groups with elements of lower dimension than the space dimension
        are skipped.
        """
        from extmods.cmesh import orient_elements

        coors = self.mesh.coors
        for ii, group in self.groups.iteritems():
            if group.shape.dim < self.shape.dim: continue

            ori, conn = group.gel.orientation, group.conn

            itry = 0
            while itry < 2:
                flag = -nm.ones(conn.shape[0], dtype=nm.int32)

                # Changes orientation if it is wrong according to swap*!
                # Changes are indicated by positive flag.
                orient_elements(flag, conn, coors,
                                ori.roots, ori.vecs,
                                ori.swap_from, ori.swap_to)

                if nm.alltrue(flag == 0):
                    if itry > 0: output('...corrected')
                    itry = -1
                    break

                output('warning: bad element orientation, trying to correct...')
                itry += 1

            if itry == 2 and flag[0] != -1:
                raise RuntimeError('elements cannot be oriented! (%d, %s)'
                                   % (ii, self.mesh.descs[ii]))
            elif flag[0] == -1:
                output('warning: element orienation not checked')

    def has_faces(self):
        return sum([group.shape.n_face
                    for group in self.iter_groups()]) > 0

    def reset_regions(self):
        """
        Reset the list of regions associated with the domain.
        """
        self.regions = OneTypeList(Region)
        self._region_stack = []
        self._bnf = create_bnf(self._region_stack)

    def create_region(self, name, select, kind='cell', parent=None,
                      check_parents=True, functions=None, add_to_regions=True):
        """
        Region factory constructor. Append the new region to
        self.regions list.
        """
        if check_parents:
            parents = get_parents(select)
            for p in parents:
                if p not in [region.name for region in self.regions]:
                    msg = 'parent region %s of %s not found!' % (p, name)
                    raise ValueError(msg)

        stack = self._region_stack
        try:
            self._bnf.parseString(select)
        except ParseException:
            print 'parsing failed:', select
            raise

        region = visit_stack(stack, region_op,
                             region_leaf(self, self.regions, select, functions))
        region.name = name
        region.definition = select
        region.set_kind(kind)
        region.parent = parent
        region.update_shape()

        if add_to_regions:
            self.regions.append(region)

        return region

    def create_regions(self, region_defs, functions=None):
        output('creating regions...')
        tt = time.clock()

        self.reset_regions()

        ##
        # Sort region definitions by dependencies.
        graph, name_to_sort_name = get_dependency_graph(region_defs)
        sorted_regions = sort_by_dependency(graph)

        ##
        # Define regions.
        for name in sorted_regions:
            sort_name = name_to_sort_name[name]
            rdef = region_defs[sort_name]

            region = self.create_region(name, rdef.select,
                                        kind=rdef.get('kind', 'cell'),
                                        parent=rdef.get('parent', None),
                                        check_parents=False,
                                        functions=functions)
            output(' ', region.name)

        output('...done in %.2f s' % (time.clock() - tt))

        return self.regions

    def save_regions(self, filename, region_names=None):
        """
        Save regions as individual meshes.

        Parameters
        ----------
        filename : str
            The output filename.
        region_names : list, optional
            If given, only the listed regions are saved.
        """
        import os

        if region_names is None:
            region_names = self.regions.get_names()

        trunk, suffix = os.path.splitext(filename)

        output('saving regions...')
        for name in region_names:
            region = self.regions[name]
            output(name)
            aux = self.mesh.from_region(region, self.mesh)
            aux.write('%s_%s%s' % (trunk, region.name, suffix),
                      io='auto')
        output('...done')

    def save_regions_as_groups(self, filename, region_names=None):
        """
        Save regions in a single mesh but mark them by using different
        element/node group numbers.

        If regions overlap, the result is undetermined, with exception of the
        whole domain region, which is marked by group id 0.

        Region masks are also saved as scalar point data for output formats
        that support this.

        Parameters
        ----------
        filename : str
            The output filename.
        region_names : list, optional
            If given, only the listed regions are saved.
        """

        output('saving regions as groups...')
        aux = self.mesh.copy()
        n_ig = c_ig = 0
        n_nod = self.shape.n_nod

        # The whole domain region should go first.
        names = (region_names if region_names is not None
                 else self.regions.get_names())
        for name in names:
            region = self.regions[name]
            if region.vertices.shape[0] == n_nod:
                names.remove(region.name)
                names = [region.name] + names
                break

        out = {}
        for name in names:
            region = self.regions[name]
            output(region.name)

            aux.ngroups[region.vertices] = n_ig
            n_ig += 1

            mask = nm.zeros((n_nod, 1), dtype=nm.float64)
            mask[region.vertices] = 1.0
            out[name] = Struct(name='region', mode='vertex', data=mask,
                               var_name=name, dofs=None)

            if region.has_cells():
                for ig in region.igs:
                    ii = region.get_cells(ig)
                    aux.mat_ids[ig][ii] = c_ig
                    c_ig += 1

        aux.write(filename, io='auto', out=out)
        output('...done')

    def get_element_diameters(self, ig, cells, vg, mode, square=True):
        group = self.groups[ig]
        diameters = nm.empty((len(cells), 1, 1, 1), dtype=nm.float64)
        if vg is None:
            diameters.fill(1.0)
        else:
            vg.get_element_diameters(diameters, group.gel.edges,
                                     self.get_mesh_coors().copy(), group.conn,
                                     cells.astype(nm.int32), mode)
        if square:
            out = diameters.squeeze()
        else:
            out = nm.sqrt(diameters.squeeze())

        return out

    def clear_surface_groups(self):
        """
        Remove surface group data.
        """
        self.surface_groups = {}

    def create_surface_group(self, region):
        """
        Create a new surface group corresponding to `region` if it does
        not exist yet.

        Notes
        -----
        Surface groups define surface facet connectivity that is needed
        for :class:`sfepy.fem.mappings.SurfaceMapping`.
        """
        for ig in region.igs:
            groups = self.surface_groups.setdefault(ig, {})
            if region.name not in groups:
                group = self.groups[ig]
                gel_faces = group.gel.get_surface_entities()

                name = 'surface_group_%s_%d' % (region.name, ig)
                surface_group = FESurface(name, region, gel_faces,
                                          group.conn, ig)

                groups[region.name] = surface_group

    def refine(self):
        """
        Uniformly refine the domain mesh.

        Returns
        -------
        domain : Domain instance
            The new domain with the refined mesh.

        Notes
        -----
        Works only for meshes with single element type! Does not
        preserve node groups!
        """

        names = set()
        for group in self.groups.itervalues():
            names.add(group.gel.name)

        if len(names) != 1:
            msg = 'refine() works only for meshes with single element type!'
            raise NotImplementedError(msg)

        el_type = names.pop()
        if el_type == '2_3':
            mesh = refine_2_3(self.mesh, self.cmesh)

        elif el_type == '2_4':
            mesh = refine_2_4(self.mesh, self.cmesh)

        elif el_type == '3_4':
            mesh = refine_3_4(self.mesh, self.cmesh)

        elif el_type == '3_8':
            mesh = refine_3_8(self.mesh, self.cmesh)

        else:
            msg = 'unsupported element type! (%s)' % el_type
            raise NotImplementedError(msg)

        domain = Domain(self.name + '_r', mesh)

        return domain
Пример #22
0
def extract_time_history(filename, extract, verbose=True):
    """Extract time history of a variable from a multi-time-step results file.

    Parameters
    ----------
    filename : str
        The name of file to extract from.
    extract : str
        The description of what to extract in a string of comma-separated
        description items. A description item consists of: name of the variable
        to extract, mode ('e' for elements, 'n' for nodes), ids of the nodes or
        elements (given by the mode). Example: 'u n 10 15, p e 0' means
        variable 'u' in nodes 10, 15 and variable 'p' in element 0.
    verbose : bool
        Verbosity control.

    Returns
    -------
    ths : dict
        The time histories in a dict with variable names as keys. If a
        nodal variable is requested in elements, its value is a dict of histories
        in the element nodes.
    ts : TimeStepper instance
        The time stepping information.
    """
    output('extracting selected data...', verbose=verbose)

    output('selection:', extract, verbose=verbose)

    ##
    # Parse extractions.
    pes = OneTypeList(Struct)
    for chunk in extract.split(','):
        aux = chunk.strip().split()
        pes.append(Struct(var = aux[0],
                          mode = aux[1],
                          indx = map(int, aux[2:]),
                          igs = None))

    ##
    # Verify array limits, set igs for element data, shift indx.
    mesh = Mesh.from_file(filename)
    n_el, n_els, offs = mesh.n_el, mesh.n_els, mesh.el_offsets
    for pe in pes:
        if pe.mode == 'n':
            for ii in pe.indx:
                if (ii < 0) or (ii >= mesh.n_nod):
                    raise ValueError('node index 0 <= %d < %d!'
                                     % (ii, mesh.n_nod))

        if pe.mode == 'e':
            pe.igs = []
            for ii, ie in enumerate(pe.indx[:]):
                if (ie < 0) or (ie >= n_el):
                    raise ValueError('element index 0 <= %d < %d!'
                                     % (ie, n_el))
                ig = (ie < n_els).argmax()
                pe.igs.append(ig)
                pe.indx[ii] = ie - offs[ig]

##     print pes

    ##
    # Extract data.
    # Assumes only one element group (ignores igs)!
    io = MeshIO.any_from_filename(filename)
    ths = {}
    for pe in pes:
        mode, nname = io.read_data_header(pe.var)
        output(mode, nname, verbose=verbose)

        if ((pe.mode == 'n' and mode == 'vertex') or
            (pe.mode == 'e' and mode == 'cell')):
            th = io.read_time_history(nname, pe.indx)

        elif pe.mode == 'e' and mode == 'vertex':
            conn = mesh.conns[0]
            th = {}
            for iel in pe.indx:
                ips = conn[iel]
                th[iel] = io.read_time_history(nname, ips)
        else:
            raise ValueError('cannot extract cell data %s in nodes!' % pe.var)
            
        ths[pe.var] = th

    output('...done', verbose=verbose)

    ts = TimeStepper(*io.read_time_stepper())

    return ths, ts