def mesh_shape(self, shp, size=0.1, order=1, max_dim=3, mesh_algo=8, interactive=False): """ :param shp: ADA shape object :param size: Size of mesh :param order: Polynomial order :param max_dim: Maximum dimensions (1, 2 or 3). :param mesh_algo: 2D mesh algorithm (1: MeshAdapt, 2: Automatic, 5: Delaunay, 6: Frontal-Delaunay, 7: BAMG, 8: Frontal-Delaunay for Quads, 9: Packing of Parallelograms) :param interactive: Enable an interactive session using GMSH GUI. :type shp: ada.Shape :rtype: ada.FEM """ gmsh.option.setNumber("Mesh.Algorithm", mesh_algo) gmsh.option.setNumber("Mesh.ElementOrder", order) gmsh.option.setNumber("Mesh.SecondOrderIncomplete", 1) gmsh.option.setNumber("Mesh.Smoothing", 3) gmsh.option.setNumber("Geometry.Tolerance", 1e-3) gmsh.model.add(shp.name) shp.to_stp("temp_occ_in", os.path.join(self.work_dir)) gmsh.open("gmsh/temp_occ_in.stp") model = gmsh.model factory = model.geo factory.synchronize() model.mesh.setRecombine(2, 1) model.mesh.generate(max_dim) model.mesh.removeDuplicateNodes() if interactive: gmsh.fltk.run()
def load_gmsh_nodes(gmshpath, entity): ''' Given a fullpath to some .msh file load in the mesh nodes IDs, triangles and coordinates. gmshpath -- path to gmsh file dimtag -- tuple specifying the (dimensionality,tagID) being loaded If entity=(dim,tag) not provided then pull the first entity and return ''' gmsh.initialize() gmsh.open(gmshpath) nodes, coords, params = gmsh.model.mesh.getNodes(entity[0], entity[1]) coords = np.array(coords).reshape((len(coords) // 3, 3)) gmsh.clear() return nodes - 1, coords, params
def test(meanFSIIt): name = [file for file in os.listdir() if ('solid' in file)] time = [float(file[8:-4]) for file in name] lastFile = name[np.argmax(time)] import gmsh gmsh.initialize() gmsh.option.setNumber('General.Terminal', 0) gmsh.open(lastFile) coord = gmsh.model.mesh.getNode(57)[0] gmsh.finalize() tests = CTests() tests.add(CTest('Middle bar coordinate X', coord[0], 0.5, 0.05, False)) tests.add( CTest('Middle bar coordinate Y', coord[1], -0.049748, 0.05, False)) tests.add( CTest('Mean number of ISI iterations', meanFSIIt, 1.749875, 0.05, False)) tests.run()
def ImportMesh(self, mesh): mesh = os.path.abspath(mesh) print('Loading {} ...'.format(mesh)) assert os.path.exists(mesh), "Cannot read '{}'".format(mesh) try: gmsh.finalize() except: pass finally: gmsh.initialize() gmsh.open(mesh) mesh = gmsh.model.mesh self.Model = gmsh.model print('Model ' + gmsh.model.getCurrent() + ' (' + str(gmsh.model.getDimension()) + 'D)') self.GetGroups() self.ImportMeshElements(mesh) self.LoadElemsAttr()
def LaG_from_msh(archivo): ''' Obtiene la matriz de interconexión nodal (LaG) que contiene la malla de EF a trabajar, a partir del archivo .msh exportado por el programa GMSH. Retorna: Matriz LaG_mat, donde la primera columna representa la super- ficie a la que pertenece cada elemento finito (ordenadas de forma ascendente desde 0), de tal manera que diferencie elementos finitos con propiedades distintas ''' gmsh.initialize() gmsh.open(archivo) LaG = np.array([]) # Matriz de interconexión nodal elems = np.array([]) # vector de elementos finitos mats = np.array([]) # Vector de materiales al que pertenece cada EF material = 0 # Se inicializa el material for ent in gmsh.model.getEntities(2): dim, tag = ent tipo, efs, nodos = gmsh.model.mesh.getElements(dim, tag) if tipo.size == 1: nodos = nodos[0] elems = np.append(elems, efs[0]).astype(int) LaG = np.append(LaG, nodos).astype(int) mats = np.append(mats, np.tile(material, efs[0].size)).astype(int) material += 1 else: raise ValueError('La malla tiene varios tipos de elementos ' 'finitos 2D.') nef = elems.size LaG = LaG.reshape((nef, -1)) - 1 LaG_mat = np.c_[mats, LaG] gmsh.finalize() return LaG_mat
meshio.write_points_cells( filename, points, centerline_cells, # Optional # point_data=point_data, # cell_data=cell_data, ) create_line_mesh(centerline_points, cells_array, output_filename + "_centerline_mesh.msh") ### ------------ Remove duplicates if any (GMSH API) ----------- ### gmsh.initialize() gmsh.open(output_filename + "_centerline_mesh.msh") # Node tags initial_node_tags = np.array(gmsh.model.mesh.getNodes()[0]) # Node coords (re-arranged as numpy array [ [x1,x2,x3]_1, ..., [x2,x3,x3]_N]) initial_node_coords = np.array(gmsh.model.mesh.getNodes()[1]) initial_node_coords = np.split(initial_node_coords, len(initial_node_coords) / 3.0) # Removing duplicate nodes gmsh.model.mesh.removeDuplicateNodes() # Updated node tags node_tags = np.array(gmsh.model.mesh.getNodes()[0]) # Updated node coords (re-arranged as numpy array [ [x1,x2,x3]_1, ..., [x2,x3,x3]_N]) node_coords = np.array(gmsh.model.mesh.getNodes()[1]) node_coords = np.split(node_coords, len(node_coords) / 3.0) # Getting array of removed nodes to update centerline data _, common_idx_init, _ = np.intersect1d(initial_node_tags,
def load_gmsh(file_name, gmsh_args=None): """ Returns a surface mesh from CAD model in Open Cascade Breap (.brep), Step (.stp or .step) and Iges formats Or returns a surface mesh from 3D volume mesh using gmsh. For a list of possible options to pass to GMSH, check: http://gmsh.info/doc/texinfo/gmsh.html An easy way to install the GMSH SDK is through the `gmsh-sdk` package on PyPi, which downloads and sets up gmsh: >>> pip install gmsh-sdk Parameters -------------- file_name : str Location of the file to be imported gmsh_args : (n, 2) list List of (parameter, value) pairs to be passed to gmsh.option.setNumber max_element : float or None Maximum length of an element in the volume mesh Returns ------------ mesh : trimesh.Trimesh Surface mesh of input geometry """ # use STL as an intermediate format from ..exchange.stl import load_stl # do import here to avoid very occasional segfaults import gmsh # start with default args for the meshing step # Mesh.Algorithm=2 MeshAdapt/Delaunay, there are others but they may include quads # With this planes are meshed using Delaunay and cylinders are meshed # using MeshAdapt args = [("Mesh.Algorithm", 2), ("Mesh.CharacteristicLengthFromCurvature", 1), ("Mesh.MinimumCirclePoints", 32)] # add passed argument tuples last so we can override defaults if gmsh_args is not None: args.extend(gmsh_args) # formats GMSH can load supported = [ '.brep', '.stp', '.step', '.igs', '.iges', '.bdf', '.msh', '.inp', '.diff', '.mesh' ] # check extensions to make sure it is supported format if file_name is not None: if not any(file_name.lower().endswith(e) for e in supported): raise ValueError( 'Supported formats are: BREP (.brep), STEP (.stp or .step), ' + 'IGES (.igs or .iges), Nastran (.bdf), Gmsh (.msh), Abaqus (*.inp), ' + 'Diffpack (*.diff), Inria Medit (*.mesh)') else: raise ValueError('No import since no file was provided!') # if we initialize with sys.argv it could be anything gmsh.initialize() gmsh.option.setNumber("General.Terminal", 1) gmsh.model.add('Surface_Mesh_Generation') gmsh.open(file_name) # create a temporary file for the results out_data = tempfile.NamedTemporaryFile(suffix='.stl', delete=False) # windows gets mad if two processes try to open the same file out_data.close() # we have to mesh the surface as these are analytic BREP formats if any(file_name.lower().endswith(e) for e in ['.brep', '.stp', '.step', '.igs', '.iges']): gmsh.model.geo.synchronize() # loop through our numbered args which do things, stuff for arg in args: gmsh.option.setNumber(*arg) # generate the mesh gmsh.model.mesh.generate(2) # write to the temporary file gmsh.write(out_data.name) else: gmsh.plugin.run("NewView") gmsh.plugin.run("Skin") gmsh.view.write(1, out_data.name) # load the data from the temporary outfile with open(out_data.name, 'rb') as f: kwargs = load_stl(f) return kwargs
import gmsh gmsh.initialize() gmsh.option.setNumber('General.Terminal', 1) # load step file gmsh.open('as1-tu-203.stp') # get all model entities ent = gmsh.model.getEntities() gmsh.model.occ.healShapes() gmsh.model.occ.synchronize() gmsh.finalize() #gmsh.fltk.run()
"""using gmsh generate surface mesh for vn calculation""" import gmsh gmsh.initialize() gmsh.open(r'/home/hao/ShapeOPT/TestDev2/Vn/NACA0012_original.igs') gmsh.model.addPhysicalGroup(2, [1], 1) gmsh.model.setPhysicalName(2, 1, r'fluid') gmsh.model.addPhysicalGroup(1, [1, 2], 1) gmsh.model.setPhysicalName(1, 1, r'farfield') gmsh.model.addPhysicalGroup(1, [3, 4], 2) gmsh.model.setPhysicalName(1, 2, r'airfoil') gmsh.model.mesh.setTransfiniteCurve(1, 36) gmsh.model.mesh.setTransfiniteCurve(2, 36) gmsh.model.mesh.setTransfiniteCurve(3, 120, r'Bump', 0.05) gmsh.model.mesh.setTransfiniteCurve(4, 120, r'Bump', 0.05) gmsh.model.geo.synchronize() gmsh.model.mesh.generate(1) gmsh.model.mesh.generate(2) gmsh.write(r'/home/hao/ShapeOPT/TestDev2/NACA0012.su2') gmsh.finalize()
def read_gmsh(mesh, **kwargs): model = gmsh.model factory = model.geo gmsh.initialize() gmsh.open(mesh) logger.info('Analyze grid') nodeTags, coord, parametricCoord = gmsh.model.mesh.getNodes() nodes = pd.DataFrame(coord.reshape(-1, 3), columns=['x', 'y', 'z']) elementTags2, nodeTags2 = gmsh.model.mesh.getElementsByType(2) elems = nodeTags2.reshape(-1, 3) tria = pd.DataFrame(elems - 1, columns=['a', 'b', 'c']) # boundaries bounds = [] bgs = gmsh.model.getPhysicalGroups() bgs = pd.DataFrame(bgs[:-1], columns=['dim', 'tag']) #open boundaries logger.info('open boundaries') obs = bgs.loc[bgs.tag < 1000] for row in obs.itertuples(index=True, name='Pandas'): onodes, xyz = gmsh.model.mesh.getNodesForPhysicalGroup( dim=getattr(row, "dim"), tag=getattr(row, "tag")) db = pd.DataFrame({'node': onodes - 1}) db['type'] = np.nan db['id'] = getattr(row, "Index") + 1 bounds.append(db) #land boundaries type logger.info('land boundaries') lbs = bgs.loc[(bgs.tag > 1000) & (bgs.tag < 2000)] lbs.reset_index(inplace=True, drop=True) for row in lbs.itertuples(index=True, name='Pandas'): lnodes, xyz = gmsh.model.mesh.getNodesForPhysicalGroup( dim=getattr(row, "dim"), tag=getattr(row, "tag")) db = pd.DataFrame({'node': lnodes - 1}) db['type'] = 0 db['id'] = -(getattr(row, "Index") + 1) bounds.append(db) if lbs.empty: #Store max index from land boundaries itag = 0 else: itag = lbs.tag.max() - 1000 #islands logger.info('islands') ibs = bgs.loc[bgs.tag > 2000] ibs.reset_index(inplace=True, drop=True) ibs.index = ibs.index + itag #set index for row in ibs.itertuples(index=True, name='Pandas'): inodes, xyz = gmsh.model.mesh.getNodesForPhysicalGroup( dim=getattr(row, "dim"), tag=getattr(row, "tag")) db = pd.DataFrame({'node': inodes - 1}) db['type'] = -1 db['id'] = -(getattr(row, "Index") + 1) bounds.append(db) if bounds != []: bnodes = pd.concat(bounds).reset_index(drop=True) bnodes.index.name = 'bnodes' bnodes = bnodes.drop_duplicates('node') bnodes['id'] = bnodes.id.astype(int) else: bnodes = pd.DataFrame({}) #check if global and reproject sproj = kwargs.get('gglobal', False) if sproj: # convert to lat/lon xd, yd = to_lat_lon(nodes.x, nodes.y) nodes['x'] = xd nodes['y'] = yd grid = pd.DataFrame({'lon': nodes.x, 'lat': nodes.y}) tri3 = tria.values logger.info('Finalize Dataset') ## make dataset els = xr.DataArray( tri3, dims=['nSCHISM_hgrid_face', 'nMaxSCHISM_hgrid_face_nodes'], name='SCHISM_hgrid_face_nodes') nod = grid.loc[:, ['lon', 'lat']].to_xarray().rename({ 'index': 'nSCHISM_hgrid_node', 'lon': 'SCHISM_hgrid_node_x', 'lat': 'SCHISM_hgrid_node_y' }) nod = nod.drop_vars('nSCHISM_hgrid_node') dep = xr.Dataset({ 'depth': (['nSCHISM_hgrid_node'], np.zeros(nod.nSCHISM_hgrid_node.shape[0])) }) gr = xr.merge([nod, els, dep, bnodes.to_xarray()]) gmsh.finalize() return gr
def mesh_model(model, max_size=1e-5, tolerance=1e-7, repair=False, terminal=1): # In/Output definitions fil = model.split("/")[-1][:-5] folder = "/".join(model.split("/")[:-1]) scale_factor = 1000.0 verts = [] norms = [] faces = [] curvs = [] vert_map = {} d1_feats = [] d2_feats = [] t_curves = [] #norm_map = {} with fileinput.FileInput(model, inplace=True) as fi: for line in fi: print(line.replace( "UNCERTAINTY_MEASURE_WITH_UNIT( LENGTH_MEASURE( 1.00000000000000E-06 )", "UNCERTAINTY_MEASURE_WITH_UNIT( LENGTH_MEASURE( 1.00000000000000E-17 )" ), end='') stats = {} # OCC definitions occ_steps = read_step_file(model) stats["#parts"] = len(occ_steps) stats["model"] = model print("Reading step %s with %i parts." % (model, len(occ_steps))) #tot = 0 #for s in occ_steps: # occ_topo = TopologyExplorer(s) # print(s) # print(len(list(occ_topo.edges()))) # tot += len(list(occ_topo.edges())) occ_cnt = 0 bbox = get_boundingbox(occ_steps[occ_cnt], use_mesh=True) diag = np.sqrt(bbox[6]**2 + bbox[7]**2 + bbox[8]**2) max_length = diag * max_size #, 9e-06 tolerance = diag * tolerance #print(fil, diag, max_length, tolerance) stats["bbox"] = bbox stats["max_length"] = float(max_length) stats["tolerance"] = float(tolerance) stats["diag"] = float(diag) occ_topo = TopologyExplorer(occ_steps[occ_cnt]) occ_top = Topo(occ_steps[occ_cnt]) occ_props = GProp_GProps() occ_brt = BRep_Tool() # Gmsh definitions gmsh.initialize() gmsh.clear() gmsh.option.setNumber("General.Terminal", terminal) gmsh.option.setNumber("Geometry.Tolerance", tolerance) gmsh.option.setNumber("Geometry.OCCFixDegenerated", 0) gmsh.option.setNumber("Geometry.OCCFixSmallEdges", 0) gmsh.option.setNumber("Geometry.OCCFixSmallFaces", 0) gmsh.option.setNumber("Geometry.OCCSewFaces", 0) gmsh.option.setNumber("Mesh.CharacteristicLengthMax", max_length) gmsh.open(model) # Gmsh meshing #gmsh.model.mesh.generate(1) #gmsh.model.mesh.refine() #gmsh.model.mesh.refine() gmsh.model.mesh.generate(2) #gmsh.write("results/" + file + ".stl") gmsh_edges = gmsh.model.getEntities(1) gmsh_surfs = gmsh.model.getEntities(2) #print("O", tot, "G", len(gmsh_edges)) #continue gmsh_entities = gmsh.model.getEntities() #gmsh.model.occ.synchronize() #print(dir(gmsh.model.occ)) total_edges = 0 total_surfs = 0 for l in range(len(occ_steps)): topo = TopologyExplorer(occ_steps[l]) total_edges += len(list(topo.edges())) total_surfs += len(list(topo.faces())) vol = brepgprop_VolumeProperties(occ_steps[l], occ_props, tolerance) #print(dir(occ_props), dir(occ_props.PrincipalProperties()), dir(occ_props.volume()), occ_props.Mass()) sur = brepgprop_SurfaceProperties(occ_steps[l], occ_props, tolerance) #print(vol, "Test", sur) stats["#edges"] = total_edges stats["#surfs"] = total_surfs stats["volume"] = vol stats["surface"] = sur stats["curves"] = [] stats["surfs"] = [] stats["#points"] = 0 print("Number of surfaces: %i, Number of curves: %i" % (total_surfs, total_edges)) #print(total_edges, total_surfs, len(gmsh_edges), len(gmsh_surfs)) if not total_edges == len(gmsh_edges): print("Skipping due to wrong EDGES", model) return if not total_surfs == len(gmsh_surfs): print("Skipping due to wrong SURFS", model) return #print("Reading curvature") v_cnt = 1 v_nodes = [] occ_offset = 0 invalid_model = False c_cnt = 0 #v_cont_cnt = 0 #print(len(list(occ_topo.edges())), len(list(occ_topo.solids())), len(list(occ_topo.faces())), len(list(occ_topo.vertices()))) for e in gmsh_entities[:]: #print(e) nodeTags, nodeCoords, nodeParams = gmsh.model.mesh.getNodes( e[0], e[1], True) elemTypes, elemTags, elemNodeTags = gmsh.model.mesh.getElements( e[0], e[1]) n_id = e[1] - occ_offset #print(e, occ_offset, n_id) #print(e, nodeTags, nodeCoords, nodeParams, gmsh.model.getType(e[0], e[1]), elemTypes, elemTags, elemNodeTags) if e[0] == 0: # Process points #print(e[1], nodeCoords) vert_map[e[1]] = v_cnt verts.append([ nodeCoords[0] * 1000.0, nodeCoords[1] * 1000.0, nodeCoords[2] * 1000.0 ]) v_cnt += 1 stats["#points"] += 1 #pass if e[0] == 1: # Process contours if n_id - 1 == len(list(occ_topo.edges())): #print("CNT", occ_cnt) occ_cnt += 1 occ_offset = e[1] - 1 n_id = 1 occ_topo = TopologyExplorer(occ_steps[occ_cnt]) occ_top = Topo(occ_steps[occ_cnt]) #print("Defunct curve", n_id, len(list(occ_topo.edges()))) #continue #print(n_id) curve = BRepAdaptor_Curve(list(occ_topo.edges())[n_id - 1]) # Add type and parametric nodes/indices #print("type", edge_map[curve.GetType()]) if gmsh.model.getType(e[0], e[1]) == "Unknown": #print("Skipping OtherCurve", nodeTags) continue for i, n in enumerate(nodeTags): if n >= v_cnt: vert_map[n] = v_cnt verts.append([ nodeCoords[i * 3] * 1000.0, nodeCoords[i * 3 + 1] * 1000.0, nodeCoords[i * 3 + 2] * 1000.0 ]) v_cnt += 1 else: print(n, v_cnt) #print(v_ind, type(v_ind), v_par, type(v_par)) stats["curves"].append(edge_map[curve.GetType()]) #print(n_id, edge_map[curve.GetType()], gmsh.model.getType(e[0], e[1])) #print(list(occ_topo.edges()), n_id-1) c_type = edge_map[curve.GetType()] #gmsh.model.getType(e[0], e[1]) if not gmsh.model.getType(e[0], e[1]) == edge_map[curve.GetType()]: print("Skipped due to non matching edges ", model, gmsh.model.getType(e[0], e[1]), edge_map[curve.GetType()]) #invalid_model = True #break d1_feat = convert_curve(curve) edg = list(occ_topo.edges())[n_id - 1] for f in occ_top.faces_from_edge(edg): #ee = (e) #print(dir(ee)) #d1_feat = {} su = BRepAdaptor_Surface(f) c = BRepAdaptor_Curve2d(edg, f) t_curve = { "surface": f, "3dcurve": c_cnt, "2dcurve": convert_2dcurve(c) } #print(edge_map[c.GetType()], surf_map[su.GetType()], edge_map[curve.GetType()]) #d1f = convert_2dcurve(c) #print(d1f) #ccnt += 1 #print(d1_feat) t_curves.append(t_curve) if len(elemNodeTags) > 0: #v_ind = [int(elemNodeTags[0][0]) - 1] # first vertex v_ind = [int(nodeTags[-2]) - 1] for no in nodeTags[:-2]: v_ind.append(int(no) - 1) # interior vertices v_ind.append(int(nodeTags[-1]) - 1) #v_ind.append(int(elemNodeTags[0][-1]) - 1) # last vertex d1_feat["vert_indices"] = v_ind #v_par = [float(curve.FirstParameter())] # first param v_par = [float(nodeParams[-2] * scale_factor)] for no in nodeParams[:-2]: v_par.append(float(no * scale_factor)) # interior params v_par.append(float(nodeParams[-1] * scale_factor)) #v_par.append(float(curve.LastParameter())) # last param d1_feat["vert_parameters"] = v_par else: print("No nodetags", edge_map[curve.GetType()], elemNodeTags) #print("VERTS", len(d1_feat["vert_indices"]), len(d1_feat["vert_parameters"])) d1_feats.append(d1_feat) c_cnt += 1 #t_curve = curve.Trim(curve.FirstParameter(), curve.LastParameter(), 0.0001).GetObject() #print(curve.FirstParameter(), curve.LastParameter()) #print("Processing surfaces") gmsh_entities = gmsh.model.getEntities(2) n_cnt = 1 occ_offset = 0 occ_cnt = 0 occ_topo = TopologyExplorer(occ_steps[occ_cnt]) occ_top = Topo(occ_steps[occ_cnt]) f_cnt = 0 f_sum = 0 first_face = True mean_curv = 0.0 curv_cnt = 0 gaus_curv = 0.0 s_cnt = 0 for e in gmsh_entities[:]: #print(e) nodeTags, nodeCoords, nodeParams = gmsh.model.mesh.getNodes( e[0], e[1], True) elemTypes, elemTags, elemNodeTags = gmsh.model.mesh.getElements( e[0], e[1]) n_id = e[1] - occ_offset #print(e, occ_offset, n_id) #print(e, nodeTags, nodeCoords, nodeParams, gmsh.model.getType(e[0], e[1]), elemTypes, elemTags, elemNodeTags) if e[0] == 2: #print(e, gmsh.model.getType(e[0], e[1]), elemTypes) if n_id - 1 == len(list(occ_topo.faces())): #print("CNT", occ_cnt) occ_cnt += 1 occ_offset = e[1] - 1 n_id = 1 occ_topo = TopologyExplorer(occ_steps[occ_cnt]) occ_top = Topo(occ_steps[occ_cnt]) if "getNormals" in dir(gmsh.model): nls = gmsh.model.getNormals(e[1], nodeParams) else: nls = gmsh.model.getNormal(e[1], nodeParams) curvMax, curvMin, dirMax, dirMin = gmsh.model.getPrincipalCurvatures( e[1], nodeParams) #surf = BRepAdaptor_Surface(list(occ_topo.faces())[n_id-1]) norm_map = {} for i, n in enumerate(nodeTags): norms.append([nls[i * 3], nls[i * 3 + 1], nls[i * 3 + 2]]) curvs.append([ curvMin[i], curvMax[i], dirMin[i * 3], dirMin[i * 3 + 1], dirMin[i * 3 + 2], dirMax[i * 3], dirMax[i * 3 + 1], dirMax[i * 3 + 2] ]) curv_cnt += 1 mean_curv += (curvMin[i] + curvMax[i]) / 2.0 gaus_curv += (curvMin[i] * curvMax[i]) norm_map[n] = n_cnt n_cnt += 1 if n in vert_map.keys(): v = verts[vert_map[n] - 1] #print("Vert contained", n) #v_cont_cnt += 1 # assert(v[0] == nodeCoords[i*3] * 1000.0 and v[1] == nodeCoords[i*3+1] * 1000.0 and v[2] == nodeCoords[i*3+2] * 1000.0) continue else: vert_map[n] = v_cnt #occ_node = surf.Value(nodeParams[i], nodeParams[i+1]) #vertices.append([occ_node.X(), occ_node.Y(), occ_node.Z()]) verts.append([ nodeCoords[i * 3] * 1000.0, nodeCoords[i * 3 + 1] * 1000.0, nodeCoords[i * 3 + 2] * 1000.0 ]) #print("S", occ_node.Coord(), [nodeCoords[i*3]*1000, nodeCoords[i*3+1]*1000, nodeCoords[i*3+2]*1000]) #print(occ_node.Coord(), nodeCoords[i*3:(i+1)*3]) v_cnt += 1 d2_faces = [] for i, t in enumerate(elemTypes): for j in range(len(elemTags[i])): faces.append([ vert_map[elemNodeTags[i][j * 3]], vert_map[elemNodeTags[i][j * 3 + 1]], vert_map[elemNodeTags[i][j * 3 + 2]], norm_map[elemNodeTags[i][j * 3]], norm_map[elemNodeTags[i][j * 3 + 1]], norm_map[elemNodeTags[i][j * 3 + 2]] ]) d2_faces.append(f_cnt) f_cnt += 1 #print(len(list(occ_topo.faces())), n_id-1) surf = BRepAdaptor_Surface(list(occ_topo.faces())[n_id - 1]) #print("type", edge_map[curve.GetType()]) #if gmsh.model.getType(e[0], e[1]) == "Unknown": # print("Skipping OtherCurve", nodeTags) # continue #print(surf) g_type = gmsh_map[gmsh.model.getType(e[0], e[1])] if g_type != "Other" and not g_type == surf_map[surf.GetType()]: print("Skipped due to non matching surfaces ", model, g_type, surf_map[surf.GetType()]) #invalid_model = True #break stats["surfs"].append(surf_map[surf.GetType()]) d2_feat = convert_surface(surf) d2_feat["face_indices"] = d2_faces for tc in t_curves: if tc["surface"] == list(occ_topo.faces())[n_id - 1]: tc["surface"] = s_cnt if len(elemNodeTags) > 0: #print(len(elemNodeTags[0]), len(nodeTags), len(nodeParams)) v_ind = [] #int(elemNodeTags[0][0])] # first vertex for no in nodeTags: v_ind.append(int(no) - 1) # interior vertices #v_ind.append(int(elemNodeTags[0][-1])) # last vertex d2_feat["vert_indices"] = v_ind v_par = [] #float(surf.FirstParameter())] # first param for io in range(int(len(nodeParams) / 2)): v_par.append([ float(nodeParams[io * 2] * scale_factor), float(nodeParams[io * 2 + 1] * scale_factor) ]) # interior params #v_par.append(float(surf.LastParameter())) # last param d2_feat["vert_parameters"] = v_par else: print("No nodetags", edge_map[curve.GetType()], elemNodeTags) f_sum += len(d2_feat["face_indices"]) d2_feats.append(d2_feat) s_cnt += 1 if invalid_model: return stats["#sharp"] = 0 stats["gaus_curv"] = float(gaus_curv / curv_cnt) stats["mean_curv"] = float(mean_curv / curv_cnt) if not f_sum == len(faces): print("Skipping due to wrong FACES", model) return if True: vert2norm = {} for f in faces: #print(f) for fii in range(3): if f[fii] in vert2norm: vert2norm[f[fii]].append(f[fii + 3]) else: vert2norm[f[fii]] = [f[fii + 3]] for d1f in d1_feats: sharp = True for vi in d1f["vert_indices"][1:-1]: #print(vi, vert2norm.keys()) nos = list(set(vert2norm[vi + 1])) if len(nos) == 2: n0 = np.array(norms[nos[0]]) n1 = np.array(norms[nos[1]]) #print(np.linalg.norm(n0), np.linalg.norm(n1)) if np.abs(n0.dot(n1)) > 0.95: sharp = False #break else: sharp = False if sharp: stats["#sharp"] += 1 d1f["sharp"] = sharp stats["#verts"] = len(verts) stats["#faces"] = len(faces) stats["#norms"] = len(norms) #with open("results/" + file + ".json", "w") as fil: # json.dump(d1_feats, fil, sort_keys=True, indent=2) #with open("results/" + file + "_faces.json", "w") as fil: # json.dump(d2_feats, fil, sort_keys=True, indent=2) features = {"curves": d1_feats, "surfaces": d2_feats, "trim": t_curves} if True: res_path = folder.replace("/step/", "/feat/") fip = fil.replace("_step_", "_features_") print("%s/%s.yml" % (res_path, fip)) with open("%s/%s.yml" % (res_path, fip), "w") as fili: yaml.dump(features, fili, indent=2) res_path = folder.replace("/step/", "/stat/") fip = fil.replace("_step_", "_stats_") with open("%s/%s.yml" % (res_path, fip), "w") as fili: yaml.dump(stats, fili, indent=2) print("Generated model with %i vertices and %i faces." % (len(verts), len(faces))) res_path = folder.replace("/step/", "/obj/") fip = fil.replace("_step_", "_trimesh_") with open("%s/%s.obj" % (res_path, fip), "w") as fili: for v in verts: fili.write("v %f %f %f\n" % (v[0], v[1], v[2])) for vn in norms: #print(np.linalg.norm(vn)) fili.write("vn %f %f %f\n" % (vn[0], vn[1], vn[2])) for vn in curvs: fili.write( "vc %f %f %f %f %f %f %f %f\n" % (vn[0], vn[1], vn[2], vn[3], vn[4], vn[5], vn[6], vn[7])) for f in faces: fili.write("f %i//%i %i//%i %i//%i\n" % (f[0], f[3], f[1], f[4], f[2], f[5])) faces = np.array(faces) face_indices = faces[:, :3] - 1 norm_indices = faces[:, 3:] - 1 gmsh.clear() gmsh.finalize() #print(curvs) return { "statistics": stats, "features": features, "vertices": np.array(verts), "normals": np.array(norms), "curvatures": np.array(curvs), "face_indices": face_indices, "normal_indices": norm_indices, "trim": t_curves }
import gmsh import math import sys # This example shows how to implement a simple interactive pre-processor for a # finite element solver; in particular, it shows how boundary conditions, # material properties, etc., can be specified on parts of the model. gmsh.initialize(sys.argv) if len(sys.argv) > 1: gmsh.open(sys.argv[1]) # For Gmsh to know which types of boundary conditions, materials, etc., are # available, you should define "template" ONELAB parameters with names # containing the following substrings: # # - "ONELAB Context/Point Template/" # - "ONELAB Context/Curve Template/" # - "ONELAB Context/Surface Template/" # - "ONELAB Context/Volume Template/" # # Double-clicking on an entity in the GUI will then pop-up a context window # where instances of these variables for the given entity can be edited. For # example, if the "ONELAB Context/Curve Template/0Boundary condition" exists, # double-clicking on curve 123 in the model (or in the visibility browser) will # create "ONELAB Context/Curve 123/0Boundary condition" (or "ONELAB # Context/Physical Curve 1000/0Boundary condition" depending on the choice in # the context window, if curve 123 belongs to the physical curve 1000). The # context window is also shown automatically when a new physical group is # created in the GUI. #
def read_gmsh(mesh, **kwargs): model = gmsh.model factory = model.geo gmsh.initialize() gmsh.open(mesh) logger.info("Analyze grid") nodeTags, coord, parametricCoord = gmsh.model.mesh.getNodes() nodes = pd.DataFrame(coord.reshape(-1, 3), columns=["x", "y", "z"]) elementTags2, nodeTags2 = gmsh.model.mesh.getElementsByType(2) elems = nodeTags2.reshape(-1, 3) tria = pd.DataFrame(elems - 1, columns=["a", "b", "c"]) # boundaries bounds = [] bgs = gmsh.model.getPhysicalGroups() bgs = pd.DataFrame(bgs[:-1], columns=["dim", "tag"]) # open boundaries logger.info("open boundaries") obs = bgs.loc[bgs.tag < 1000] for row in obs.itertuples(index=True, name="Pandas"): onodes, xyz = gmsh.model.mesh.getNodesForPhysicalGroup( dim=getattr(row, "dim"), tag=getattr(row, "tag")) db = pd.DataFrame({"node": onodes - 1}) db["type"] = np.nan db["id"] = getattr(row, "Index") + 1 bounds.append(db) # land boundaries type logger.info("land boundaries") lbs = bgs.loc[(bgs.tag > 1000) & (bgs.tag < 2000)] lbs.reset_index(inplace=True, drop=True) for row in lbs.itertuples(index=True, name="Pandas"): lnodes, xyz = gmsh.model.mesh.getNodesForPhysicalGroup( dim=getattr(row, "dim"), tag=getattr(row, "tag")) db = pd.DataFrame({"node": lnodes - 1}) db["type"] = 0 db["id"] = -(getattr(row, "Index") + 1) bounds.append(db) if lbs.empty: # Store max index from land boundaries itag = 0 else: itag = lbs.tag.max() - 1000 # islands logger.info("islands") ibs = bgs.loc[bgs.tag > 2000] ibs.reset_index(inplace=True, drop=True) ibs.index = ibs.index + itag # set index for row in ibs.itertuples(index=True, name="Pandas"): inodes, xyz = gmsh.model.mesh.getNodesForPhysicalGroup( dim=getattr(row, "dim"), tag=getattr(row, "tag")) db = pd.DataFrame({"node": inodes - 1}) db["type"] = -1 db["id"] = -(getattr(row, "Index") + 1) bounds.append(db) if bounds != []: bnodes = pd.concat(bounds).reset_index(drop=True) bnodes.index.name = "bnodes" bnodes = bnodes.drop_duplicates("node") bnodes["id"] = bnodes.id.astype(int) else: bnodes = pd.DataFrame({}) # check if global and reproject sproj = kwargs.get("gglobal", False) if sproj: # convert to lat/lon xd, yd = to_lat_lon(nodes.x, nodes.y) nodes["x"] = xd nodes["y"] = yd grid = pd.DataFrame({"lon": nodes.x, "lat": nodes.y}) tri3 = tria.values logger.info("Finalize Dataset") ## make dataset els = xr.DataArray( tri3, dims=["nSCHISM_hgrid_face", "nMaxSCHISM_hgrid_face_nodes"], name="SCHISM_hgrid_face_nodes") nod = (grid.loc[:, ["lon", "lat"]].to_xarray().rename({ "index": "nSCHISM_hgrid_node", "lon": "SCHISM_hgrid_node_x", "lat": "SCHISM_hgrid_node_y" })) nod = nod.drop_vars("nSCHISM_hgrid_node") dep = xr.Dataset({ "depth": (["nSCHISM_hgrid_node"], np.zeros(nod.nSCHISM_hgrid_node.shape[0])) }) gr = xr.merge([nod, els, dep, bnodes.to_xarray()]) gmsh.finalize() return gr
import gmsh import sys import numpy as np gmsh.initialize(sys.argv) gmsh.option.setNumber("General.Terminal", 1) print(gmsh.option.getNumber("Mesh.Algorithm")) gmsh.open("cube2d.msh") model = gmsh.model print("Nodes") tags, coord, _ = model.mesh.getNodes(2, -1) print(tags) print(coord) coord2 = np.asarray(coord) coord2 = np.reshape(coord2, (np.int32(coord2.shape[0]) / 3, 3)) print(coord2) gmsh.finalize() import matplotlib.pyplot as plt plt.figure(0) plt.plot(coord2[:, 0], coord2[:, 1], 'b.') plt.show()
def gmsh_to_mesh(self, filename): """Initialize self.points, self.segments and self.triangles with mesh stored in filename. Parameters ---------- filename : str the file name """ self.filename = filename gmsh.open(filename) # Fill self.points nodeTags, nodeCoords, _ = gmsh.model.mesh.getNodes() X = nodeCoords[0::3] Y = nodeCoords[1::3] for (tag, x, y) in zip(nodeTags, X, Y): point = Point(np.array([x, y]), tag) self.points.append(point) # Set number of points of mesh self.nbPoints = len(X) # Fill self.segments, self.triangles for dim, physical_tag in gmsh.model.getPhysicalGroups(): for entity_tag in gmsh.model.getEntitiesForPhysicalGroup( dim, physical_tag): elmType, elmTags, nodeTags = gmsh.model.mesh.getElements( dim, entity_tag) # Segment if dim == 1: for j in range(len(elmTags[0])): ids = [nodeTags[0][2 * j], nodeTags[0][2 * j + 1]] pts = [ point for point in self.points if point.id in ids ] segment = Segment(pts, physical_tag) self.segments.append(segment) # Triangle elif dim == 2: for j in range(len(elmTags[0])): ids = [ nodeTags[0][3 * j], nodeTags[0][3 * j + 1], nodeTags[0][3 * j + 2] ] points = [ point for point in self.points if point.tag in ids ] try: triangle = Triangle(points, physical_tag) self.triangles.append(triangle) except Exception as e: print("[WARNING] `Mesh.gmsh_to_mesh`:", e) print("Points are:", [point.X for point in points]) # Others else: print( f"[WARNING] `Mesh.gmsh_to_mesh`: Unknown element type '{dim}'." )
import gmsh import sys gmsh.initialize(sys.argv) gmsh.option.setNumber("General.Terminal", 1) print(gmsh.option.getNumber("Mesh.Algorithm")) gmsh.open("square.msh") model = gmsh.model model.add("square") factory = model.geo factory.addPoint(0,0,0,0.1,1) factory.addPoint(1,0,0,0.1,2) factory.addPoint(1,1,0,0.1,3) factory.addPoint(0,1,0,0.1,4) factory.addLine(1,2,1) factory.addLine(2,3,2) factory.addLine(3,4,3) line4 = factory.addLine(4,1) print("line4 received tag ", line4) factory.addCurveLoop([1,2,3,line4],1) factory.addPlaneSurface([1],6) factory.synchronize() ptag = model.addPhysicalGroup(1,[1,2,3,4]) ent = model.getEntitiesForPhysicalGroup(1,ptag) print("new physical group ",ptag,":",ent, type(ent)) model.addPhysicalGroup(2,[6])
def get_plate_particles(): gmsh.initialize() gmsh.open('t.msh') # Launch the GUI to see the results: # if '-nopopup' not in sys.argv: # gmsh.fltk.run() nodeTags, nodesCoord, parametricCoord = gmsh.model.mesh.getNodes() liquid_x = nodesCoord[1::3] liquid_y = nodesCoord[2::3] liquid_z = nodesCoord[0::3] liquid_y = liquid_y + abs(min(liquid_y)) liquid_x = liquid_x + abs(min(liquid_x)) liquid_x = liquid_x[0::5] * 1e-3 - 0.002 liquid_y = liquid_y[0::5] * 1e-3 - 0.1 liquid_z = liquid_z[0::5] * 1e-3 - 0.005 print('%d Target particles' % len(liquid_x)) hf = numpy.ones_like(liquid_x) * h mf = numpy.ones_like(liquid_x) * dx * dy * dz * ro1 rhof = numpy.ones_like(liquid_x) * ro1 csf = numpy.ones_like(liquid_x) * cs1 pa = plate = get_particle_array(name="plate", x=liquid_x, y=liquid_y, z=liquid_z, h=hf, m=mf, rho=rhof, cs=csf) # add requisite properties # sound speed etc. add_properties(pa, 'e') # velocity gradient properties add_properties(pa, 'v00', 'v01', 'v02', 'v10', 'v11', 'v12', 'v20', 'v21', 'v22') # artificial stress properties add_properties(pa, 'r00', 'r01', 'r02', 'r11', 'r12', 'r22') # deviatoric stress components add_properties(pa, 's00', 's01', 's02', 's11', 's12', 's22') # deviatoric stress accelerations add_properties(pa, 'as00', 'as01', 'as02', 'as11', 'as12', 'as22') # deviatoric stress initial values add_properties(pa, 's000', 's010', 's020', 's110', 's120', 's220') # standard acceleration variables add_properties(pa, 'arho', 'au', 'av', 'aw', 'ax', 'ay', 'az', 'ae') # initial values add_properties(pa, 'rho0', 'u0', 'v0', 'w0', 'x0', 'y0', 'z0', 'e0') pa.add_constant('G', G1) pa.add_constant('n', 4) kernel = Gaussian(dim=3) wdeltap = kernel.kernel(rij=dx, h=hdx * dx) pa.add_constant('wdeltap', wdeltap) # load balancing properties pa.set_lb_props(list(pa.properties.keys())) # removed S_00 and similar components plate.v[:] = 0.0 return plate
def refine_mesh( in_file: str, out_file: str, dim: int, network: Union[pp.FractureNetwork3d, pp.FractureNetwork2d], num_refinements: int = 1, ) -> List[pp.GridBucket]: """ Refine a mesh by splitting, using gmsh Parameters ---------- in_file : str path to .geo file to read out_file : str path to new .msh file to store mesh in, excluding the ending '.msh'. dim : int {2, 3} Dimension of domain to mesh network : Union[pp.FractureNetwork2d, pp.FractureNetwork3d] PorePy class defining the fracture network that is described by the .geo in_file num_refinements : int : Optional. Default = 1 Number of refinements """ try: import gmsh except ModuleNotFoundError: raise ModuleNotFoundError( "To run gmsh python api on your system, " "download the relevant gmsh*-sdk.* from http://gmsh.info/bin/. " "Then, Add the 'lib' directory from the SDK to PYTHONPATH: \n" "export PYTHONPATH=${PYTHONPATH}:path/to/gmsh*-sdk.*/lib" ) from porepy.fracs.simplex import tetrahedral_grid_from_gmsh from porepy.fracs.meshing import grid_list_to_grid_bucket assert os.path.isfile(in_file) # Run gmsh gmsh.initialize() gmsh.open(in_file) gmsh.model.mesh.generate(dim=dim) if out_file[-4:] == ".msh": out_file = out_file[:-4] # Save coarsest grid fname = f"{out_file}_0.msh" gmsh.write(fname) grid_list_ref = tetrahedral_grid_from_gmsh(network=network, file_name=fname) gb_list = [grid_list_to_grid_bucket(grid_list_ref)] for i in range(num_refinements): gmsh.model.mesh.refine() # Refined grid fname = f"{out_file}_{i+1}.msh" gmsh.write(fname) # Create grid bucket from refined grid output grid_list_ref = tetrahedral_grid_from_gmsh(network=network, file_name=fname) gb_ref = grid_list_to_grid_bucket(grid_list_ref) gb_list.append(gb_ref.copy()) gmsh.finalize() return gb_list
def create(self, is3D=False): ''' Meshes a surface or volume defined by the geometry in geoData. Parameters: is3D - Optional parameter that only needs to be set if geometry is loaded from a geo-file, i.e. if geoData is a path string. Default False. Returns: coords Node coordinates [[n0_x, n0_y, n0_z], [ ... ], [nn_x, nn_y, nn_z]] edof Element topology [[el0_dof1, ..., el0_dofn], [ ... ], [eln_dof1, ..., eln_dofn]] dofs Node dofs [[n0_dof1, ..., n0_dofn], [ ... ], [nn_dof1, ..., nn_dofn]] bdofs Boundary dofs. Dictionary containing lists of dofs for each boundary marker. Dictionary key = marker id. elementmarkers List of integer markers. Row i contains the marker of element i. Markers are similar to boundary markers and can be used to identify in which region an element lies. boundaryElements (optional) returned if self.return_boundary_elements is true. Contains dictionary with boundary elements. The keys are markers and the values are lists of elements for that marker. Running this function also creates object variables: nodesOnCurve Dictionary containing lists of node-indices. Key is a curve-ID and the value is a list of indices of all nodes on that curve, including its end points. nodesOnSurface Dictionary containing lists of node-indices. Key is a surface-ID and the value is a list of indices of the nodes on that surface, including its boundary. nodesOnVolume Dictionary containing lists of node-indices. Key is a volume-ID and the value is a list of indices of the nodes in that volume, including its surface. ''' # Nodes per element for different element types: # (taken from Chapter 9, page 89 of the gmsh manual) nodesPerElmDict = {1: 2, 2: 3, 3: 4, 4: 4, 5: 8, 6: 6, 7: 5, 8: 3, 9: 6, 10: 9, 11: 10, 12: 27, 13: 18, 14: 14, 15: 1, 16: 8, 17: 20, 18: 15, 19: 13, 20: 9, 21: 10, 22: 12, 23: 15, 24: 15, 25: 21, 26: 4, 27: 5, 28: 6, 29: 20, 30: 35, 31: 56, 92: 64, 93: 125} nodesPerElement = nodesPerElmDict[self.el_type] # Check for GMSH executable # # Consider using the gmsh_extension module if not self.use_gmsh_module: gmshExe = self.gmsh_exec_path if gmshExe == None: gmshExe = None if sys.platform == "win32": gmshExe = which("gmsh.bat") if gmshExe == None: gmshExe = which("gmsh.exe") else: gmshExe = which("gmsh") else: if not os.path.exists(gmshExe): gmshExe = os.path.join( os.getcwd(), self.gmsh_exec_path) # Try relative path if not os.path.exists(gmshExe): gmshExe = None # Relative path didnt work either if gmshExe == None: raise IOError( "Error: Could not find GMSH. Please make sure that the \GMSH executable is available on the search path (PATH).") else: print("Info : GMSH -> %s" % gmshExe) else: print("Info : GMSH -> Python-module") # Create a temporary directory for GMSH oldStyleTempDir = False if self.mesh_dir != "": tempMeshDir = self.mesh_dir if not os.path.exists(tempMeshDir): os.mkdir(tempMeshDir) else: tempMeshDir = tempfile.mkdtemp() # If geometry data is given as a .geo file we will just pass it on to gmsh later. if type(self.geometry) is str: geoFilePath = self.geometry # In this case geoData is a path string, so the dimension must be supplied by the user. dim = 3 if is3D else 2 if not os.path.exists(geoFilePath): geoFilePath = os.path.join( os.getcwd(), geoFilePath) # Try relative path if not os.path.exists(geoFilePath): raise IOError( "Error: Could not find geo-file " + geoFilePath) else: # Get the dimension of the model from geoData. dim = 3 if self.geometry.is3D else 2 if oldStyleTempDir: if not os.path.exists("./gmshMeshTemp"): os.mkdir("./gmshMeshTemp") geoFilePath = os.path.normpath(os.path.join( os.getcwd(), "gmshMeshTemp/tempGeometry.geo")) # "gmshMeshTemp/tempGeometry.geo" else: geoFilePath = os.path.normpath( os.path.join(tempMeshDir, 'tempGeometry.geo')) with open(geoFilePath, "w") as self.geofile: self._writeGeoFile() # Write geoData to file if oldStyleTempDir: # Filepath to the msh-file that will be generated. mshFileName = os.path.normpath(os.path.join( os.getcwd(), 'gmshMeshTemp/meshFile.msh')) else: mshFileName = os.path.normpath( os.path.join(tempMeshDir, 'meshFile.msh')) # construct options string: options = "" options += ' -' + str(dim) options += ' -clscale ' + str(self.el_size_factor) # scale factor options += ' -o \"%s\"' % mshFileName options += ' -clcurv' if self.clcurv else '' options += ' -clmin ' + \ str(self.min_size) if self.min_size is not None else '' options += ' -clmax ' + \ str(self.max_size) if self.max_size is not None else '' options += ' -algo ' + self.meshing_algorithm if self.meshing_algorithm is not None else '' options += ' -order 2' if self.el_type in self._2ndOrderElms else '' options += ' -format msh22' options += ' -v 5' options += ' ' + self.additional_options # Execute gmsh if self.use_gmsh_module: # Meshing using gmsh extension module if self.initialize_gmsh: gmsh.initialize(sys.argv) # This is a hack to enable the use of gmsh in # a separate thread. if self.remove_gmsh_signal_handler: gmsh.oldsig = None # Load .geo file gmsh.open(geoFilePath) gmsh.model.geo.synchronize() # Set meshing options if self.el_type in self._2ndOrderElms: gmsh.option.setNumber("Mesh.ElementOrder", 2) if self.meshing_algorithm is not None: gmsh.option.setString(self.meshing_algorithm) gmsh.option.setNumber("Mesh.MshFileVersion", 2.2) gmsh.option.setNumber("Mesh.MeshSizeFactor", self.el_size_factor) if self.clcurv is not None: gmsh.option.setNumber("Mesh.MeshSizeFromCurvature", self.clcurv) if self.min_size is not None: gmsh.option.setNumber('Mesh.MeshSizeMin', self.min_size) if self.max_size is not None: gmsh.option.setNumber('Mesh.MeshSizeMax', self.max_size) # Generate mesh gmsh.model.mesh.generate(2) # Write .msh file gmsh.write(mshFileName) # Close extension module if self.initialize_gmsh: gmsh.finalize() else: gmshExe = os.path.normpath(gmshExe) info("GMSH binary: "+gmshExe) output = subprocess.Popen(r'"%s" "%s" %s' % ( gmshExe, geoFilePath, options), shell=True, stdout=subprocess.PIPE).stdout.read() # Read generated msh file: # print("Opening msh file " + mshFileName)#TEMP with open(mshFileName, 'r') as mshFile: info("Mesh file : "+mshFileName) # print("Reading msh file...") ln = mshFile.readline() while(ln != '$Nodes\n'): # Read until we find the nodes ln = mshFile.readline() nbrNodes = int(mshFile.readline()) allNodes = np.zeros([nbrNodes, dim], 'd') for i in range(nbrNodes): line = list(map(float, mshFile.readline().split())) # Grab the coordinates (1:3 if 2D, 1:4 if 3D) allNodes[i, :] = line[1:dim+1] while(mshFile.readline() != '$Elements\n'): # Read until we find the elements pass # The nbr of elements (including marker elements). nbrElements = int(mshFile.readline()) elements = [] elementmarkers = [] # temp dictionary of sets. Key:MarkerID. Value:Set. The sets will be converted to lists. bdofs = {} boundaryElements = {} # nodeOnPoint = {} #dictionary pointID : nodeNumber self.nodesOnCurve = {} # dictionary lineID : set of [nodeNumber] self.nodesOnSurface = {} # dictionary surfID : set of [nodeNumber] self.nodesOnVolume = {} # dictionary volID : set of [nodeNumber] # Read all elements (points, surfaces, etc): for i in range(nbrElements): line = list(map(int, mshFile.readline().split())) eType = line[1] # second int is the element type. nbrTags = line[2] # Third int is the nbr of tags on this element. marker = line[3] # Fourth int (first tag) is the marker. # Fifth int is the ID of the geometric entity (points, curves, etc) that the element belongs to entityID = line[4] # The rest after tags are node indices. nodes = line[3+nbrTags: len(line)] # If the element type is the kind of element we are looking for: if(eType == self.el_type): # Add the nodes of the elements to the list. elements.append(nodes) # Add element marker. It is used for keeping track of elements (thickness, heat-production and such) elementmarkers.append(marker) else: # If the element is not a "real" element we store its node at marker in bdof instead: _insertInSetDict(bdofs, marker, nodes) # We also store the full information as 'boundary elements' _insertBoundaryElement(boundaryElements, eType, marker, nodes) # if eType == 15: #If point. Commmented away because points only make elements if they have non-zero markers, so nodeOnPoint is not very useful. # nodeOnPoint[entityID-1] = nodes[0] #insert node into nodeOnPoint. (ID-1 because we want 0-based indices) if eType in [1, 8, 26, 27, 28]: # If line # insert nodes into nodesOnCurve _insertInSetDict(self.nodesOnCurve, entityID - 1, _offsetIndices(nodes, -1)) elif eType in [2, 3, 9, 10, 16, 20, 21, 22, 23, 24, 25]: # If surfaceelement # insert nodes into nodesOnSurface _insertInSetDict(self.nodesOnSurface, entityID - 1, _offsetIndices(nodes, -1)) else: # if volume element. _insertInSetDict(self.nodesOnVolume, entityID - 1, _offsetIndices(nodes, -1)) elements = np.array(elements) for key in bdofs.keys(): # Convert the sets of boundary nodes to lists. bdofs[key] = list(bdofs[key]) for key in self.nodesOnCurve.keys(): # Convert set to list self.nodesOnCurve[key] = list(self.nodesOnCurve[key]) for key in self.nodesOnSurface.keys(): # Convert set to list self.nodesOnSurface[key] = list(self.nodesOnSurface[key]) for key in self.nodesOnVolume.keys(): # Convert set to list self.nodesOnVolume[key] = list(self.nodesOnVolume[key]) # Remove temporary mesh directory if not explicetly specified. if self.mesh_dir == "": shutil.rmtree(tempMeshDir) dofs = createdofs(np.size(allNodes, 0), self.dofs_per_node) if self.dofs_per_node > 1: # This if-chunk copied from pycalfem_utils.py self.topo = elements expandedElements = np.zeros( (np.size(elements, 0), nodesPerElement*self.dofs_per_node), 'i') elIdx = 0 for elementTopo in elements: for i in range(nodesPerElement): expandedElements[elIdx, i*self.dofs_per_node:( i*self.dofs_per_node+self.dofs_per_node)] = dofs[elementTopo[i]-1, :] elIdx += 1 for keyID in bdofs.keys(): bVerts = bdofs[keyID] bVertsNew = [] for i in range(len(bVerts)): for j in range(self.dofs_per_node): bVertsNew.append(dofs[bVerts[i]-1][j]) bdofs[keyID] = bVertsNew if self.return_boundary_elements: return allNodes, np.asarray(expandedElements), dofs, bdofs, elementmarkers, boundaryElements return allNodes, np.asarray(expandedElements), dofs, bdofs, elementmarkers if self.return_boundary_elements: return allNodes, elements, dofs, bdofs, elementmarkers, boundaryElements return allNodes, elements, dofs, bdofs, elementmarkers
if __name__ == "__main__": import argparse parser = argparse.ArgumentParser() parser.add_argument("-m", "--mesh_file", action='store', default="mesh.msh", help="def = 'mesh.msh'") parser.add_argument("-n", "--group_name", action='store', default="reticle_FS", help="def = 'reticle_FS'") parser.add_argument("-dx", action='store', default=None, help="x boundaries of area of interest; format 'lhs rhs' [def=None - no restriction]") parser.add_argument("-dy", action='store', default=None, help="y boundaries of area of interest; format 'lhs rhs' [def=None - no restriction]") parser.add_argument("-dz", action='store', default=None, help="z boundaries of area of interest; format 'lhs rhs' [def=None - no restriction]") args = parser.parse_args() x_bnd = get_boundary(args.dx) y_bnd = get_boundary(args.dy) z_bnd = get_boundary(args.dz) gmsh.initialize() gmsh.open(args.mesh_file) dim_tag = get_phys_group_dim_tag(args.group_name) entity_data = download_elements(dim_tag) print("Finished with entity data") area = calculate_area(entity_data, x_bnd, y_bnd, z_bnd) gmsh.finalize() print("Area = %.6e cm^2" % area)
def meshFromParametricGeometry(filepath, outputdir='autogen/', meshtype='Surface', **kwargs): """ generate a tetrahedron and/or a surface mesh from the provided file and store the result in a volumetric (vtk) or surfacic file (stl, etc.). The path to the file is returned. :param str filepath: The path to the file (including extension) to the parametric mesh. :param str outputdir: The path to the directory where the meshed file will be stored. :param str meshtype: This accepts the values 'Surface' or 'Volumetric', i.e. the type of mesh to generate from the source :param dict **kwargs: This function accepts through the kwargs all options that can be set in Gmsh as found in the documentation: http://gmsh.info/doc/texinfo/gmsh.html. The options in the referenced documentation are sorted into categories ("Mesh", "Geometry", etc.) and separated by a point, e.g. "Mesh.CharacteristicLengthFactor". The same option passed as kwarg is separated by an underscore, e.g. "Mesh_CharacteristicLengthFactor=0.8". See example below. """ import splib.caching.cacher as cch import gmsh import os import numpy as np #import locale #locale.setlocale(locale.LC_ALL, "C") with LocaleManager('C'): # Set options from kwargs OptionsStrings, Values = cch.extractOptions(kwargs) gmsh.initialize() for i in range(0, len(OptionsStrings)): SplitStr = OptionsStrings[i].split('_') Category = SplitStr[0] Option = SplitStr[1] GmshOptionStr = Category+'.'+Option if isinstance(Values[i], str): # need to be careful to call the correct function according to the type of value (string or numerical) gmsh.option.setString(GmshOptionStr, Values[i]) else: gmsh.option.setNumber(GmshOptionStr, Values[i]) Refresh = False OutputFilePath = '' FileNameWithExt = os.path.split(filepath)[1] FileNameNoExt = os.path.splitext(FileNameWithExt)[0] #Refresh, OutputFilePath = casher(filepath, outputdir, '.stl', kwargs, FileNameNoExt) if meshtype == 'Surface': Refresh, OutputFilePath = cch.cacher(filepath, outputdir, '.stl', kwargs, FileNameNoExt) elif meshtype == 'Volumetric': Refresh, OutputFilePath = cch.cacher(filepath, outputdir, '.vtk', kwargs, FileNameNoExt) if Refresh: logging.info(' Beginning meshing ' + str(filepath) + ' ...') gmsh.initialize() gmsh.open(filepath) if meshtype == 'Surface': gmsh.model.mesh.generate(2) elif meshtype == 'Volumetric': gmsh.model.mesh.generate(3) gmsh.write(OutputFilePath) logging.info(' Finished meshing.') gmsh.finalize() return OutputFilePath
def tag_mesh_entities(input_mesh, boundary_files, roi_labels, scale_ratio=1.0, \ duplicate=False, output_mesh=None, interactive=False): """Tag mesh entities Args: input_mesh: path to a GMSH mesh boundary_mesh_files: A list of file locations to surface meshes whose combinations define the ROI boundaries. roi_labels: A dict of [ROI_ID : ROI_SIGNATURES] pairs. scale_ratio: scale conversion factor between stl and msh duplicate: allow duplication of tets tagged multiple times interactive: to visualize the mesh using the graphical UI provide by gmsh API output_mesh: in-place edit if None, path to output mesh otherwise """ gmsh.option.setNumber("General.Terminal", 1) # Open file gmsh.open(input_mesh) if gmsh.model.getDimension() < 0: print("Could not find " + input_mesh, file=sys.stderr) exit() # Print the model name and dimension: print('Model ' + gmsh.model.getCurrent() + ' (' + str(gmsh.model.getDimension()) + 'D)') # Create spatial index spatial_index = gen_tet_spatial_index(gmsh.model.mesh) # Tag ROIs ROIs = add_tet_ROIs(gmsh.model.mesh, scale_ratio, spatial_index, \ boundary_files, roi_labels) print("Found: ", len(ROIs), "ROIs") # Get element ids and node ids in mesh from element type ele_ids, node_ids = gmsh.model.mesh.getElementsByType(tet_t.etype) nTets = len(ele_ids) print("Number of tets in original mesh: ", nTets) # Save old entities old_ent = gmsh.model.getEntities(dim=tet_t.dim) nEntities_old = len(old_ent) print("Number of entities in original mesh: ", nEntities_old) # Save old phys groups and names (only 3D) old_grp = gmsh.model.getPhysicalGroups(dim=tet_t.dim) old_grp_names = list() for grp in old_grp: old_grp_names.append(gmsh.model.getPhysicalName(grp[0], grp[1])) # Select tets based on ROI list nROIs = len(ROIs) nEntities = nROIs + nEntities_old # ROIs plus original volumes tets_select = [[] for _ in range(nEntities)] # selected elements nodes_select = [[] for _ in range(nEntities)] # correspoding nodes nodes_coords = [[] for _ in range(nEntities)] # nodes coordinates for i in range(nTets): is_in_ROIs = False # Loop over ROIs to select tag for id_roi in range(nROIs): for t in ROIs[id_roi]: if t == i: if is_in_ROIs and not duplicate: raise Exception( "ROIs overlap detected, you need to enable dublication of tets" ) is_in_ROIs = True id_entity = id_roi + nEntities_old tets_select[id_entity].extend([ele_ids[i]]) nodes_select[id_entity].extend(node_ids[tet_t.nnodes*i:\ tet_t.nnodes*i+tet_t.nnodes]) for n in range(tet_t.nnodes): node = node_ids[i * tet_t.nnodes + n] # Get coordinates (and parametric coor if available) from node id node_coo = gmsh.model.mesh.getNode(node)[0] nodes_coords[id_entity].extend(node_coo) if not is_in_ROIs: # Not in a ROI, check to which entity it used to belong id_entity = -1 ent_count = 0 for dont_care, ent_tag in old_ent: elementTags, nodeTags = gmsh.model.mesh.getElementsByType( tet_t.etype, tag=ent_tag) if np.isin(elementTags, ele_ids[i]).any(): id_entity = ent_count ent_count += 1 # Did we find the tet if id_entity < 0: raise "cannot find entity fot tet" tets_select[id_entity].extend([ele_ids[i]]) nodes_select[id_entity].extend(node_ids[tet_t.nnodes*i:\ tet_t.nnodes*i+tet_t.nnodes]) for n in range(tet_t.nnodes): node = node_ids[i * tet_t.nnodes + n] # Get coordinates (and parametric coor if available) from node id node_coo = gmsh.model.mesh.getNode(node)[0] nodes_coords[id_entity].extend(node_coo) # Clear mesh and model if (output_mesh == None): output_mesh = gmsh.model.getCurrent() + ".msh" gmsh.clear() # Add new discrete entities: old entities + ROIs based entities if old_grp: # get last old tag base_tag = old_grp[-1][1] else: # only untagged tets were present base_tag = 1 roi_names = list(roi_labels.keys()) for i in range(nEntities): vnew = gmsh.model.addDiscreteEntity(tet_t.dim) gmsh.model.mesh.addNodes(tet_t.dim, vnew, nodes_select[i], nodes_coords[i]) gmsh.model.mesh.removeDuplicateNodes() gmsh.model.mesh.addElementsByType(vnew, tet_t.etype, tets_select[i], nodes_select[i]) if i < nEntities_old: if old_grp: volume_tag = old_grp[i][1] else: volume_tag = base_tag gmsh.model.addPhysicalGroup(dim=tet_t.dim, tags=[vnew], tag=volume_tag) if old_grp_names: ent_tag = old_grp_names[i] gmsh.model.setPhysicalName(dim=tet_t.dim, tag=volume_tag, name=ent_tag) else: volume_tag = base_tag + i - nEntities_old + 1 gmsh.model.addPhysicalGroup(dim=tet_t.dim, tags=[vnew], tag=volume_tag) gmsh.model.setPhysicalName(dim=tet_t.dim, tag=volume_tag, name=roi_names[i - nEntities_old]) # Get element ids and node ids in mesh from element type (check nTets) ele_ids, node_ids = gmsh.model.mesh.getElementsByType(tet_t.etype) nTets = len(ele_ids) print("Number of tets in new mesh: ", nTets) # To visualize the model we can run the graphical user interface from gmsh if interactive: gmsh.fltk.run() gmsh.write(output_mesh)
def __init__(self, AP, path_to_geo, S=None, R=None, fmax=1000, num_freq=6, scale=1, order=1, plot=False): self.R = R self.S = S self.path_to_geo = path_to_geo self.fmax = fmax self.num_freq = num_freq self.scale = scale self.order = order self.c0 = np.real(AP.c0) import meshio import gmsh import sys import os filename, file_extension = os.path.splitext(path_to_geo) if path_to_geo == '.geo' or '.brep': gmsh.initialize(sys.argv) gmsh.open(self.path_to_geo) # Open msh # dT = gmsh.model.getEntities() # gmsh.model.occ.dilate(dT,0,0,0,1/scale,1/scale,1/scale) gmsh.option.setNumber("Mesh.MeshSizeMax", (self.c0 * self.scale) / self.fmax / self.num_freq) gmsh.option.setNumber( "Mesh.MeshSizeMin", 0.1 * (self.c0 * self.scale) / self.fmax / self.num_freq) lc = 0 #(self.c0*self.scale)/self.fmax/self.num_freq tg = gmsh.model.occ.getEntities(3) # tg2 = gmsh.model.occ.getEntities(2) if self.R != None: for i in range(len(self.R.coord)): it = gmsh.model.occ.addPoint(self.R.coord[i, 0], self.R.coord[i, 1], self.R.coord[i, 2], lc, -1) gmsh.model.occ.synchronize() gmsh.model.mesh.embed(0, [it], 3, tg[0][1]) if self.S != None: for i in range(len(self.S.coord)): it = gmsh.model.occ.addPoint(self.S.coord[i, 0], self.S.coord[i, 1], self.S.coord[i, 2], lc, -1) gmsh.model.occ.synchronize() gmsh.model.mesh.embed(0, [it], 3, tg[0][1]) # gmsh.model.mesh.embed(0, [15000], 3, tg[0][1]) gmsh.model.mesh.generate(3) gmsh.model.mesh.setOrder(self.order) # gmsh.model.mesh.optimize(method='Relocate3D',force=False) if self.order == 1: elemTy, elemTa, nodeTags = gmsh.model.mesh.getElements(3) self.elem_vol = np.array(nodeTags, dtype=int).reshape(-1, 4) - 1 elemTys, elemTas, nodeTagss = gmsh.model.mesh.getElements(2) self.elem_surf = np.array(nodeTagss, dtype=int).reshape(-1, 3) - 1 vtags, vxyz, _ = gmsh.model.mesh.getNodes() self.nos = vxyz.reshape((-1, 3)) / scale if self.order == 2: elemTy, elemTa, nodeTags = gmsh.model.mesh.getElements(3) self.elem_vol = np.array(nodeTags, dtype=int).reshape(-1, 10) - 1 elemTys, elemTas, nodeTagss = gmsh.model.mesh.getElements(2) self.elem_surf = np.array(nodeTagss, dtype=int).reshape(-1, 6) - 1 vtags, vxyz, _ = gmsh.model.mesh.getNodes() self.nos = vxyz.reshape((-1, 3)) / scale pg = gmsh.model.getPhysicalGroups(2) va = [] vpg = [] for i in range(len(pg)): v = gmsh.model.getEntitiesForPhysicalGroup(2, pg[i][1]) for ii in range(len(v)): # print(v[ii]) vvv = gmsh.model.mesh.getElements(2, v[ii])[1][0] pgones = np.ones_like(vvv) * pg[i][1] va = np.hstack((va, vvv)) # print(pgones) vpg = np.hstack((vpg, pgones)) vas = np.argsort(va) self.domain_index_surf = vpg[vas] pgv = gmsh.model.getPhysicalGroups(3) vav = [] vpgv = [] for i in range(len(pgv)): vv = gmsh.model.getEntitiesForPhysicalGroup(3, pgv[i][1]) for ii in range(len(vv)): # print(v[ii]) vvv = gmsh.model.mesh.getElements(3, vv[ii])[1][0] pgones = np.ones_like(vvv) * pgv[i][1] vavsv = np.hstack((vav, vvv)) # print(pgones) vpgv = np.hstack((vpgv, pgones)) vasv = np.argsort(vavsv) self.domain_index_vol = vpgv[vasv] # gmsh.model.mesh.optimize() gmsh.model.occ.synchronize() if plot: gmsh.fltk.run() # gmsh.fltk.run() path_name = os.path.dirname(self.path_to_geo) gmsh.write(path_name + '/current_mesh2.vtk') self.model = gmsh.model gmsh.finalize() msh = meshio.read(path_name + '/current_mesh2.vtk') elif file_extension == '.msh' or 'vtk': msh = meshio.read(path_to_geo) self.msh = msh # os.remove(path_name+'/current_mesh.msh') if order == 1: self.nos = msh.points / scale self.elem_surf = msh.cells_dict["triangle"] self.elem_vol = msh.cells_dict["tetra"] self.domain_index_surf = msh.cell_data_dict["CellEntityIds"][ "triangle"] self.domain_index_vol = msh.cell_data_dict["CellEntityIds"][ "tetra"] # self.domain_index_surf = msh.cell_data_dict["gmsh:physical"]["triangle"] # self.domain_index_vol = msh.cell_data_dict["gmsh:physical"]["tetra"] # elif order == 2: # self.elem_surf = msh.cells_dict["triangle6"] # self.elem_vol = msh.cells_dict["tetra10"] # self.domain_index_surf = msh.cell_data_dict["gmsh:physical"]["triangle6"] # self.domain_index_vol = msh.cell_data_dict["gmsh:physical"]["tetra10"] elif order == 2: # self.elem_surf = msh.cells_dict["triangle6"] # self.elem_vol = msh.cells_dict["tetra10"] self.domain_index_surf = msh.cell_data_dict["CellEntityIds"][ "triangle6"] self.domain_index_vol = msh.cell_data_dict["CellEntityIds"][ "tetra10"] self.number_ID_faces = np.unique(self.domain_index_surf) self.number_ID_vol = np.unique(self.domain_index_vol) self.NumNosC = len(self.nos) self.NumElemC = len(self.elem_vol)
def read_msh(filename, **kwargs): model = gmsh.model factory = model.geo gmsh.initialize() gmsh.open(filename) logger.info("Analyze grid") nodeTags, coord, parametricCoord = gmsh.model.mesh.getNodes() nodes = pd.DataFrame(coord.reshape(-1, 3), columns=["x", "y", "z"]) elementTags2, nodeTags2 = gmsh.model.mesh.getElementsByType(2) elems = nodeTags2.reshape(-1, 3) tria = pd.DataFrame(elems - 1, columns=["a", "b", "c"]) # boundaries bounds = [] bgs = gmsh.model.getPhysicalGroups() bgs = pd.DataFrame(bgs[:-1], columns=["dim", "tag"]) # open boundaries logger.info("open boundaries") obs = bgs.loc[bgs.tag < 1000] for row in obs.itertuples(index=True, name="Pandas"): onodes, xyz = gmsh.model.mesh.getNodesForPhysicalGroup( dim=getattr(row, "dim"), tag=getattr(row, "tag")) db = pd.DataFrame({"node": onodes - 1}) db["type"] = "open" db["id"] = getattr(row, "Index") + 1 bounds.append(db) # land boundaries type logger.info("land boundaries") lbs = bgs.loc[(bgs.tag > 1000) & (bgs.tag < 2000)] lbs.reset_index(inplace=True, drop=True) for row in lbs.itertuples(index=True, name="Pandas"): lnodes, xyz = gmsh.model.mesh.getNodesForPhysicalGroup( dim=getattr(row, "dim"), tag=getattr(row, "tag")) db = pd.DataFrame({"node": lnodes - 1}) db["type"] = "land" db["id"] = 1000 + (getattr(row, "Index") + 1) bounds.append(db) # islands logger.info("islands") ibs = bgs.loc[bgs.tag > 2000] ibs.reset_index(inplace=True, drop=True) for row in ibs.itertuples(index=True, name="Pandas"): inodes, xyz = gmsh.model.mesh.getNodesForPhysicalGroup( dim=getattr(row, "dim"), tag=getattr(row, "tag")) db = pd.DataFrame({"node": inodes - 1}) db["type"] = "island" db["id"] = -(getattr(row, "Index") + 1) bounds.append(db) if bounds != []: bnodes = pd.concat(bounds).reset_index(drop=True) bnodes.index.name = "bnodes" bnodes = bnodes.drop_duplicates("node") bnodes["id"] = bnodes.id.astype(int) else: bnodes = pd.DataFrame({}) gglobal = kwargs.get("gglobal", False) if gglobal: use_bindings = kwargs.get("use_bindings", True) if not use_bindings: bnodes["type"] = "island" # Fix for binary run and GLOBAL. CHECK bnodes["id"] = -bnodes.id.values bnodes = bnodes.sort_values(["type", "id", "node"]).reset_index(drop=True) # sort bnodes.index.name = "bnodes" # check orientation if use_bindings: nodes, tria = orient(nodes, tria, x="x", y="y") else: bgmesh = kwargs.get("bgmesh", None) if not bgmesh: tria = tria.reindex(columns=["a", "c", "b"]) # check if global and reproject sproj = kwargs.get("gglobal", False) if sproj: # convert to lat/lon if nodes.z.any() != 0: xd, yd = to_lat_lon(nodes.x, nodes.y, nodes.z) nodes["x"] = xd nodes["y"] = yd else: xd, yd = to_lat_lon(nodes.x, nodes.y) nodes["x"] = xd nodes["y"] = yd grid = pd.DataFrame({"lon": nodes.x, "lat": nodes.y}) tri3 = tria.values logger.info("Finalize Dataset") ## make dataset els = xr.DataArray( tri3, dims=["nSCHISM_hgrid_face", "nMaxSCHISM_hgrid_face_nodes"], name="SCHISM_hgrid_face_nodes", ) nod = (grid.loc[:, ["lon", "lat"]].to_xarray().rename({ "index": "nSCHISM_hgrid_node", "lon": "SCHISM_hgrid_node_x", "lat": "SCHISM_hgrid_node_y", })) nod = nod.drop_vars("nSCHISM_hgrid_node") dep = xr.Dataset({ "depth": (["nSCHISM_hgrid_node"], np.zeros(nod.nSCHISM_hgrid_node.shape[0])) }) gr = xr.merge([nod, els, dep, bnodes.to_xarray()]) gmsh.finalize() return gr
def run_gmsh(in_file: Union[str, Path], out_file: Union[str, Path], dim: int) -> None: """Convenience function to run gmsh. Parameters: in_file : str or pathlib.Path Name of (or path to) gmsh configuration file (.geo) out_file : str or pathlib.Path Name of (or path to) output file for gmsh (.msh) dim : int Number of dimensions gmsh should grid. If dims is less than the geometry dimensions, gmsh will grid all lower-dimensional objects described in in_file (e.g. all surfaces embedded in a 3D geometry). """ # Helper functions def _dump_gmsh_log(_log: List[str], in_file_name: Path) -> Path: """Write a gmsh log to file. Takes in the entire log and path to the in_file (from outer scope) Return name of the log file """ debug_file_name = in_file_name.with_name( f"gmsh_log_{in_file_name.stem}.dbg") with debug_file_name.open(mode="w") as f: for _line in _log: f.write(_line + "\n") return debug_file_name # Ensure that in_file has extension .geo, out_file extension .msh in_file = Path(in_file).with_suffix(".geo") out_file = Path(out_file).with_suffix(".msh") if not in_file.is_file(): raise FileNotFoundError(f"file {in_file!r} not found.") gmsh.initialize() # Experimentation indicated that the gmsh api failed to raise error values when # passed corrupted .geo files. To catch errors we therefore read the gmsh log, and # look for error messages. gmsh.logger.start() gmsh.open(str(in_file)) # Look for errors log = gmsh.logger.get() for line in log: if "Error:" in line: fn = _dump_gmsh_log(log, in_file) raise ValueError(f"""Error when reading gmsh file {in_file}. Gmsh log written to file {fn}""") # Generate the mesh gmsh.model.mesh.generate(dim=dim) # Look for errors log = gmsh.logger.get() for line in log: if "Error:" in line: fn = _dump_gmsh_log(log, in_file) raise ValueError( f"Error in gmsh when generating mesh for {in_file}\n" f"Gmsh log written to file {fn}") # The gmsh write should be safe for errors gmsh.write(str(out_file)) # Done gmsh.finalize()
main_box_coors, component_boxes = split_boxes(boxes_to_params, config_data["main_box_mark"]) #get brep file translations component_to_translation = get_component_translations( name_to_brep, GEO_FILE) #apply brep file translations and subtract files --> bounding boxes for all surfaces component_to_bnd_box = get_surfaces_for_components( component_to_fancy, component_boxes, brep_to_name, component_to_translation, main_box_coors) plane_compon_to_bnd_box, vol_compon_to_bnd_box = split_components_bnd_box( component_to_bnd_box, component_to_fancy, config_data["surface_names"], config_data["volume_names"]) #Load gmsh geometry for calculations imitate_gmsh_reload(GEO_FILE) gmsh.initialize() gmsh.open(GEO_FILE) geo_planes, geo_vols = download_geo_entities() gmsh.finalize() #paint stuff print("Searching for surfaces") marked_planes = [] fancy_name_to_plane_tag = get_empty_key_dict( config_data["surface_names"]) #dictionary name --> tag for plane in geo_planes: component_it_belongs = find_component_for_plane( plane, plane_compon_to_bnd_box, config_data["match_precision"]) if component_it_belongs: name = component_to_fancy[component_it_belongs] fancy_name_to_plane_tag[name].append(plane[0]) if plane[0] in marked_planes: raise Warning(
def process_mesh(self, file_in, file_out, is_get_lam=True, is_get_magnet=False, is_hole_air=True): """Preprocess the GMSH model, i.e. remove unused parts, rename boundaries, ...""" # TODO utilize 'translation' dict gmsh.initialize() gmsh.open(file_in) gmsh.model.geo.removeAllDuplicates() # remove unused model parts sta_lam = (STATOR_LAB_S + "-0_" + LAM_LAB_S).lower() # Stator Lamination sta_wind = (STATOR_LAB_S + "-0_" + WIND_LAB_S).lower() # Stator Winding _remove_entities(gmsh, labels=[sta_lam, sta_wind]) # get group names grps = gmsh.model.getPhysicalGroups(-1) grp_names = [gmsh.model.getPhysicalName(*grp) for grp in grps] # get lists of some surfaces by name magnet_list = [] for grp, name in zip(grps, grp_names): label_dict = decode_label(name) if HOLEM_LAB_S in label_dict["surf_type"]: entities = gmsh.model.getEntitiesForPhysicalGroup(*grp) if grp[0] == 2: magnet_list.extend(entities.tolist()) if True: # is_get_lam: lam_list = [] for grp, name in zip(grps, grp_names): label_dict = decode_label(name) if (ROTOR_LAB_S in label_dict["lam_type"] and LAM_LAB_S in label_dict["surf_type"]): entities = gmsh.model.getEntitiesForPhysicalGroup(*grp) if grp[0] == 2: lam_list.extend(entities.tolist()) lam_lines = [] for lam in lam_list: lam_lines.extend(gmsh.model.getBoundary([(2, lam)], oriented=False)) lam_lines = list(set([lam[1] for lam in lam_lines])) # unique hole_lines = [] for line in lam_lines: names = _get_names_physical( gmsh, dimtag=[ 1, line, ], ) if any([ HOLEV_LAB_S in decode_label(name)["surf_type"] for name in names ]): hole_lines.append(line) if is_get_lam and not is_get_magnet: ext = "Master" else: ext = "Slave" # setup dict to store physical groups, key: group name, value: list of tags groups_dict = {} # get lines of magnets for processing their physical groups for id, magnet in enumerate(magnet_list): lines = gmsh.model.getBoundary([(2, magnet)]) # store new group names in 'groups_dict' to set it later for line in lines: names = _get_names_physical( gmsh, dimtag=[ 1, abs(line[1]), ], ) if not names: print( f"Warning: Found magnet line without label - line {line[1]}" ) if is_get_magnet or (is_get_lam and line[1] in lam_lines): for name in names: label_dict = decode_label(name) if HOLEM_LAB_S in label_dict["surf_type"]: if (line[1] in lam_lines ): # only lines with direct contact for now # replace number and add 'Slave' s = name.split("_") s.append(ext) # add extension s[2] = str(id) # renumber key = "_".join(s) # new name if key not in groups_dict.keys(): groups_dict[key] = [] groups_dict[key].append(line) # Test if other lines (with 'Hole' phy. group) and same phy. group ext. # ('Left', ...) share the same points to add them as well # TODO if not used with direct contact (see above), # but I will keep it for Contact Simulation # if is_get_lam: # # get the name of the magnets line # s = None # for name in names: # if "Magnet" in name: # s = name.split('_') # # basic check of magnet line name # if s is not None and len(s) >= 3: # for hline in hole_lines: # if hline != abs(line[1]): # skip if hole line == magnet line # # test for same extension ('Left', 'Right', ...) # names = _get_names_physical(gmsh, dimtag=[1, hline]) # if any([s[2] in name for name in names]): # p1 = [x[1] for x in gmsh.model.getBoundary([line])] # p2 = [x[1] for x in gmsh.model.getBoundary([(1, hline)])] # pt = [p for p in p1 if p in p2] # if pt: # if len(s) == 3: # s.append('Master') # add extension # s[1] = str(id) # renumber # key = "_".join(s) # new name # if key not in groups_dict.keys(): # groups_dict[key] = [] # groups_dict[key].append((1, hline)) # if not is_hole_air: # pass # TODO implement if is_get_magnet: # store new magnet body name s = "Magnet_" + str(id) + "_Body" groups_dict[s] = [ (2, magnet), ] if is_get_lam: # store new lamination body name for id, lam in enumerate(lam_list): s = "Lamination_" + str(id) + "_Body" if s not in groups_dict: groups_dict[s] = [] groups_dict[s].append((2, lam)) # store hole if not air if not is_hole_air: pass # TODO # add symmetry boundaries to keeper dict 'groups_dict' if is_get_lam: keeper_list = [ "MASTER_ROTOR_BOUNDARY", "SLAVE_ROTOR_BOUNDARY", "Rotor_Tangential_Bridge", "Rotor_Radial_Bridge", "ROTOR_BORE_CURVE", ] for line in lam_lines: names = _get_names_physical(gmsh, dimtag=[1, line]) for key in keeper_list: if any([key in name for name in names]): if key not in groups_dict: groups_dict[key] = [] groups_dict[key].append((1, line)) # update group names grps = gmsh.model.getPhysicalGroups(-1) grp_names = [gmsh.model.getPhysicalName(*grp) for grp in grps] # delete unused surfaces RL = ROTOR_LAB_S + "-0_" del_list = [SHAFT_LAB, RL + HOLEV_LAB_S] if not is_get_magnet: del_list.append(RL + HOLEM_LAB_S) if not is_get_lam: rot_lam = (RL + LAM_LAB_S).lower() # Rotor Lamination del_list.append(rot_lam) for grp, name in zip(grps, grp_names): if any([n in name.lower() for n in del_list]): entities = gmsh.model.getEntitiesForPhysicalGroup(*grp).tolist() for entity in entities: if grp[0] == 2: gmsh.model.geo.remove([(2, entity)], recursive=False) # set new physical group names after removing all 'old' physical groups gmsh.model.removePhysicalGroups(dimTags=[]) for name in grp_names: gmsh.model.removePhysicalName(name) for key, values in groups_dict.items(): # lines tags = [abs(dimtag[1]) for dimtag in values if dimtag[0] == 1] tags = list(set(tags)) if tags: print(f"Add physical group {key} with lines {tags}") pg = gmsh.model.addPhysicalGroup(1, tags, tag=-1) gmsh.model.setPhysicalName(1, pg, key) # surfaces tags = [abs(dimtag[1]) for dimtag in values if dimtag[0] == 2] tags = list(set(tags)) if tags: print(f"Add physical group {key} with surface {tags}") pg = gmsh.model.addPhysicalGroup(2, tags, tag=-1) gmsh.model.setPhysicalName(2, pg, key) # cleanup # get all entities gmsh.model.geo.synchronize() entities_all = gmsh.model.getEntities(dim=-1) surf_list = gmsh.model.getEntities(dim=2) print(surf_list) # get lines of surfaces line_list = [] for surf in surf_list: line_list.extend(gmsh.model.getBoundary([surf])) line_list = [(line[0], abs(line[1])) for line in line_list] # remove all lines that are not part of the surfaces for entity in entities_all: if (entity[0], abs(entity[1])) not in line_list and entity[0] == 1: gmsh.model.geo.remove([entity], recursive=False) # entities_all = gmsh.model.getEntities(dim=-1) # remove unknown/unused physical groups # TODO # save gmsh.model.geo.synchronize() # gmsh.model.geo.mesh.setTransfiniteSurface(tag) for surf in surf_list: gmsh.model.mesh.setRecombine(2, surf[1]) # gmsh.option.setNumber("Mesh.RecombinationAlgorithm", 1) gmsh.model.mesh.generate(2) # gmsh.model.mesh.recombine() gmsh.model.mesh.refine() # gmsh.model.mesh.refine() # gmsh.model.mesh.recombine() # gmsh.model.mesh.refine() # save mesh or geo file depending on file extension filename, file_extension = splitext(file_out) if file_extension == ".geo": gmsh.write(filename + ".geo_unrolled") replace(filename + ".geo_unrolled", filename + file_extension) else: gmsh.model.mesh.generate(2) gmsh.write(file_out) # gmsh.fltk.run() # Uncomment to launch Gmsh GUI # update group names once again grps = gmsh.model.getPhysicalGroups(-1) grp_names = [gmsh.model.getPhysicalName(*grp) for grp in grps] gmsh.finalize() return gmsh, grps, grp_names
def imitate_gmsh_reload(fname): gmsh.initialize() gmsh.open(fname) gmsh.finalize() return 0
def refine_mesh_by_splitting( in_file: Union[str, Path], out_file: Union[str, Path], dim: int, gb_set_projections: bool = True, ) -> Generator[pp.GridBucket, None, None]: """ Refine a mesh by splitting using gmsh The method generates refinements on the fly by yielding GridBuckets as desired. Note: When the desired number of refinements is reached, you should call refine_mesh_by_splitting.close() so that gmsh.finalize() is called. Parameters ---------- in_file : Union[str, Path] path to .geo file to read out_file : Union[str, Path] path to new .msh file to store mesh in, excluding the ending '.msh'. dim : int {2, 3} Dimension of domain to mesh gb_set_projections : bool (Default: True) Call pp.contact_conditions.set_projections(gb) before yielding result Returns ------- Generator[gb] A generator for the refined grid buckets, starting with the coarsest. """ # Ensure that in- and out paths are formatted correctly. assert Path(in_file).is_file() out_file = Path(out_file) out_file = out_file.parent / out_file.stem try: import gmsh except ModuleNotFoundError: raise ModuleNotFoundError( "To run gmsh python api on your system, " "download the relevant gmsh*-sdk.* from http://gmsh.info/bin/. " "Then, Add the 'lib' directory from the SDK to PYTHONPATH: \n" "export PYTHONPATH=${PYTHONPATH}:path/to/gmsh*-sdk.*/lib" ) # gmsh must always be finalized after it has be initialized # (see 'finally' clause). # Therefore, we wrap the entire function body in a try-finally context. try: # Initialize gmsh and generate the first (coarsest) mesh gmsh.initialize() gmsh.open(in_file) gmsh.model.mesh.generate(dim=dim) num_refinements = 0 # Enter an infinite loop while True: out_file_name = f"{out_file}_{num_refinements}.msh" # The first mesh is already done. # Start refining all subsequent meshes. if num_refinements > 0: gmsh.model.mesh.refine() # Refine the mesh gmsh.write(out_file_name) # Write the result to '.msh' file # Generate List[pp.Grid] grids = tetrahedral_grid_from_gmsh(file_name=out_file_name) # Convert List[pp.Grid] to pp.GridBucket gb = grid_list_to_grid_bucket(grids) # Set projection operators for mixed-dimensional grids if gb_set_projections: pp.contact_conditions.set_projections(gb) # yield the resulting grid bucket yield gb # finally, prepare the next iteration num_refinements += 1 finally: # When refine_mesh_by_splitting.close() is called, we get here. gmsh.finalize()
def _initialize_gmsh(path): gmsh.initialize('', False) gmsh.open(path)