예제 #1
0
def quality(grid):
    """Compute the minimum scaled Jacobian cell quality of an UnstructuredGrid.

    Negative values indicate invalid cells while positive values
    indicate valid cells.  Varies between -1 and 1.

    Examples
    --------
    >>> import pyansys
    >>> import pyvista as pv
    >>> x = np.arange(-10, 10, 5)
    >>> y = np.arange(-10, 10, 5)
    >>> z = np.arange(-10, 10, 5)
    >>> x, y, z = np.meshgrid(x, y, z)
    >>> grid = pv.StructuredGrid(x, y, z)
    >>> pyansys.quality(grid)
    array([1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1.,
           1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1.])
    """
    flip = False
    if isinstance(grid, pv.StructuredGrid):
        grid = grid.cast_to_unstructured_grid()
        flip = True
    elif not isinstance(grid, pv.UnstructuredGrid):
        grid = pv.wrap(grid)
        if not isinstance(pv.UnstructuredGrid):
            raise TypeError(
                'Input grid should be a pyvista or vtk UnstructuredGrid')

    celltypes = grid.celltypes
    points = grid.points
    cells, offset = vtk_cell_info(grid)
    if points.dtype == np.float64:
        qual = cell_quality(cells, offset, celltypes, points)
    elif points.dtype == np.float32:
        qual = cell_quality_float(cells, offset, celltypes, points)
    else:
        points = points.astype(np.float64)
        qual = cell_quality(cells, offset, celltypes, points)

    # set qual of null cells to 1
    qual[grid.celltypes == 0] = 1
    if flip:  # for strucutred grids
        return -qual
    return qual
예제 #2
0
파일: archive.py 프로젝트: vsriv90/pyansys
    def quality(self):
        """Minimum scaled jacobian cell quality.

        Negative values indicate invalid cells while positive values
        indicate valid cells.  Varies between -1 and 1.

        Examples
        --------
        >>> import pyansys
        >>> archive = pyansys.Archive(pyansys.examples.hexarchivefile,
        >>> archive.quality
        array([1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1.,
               1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1.,
               1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1.])
        """
        celltypes = self.grid.celltypes
        points = self.grid.points
        cells, offset = vtk_cell_info(self.grid)
        if points.dtype == np.float64:
            return cell_quality(cells, offset, celltypes, points)

        return cell_quality_float(cells, offset, celltypes, points)
