Esempio n. 1
0
    def remove_point(self, id_or_name):
        """
        Remove a point by its name or ID.

        If Points are removed, that define polylines,
        they will be removed. Same for surfaces and volumes.

        Parameters
        ----------
        id_or_name : int or str or list of int or list of str
            Points to be removed. Unknown names or IDs are ignored.
        """
        if not isinstance(id_or_name, (list, tuple, set)):
            id_or_name = [id_or_name]

        index_list = []
        for pnt in id_or_name:
            index = -1
            if isinstance(pnt, STRTYPE) and pnt in self.POINT_NAMES:
                index = list(self.POINT_NAMES).index(pnt)
            else:
                try:
                    pnt = int(pnt)
                except ValueError:
                    continue
                if 0 <= pnt < self.POINT_NO:
                    index = pnt
            if index == -1:
                continue
            if index not in index_list:
                index_list.append(index)

        ply_remove = []
        for ply in self.POLYLINES:
            if any([idx in ply["POINTS"] for idx in index_list]):
                ply_remove.append(ply["NAME"])
        self.remove_polyline(ply_remove)

        old_ids = np.delete(np.arange(self.POINT_NO), index_list, 0)
        new_ids = np.arange(len(old_ids))

        for ply in self.POLYLINES:
            ply["POINTS"] = replace(ply["POINTS"], old_ids, new_ids)

        self.POINTS = np.delete(self.POINTS, index_list, 0)
        self.POINT_NAMES = np.delete(self.POINT_NAMES, index_list, 0)
        self.POINT_MD = np.delete(self.POINT_MD, index_list, 0)
Esempio n. 2
0
def combine(mesh_1, mesh_2, decimals=4, fast=True):
    """
    Combine mesh_1 and mesh_2 to one single mesh. The node list will be
    updated to eliminate duplicates. Element intersections are not checked.

    Parameters
    ----------
    mesh_1,mesh_2 : dict
        dictionaries that contain one '#FEM_MSH' block each
        with the following information
            mesh_data : dict
                containing optional information about
                    - AXISYMMETRY (bool)
                    - CROSS_SECTION (bool)
                    - PCS_TYPE (str)
                    - GEO_TYPE (str)
                    - GEO_NAME (str)
                    - LAYER (int)
            nodes : ndarray
                Array with all node postions
            elements : dictionary
                contains array of nodes for elements sorted by element types
            material_id : dictionary
                contains material ids for each element sorted by element types
            element_id : dictionary
                contains element ids for each element sorted by element types
    decimals : int, optional
        Number of decimal places to round the nodes to (default: 3).
        This will not round the output, it is just for comparison of the
        node vectors.
    fast : bool, optional
        If fast is True, the vector comparison is executed by a
        decimal comparison. If fast is False, all pairwise distances
        are calculated. Default: True

    Returns
    -------
    out : dict
        dictionary containing one '#FEM_MSH' block of the mesh file
        with the following information
            mesh_data : dict
                taken from mesh_1
            nodes : ndarray
                Array with all unique node postions
            elements : dictionary
                contains array of nodes for elements sorted by element types
            material_id : dictionary
                contains material ids for each element sorted by element types
            element_id : dictionary
                contains element ids for each element sorted by element types
    """
    # hack to prevent numerical errors from decimal rounding (random shift)
    shift = np.random.rand(3)
    shift_mesh(mesh_1, shift)
    shift_mesh(mesh_2, shift)
    # combine the node lists and make them unique
    nodes, __, ixr = unique_rows(
        np.vstack((mesh_1["nodes"], mesh_2["nodes"])),
        decimals=decimals,
        fast=fast,
    )
    node_id_repl = range(len(ixr))
    node_offset = mesh_1["nodes"].shape[0]

    elements = {}
    material_id = {}
    element_id = {}
    offset = no_of_elements(mesh_1)

    # combine the element lists and replace the new node IDs
    for elem in ELEM_NAMES:
        if elem not in mesh_1["elements"] and elem not in mesh_2["elements"]:
            continue
        elif elem in mesh_1["elements"] and elem not in mesh_2["elements"]:
            tmp = dcp(mesh_1["elements"][elem])
            elements[elem] = replace(tmp, node_id_repl, ixr)
            material_id[elem] = mesh_1["material_id"][elem]
            element_id[elem] = mesh_1["element_id"][elem]
        elif elem not in mesh_1["elements"] and elem in mesh_2["elements"]:
            tmp = mesh_2["elements"][elem] + node_offset
            elements[elem] = replace(tmp, node_id_repl, ixr)
            material_id[elem] = mesh_2["material_id"][elem]
            element_id[elem] = mesh_2["element_id"][elem] + offset
        else:
            tmp = np.vstack((
                mesh_1["elements"][elem],
                mesh_2["elements"][elem] + node_offset,
            ))
            elements[elem] = replace(tmp, node_id_repl, ixr)
            material_id[elem] = np.hstack(
                (mesh_1["material_id"][elem], mesh_2["material_id"][elem]))
            element_id[elem] = np.hstack((
                mesh_1["element_id"][elem],
                mesh_2["element_id"][elem] + offset,
            ))
    # create the ouput dict
    out = {
        "mesh_data": mesh_1["mesh_data"],
        "nodes": nodes,
        "elements": elements,
        "material_id": material_id,
        "element_id": element_id,
    }

    # back shifting of the meshes
    shift_mesh(out, -shift)
    shift_mesh(mesh_1, -shift)
    shift_mesh(mesh_2, -shift)

    return out
