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
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