예제 #3
0
def save_as_archive(filename,
                    grid,
                    mtype_start=1,
                    etype_start=1,
                    real_constant_start=1,
                    mode='w',
                    nblock=True,
                    enum_start=1,
                    nnum_start=1,
                    include_etype_header=True,
                    reset_etype=False,
                    allow_missing=True,
                    include_surface_elements=True,
                    include_solid_elements=True):
    """Writes FEM as an ANSYS APDL archive file.  This function
    supports the following element types:

        - ``vtk.VTK_TETRA``
        - ``vtk.VTK_QUADRATIC_TETRA``
        - ``vtk.VTK_PYRAMID``
        - ``vtk.VTK_QUADRATIC_PYRAMID``
        - ``vtk.VTK_WEDGE``
        - ``vtk.VTK_QUADRATIC_WEDGE``
        - ``vtk.VTK_HEXAHEDRON``
        - ``vtk.VTK_QUADRATIC_HEXAHEDRON``

    Will automatically renumber nodes and elements if the FEM does not
    contain ANSYS node or element numbers.  Node numbers are stored as
    a point array "ansys_node_num", and cell numbers are stored as
    cell array "ansys_elem_num".

    Parameters
    ----------
    filename : str
       Filename to write archive file.

    grid : vtk.UnstructuredGrid
        VTK UnstructuredGrid to convert to an APDL archive file.
        PolyData will automatically be converted to an unstructured
        mesh.

    mtype_start : int, optional
        Material number to assign to elements.  Can be set manually by
        adding the cell array "mtype" to the unstructured grid.

    etype_start : int, optional
        Starting element type number.  Can be manually set by adding
        the cell array "ansys_etype" to the unstructured grid.

    real_constant_start : int, optional
        Starting real constant to assign to unset cells.  Can be
        manually set by adding the cell array "ansys_real_constant" to
        the unstructured grid.

    mode : str, optional
        File mode.  See help(open)

    nblock : bool, optional
        Write node block when writing archive file.

    enum_start : int, optional
        Starting element number to assign to unset cells.  Can be
        manually set by adding the cell array "ansys_elem_num" to the
        unstructured grid.

    nnum_start : int, optional
        Starting element number to assign to unset points.  Can be
        manually set by adding the point array "ansys_node_num" to the
        unstructured grid.

    include_etype_header : bool, optional
        For each element type, includes element type command
        (e.g. "ET, 1, 186") in the archive file.

    reset_etype : bool, optional
        Resets element type.  Element types will automatically be
        determined by the shape of the element (i.e. quadradic
        tetrahedrals will be saved as SOLID187, linear hexahedrals as
        SOLID185).  Default True.

    include_surface_elements : bool, optional
        Includes surface elements when writing the archive file and
        saves them as SHELL181.

    include_solid_elements : bool, optional
        Includes solid elements when writing the archive file and
        saves them as SOLID185, SOLID186, or SOLID187.

    """
    header = '/PREP7\n'

    if isinstance(grid, pv.PolyData):
        grid = grid.cast_to_unstructured_grid()

    allowable = []
    if include_solid_elements:
        allowable.extend([
            VTK_TETRA, VTK_QUADRATIC_TETRA, VTK_PYRAMID, VTK_QUADRATIC_PYRAMID,
            VTK_WEDGE, VTK_QUADRATIC_WEDGE, VTK_HEXAHEDRON,
            VTK_QUADRATIC_HEXAHEDRON
        ])

    if include_surface_elements:
        allowable.extend([VTK_TRIANGLE, VTK_QUAD])
        # VTK_QUADRATIC_TRIANGLE,
        # VTK_QUADRATIC_QUAD

    # extract allowable cell types
    mask = np.in1d(grid.celltypes, allowable)
    grid = grid.extract_cells(mask)

    # node numbers
    if 'ansys_node_num' in grid.point_arrays:
        nodenum = grid.point_arrays['ansys_node_num']
    else:
        log.info('No ANSYS node numbers set in input.  ' +
                 'Adding default range')
        nodenum = np.arange(1, grid.number_of_points + 1)

    if np.any(nodenum == -1):
        if not allow_missing:
            raise Exception(
                'Missing node numbers.  Exiting due "allow_missing=False"')
        start_num = nodenum.max() + 1
        if nnum_start > start_num:
            start_num = nnum_start
        nadd = np.sum(nodenum == -1)
        end_num = start_num + nadd
        log.info('FEM missing some node numbers.  Adding node numbering ' +
                 'from %d to %d' % (start_num, end_num))
        nodenum[nodenum == -1] = np.arange(start_num, end_num)

    # element block
    ncells = grid.number_of_cells
    if 'ansys_elem_num' in grid.cell_arrays:
        enum = grid.cell_arrays['ansys_elem_num']
    else:
        if not allow_missing:
            raise Exception(
                'Missing node numbers.  Exiting due "allow_missing=False"')
        log.info('No ANSYS element numbers set in input.  ' +
                 'Adding default range starting from %d' % enum_start)
        enum = np.arange(1, ncells + 1)

    if np.any(enum == -1):
        if not allow_missing:
            raise Exception('-1 encountered in "ansys_elem_num".\n' +
                            'Exiting due "allow_missing=False"')

        start_num = enum.max() + 1
        if enum_start > start_num:
            start_num = enum_start
        nadd = np.sum(enum == -1)
        end_num = start_num + nadd
        log.info('FEM missing some cell numbers.  Adding numbering ' +
                 'from %d to %d' % (start_num, end_num))
        enum[enum == -1] = np.arange(start_num, end_num)

    # material type
    if 'ansys_material_type' in grid.cell_arrays:
        mtype = grid.cell_arrays['ansys_material_type']
    else:
        log.info('No ANSYS element numbers set in input.  ' +
                 'Adding default range starting from %d' % mtype_start)
        mtype = np.arange(1, ncells + 1)

    if np.any(mtype == -1):
        log.info('FEM missing some material type numbers.  Adding...')
        mtype[mtype == -1] = mtype_start

    # real constant
    if 'ansys_real_constant' in grid.cell_arrays:
        rcon = grid.cell_arrays['ansys_real_constant']
    else:
        log.info('No ANSYS element numbers set in input.  ' +
                 'Adding default range starting from %d' % real_constant_start)
        rcon = np.arange(1, ncells + 1)

    if np.any(rcon == -1):
        log.info('FEM missing some material type numbers.  Adding...')
        rcon[rcon == -1] = real_constant_start

    # element type
    invalid = False
    if 'ansys_etype' in grid.cell_arrays and not reset_etype:
        missing = False
        typenum = grid.cell_arrays['ansys_elem_type_num']
        etype = grid.cell_arrays['ansys_etype']
        if np.any(etype == -1):
            log.warning('Some elements are missing element type numbers.')
            invalid = True

        if include_etype_header and not invalid:
            _, ind = np.unique(etype, return_index=True)
            for idx in ind:
                header += 'ET, %d, %d\n' % (etype[idx], typenum[idx])
    else:
        missing = True

    # check if valid
    if not missing:
        mask = grid.celltypes < 20
        if np.any(grid.cell_arrays['ansys_elem_type_num'][mask] == 186):
            invalid = True
            log.warning('Invalid ANSYS element types.')

    if invalid or missing:
        if not allow_missing:
            raise Exception(
                'Invalid or missing data in "ansys_elem_type_num"' +
                ' or "ansys_etype".  Exiting due "allow_missing=False"')

        log.info('No ANSYS element type or invalid data input.  ' +
                 'Adding default range starting from %d' % etype_start)

        etype = np.empty(grid.number_of_cells, np.int32)
        etype_185 = etype_start + 2
        etype[grid.celltypes == VTK_TETRA] = etype_185
        etype[grid.celltypes == VTK_HEXAHEDRON] = etype_185
        etype[grid.celltypes == VTK_WEDGE] = etype_185
        etype[grid.celltypes == VTK_PYRAMID] = etype_185

        etype_186 = etype_start
        etype[grid.celltypes == VTK_QUADRATIC_HEXAHEDRON] = etype_186
        etype[grid.celltypes == VTK_QUADRATIC_WEDGE] = etype_186
        etype[grid.celltypes == VTK_QUADRATIC_PYRAMID] = etype_186

        etype_187 = etype_start + 1
        etype[grid.celltypes == VTK_QUADRATIC_TETRA] = etype_187

        # Surface elements
        etype_181 = etype_start + 3
        etype[grid.celltypes == VTK_TRIANGLE] = etype_181
        etype[grid.celltypes == VTK_QUAD] = etype_181

        typenum = np.empty_like(etype)
        typenum[etype == etype_185] = 185
        typenum[etype == etype_186] = 186
        typenum[etype == etype_187] = 187
        typenum[etype == etype_181] = 181

        header += 'ET, %d, 185\n' % etype_185
        header += 'ET, %d, 186\n' % etype_186
        header += 'ET, %d, 187\n' % etype_187
        header += 'ET, %d, 181\n' % etype_181

    # number of nodes written per element
    elem_nnodes = np.empty(etype.size, np.int32)
    elem_nnodes[typenum == 181] = 4
    elem_nnodes[typenum == 185] = 8
    elem_nnodes[typenum == 186] = 20
    elem_nnodes[typenum == 187] = 10

    with open(str(filename), mode) as f:
        f.write(header)

        # write node block
        if write_nblock:
            write_nblock(f, nodenum, grid.points)

        # eblock header
        h = ''
        h += 'EBLOCK,19,SOLID,{:10d},{:10d}\n'.format(enum[-1], ncells)
        h += '(19i8)\n'
        f.write(h)

        celltypes = grid.celltypes
        cells, offset = vtk_cell_info(grid)
        if VTK9:
            offset += 1

        for i in range(ncells):
            if VTK9:
                nodes = nodenum[cells[offset[i]:offset[i + 1]]]
            else:
                c = offset[i]
                nnode = cells[c]
                c += 1
                nodes = nodenum[cells[c:c + nnode]]

            cellinfo = (
                mtype[i],  # Field 1: material reference number
                etype[i],  # Field 2: element type number
                rcon[i],  # Field 3: real constant reference number
                1,  # Field 4: section number
                0,  # Field 5: element coordinate system
                0,  # Field 6: Birth/death flag
                0,  # Field 7:
                0,  # Field 8:
                elem_nnodes[i],  # Field 9: Number of nodes
                0,  # Field 10: Not Used
                enum[i])  # Field 11: Element number
            line = '%8d%8d%8d%8d%8d%8d%8d%8d%8d%8d%8d' % cellinfo

            if celltypes[i] == VTK_QUADRATIC_TETRA:
                if typenum[i] == 187:
                    line += '%8d%8d%8d%8d%8d%8d%8d%8d\n%8d%8d\n' % tuple(nodes)
                else:  # must be 186
                    writenodes = (
                        nodes[0],  # 0,  I
                        nodes[1],  # 1,  J
                        nodes[2],  # 2,  K
                        nodes[2],  # 3,  L (duplicate of K)
                        nodes[3],  # 4,  M
                        nodes[3],  # 5,  N (duplicate of M)
                        nodes[3],  # 6,  O (duplicate of M)
                        nodes[3],  # 7,  P (duplicate of M)
                        nodes[4],  # 8,  Q
                        nodes[5],  # 9,  R
                        nodes[3],  # 10, S (duplicate of K)
                        nodes[6],  # 11, T
                        nodes[3],  # 12, U (duplicate of M)
                        nodes[3],  # 13, V (duplicate of M)
                        nodes[3],  # 14, W (duplicate of M)
                        nodes[3],  # 15, X (duplicate of M)
                        nodes[7],  # 16, Y
                        nodes[8],  # 17, Z
                        nodes[9],  # 18, A
                        nodes[9])  # 19, B (duplicate of A)

                    line += '%8d%8d%8d%8d%8d%8d%8d%8d\n' % writenodes[:8]
                    line += '%8d%8d%8d%8d%8d%8d%8d%8d%8d%8d%8d%8d\n' % writenodes[
                        8:]

            elif celltypes[i] == VTK_TETRA:
                writenodes = (
                    nodes[0],  # 0,  I
                    nodes[1],  # 1,  J
                    nodes[2],  # 2,  K
                    nodes[2],  # 3,  L (duplicate of K)
                    nodes[3],  # 4,  M
                    nodes[3],  # 5,  N (duplicate of M)
                    nodes[3],  # 6,  O (duplicate of M)
                    nodes[3])  # 7,  P (duplicate of M)
                line += '%8d%8d%8d%8d%8d%8d%8d%8d\n' % writenodes

            elif celltypes[i] == VTK_WEDGE:
                writenodes = (
                    nodes[2],  # 0,  I
                    nodes[1],  # 1,  J
                    nodes[0],  # 2,  K
                    nodes[0],  # 3,  L (duplicate of K)
                    nodes[5],  # 4,  M
                    nodes[4],  # 5,  N
                    nodes[3],  # 6,  O
                    nodes[3])  # 7,  P (duplicate of O)
                line += '%8d%8d%8d%8d%8d%8d%8d%8d\n' % writenodes

            elif celltypes[i] == VTK_QUADRATIC_WEDGE:
                writenodes = (
                    nodes[2],  # 0,  I
                    nodes[1],  # 1,  J
                    nodes[0],  # 2,  K
                    nodes[0],  # 3,  L (duplicate of K)
                    nodes[5],  # 4,  M
                    nodes[4],  # 5,  N
                    nodes[3],  # 6,  O
                    nodes[3],  # 7,  P (duplicate of O)
                    nodes[7],  # 8,  Q
                    nodes[6],  # 9,  R
                    nodes[0],  # 10, S   (duplicate of K)
                    nodes[8],  # 11, T
                    nodes[10],  # 12, U
                    nodes[9],  # 13, V
                    nodes[3],  # 14, W (duplicate of O)
                    nodes[11],  # 15, X
                    nodes[14],  # 16, Y
                    nodes[13],  # 17, Z
                    nodes[12],  # 18, A
                    nodes[12])  # 19, B (duplicate of A)
                line += '%8d%8d%8d%8d%8d%8d%8d%8d\n' % writenodes[:8]
                line += '%8d%8d%8d%8d%8d%8d%8d%8d%8d%8d%8d%8d\n' % writenodes[
                    8:]

            elif celltypes[i] == VTK_QUADRATIC_PYRAMID:
                writenodes = (
                    nodes[0],  # 0,  I
                    nodes[1],  # 1,  J
                    nodes[2],  # 2,  K
                    nodes[3],  # 3,  L
                    nodes[4],  # 4,  M
                    nodes[4],  # 5,  N (duplicate of M)
                    nodes[4],  # 6,  O (duplicate of M)
                    nodes[4],  # 7,  P (duplicate of M)
                    nodes[5],  # 8,  Q
                    nodes[6],  # 9,  R
                    nodes[7],  # 10, S
                    nodes[8],  # 11, T
                    nodes[4],  # 12, U (duplicate of M)
                    nodes[4],  # 13, V (duplicate of M)
                    nodes[4],  # 14, W (duplicate of M)
                    nodes[4],  # 15, X (duplicate of M)
                    nodes[9],  # 16, Y
                    nodes[10],  # 17, Z
                    nodes[11],  # 18, A
                    nodes[12])  # 19, B (duplicate of A)

                line += '%8d%8d%8d%8d%8d%8d%8d%8d\n' % writenodes[:8]
                line += '%8d%8d%8d%8d%8d%8d%8d%8d%8d%8d%8d%8d\n' % writenodes[
                    8:]

            elif celltypes[i] == VTK_PYRAMID:
                writenodes = (
                    nodes[0],  # 0,  I
                    nodes[1],  # 1,  J
                    nodes[2],  # 2,  K
                    nodes[3],  # 3,  L
                    nodes[4],  # 4,  M
                    nodes[4],  # 5,  N (duplicate of M)
                    nodes[4],  # 6,  O (duplicate of M)
                    nodes[4])  # 7,  P (duplicate of M)
                line += '%8d%8d%8d%8d%8d%8d%8d%8d\n' % writenodes[:8]

            elif celltypes[i] == VTK_HEXAHEDRON:
                line += '%8d%8d%8d%8d%8d%8d%8d%8d\n' % tuple(nodes[:8])

            elif celltypes[i] == VTK_QUADRATIC_HEXAHEDRON:
                line += '%8d%8d%8d%8d%8d%8d%8d%8d\n' % tuple(nodes[:8])
                line += '%8d%8d%8d%8d%8d%8d%8d%8d%8d%8d%8d%8d\n' % tuple(
                    nodes[8:])

            elif celltypes[i] == VTK_TRIANGLE:
                writenodes = (
                    nodes[0],  # 0,  I
                    nodes[1],  # 1,  J
                    nodes[2],  # 2,  K
                    nodes[2])  # 3,  L (duplicate of K)
                line += '%8d%8d%8d%8d\n' % writenodes

            elif celltypes[i] == VTK_QUAD:
                writenodes = (
                    nodes[0],  # 0,  I
                    nodes[1],  # 1,  J
                    nodes[2],  # 2,  K
                    nodes[3])  # 3,  L
                line += '%8d%8d%8d%8d\n' % writenodes

            # else:
            #     raise RuntimeError('Invalid write cell type %d' % celltypes[i])

            f.write(line)

        f.write('      -1\n')