Esempio n. 3
0
    def add_polyline(
        self,
        name,
        points,
        ply_id=None,
        epsilon=None,
        ply_type=None,
        mat_group=None,
        point_vector=None,
        closed=False,
        decimals=4,
    ):
        """
        Add a polyline to the gli.

        Parameters
        ----------
        points : ndarray
            Array with new points. Either of shape (n,3) to add new points
            by their coordinates or a list of points IDs refering to existing
            points.
        name : str
            name of the new polyline
        points : ndarray
            Array with the points. Either array of point IDs
            or new coordinates.
        ply_id : int or None, optional
            Default: None
        epsilon : float or None, optional
            Default: None
        ply_type : int or None, optional
            Default: None
        mat_group : int or None, optional
            Default: None
        point_vector : str or None, optional
            Default: None
        closed : bool, optional
            If the polyline shall be closed, the first point will be added
            as last point again. Default: False
        decimals : int, optional
            Number of decimal places to round the added points to (default: 4).
            If decimals is negative, it specifies the number of positions
            to the left of the decimal point.
            This will not round the new points, it's just for comparison of the
            already present points to guarante uniqueness.
        """
        points = np.asanyarray(points)
        name = str(name)
        safe_dict = self()
        if name in self.POLYLINE_NAMES:
            print("gli.add_polyline: Polyline-name already present!")
            return
        # add by id
        if (np.issubdtype(points.dtype, np.integer) and points.ndim == 1
                and points.shape[0] >= 2 and np.min(points) >= 0
                and np.max(points) < self.POINT_NO):
            if closed:
                points = np.hstack((points, points[0]))
            new_ply = {
                "NAME": name,
                "POINTS": points,
                "ID": ply_id,
                "EPSILON": epsilon,
                "TYPE": ply_type,
                "MAT_GROUP": mat_group,
                "POINT_VECTOR": point_vector,
            }
        # add by name
        elif (is_str_array(points) and points.ndim == 1
              and points.shape[0] >= 2
              and all([str(pnt) in self.POINT_NAMES for pnt in points])):
            if closed:
                points = np.hstack((points, points[0]))
            # get IDs from the given names
            # see: https://stackoverflow.com/a/32191125/6696397
            # after the check, if points are IDs...
            points = np.array(
                [
                    np.where(self.POINT_NAMES == str(pnt))[0][0]
                    for pnt in points
                ],
                dtype=int,
            )
            new_ply = {
                "NAME": name,
                "POINTS": points,
                "ID": ply_id,
                "EPSILON": epsilon,
                "TYPE": ply_type,
                "MAT_GROUP": mat_group,
                "POINT_VECTOR": point_vector,
            }
        # add by coordinates
        elif (points.ndim == 2 and points.shape[0] >= 2
              and points.shape[1] == 3):
            if closed:
                points = np.vstack((points, points[0]))
            unique_pnt, __, ixr = unique_rows(points, decimals=decimals)
            new_pos = self.add_points(unique_pnt, decimals=decimals)
            new_points = replace(ixr, np.arange(unique_pnt.shape[0]), new_pos)
            new_ply = {
                "NAME": name,
                "POINTS": new_points,
                "ID": ply_id,
                "EPSILON": epsilon,
                "TYPE": ply_type,
                "MAT_GROUP": mat_group,
                "POINT_VECTOR": point_vector,
            }
        else:
            print("gli.add_polyline: Polyline-points not valid!")
            return
        # add the new polyline
        self.__dict["polylines"].append(new_ply)
        if not check_polyline(new_ply, self.POINT_NO, verbose=False):
            print("gli.add_polyline: Polyline not valid!")
            self.__dict = safe_dict
