Example #1
0
def fix_missing_midside(cells, nodes, celltypes, offset, angles, nnum):
    """Adds missing midside nodes to cells.

    ANSYS sometimes does not add midside nodes, and this is denoted in
    the element array with a ``0``.  When translated to VTK, this is
    saved as a ``-1``.  If this is not corrected, VTK will segfault.

    This function creates missing midside nodes for the quadratic
    elements.
    """
    # Check for missing midside nodes
    mask = cells == -1
    nnodes = nodes.shape[0]

    nextra = mask.sum()
    cells[mask] = np.arange(nnodes, nnodes + nextra)

    nodes_new = np.empty((nnodes + nextra, 3))
    nodes_new[:nnodes] = nodes
    nodes_new[nnodes:] = 0  # otherwise, segfault disaster

    # Set new midside nodes directly between their edge nodes
    temp_nodes = nodes_new.copy()
    _relaxmidside.reset_midside(cells, celltypes, offset, temp_nodes)

    # merge midside nodes
    unique_nodes, idx_a, idx_b = unique_rows(temp_nodes[nnodes:])

    # rewrite node numbers
    cells[mask] = idx_b + nnodes
    nextra = idx_a.shape[0]  # extra unique nodes
    nodes_new = nodes_new[:nnodes + nextra]
    nodes_new[nnodes:] = unique_nodes

    if angles is not None:
        new_angles = np.empty((nnodes + nextra, 3))
        new_angles[:nnodes] = angles
        new_angles[nnodes:] = 0
    else:
        new_angles = None

    # Add extra node numbers
    nnum_new = np.empty(nnodes + nextra)
    nnum_new[:nnodes] = nnum
    nnum_new[nnodes:] = -1
    return nodes_new, new_angles, nnum_new
Example #2
0
    def parse_vtk(self,
                  force_linear=False,
                  allowable_types=None,
                  null_unallowed=False):
        """Parses raw data into to VTK format.

        Parameters
        ----------
        force_linear : bool, optional
            This parser creates quadratic elements if available.  Set
            this to True to always create linear elements.  Defaults
            to False.

        allowable_types : list, optional
            Allowable element types.  Defaults to all valid element
            types in ``from pyansys.elements.valid_types``

            See help(pyansys.elements) for available element types.

        null_unallowed : bool, optional
            Elements types not matching element types will be stored
            as empty (null) elements.  Useful for debug or tracking
            element numbers.  Default False.

        Returns
        -------
        grid : vtk.vtkUnstructuredGrid
            VTK unstructured grid from archive file.
        """
        if self.check_raw():
            raise Exception('Invalid file or missing key data.  ' +
                            'Cannot parse into unstructured grid')

        # Convert to vtk style arrays
        if allowable_types is None:
            allowable_types = valid_types
        else:
            assert isinstance(allowable_types, list), \
                   'allowable_types must be a list'
            for eletype in allowable_types:
                if str(eletype) not in valid_types:
                    raise Exception('Element type "%s" ' % eletype +
                                    'cannot be parsed in pyansys')

        # construct keyoption array
        keyopts = np.zeros((10000, 20), np.int16)

        for keyopt_key in self.raw['keyopt']:
            for index, value in self.raw['keyopt'][keyopt_key]:
                keyopts[keyopt_key, index] = value

        # parse raw output
        parsed = _parser.parse(self.raw, force_linear, allowable_types,
                               null_unallowed, keyopts)
        cells = parsed['cells']
        offset = parsed['offset']
        cell_type = parsed['cell_type']
        numref = parsed['numref']
        enum = parsed['enum']

        # Check for missing midside nodes
        if force_linear or np.all(cells != -1):
            nodes = self.raw['nodes'][:, :3].copy()
            nnum = self.raw['nnum']
            angles = self.raw['nodes'][:, 3:]
        else:
            mask = cells == -1

            nextra = mask.sum()
            maxnum = numref.max() + 1
            cells[mask] = np.arange(maxnum, maxnum + nextra)

            nnodes = self.raw['nodes'].shape[0]
            nodes = np.zeros((nnodes + nextra, 3))
            nodes[:nnodes] = self.raw['nodes'][:, :3]

            # Set new midside nodes directly between their edge nodes
            temp_nodes = nodes.copy()
            _relaxmidside.reset_midside(cells, cell_type, offset, temp_nodes)
            nodes[nnodes:] = temp_nodes[nnodes:]

            # merge nodes
            new_nodes = temp_nodes[nnodes:]
            unique_nodes, idxA, idxB = unique_rows(new_nodes)

            # rewrite node numbers
            cells[mask] = idxB + maxnum
            nextra = idxA.shape[0]
            nodes = np.empty((nnodes + nextra, 3))
            nodes[:nnodes] = self.raw['nodes'][:, :3]
            nodes[nnodes:] = unique_nodes

            angles = np.empty((nnodes + nextra, 3))
            angles[:nnodes] = self.raw['nodes'][:, 3:]
            angles[nnodes:] = 0

            # Add extra node numbers
            nnum = np.hstack(
                (self.raw['nnum'], np.ones(nextra, np.int32) * -1))

        # Create unstructured grid
        grid = pv.UnstructuredGrid(offset, cells, cell_type, nodes)

        # Store original ANSYS element and cell information
        grid.point_arrays['ansys_node_num'] = nnum
        grid.cell_arrays['ansys_elem_num'] = enum
        grid.cell_arrays['ansys_elem_type_num'] = parsed['etype']
        grid.cell_arrays['ansys_real_constant'] = parsed['rcon']
        grid.cell_arrays['ansys_material_type'] = parsed['mtype']
        grid.cell_arrays['ansys_etype'] = parsed['ansys_etype']

        # Add element components to unstructured grid
        for comp in self.raw['elem_comps']:
            mask = np.in1d(enum,
                           self.raw['elem_comps'][comp],
                           assume_unique=True)
            grid.cell_arrays[comp.strip()] = mask

        # Add node components to unstructured grid
        for comp in self.raw['node_comps']:
            mask = np.in1d(nnum,
                           self.raw['node_comps'][comp],
                           assume_unique=True)
            grid.point_arrays[comp.strip()] = mask

        # Add tracker for original node numbering
        ind = np.arange(grid.number_of_points)
        grid.point_arrays['origid'] = ind
        grid.point_arrays['VTKorigID'] = ind

        # store node angles
        grid.point_arrays['angles'] = angles

        self.grid = grid
        return grid