def grid(self): """ Returns a vtkInterface unstructured grid """ if 'vtkInterface' not in sys.modules: raise Exception('Cannot create grid without vtkInterface.\n' + 'Please run:\npip install vtkInterface') elif not hasattr(self, 'node'): raise Exception('Run Tetrahedralize first') if hasattr(self, '_grid') and not self._updated: return self._grid buf = np.empty((self.elem.shape[0], 1), np.int64) cell_type = np.empty(self.elem.shape[0], dtype='uint8') if self.elem.shape[1] == 4: # linear buf[:] = 4 cell_type[:] = 10 elif self.elem.shape[1] == 10: # quadradic buf[:] = 10 cell_type[:] = 24 else: raise Exception('Invalid element array shape %s' % str(self.elem.shape)) offset = np.cumsum(buf + 1) - (buf[0] + 1) cells = np.hstack((buf, self.elem)) self._grid = vtki.UnstructuredGrid(offset, cells, cell_type, self.node) self._updated = False return self._grid
def AddCyclicProperties(self): """ Adds cyclic properties to result object """ # ansys's duplicate sector contains nodes from the second half of the node # numbering # # ansys node numbering for the duplicate sector is # nnum.min() + nnum.max() # where nnum is the node numbering for the master sector # if not vtkloaded: # raise Exception('Unable to add ') # master sector max node number num_master_max = self.nnum[int(self.nnum.size / 2) - 1] # identify master and duplicate cyclic sectors cells = np.arange(self.enum.size) dup_cells = np.where( np.any( self.geometry['elem'] > num_master_max, 1))[0] mas_cells = np.setdiff1d(cells, dup_cells) self.sector = self.grid.ExtractSelectionCells(mas_cells) dup_sector = self.grid.ExtractSelectionCells(dup_cells) # Store the indices of the master and duplicate nodes self.mas_ind = self.sector.GetPointScalars('vtkOriginalPointIds') self.dup_ind = dup_sector.GetPointScalars('vtkOriginalPointIds') # store cyclic node numbers self.cyc_nnum = self.nnum[self.mas_ind] # create full rotor nSector = self.resultheader['nSector'] # Copy and translate mesh vtkappend = vtk.vtkAppendFilter() rang = 360.0 / nSector for i in range(nSector): # Transform mesh sector = self.sector.Copy() sector.RotateZ(rang * i) vtkappend.AddInputData(sector) # Combine meshes and add VTK_Utilities functions # vtkappend.MergePointsOn() vtkappend.Update() self.rotor = vtkInterface.UnstructuredGrid(vtkappend.GetOutput())
def read_cell_data(self, fn_start): """Read cell data from ``vtk`` Args: fn_start (:obj:`int`): the index of starting letter in ``ls -lrth`` corresponding to vtk filename """ # We list all the files in ``vtk_folder``, then we extract the # vtk filename without the affix and append with list. # Then we sort it from small to large, since we need the vtk data # to be sequential in time. Finally we put the vectorized data as # `UV_concate_cell_array`. vtk_file_list = [] file_list = os.listdir(self.vtk_folder) for names in file_list: if names.endswith(".vtk"): vtk_file_list.append(names[fn_start:-4]) vtk_file_array = np.array(vtk_file_list, dtype=int) vtk_file_array.sort() uv_concate_cell_list = [] for vtk_file in vtk_file_array: print 'current working on ', vtk_file # Note: grid is the central object in VTK where every field is added on to grid grid = vtki.UnstructuredGrid(self.vtk_folder + self.case_name + '_' + str(vtk_file) + \ '.vtk') vel_cell = grid.cell_arrays['U'] # get the vector velocity u_cell = vel_cell[:, 0] # get Ux v_cell = vel_cell[:, 1] # get Uy uv_concate_cell = np.hstack( (u_cell, v_cell)) # concate U,V together uv_concate_cell_list.append( uv_concate_cell) # we append the snapshots of stacked state # vector self.UV_concate_cell_array = np.array( uv_concate_cell_list) # we transform it into
def StoreGeometry(self): """ Stores the geometry from the result file """ # read in the geometry from the result file with open(self.filename, 'rb') as f: f.seek((self.resultheader['ptrGEO'] + 2) * 4) geotable = np.fromfile(f, self.resultheader['endian'] + 'i', 80) geotable.tolist() ptrLOC = geotable[26] # Node information nnod = self.resultheader['nnod'] nnum = np.empty(nnod, np.int32) nloc = np.empty((nnod, 6), np.float) _rstHelper.LoadNodes(self.filename, ptrLOC, nnod, nloc, nnum) # Element Information nelm = geotable[4] ptrEID = geotable[28] maxety = geotable[1] # pointer to the element type index table ptrETYP = geotable[20] f.seek((ptrETYP + 2) * 4) e_type_table = np.fromfile( f, self.resultheader['endian'] + 'i', maxety) # store information for each element type # make these arrays large so you can reference a value via element # type numbering # number of nodes for this element type nodelm = np.empty(10000, np.int32) # number of nodes per element having nodal forces nodfor = np.empty(10000, np.int32) # number of nodes per element having nodal stresses nodstr = np.empty(10000, np.int32) etype_ID = np.empty(maxety, np.int32) ekey = [] for i in range(maxety): f.seek((ptrETYP + e_type_table[i] + 2) * 4) einfo = np.fromfile(f, self.resultheader['endian'] + 'i', 2) etype_ref = einfo[0] etype_ID[i] = einfo[1] ekey.append(einfo) f.seek((ptrETYP + e_type_table[i] + 2 + 60) * 4) nodelm[etype_ref] = np.fromfile( f, self.resultheader['endian'] + 'i', 1) f.seek((ptrETYP + e_type_table[i] + 2 + 62) * 4) nodfor[etype_ref] = np.fromfile( f, self.resultheader['endian'] + 'i', 1) f.seek((ptrETYP + e_type_table[i] + 2 + 93) * 4) nodstr[etype_ref] = np.fromfile( f, self.resultheader['endian'] + 'i', 1) # store element table data self.element_table = {'nodelm': nodelm, 'nodfor': nodfor, 'nodstr': nodstr} # get the element description table f.seek((ptrEID + 2) * 4) e_disp_table = np.empty(nelm, np.int32) e_disp_table[:] = np.fromfile( f, self.resultheader['endian'] + 'i8', nelm) # get pointer to start of element table and adjust element pointers ptr = ptrEID + e_disp_table[0] e_disp_table -= e_disp_table[0] # The following is stored for each element # mat - material reference number # type - element type number # real - real constant reference number # secnum - section number # esys - element coordinate system # death - death flat (1 live, 0 dead) # solidm - solid model reference # shape - coded shape key # elnum - element number # baseeid - base element number # NODES - node numbers defining the element # allocate memory for this (a maximum of 21 points per element) etype = np.empty(nelm, np.int32) elem = np.empty((nelm, 20), np.int32) elem[:] = -1 # load elements _rstHelper.LoadElements(self.filename, ptr, nelm, e_disp_table, elem, etype) enum = self.resultheader['eeqv'] # store geometry dictionary self.geometry = {'nnum': nnum, 'nodes': nloc, 'etype': etype, 'elem': elem, 'enum': enum, 'ekey': np.asarray(ekey, ctypes.c_long), 'e_rcon': np.ones_like(enum)} # store the reference array cell_type = ['45', '95', '185', '186', '92', '187', '154'] result = _parser.Parse(self.geometry, True, cell_type) # force_linear cells, offset, cell_type, self.numref, _, _, _ = result # Create vtk object if vtk installed if vtkloaded: nodes = nloc[:, :3] self.grid = vtkInterface.UnstructuredGrid(offset, cells, cell_type, nodes) # get edge nodes nedge = nodstr[etype].sum() self.edge_idx = np.empty(nedge, np.int32) _rstHelper.AssembleEdges( nelm, etype, elem, self.numref.astype( np.int32), self.edge_idx, nodstr) # store edge node numbers and indices to the node array self.edge_node_num_idx = np.unique(self.edge_idx)
def test_merge(): from vtkInterface import examples beamA = vtki.UnstructuredGrid(examples.hexbeamfile) beamB = beamA.Copy() beamB.points[:, 1] += 1 beamA.Merge(beamB)
def BeamExample(): # Load module and example file hexfile = hexbeamfile # Load Grid grid = vtkInterface.UnstructuredGrid(hexfile) # Create fiticious displacements as a function of Z location pts = grid.GetNumpyPoints(deep=True) d = np.zeros_like(pts) d[:, 1] = pts[:, 2]**3/250 # Displace original grid grid.SetNumpyPoints(pts + d) # Camera position cpos = [(11.915126303095157, 6.11392754955802, 3.6124956735471914), (0.0, 0.375, 2.0), (-0.42546442225230097, 0.9024244135964158, -0.06789847673314177)] try: import matplotlib colormap = 'bwr' except ImportError: colormap = None # plot this displaced beam plobj = vtkInterface.PlotClass() plobj.AddMesh(grid, scalars=d[:, 1], stitle='Y Displacement', rng=[-d.max(), d.max()], colormap=colormap) plobj.SetCameraPosition(cpos) plobj.AddText('Static Beam Example') cpos = plobj.Plot(autoclose=False) # store camera position # plobj.TakeScreenShot('beam.png') plobj.Close() # Animate plot plobj = vtkInterface.PlotClass() plobj.AddMesh(grid, scalars=d[:, 1], stitle='Y Displacement', showedges=True, rng=[-d.max(), d.max()], interpolatebeforemap=True, colormap=colormap) plobj.SetCameraPosition(cpos) plobj.AddText('Beam Animation Example') plobj.Plot(interactive=False, autoclose=False, window_size=[800, 600]) #plobj.OpenMovie('beam.mp4') # plobj.OpenGif('beam.gif') for phase in np.linspace(0, 4*np.pi, 100): plobj.UpdateCoordinates(pts + d*np.cos(phase), render=False) plobj.UpdateScalars(d[:, 1]*np.cos(phase), render=False) plobj.Render() # plobj.WriteFrame() time.sleep(0.01) plobj.Close() # Animate plot as a wireframe plobj = vtkInterface.PlotClass() plobj.AddMesh(grid, scalars=d[:, 1], stitle='Y Displacement', showedges=True, rng=[-d.max(), d.max()], colormap=colormap, interpolatebeforemap=True, style='wireframe') plobj.SetCameraPosition(cpos) plobj.AddText('Beam Animation Example 2') plobj.Plot(interactive=False, autoclose=False, window_size=[800, 600]) # plobj.OpenMovie('beam.mp4') # plobj.OpenGif('beam_wireframe.gif') for phase in np.linspace(0, 4*np.pi, 100): plobj.UpdateCoordinates(pts + d*np.cos(phase), render=False) plobj.UpdateScalars(d[:, 1]*np.cos(phase), render=False) plobj.Render() # plobj.WriteFrame() time.sleep(0.01) plobj.Close()
def ParseVTK(self, force_linear=False, allowable_types=None, null_unallowed=False): """ Parses raw data from cdb file to VTK format. Parameters ---------- force_linear : bool, optional This parser creates quadradic elements if available. Set this to True to always create linear elements. Defaults to False. allowable_types : list, optional Allowable element types. Defaults to: ['45', '95', '185', '186', '92', '187'] 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 ------- uGrid : vtk.vtkUnstructuredGrid VTK unstructured grid from archive file. """ if not vtk_loaded: raise Exception( 'Unable to load VTK module. Cannot parse raw cdb data') if self.CheckRaw(): raise Exception( 'Missing key data. Cannot parse into unstructured grid') # Convert to vtk style arrays if allowable_types is None: allowable_types = ['45', '95', '185', '186', '92', '187'] else: assert isinstance(allowable_types, list), \ 'allowable_types must be a list' for eletype in allowable_types: if eletype not in valid_types: raise Exception('Element type "%s" ' % eletype + 'cannot be parsed in pyansys') result = _parser.Parse(self.raw, force_linear, allowable_types, null_unallowed) cells, offset, cell_type, numref, enum, etype, rcon = result # catch bug cells[cells > numref.max()] = -1 # Check for missing midside nodes if force_linear or np.all(cells != -1): nodes = self.raw['nodes'][:, :3].copy() nnum = self.raw['nnum'] 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.ResetMidside(cells, temp_nodes) nodes[nnodes:] = temp_nodes[nnodes:] # merge nodes new_nodes = temp_nodes[nnodes:] unique_nodes, idxA, idxB = UniqueRows(new_nodes, return_index=True, return_inverse=True) # rewrite node numbers cells[mask] = idxB + maxnum nextra = idxA.shape[0] nodes = np.zeros((nnodes + nextra, 3)) nodes[:nnodes] = self.raw['nodes'][:, :3] nodes[nnodes:] = unique_nodes # Add extra node numbers nnum = np.hstack((self.raw['nnum'], np.ones(nextra, np.int32) * -1)) # Create unstructured grid grid = vtkInterface.UnstructuredGrid(offset, cells, cell_type, nodes) # Store original ANSYS numbering grid.AddPointScalars(nnum, 'ANSYSnodenum') grid.AddCellScalars(enum, 'ANSYS_elem_num') grid.AddCellScalars(etype, 'ANSYS_elem_typenum') grid.AddCellScalars(rcon, 'ANSYS_real_constant') # Add element components to unstructured grid # ibool = np.empty(grid.GetNumberOfCells(), dtype=np.int8) for comp in self.raw['elem_comps']: mask = np.in1d(enum, self.raw['elem_comps'][comp], assume_unique=True) grid.AddCellScalars(mask, comp.strip()) # Add node components to unstructured grid ibool = np.empty(grid.GetNumberOfPoints(), dtype=np.int8) for comp in self.raw['node_comps']: ibool[:] = 0 # reset component array # Convert to new node numbering nodenum = numref[self.raw['node_comps'][comp]] ibool[nodenum] = 1 grid.AddPointScalars(ibool, comp.strip()) grid.AddPointScalars(np.arange(grid.points.shape[0]), 'origid') # Add tracker for original node numbering npoints = grid.GetNumberOfPoints() grid.AddPointScalars(np.arange(npoints), 'VTKorigID') self.vtkuGrid = grid return grid
def pps_paraview_cylinder( self, cylinder_folder="./50d_cylinder_flow_pod_case", pod_path="/media/shaowu/shaowu_main_hard/shaowu/OpenFOAM/shaowu-6/run/vortex_shedding/c6_re100_whole_POD.npz" ): """postprocessing for cylinder case with paraview. This is a very problem specific method. It will use the POD weights and it will use eval trajectory to get the full field projected and saved into vtk files. It is a good example for extending to other cases. Args: cylinder_folder (:obj:`str`): path to the full POD data. """ # 1. read POD data from POD path pod_data = np.load(pod_path) vh = pod_data['vh'] # s = pod_data['s'] # u = pod_data['u'] # 2. read eval file eval_file_name = 'save_trj_comparison_whole.npz' eval_file_data = np.load(self.eval_dir + '/' + self.params['model_name'] + '/' + eval_file_name) true_trajectory = eval_file_data['ttrj'] pred_trajectory = eval_file_data['ptrj'] # compute the mean and std print('') print('pred trajectory shape = ') print(pred_trajectory.shape) print('') pred_trajectory_mean = np.mean(pred_trajectory, axis=0) pred_trajectory_std = np.std(pred_trajectory, axis=0) print('pred_trajectory_std shape = ', pred_trajectory_std.shape) # 3. generate VTK files self.vtk_folder = self.pps_dir + '/VTK' # make directory for vtk mkdir(self.vtk_folder) # 3.1 generate true flowfield VTK true_data_UV_array = np.matmul(true_trajectory, vh[:true_trajectory.shape[1], :]) true_data_U = true_data_UV_array[:, :int(true_data_UV_array.shape[1] / 2)] true_data_V = true_data_UV_array[:, int(true_data_UV_array.shape[1] / 2):] true_data_W = np.zeros(true_data_U.shape) # get 3d true velo true_data_vel = np.stack((true_data_U, true_data_V, true_data_W), axis=2) # 3.2 generate pred flowfield VTK -- mean pred_data_UV_array = np.matmul(pred_trajectory_mean, vh[:pred_trajectory_mean.shape[1], :]) pred_data_U = pred_data_UV_array[:, :int(pred_data_UV_array.shape[1] / 2)] pred_data_V = pred_data_UV_array[:, int(pred_data_UV_array.shape[1] / 2):] pred_data_W = np.zeros(pred_data_U.shape) # get 3d pred velo pred_data_vel_mean = np.stack((pred_data_U, pred_data_V, pred_data_W), axis=2) # 3.2 -- std pred_data_UV_array_std = np.matmul( pred_trajectory_std, vh[:pred_trajectory_std.shape[1], :]) pred_data_U_std = pred_data_UV_array_std[:, :int(pred_data_UV_array_std .shape[1] / 2)] pred_data_V_std = pred_data_UV_array_std[:, int(pred_data_UV_array_std. shape[1] / 2):] pred_data_W_std = np.zeros(pred_data_U_std.shape) # get 3d pred velo -- std pred_data_vel_std = np.stack( (pred_data_U_std, pred_data_V_std, pred_data_W_std), axis=2) # 3.5 read blank VTK files for cylinder to write new things on: loop over time for time_step in range(true_data_U.shape[0]): true_data = vtki.UnstructuredGrid(cylinder_folder + '/base.vtk') pred_data = vtki.UnstructuredGrid(cylinder_folder + '/base.vtk') # 3.2 add fields in true_data.AddCellScalars(true_data_vel[time_step, :, :], 'U') pred_data.AddCellScalars(pred_data_vel_mean[time_step, :, :], 'U_mean') pred_data.AddCellScalars(pred_data_vel_std[time_step, :, :], 'U_std') # save true_data.Write(self.vtk_folder + '/true_flowfield_' + str(time_step) + '.vtk') pred_data.Write(self.vtk_folder + '/pred_flowfield_' + str(time_step) + '.vtk') del (true_data) del (pred_data)
def ParseVTK(self, force_linear=False, allowable_types=None): """ Parses raw data from cdb file to VTK format. Parameters ---------- force_linear : bool, optional This parser creates quadradic elements if available. Set this to True to always create linear elements. Defaults to False. allowable_types : list, optional Allowable element types. Defaults to: ['45', '95', '185', '186', '92', '187'] Can include: ['45', '95', '185', '186', '92', '187', '154'] Returns ------- uGrid : vtk.vtkUnstructuredGrid VTK unstructured grid from archive file. """ if not vtk_loaded: raise Exception( 'Unable to load VTK module. Cannot parse raw cdb data') if self.CheckRaw(): raise Exception( 'Missing key data. Cannot parse into unstructured grid') # Convert to vtk style arrays if allowable_types is None: allowable_types = ['45', '95', '185', '186', '92', '187'] else: assert isinstance(allowable_types, list), \ 'allowable_types must be a list' result = _parser.Parse(self.raw, force_linear, allowable_types) cells, offset, cell_type, numref, enum, etype, rcon = result # catch bug cells[cells > numref.max()] = -1 # Check for missing midside nodes possible_merged = False if force_linear or np.all(cells != -1): nodes = self.raw['nodes'][:, :3].copy() nnum = self.raw['nnum'] 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] # Add extra node numbers nnum = np.hstack((self.raw['nnum'], np.ones(nextra, np.int32) * -1)) # Set new midside nodes directly between their edge nodes temp_nodes = nodes.copy() _relaxmidside.ResetMidside(cells, temp_nodes) nodes[nnodes:] = temp_nodes[nnodes:] possible_merged = True # Create unstructured grid grid = vtkInterface.UnstructuredGrid(offset, cells, cell_type, nodes) # Store original ANSYS numbering grid.AddPointScalars(nnum, 'ANSYSnodenum') grid.AddCellScalars(enum, 'ANSYS_elem_num') grid.AddCellScalars(etype, 'ANSYS_elem_typenum') grid.AddCellScalars(rcon, 'ANSYS_real_constant') # Add node components to unstructured grid ibool = np.empty(grid.GetNumberOfPoints(), dtype=np.int8) for comp in self.raw['node_comps']: ibool[:] = 0 # reset component array # Convert to new node numbering nodenum = numref[self.raw['node_comps'][comp]] ibool[nodenum] = 1 grid.AddPointScalars(ibool, comp.strip()) # merge duplicate points if possible_merged: vtkappend = vtk.vtkAppendFilter() vtkappend.AddInputData(grid) vtkappend.MergePointsOn() vtkappend.Update() grid = vtkInterface.UnstructuredGrid(vtkappend.GetOutput()) # Add tracker for original node numbering npoints = grid.GetNumberOfPoints() grid.AddPointScalars(np.arange(npoints), 'VTKorigID') self.vtkuGrid = grid return grid