Esempio n. 4
0
    def add_points(self, points, names=None, md=None, decimals=4):
        """
        Add a list of points (ndarray with shape (n,3)).

        Keeps the pointlist unique.
        If a named point is added, that was already present,
        it will be renamed with the new name. Same for md.
        The pointlists of the polylines will be updated.

        Parameters
        ----------
        points : ndarray
            Array with new points.
        names : ndarray of str or None, optional
            array containing the names.
            If None, all new points are unnamed.
            Default: None
        md : ndarray of float or None, optional
            array containing the material densitiy.
            If None, all new points will have unspecified md.
            Default: None
        decimals : int, optional
            Number of decimal places to round the added points to (default: 4).
            If decimals is negative, it specifies the number of positions
            to the left of the decimal point.
            This will not round the new points, it's just for comparison of the
            already present points to guarante uniqueness.

        Returns
        -------
        new_pos : ndarray
            array with the IDs of the added points in the pointlist of the gli.
        """
        # check if given points are unique
        points = np.array(points, dtype=float, ndmin=2)
        if names is not None:
            names = np.array(names, dtype=object, ndmin=1)
            if points.shape[0] != names.shape[0]:
                print("gli.add_points: Given names are not valid!")
                return np.zeros(0)
        if md is not None:
            md = np.array(md, dtype=float, ndmin=1)
            if points.shape[0] != md.shape[0]:
                print("gli.add_points: Given MDs are not valid!")
                return np.zeros(0)
        if points.shape[1] != 3:
            print("gli.add_points: Given points are not valid!")
            return np.zeros(0)
        check_points, __, __ = unique_rows(points, decimals=decimals)
        if check_points.shape[0] != points.shape[0]:
            print("gli.add_points: Given points are not unique!")
            return np.zeros(0)
        # workaround, if Points are None
        if self.POINT_NO == 0:
            self.POINTS = np.empty((0, 3), dtype=float)
            self.POINT_NAMES = np.empty(0, dtype=object)
            self.POINT_MD = np.empty(0, dtype=float)
        new_points = np.vstack((self.POINTS, points))
        new_points, __, ixr = unique_rows(new_points, decimals=decimals)
        old_pos = ixr[:self.POINT_NO]
        new_pos = ixr[self.POINT_NO:]
        # set the new names
        new_names = np.array(new_points.shape[0] * [""], dtype=object)
        new_names[old_pos] = self.POINT_NAMES
        if names is not None:
            new_names[new_pos] = names
        # set the new MDs
        new_md = -np.inf * np.ones(new_points.shape[0], dtype=float)
        new_md[old_pos] = self.POINT_MD
        if md is not None:
            new_md[new_pos] = md
        # reset the point IDs within the polylines
        for ply_i in range(self.POLYLINE_NO):
            self.__dict["polylines"][ply_i]["POINTS"] = replace(
                self.__dict["polylines"][ply_i]["POINTS"],
                np.arange(self.POINT_NO),
                old_pos,
            )
        # set the new points
        self.POINTS = new_points
        self.POINT_NAMES = new_names
        self.POINT_MD = new_md
        # return the new positions of the added points
        return new_pos