예제 #4
0
    def _nodal_result(self, rnum, result_type, **kwargs):
        """Load generic nodal result

        Parameters
        ----------
        rnum : int
            Result number.

        result_type : int
            EMS: misc. data
            ENF: nodal forces
            ENS: nodal stresses
            ENG: volume and energies
            EGR: nodal gradients
            EEL: elastic strains
            EPL: plastic strains
            ECR: creep strains
            ETH: thermal strains
            EUL: euler angles
            EFX: nodal fluxes
            ELF: local forces
            EMN: misc. non-sum values
            ECD: element current densities
            ENL: nodal nonlinear data
            EHC: calculated heat
            EPT: element temperatures
            ESF: element surface stresses
            EDI: diffusion strains
            ETB: ETABLE items(post1 only
            ECT: contact data
            EXY: integration point locations
            EBA: back stresses
            ESV: state variables
            MNL: material nonlinear record

        Returns
        -------
        nnum : np.ndarray
            ANSYS node numbers

        result : np.ndarray
            Array of result data
        """
        # check result exists
        if not self.available_results[result_type]:
            raise ValueError('Result %s is not available in this result file' %
                             result_type)

        # element header
        rnum = self.parse_step_substep(rnum)

        result_type = result_type.upper()
        nitem = self._result_nitem(rnum, result_type)
        result_index = ELEMENT_INDEX_TABLE_KEYS.index(result_type)

        # Element types for nodal averaging from the global mesh
        n_points = self.grid.n_points
        cells, offset = vtk_cell_info(self.grid)
        data = np.zeros((n_points, nitem), np.float64)
        ncount = np.zeros(n_points, np.int32)

        c = 0  # global cell index counter
        for result in self._results:
            ele_ind_table, nodstr, etype, ptr_off = result._element_solution_header(
                rnum)
            # we return c here since it is copied to C, not passed by reference
            c = read_nodal_values_dist(result.filename, self.grid.celltypes,
                                       ele_ind_table, offset, cells, nitem,
                                       n_points, nodstr, etype,
                                       self._mesh.etype, result_index, ptr_off,
                                       ncount, data, c)

        if result_type == 'ENS' and nitem != 6:
            data = data[:, :6]

        if not np.any(ncount):
            raise ValueError(
                'Result file contains no %s records for result %d' %
                (element_index_table_info[result_type.upper()], rnum))

        # average across nodes
        data /= ncount.reshape(-1, 1)
        return self.grid.point_arrays['ansys_node_num'], data