def convert_and_create_facet_mesh_function(ifilename, ofilename): # First convert the gmsh mesh meshconvert.convert2xml(ifilename, ofilename) # Now load the created mesh and initialise the required connectivity information mesh = Mesh(ofilename) mesh.order() File(ofilename) << mesh D = mesh.topology().dim() mesh.init(D - 1, 0) # read the data from the gmsh file once again dim_count, vertices_used, tags = process_gmsh_elements(ifilename, D - 1) # Get the facet-node connectivity information (reshape as a row of node indices per facet) facets_as_nodes = mesh.topology()(D - 1, 0)().reshape(mesh.num_facets(), D) # Create and initialise the mesh function facet_mark_function = MeshFunction('uint', mesh, D - 1) facet_mark_function.set_all(0) # set the relevant values of the mesh function facets_to_check = range(mesh.num_facets()) for i in range(len(tags)): nodes = np.sort(np.array(vertices_used[2 * i:(2 * i + D)])) value = tags[i][0] if value != 0: found = False for j in range(len(facets_to_check)): index = facets_to_check[j] if np.array_equal(facets_as_nodes[index, :], nodes): found = True facets_to_check.pop(j) # set the value of the mesh function facet_mark_function[index] = value break if not found: raise Exception("The facet (%d) was not found to mark: %s" % (i, nodes)) # save the mesh function to file fname = os.path.splitext(ofilename)[0] mesh_function_file = File("%s_%s.xml" % (fname, "facet_regions")) mesh_function_file << facet_mark_function
def convert_and_create_facet_mesh_function ( ifilename, ofilename ): # First convert the gmsh mesh meshconvert.convert2xml ( ifilename, ofilename ) # Now load the created mesh and initialise the required connectivity information mesh = Mesh ( ofilename ) mesh.order() File ( ofilename ) << mesh D = mesh.topology().dim() mesh.init(D-1, 0) # read the data from the gmsh file once again dim_count, vertices_used, tags = process_gmsh_elements( ifilename, D-1 ) # Get the facet-node connectivity information (reshape as a row of node indices per facet) facets_as_nodes = mesh.topology()(D-1,0)().reshape ( mesh.num_facets(), D ) # Create and initialise the mesh function facet_mark_function = MeshFunction ( 'uint', mesh, D-1 ) facet_mark_function.set_all( 0 ) # set the relevant values of the mesh function facets_to_check = range( mesh.num_facets() ) for i in range(len(tags)): nodes = np.sort(np.array(vertices_used[2*i:(2*i+D)])) value = tags[i][0] if value != 0: found = False for j in range(len(facets_to_check)): index = facets_to_check[j] if np.array_equal(facets_as_nodes[index,:], nodes): found = True; facets_to_check.pop(j) # set the value of the mesh function facet_mark_function[index] = value break; if not found: raise Exception ( "The facet (%d) was not found to mark: %s" % (i, nodes) ) # save the mesh function to file fname = os.path.splitext(ofilename)[0] mesh_function_file = File("%s_%s.xml" % (fname, "facet_regions")) mesh_function_file << facet_mark_function
def convert(ifilename, handler): """ Convert from Abaqus. The Abaqus format first defines a node block, then there should be a number of elements containing these nodes. """ # Dictionary of nodes (maps node id to coordinates) nodes = {} # Dictionary of elements (maps cell id to list of cell nodes) elems = {} # Lists of nodes for given name (key) node_sets = {} # Lists of cells for given name (key) cell_sets = {} # Lists of surfaces for given name (key) in the format: # {'SS1': [set(['SS1_S1', 'S1']), set(['SS1_S4', 'S4'])]}, # where SS1 is the name of the surface, SS1_S1 is the name of the # cell list whose first face is to be selected, ... surface_sets = {} # Open file Abaqus file csv_file = csv.reader(open(ifilename, 'rb'), delimiter=',', skipinitialspace=True) node_set_name = None generate = None # Set intial state state state = State.Init # Read data from input file for l in csv_file: # Sanity check if (len(l) == 0): print "Ooops, zero length." if l[0].startswith('**'): # Pass over comments continue elif l[0].startswith('*'): # Have a keyword state = State.Unknown if l[0].lower() == "*heading": state = State.ReadHeading elif l[0].lower() == "*part": part_name = _read_part_name(l) elif l[0].lower() == "*end part": state = State.Invalid elif l[0].lower() == "*node": node_set_name = _create_node_list_entry(node_sets, l) state = State.ReadNodes elif l[0].lower() == "*element": cell_type, cell_set_name = _read_element_keywords(cell_sets, l) state = State.ReadCells elif l[0].lower() == "*nset": node_set_name, generate = _read_nset_keywords(node_sets, l) state = State.ReadNodeSet elif l[0].lower() == "*elset": cell_set_name, generate = _read_elset_keywords(cell_sets, l) if generate: print "WARNING: generation of *elsets not tested." state = State.ReadCellSet elif l[0].lower() == "*surface": surface_set_name, generate = _read_surface_keywords(surface_sets, l) state = State.ReadSurfaceSet else: print "WARNING: unrecognised Abaqus input keyword:", l[0] state = State.Unknown else: if state == State.ReadHeading: model_name = _read_heading(l) elif state == State.ReadNodes: node_id = int(l[0]) - 1 coords = [float(c) for c in l[1:]] nodes[node_id] = coords if node_set_name is not None: node_sets[node_set_name].add(node_id) elif state == State.ReadCells: cell_id = int(l[0]) - 1 cell_connectivity = [int(v) - 1 for v in l[1:]] elems[cell_id] = cell_connectivity if cell_set_name is not None: cell_sets[cell_set_name].add(cell_id) elif state == State.ReadNodeSet: try: if generate: n0, n1, increment = l node_range = range(int(n0) - 1, int(n1) - 1, int(increment)) node_range.append(int(n1) - 1) node_sets[node_set_name].update(node_range) else: # Strip empty term at end of list, if present if l[-1] == '': l.pop(-1) node_range = [int(n) - 1 for n in l] node_sets[node_set_name].update(node_range) except: print "WARNING: Non-integer node sets not yet supported." elif state == State.ReadCellSet: try: if generate: n0, n1, increment = l cell_range = range(int(n0) - 1, int(n1) - 1, int(increment)) cell_range.append(int(n1) - 1) cell_sets[cell_set_name].update(cell_range) else: # Strip empty term at end of list, if present if l[-1] == '': l.pop(-1) cell_range = [int(n) - 1 for n in l] cell_sets[cell_set_name].update(cell_range) except: print "WARNING: Non-integer element sets not yet supported." elif state == State.ReadSurfaceSet: # Strip empty term at end of list, if present if l[-1] == '': l.pop(-1) surface_sets[surface_set_name].update([tuple(l)]) elif state == State.Invalid: # part raise StandardError("Inavlid Abaqus parser state..") # Close CSV object del csv_file # Write data to XML file # Note that vertices/cells must be consecutively numbered, which # isn't necessarily the case in Abaqus. Therefore we enumerate and # translate original IDs to sequence indexes if gaps are present. # FIXME handler.set_mesh_type("tetrahedron", 3) process_facets = len(surface_sets) > 0 if process_facets: try: from dolfin import MeshEditor, Mesh except ImportError: _error("DOLFIN must be installed to handle Abaqus boundary regions") mesh = Mesh() mesh_editor = MeshEditor() mesh_editor.open(mesh, 3, 3) node_ids_order = {} # Check for gaps in vertex numbering node_ids = nodes.keys() if len(node_ids) > 0: vertex_gap = (min(node_ids) != 0 or max(node_ids) != len(node_ids) - 1) for x, y in enumerate(node_ids): node_ids_order[y]= x # Maps Abaqus IDs to Dolfin IDs else: vertex_gap = True # Check for gaps in cell numbering elemids = elems.keys() if len(elemids) > 0: cell_gap = (min(elemids) != 0 or max(elemids) != len(elemids) - 1) else: cell_gap = True # Write vertices to XML file handler.start_vertices(len(nodes)) if process_facets: mesh_editor.init_vertices (len(nodes)) if not vertex_gap: for v_id, v_coords in nodes.items(): handler.add_vertex(v_id, v_coords) if process_facets: mesh_editor.add_vertex(v_id, np.array(v_coords, dtype=np.float_)) else: for idx, (v_id, v_coords) in enumerate(nodes.items()): handler.add_vertex(idx, v_coords) if process_facets: mesh_editor.add_vertex(idx, np.array(v_coords, dtype=np.float_)) handler.end_vertices() # Write cells to XML file handler.start_cells(len(elems)) if process_facets: mesh_editor.init_cells(len(elems)) if not vertex_gap and not cell_gap: for c_index, c_data in elems.items(): for v_id in c_data: if not (0 <= v_id < len(nodes)): handler.error("Element %s references non-existent node %s" % (c_index, v_id)) handler.add_cell(c_index, c_data) if process_facets: c_data_tmp = np.array(c_data) c_data_tmp.sort() mesh_editor.add_cell(c_index, np.array(c_data_tmp, dtype=np.uintp)) elif not vertex_gap and cell_gap: for idx, (c_index, c_data) in enumerate(elems.items()): for v_id in c_data: if not (0 <= v_id < len(nodes)): handler.error("Element %s references non-existent node %s" % (c_index, v_id)) handler.add_cell(idx, c_data) if process_facets: c_data_tmp = np.array(c_data) c_data_tmp.sort() mesh_editor.add_cell(idx, np.array(c_data_tmp, dtype=np.uintp)) else: for idx, (c_id, c_data) in enumerate(elems.items()): c_nodes = [] for v_id in c_data: try: c_nodes.append(node_ids_order[v_id]) except ValueError: handler.error("Element %s references non-existent node %s" % (c_id, v_id)) handler.add_cell(idx, c_nodes) if process_facets: c_nodes.sort() mesh_editor.add_cell(idx, np.array(c_nodes, dtype=np.uintp)) handler.end_cells() # Write MeshValueCollections to XML file handler.start_domains() # Build a abaqus node ID -> dolfin cell ID map (which is not unique but that is irrelevant here) # and its local entity. if len(node_sets.items()) > 0: node_cell_map = {} for c_dolfin_index, (c_index, c_data) in enumerate(elems.items()): c_data_tmp = np.array(c_data) c_data_tmp.sort() for local_entity, n_index in enumerate(c_data_tmp): node_cell_map[n_index] = (c_dolfin_index, local_entity) # Write vertex/node sets dim = 0 for value, (name, node_set) in enumerate(node_sets.items()): handler.start_mesh_value_collection(name, dim, len(node_set), "uint") for node in node_set: try: cell, local_entity = node_cell_map[node] handler.add_entity_mesh_value_collection(dim, cell, value, local_entity=local_entity) except KeyError: print "Warning: Boundary references non-existent node %s" % node handler.end_mesh_value_collection() # Write cell/element sets dim = 3 for name, s in cell_sets.items(): handler.start_mesh_value_collection(name, dim, len(s), "uint") for cell in s: handler.add_entity_mesh_value_collection(dim, cell, 0) handler.end_mesh_value_collection() # Write surface sets if process_facets: dim = 2 nodes_facet_map = _nodes_facet_map(mesh) data = [int(0)] * mesh.num_facets() S1 = [0, 1, 2] S2 = [0, 3, 1] S3 = [1, 3, 2] S4 = [2, 3, 0] node_selector = {'S1': S1, 'S2': S2, 'S3': S3, 'S4': S4, } for index, (name, s) in enumerate(surface_sets.items()): cell_face_list = [] for cell_set_name, face_index in s: cell_face_list += [(cell, face_index) for cell in cell_sets[cell_set_name]] for cell, face in cell_face_list: cell_nodes = elems[cell] # Extract the face nodes face_nodes = [cell_nodes[i] for i in node_selector[face]] dolfin_face_nodes = [node_ids_order[n] for n in face_nodes] dolfin_face_nodes.sort() # Convert the face_nodes to dolfin IDs face_id = nodes_facet_map[tuple(dolfin_face_nodes)] data[face_id] = index + 1 # Create and initialise the mesh function handler.start_meshfunction("facet_region", dim, mesh.num_facets() ) for index, physical_region in enumerate (data): handler.add_entity_meshfunction(index, physical_region) handler.end_meshfunction() handler.end_domains()
def gmsh2xml(ifilename, handler): """Convert between .gmsh v2.0 format (http://www.geuz.org/gmsh/) and .xml, parser implemented as a state machine: 0 = read 'MeshFormat' 1 = read mesh format data 2 = read 'EndMeshFormat' 3 = read 'Nodes' 4 = read number of vertices 5 = read vertices 6 = read 'EndNodes' 7 = read 'Elements' 8 = read number of cells 9 = read cells 10 = done Afterwards, extract physical region numbers if they are defined in the mesh file as a mesh function. """ print "Converting from Gmsh format (.msh, .gmsh) to DOLFIN XML format" # The dimension of the gmsh element types supported here as well as the dolfin cell types for each dimension gmsh_dim = {15: 0, 1: 1, 2: 2, 4: 3} cell_type_for_dim = {1: "interval", 2: "triangle", 3: "tetrahedron" } # the gmsh element types supported for conversion supported_gmsh_element_types = [1, 2, 4, 15] # Open files ifile = open(ifilename, "r") # Scan file for cell type cell_type = None highest_dim = 0 line = ifile.readline() while line: # Remove newline if line[-1] == "\n": line = line[:-1] # Read dimension if line.find("$Elements") == 0: line = ifile.readline() num_elements = int(line) if num_elements == 0: _error("No elements found in gmsh file.") line = ifile.readline() # Now iterate through elements to find largest dimension. Gmsh # format might include elements of lower dimensions in the element list. # We also need to count number of elements of correct dimensions. # Also determine which vertices are not used. dim_count = {0: 0, 1: 0, 2: 0, 3: 0} vertices_used_for_dim = {0: [], 1: [], 2: [], 3: []} # Array used to store gmsh tags for 1D (type 1/line), 2D (type 2/triangular) elements and 3D (type 4/tet) elements tags_for_dim = {0: [], 1: [], 2: [], 3: []} while line.find("$EndElements") == -1: element = line.split() elem_type = int(element[1]) num_tags = int(element[2]) if elem_type in supported_gmsh_element_types: dim = gmsh_dim[elem_type] if highest_dim < dim: highest_dim = dim node_num_list = [int(node) for node in element[3 + num_tags:]] vertices_used_for_dim[dim].extend(node_num_list) if num_tags > 0: tags_for_dim[dim].append(tuple(int(tag) for tag in element[3:3+num_tags])) dim_count[dim] += 1 else: #TODO: output a warning here. "gmsh element type %d not supported" % elem_type pass line = ifile.readline() else: # Read next line line = ifile.readline() # Check that we got the cell type and set num_cells_counted if highest_dim == 0: _error("Unable to find cells of supported type.") num_cells_counted = dim_count[highest_dim] vertex_set = set(vertices_used_for_dim[highest_dim]) vertices_used_for_dim[highest_dim] = None vertex_dict = {} for n,v in enumerate(vertex_set): vertex_dict[v] = n # Step to beginning of file ifile.seek(0) # Set mesh type handler.set_mesh_type(cell_type_for_dim[highest_dim], highest_dim) # Initialise node list (gmsh does not export all vertexes in order) nodelist = {} # Current state state = 0 # Write data num_vertices_read = 0 num_cells_read = 0 # Only import the dolfin objects if facet markings exist process_facets = False if len(tags_for_dim[highest_dim-1]) > 0: # first construct the mesh try: from dolfin import MeshEditor, Mesh except ImportError: _error("DOLFIN must be installed to handle Gmsh boundary regions") mesh = Mesh() mesh_editor = MeshEditor () mesh_editor.open( mesh, highest_dim, highest_dim ) process_facets = True else: # TODO: Output a warning or an error here me = None while state != 10: # Read next line line = ifile.readline() if not line: break # Skip comments if line[0] == '#': continue # Remove newline if line[-1] == "\n": line = line[:-1] if state == 0: if line == "$MeshFormat": state = 1 elif state == 1: (version, file_type, data_size) = line.split() state = 2 elif state == 2: if line == "$EndMeshFormat": state = 3 elif state == 3: if line == "$Nodes": state = 4 elif state == 4: num_vertices = len(vertex_dict) handler.start_vertices(num_vertices) if process_facets: mesh_editor.init_vertices ( num_vertices ) state = 5 elif state == 5: (node_no, x, y, z) = line.split() node_no = int(node_no) x,y,z = [float(xx) for xx in (x,y,z)] if vertex_dict.has_key(node_no): node_no = vertex_dict[node_no] else: continue nodelist[int(node_no)] = num_vertices_read handler.add_vertex(num_vertices_read, [x, y, z]) if process_facets: if highest_dim == 1: coords = numpy.array([x]) elif highest_dim == 2: coords = numpy.array([x, y]) elif highest_dim == 3: coords = numpy.array([x, y, z]) mesh_editor.add_vertex(num_vertices_read, coords) num_vertices_read +=1 if num_vertices == num_vertices_read: handler.end_vertices() state = 6 elif state == 6: if line == "$EndNodes": state = 7 elif state == 7: if line == "$Elements": state = 8 elif state == 8: handler.start_cells(num_cells_counted) if process_facets: mesh_editor.init_cells( num_cells_counted ) state = 9 elif state == 9: element = line.split() elem_type = int(element[1]) num_tags = int(element[2]) if elem_type in supported_gmsh_element_types: dim = gmsh_dim[elem_type] else: dim = 0 if dim == highest_dim: node_num_list = [vertex_dict[int(node)] for node in element[3 + num_tags:]] for node in node_num_list: if not node in nodelist: _error("Vertex %d of %s %d not previously defined." % (node, cell_type_for_dim[dim], num_cells_read)) cell_nodes = [nodelist[n] for n in node_num_list] handler.add_cell(num_cells_read, cell_nodes) if process_facets: cell_nodes = numpy.array([nodelist[n] for n in node_num_list], dtype=numpy.uintp) mesh_editor.add_cell(num_cells_read, cell_nodes) num_cells_read +=1 if num_cells_counted == num_cells_read: handler.end_cells() if process_facets: mesh_editor.close() state = 10 elif state == 10: break # Write mesh function based on the Physical Regions defined by # gmsh, but only if they are not all zero. All zero physical # regions indicate that no physical regions were defined. if highest_dim not in [1,2,3]: _error("Gmsh tags not supported for dimension %i. Probably a bug" % dim) tags = tags_for_dim[highest_dim] physical_regions = tuple(tag[0] for tag in tags) if not all(tag == 0 for tag in physical_regions): handler.start_meshfunction("physical_region", dim, num_cells_counted) for i, physical_region in enumerate(physical_regions): handler.add_entity_meshfunction(i, physical_region) handler.end_meshfunction() # Now process the facet markers tags = tags_for_dim[highest_dim-1] if (len(tags) > 0) and (mesh is not None): physical_regions = tuple(tag[0] for tag in tags) if not all(tag == 0 for tag in physical_regions): mesh.init(highest_dim-1,0) # Get the facet-node connectivity information (reshape as a row of node indices per facet) if highest_dim==1: # for 1d meshes the mesh topology returns the vertex to vertex map, which isn't what we want # as facets are vertices facets_as_nodes = numpy.array([[i] for i in range(mesh.num_facets())]) else: facets_as_nodes = mesh.topology()(highest_dim-1,0)().reshape ( mesh.num_facets(), highest_dim ) # Build the reverse map nodes_as_facets = {} for facet in range(mesh.num_facets()): nodes_as_facets[tuple(facets_as_nodes[facet,:])] = facet data = [int(0*k) for k in range(mesh.num_facets()) ] for i, physical_region in enumerate(physical_regions): nodes = [n-1 for n in vertices_used_for_dim[highest_dim-1][highest_dim*i:(highest_dim*i+highest_dim)]] nodes.sort() if physical_region != 0: try: index = nodes_as_facets[tuple(nodes)] data[index] = physical_region except IndexError: raise Exception ( "The facet (%d) was not found to mark: %s" % (i, nodes) ) # # Create and initialise the mesh function handler.start_meshfunction("facet_region", highest_dim-1, mesh.num_facets() ) for index, physical_region in enumerate ( data ): handler.add_entity_meshfunction(index, physical_region) handler.end_meshfunction() # Check that we got all data if state == 10: print "Conversion done" else: _error("Missing data, unable to convert \n\ Did you use version 2.0 of the gmsh file format?") # Close files ifile.close()
def convert(ifilename, handler): """ Convert from Abaqus. The Abaqus format first defines a node block, then there should be a number of elements containing these nodes. """ # Dictionary of nodes (maps node id to coordinates) nodes = {} # Dictionary of elements (maps cell id to list of cell nodes) elems = {} # Lists of nodes for given name (key) node_sets = {} # Lists of cells for given name (key) cell_sets = {} # Lists of surfaces for given name (key) in the format: # {'SS1': [set(['SS1_S1', 'S1']), set(['SS1_S4', 'S4'])]}, # where SS1 is the name of the surface, SS1_S1 is the name of the # cell list whose first face is to be selected, ... surface_sets = {} # Open file Abaqus file file = open(ifilename, 'r') csv_file = csv.reader(file, delimiter=',', skipinitialspace=True) node_set_name = None generate = None # Set intial state state state = State.Init # Read data from input file for l in csv_file: # Sanity check if (len(l) == 0): print("Ooops, zero length.") if l[0].startswith('**'): # Pass over comments continue elif l[0].startswith('*'): # Have a keyword state = State.Unknown if l[0].lower() == "*heading": state = State.ReadHeading elif l[0].lower() == "*part": part_name = _read_part_name(l) elif l[0].lower() == "*end part": state = State.Invalid elif l[0].lower() == "*node": node_set_name = _create_node_list_entry(node_sets, l) state = State.ReadNodes elif l[0].lower() == "*element": cell_type, cell_set_name = _read_element_keywords(cell_sets, l) state = State.ReadCells elif l[0].lower() == "*nset": node_set_name, generate = _read_nset_keywords(node_sets, l) state = State.ReadNodeSet elif l[0].lower() == "*elset": cell_set_name, generate = _read_elset_keywords(cell_sets, l) if generate: print("WARNING: generation of *elsets not tested.") state = State.ReadCellSet elif l[0].lower() == "*surface": surface_set_name, generate = _read_surface_keywords( surface_sets, l) state = State.ReadSurfaceSet else: print("WARNING: unrecognised Abaqus input keyword:", l[0]) state = State.Unknown else: if state == State.ReadHeading: model_name = _read_heading(l) elif state == State.ReadNodes: node_id = int(l[0]) - 1 coords = [float(c) for c in l[1:]] nodes[node_id] = coords if node_set_name is not None: node_sets[node_set_name].add(node_id) elif state == State.ReadCells: cell_id = int(l[0]) - 1 cell_connectivity = [int(v) - 1 for v in l[1:]] elems[cell_id] = cell_connectivity if cell_set_name is not None: cell_sets[cell_set_name].add(cell_id) elif state == State.ReadNodeSet: try: if generate: n0, n1, increment = l node_range = list( range(int(n0) - 1, int(n1) - 1, int(increment))) node_range.append(int(n1) - 1) node_sets[node_set_name].update(node_range) else: # Strip empty term at end of list, if present if l[-1] == '': l.pop(-1) node_range = [int(n) - 1 for n in l] node_sets[node_set_name].update(node_range) except: print("WARNING: Non-integer node sets not yet supported.") elif state == State.ReadCellSet: try: if generate: n0, n1, increment = l cell_range = list( range(int(n0) - 1, int(n1) - 1, int(increment))) cell_range.append(int(n1) - 1) cell_sets[cell_set_name].update(cell_range) else: # Strip empty term at end of list, if present if l[-1] == '': l.pop(-1) cell_range = [int(n) - 1 for n in l] cell_sets[cell_set_name].update(cell_range) except: print( "WARNING: Non-integer element sets not yet supported.") elif state == State.ReadSurfaceSet: # Strip empty term at end of list, if present if l[-1] == '': l.pop(-1) surface_sets[surface_set_name].update([tuple(l)]) elif state == State.Invalid: # part raise Exception("Inavlid Abaqus parser state..") # Close CSV object file.close() del csv_file # Write data to XML file # Note that vertices/cells must be consecutively numbered, which # isn't necessarily the case in Abaqus. Therefore we enumerate and # translate original IDs to sequence indexes if gaps are present. # FIXME handler.set_mesh_type("tetrahedron", 3) process_facets = len(surface_sets) > 0 if process_facets: try: from dolfin import MeshEditor, Mesh except ImportError: _error( "DOLFIN must be installed to handle Abaqus boundary regions") mesh = Mesh() mesh_editor = MeshEditor() mesh_editor.open(mesh, 3, 3) node_ids_order = {} # Check for gaps in vertex numbering node_ids = list(iterkeys(nodes)) if len(node_ids) > 0: vertex_gap = (min(node_ids) != 0 or max(node_ids) != len(node_ids) - 1) for x, y in enumerate(node_ids): node_ids_order[y] = x # Maps Abaqus IDs to Dolfin IDs else: vertex_gap = True # Check for gaps in cell numbering elemids = list(iterkeys(elems)) if len(elemids) > 0: cell_gap = (min(elemids) != 0 or max(elemids) != len(elemids) - 1) else: cell_gap = True # Write vertices to XML file handler.start_vertices(len(nodes)) if process_facets: mesh_editor.init_vertices_global(len(nodes), len(nodes)) if not vertex_gap: for v_id, v_coords in list(iteritems(nodes)): handler.add_vertex(v_id, v_coords) if process_facets: mesh_editor.add_vertex(v_id, np.array(v_coords, dtype=np.float_)) else: for idx, (v_id, v_coords) in enumerate(iteritems(nodes)): handler.add_vertex(idx, v_coords) if process_facets: mesh_editor.add_vertex(idx, np.array(v_coords, dtype=np.float_)) handler.end_vertices() # Write cells to XML file handler.start_cells(len(elems)) if process_facets: mesh_editor.init_cells_global(len(elems), len(elems)) if not vertex_gap and not cell_gap: for c_index, c_data in list(iteritems(elems)): for v_id in c_data: if not (0 <= v_id < len(nodes)): handler.error( "Element %s references non-existent node %s" % (c_index, v_id)) handler.add_cell(c_index, c_data) if process_facets: c_data_tmp = np.array(c_data) c_data_tmp.sort() mesh_editor.add_cell(c_index, np.array(c_data_tmp, dtype=np.uintp)) elif not vertex_gap and cell_gap: for idx, (c_index, c_data) in enumerate(iteritems(elems)): for v_id in c_data: if not (0 <= v_id < len(nodes)): handler.error( "Element %s references non-existent node %s" % (c_index, v_id)) handler.add_cell(idx, c_data) if process_facets: c_data_tmp = np.array(c_data) c_data_tmp.sort() mesh_editor.add_cell(idx, np.array(c_data_tmp, dtype=np.uintp)) else: for idx, (c_id, c_data) in enumerate(iteritems(elems)): c_nodes = [] for v_id in c_data: try: c_nodes.append(node_ids_order[v_id]) except ValueError: handler.error( "Element %s references non-existent node %s" % (c_id, v_id)) handler.add_cell(idx, c_nodes) if process_facets: c_nodes.sort() mesh_editor.add_cell(idx, np.array(c_nodes, dtype=np.uintp)) handler.end_cells() # Write MeshValueCollections to XML file handler.start_domains() # Build a abaqus node ID -> dolfin cell ID map (which is not unique but that is irrelevant here) # and its local entity. if len(node_sets) > 0: node_cell_map = {} for c_dolfin_index, (c_index, c_data) in enumerate(iteritems(elems)): c_data_tmp = np.array(c_data) c_data_tmp.sort() for local_entity, n_index in enumerate(c_data_tmp): node_cell_map[n_index] = (c_dolfin_index, local_entity) # Write vertex/node sets dim = 0 for value, (name, node_set) in enumerate(iteritems(node_sets)): handler.start_mesh_value_collection(name, dim, len(node_set), "uint") for node in node_set: try: cell, local_entity = node_cell_map[node] handler.add_entity_mesh_value_collection( dim, cell, value, local_entity=local_entity) except KeyError: print("Warning: Boundary references non-existent node %s" % node) handler.end_mesh_value_collection() # Write cell/element sets dim = 3 for name, s in list(iteritems(cell_sets)): handler.start_mesh_value_collection(name, dim, len(s), "uint") for cell in s: handler.add_entity_mesh_value_collection(dim, cell, 0) handler.end_mesh_value_collection() # Write surface sets if process_facets: dim = 2 nodes_facet_map = _nodes_facet_map(mesh) data = [int(0)] * mesh.num_facets() S1 = [0, 1, 2] S2 = [0, 3, 1] S3 = [1, 3, 2] S4 = [2, 3, 0] node_selector = { 'S1': S1, 'S2': S2, 'S3': S3, 'S4': S4, } for index, (name, s) in enumerate(iteritems(surface_sets)): cell_face_list = [] for cell_set_name, face_index in s: cell_face_list += [(cell, face_index) for cell in cell_sets[cell_set_name]] for cell, face in cell_face_list: cell_nodes = elems[cell] # Extract the face nodes face_nodes = [cell_nodes[i] for i in node_selector[face]] dolfin_face_nodes = [node_ids_order[n] for n in face_nodes] dolfin_face_nodes.sort() # Convert the face_nodes to dolfin IDs face_id = nodes_facet_map[tuple(dolfin_face_nodes)] data[face_id] = index + 1 # Create and initialise the mesh function handler.start_meshfunction("facet_region", dim, mesh.num_facets()) for index, physical_region in enumerate(data): handler.add_entity_meshfunction(index, physical_region) handler.end_meshfunction() handler.end_domains()
def gmsh2xml(ifilename, handler): """Convert between .gmsh v2.0 format (http://www.geuz.org/gmsh/) and .xml, parser implemented as a state machine: 0 = read 'MeshFormat' 1 = read mesh format data 2 = read 'EndMeshFormat' 3 = read 'Nodes' 4 = read number of vertices 5 = read vertices 6 = read 'EndNodes' 7 = read 'Elements' 8 = read number of cells 9 = read cells 10 = done Afterwards, extract physical region numbers if they are defined in the mesh file as a mesh function. """ print("Converting from Gmsh format (.msh, .gmsh) to DOLFIN XML format") # The dimension of the gmsh element types supported here as well as the dolfin cell types for each dimension gmsh_dim = {15: 0, 1: 1, 2: 2, 4: 3} cell_type_for_dim = {1: "interval", 2: "triangle", 3: "tetrahedron" } # the gmsh element types supported for conversion supported_gmsh_element_types = [1, 2, 4, 15] # Open files ifile = open(ifilename, "r") # Scan file for cell type cell_type = None highest_dim = 0 line = ifile.readline() while line: # Remove newline line = line.rstrip("\n\r") # Read dimension if line.find("$Elements") == 0: line = ifile.readline() num_elements = int(line) if num_elements == 0: _error("No elements found in gmsh file.") line = ifile.readline() # Now iterate through elements to find largest dimension. Gmsh # format might include elements of lower dimensions in the element list. # We also need to count number of elements of correct dimensions. # Also determine which vertices are not used. dim_count = {0: 0, 1: 0, 2: 0, 3: 0} vertices_used_for_dim = {0: [], 1: [], 2: [], 3: []} # Array used to store gmsh tags for 1D (type 1/line), 2D (type 2/triangular) elements and 3D (type 4/tet) elements tags_for_dim = {0: [], 1: [], 2: [], 3: []} while line.find("$EndElements") == -1: element = line.split() elem_type = int(element[1]) num_tags = int(element[2]) if elem_type in supported_gmsh_element_types: dim = gmsh_dim[elem_type] if highest_dim < dim: highest_dim = dim node_num_list = [int(node) for node in element[3 + num_tags:]] vertices_used_for_dim[dim].extend(node_num_list) if num_tags > 0: tags_for_dim[dim].append(tuple(int(tag) for tag in element[3:3+num_tags])) dim_count[dim] += 1 else: #TODO: output a warning here. "gmsh element type %d not supported" % elem_type pass line = ifile.readline() else: # Read next line line = ifile.readline() # Check that we got the cell type and set num_cells_counted if highest_dim == 0: _error("Unable to find cells of supported type.") num_cells_counted = dim_count[highest_dim] vertex_set = set(vertices_used_for_dim[highest_dim]) vertices_used_for_dim[highest_dim] = None vertex_dict = {} for n,v in enumerate(vertex_set): vertex_dict[v] = n # Step to beginning of file ifile.seek(0) # Set mesh type handler.set_mesh_type(cell_type_for_dim[highest_dim], highest_dim) # Initialise node list (gmsh does not export all vertexes in order) nodelist = {} # Current state state = 0 # Write data num_vertices_read = 0 num_cells_read = 0 # Only import the dolfin objects if facet markings exist process_facets = False if len(tags_for_dim[highest_dim-1]) > 0: # first construct the mesh try: from dolfin import MeshEditor, Mesh except ImportError: _error("DOLFIN must be installed to handle Gmsh boundary regions") mesh = Mesh() mesh_editor = MeshEditor () mesh_editor.open( mesh, highest_dim, highest_dim ) process_facets = True else: # TODO: Output a warning or an error here me = None while state != 10: # Read next line line = ifile.readline() if not line: break # Skip comments if line[0] == '#': continue # Remove newline line = line.rstrip("\n\r") if state == 0: if line == "$MeshFormat": state = 1 elif state == 1: (version, file_type, data_size) = line.split() state = 2 elif state == 2: if line == "$EndMeshFormat": state = 3 elif state == 3: if line == "$Nodes": state = 4 elif state == 4: num_vertices = len(vertex_dict) handler.start_vertices(num_vertices) if process_facets: mesh_editor.init_vertices_global(num_vertices, num_vertices) state = 5 elif state == 5: (node_no, x, y, z) = line.split() node_no = int(node_no) x,y,z = [float(xx) for xx in (x,y,z)] if node_no in vertex_dict: node_no = vertex_dict[node_no] else: continue nodelist[int(node_no)] = num_vertices_read handler.add_vertex(num_vertices_read, [x, y, z]) if process_facets: if highest_dim == 1: coords = numpy.array([x]) elif highest_dim == 2: coords = numpy.array([x, y]) elif highest_dim == 3: coords = numpy.array([x, y, z]) mesh_editor.add_vertex(num_vertices_read, coords) num_vertices_read +=1 if num_vertices == num_vertices_read: handler.end_vertices() state = 6 elif state == 6: if line == "$EndNodes": state = 7 elif state == 7: if line == "$Elements": state = 8 elif state == 8: handler.start_cells(num_cells_counted) if process_facets: mesh_editor.init_cells_global(num_cells_counted, num_cells_counted) state = 9 elif state == 9: element = line.split() elem_type = int(element[1]) num_tags = int(element[2]) if elem_type in supported_gmsh_element_types: dim = gmsh_dim[elem_type] else: dim = 0 if dim == highest_dim: node_num_list = [vertex_dict[int(node)] for node in element[3 + num_tags:]] for node in node_num_list: if not node in nodelist: _error("Vertex %d of %s %d not previously defined." % (node, cell_type_for_dim[dim], num_cells_read)) cell_nodes = [nodelist[n] for n in node_num_list] handler.add_cell(num_cells_read, cell_nodes) if process_facets: cell_nodes = numpy.array([nodelist[n] for n in node_num_list], dtype=numpy.uintp) mesh_editor.add_cell(num_cells_read, cell_nodes) num_cells_read +=1 if num_cells_counted == num_cells_read: handler.end_cells() if process_facets: mesh_editor.close() state = 10 elif state == 10: break # Write mesh function based on the Physical Regions defined by # gmsh, but only if they are not all zero. All zero physical # regions indicate that no physical regions were defined. if highest_dim not in [1,2,3]: _error("Gmsh tags not supported for dimension %i. Probably a bug" % dim) tags = tags_for_dim[highest_dim] physical_regions = tuple(tag[0] for tag in tags) if not all(tag == 0 for tag in physical_regions): handler.start_meshfunction("physical_region", dim, num_cells_counted) for i, physical_region in enumerate(physical_regions): handler.add_entity_meshfunction(i, physical_region) handler.end_meshfunction() # Now process the facet markers tags = tags_for_dim[highest_dim-1] if (len(tags) > 0) and (mesh is not None): physical_regions = tuple(tag[0] for tag in tags) if not all(tag == 0 for tag in physical_regions): mesh.init(highest_dim-1,0) # Get the facet-node connectivity information (reshape as a row of node indices per facet) if highest_dim==1: # for 1d meshes the mesh topology returns the vertex to vertex map, which isn't what we want # as facets are vertices facets_as_nodes = numpy.array([[i] for i in range(mesh.num_facets())]) else: facets_as_nodes = mesh.topology()(highest_dim-1,0)().reshape ( mesh.num_facets(), highest_dim ) # Build the reverse map nodes_as_facets = {} for facet in range(mesh.num_facets()): nodes_as_facets[tuple(facets_as_nodes[facet,:])] = facet data = [int(0*k) for k in range(mesh.num_facets()) ] for i, physical_region in enumerate(physical_regions): nodes = [n-1 for n in vertices_used_for_dim[highest_dim-1][highest_dim*i:(highest_dim*i+highest_dim)]] nodes.sort() if physical_region != 0: try: index = nodes_as_facets[tuple(nodes)] data[index] = physical_region except IndexError: raise Exception ( "The facet (%d) was not found to mark: %s" % (i, nodes) ) # Create and initialise the mesh function handler.start_meshfunction("facet_region", highest_dim-1, mesh.num_facets() ) for index, physical_region in enumerate ( data ): handler.add_entity_meshfunction(index, physical_region) handler.end_meshfunction() # Check that we got all data if state == 10: print("Conversion done") else: _error("Missing data, unable to convert \n\ Did you use version 2.0 of the gmsh file format?") # Close files ifile.close()
def gmsh_to_dolfin_mesh(ifilename, handler): """Convert between .gmsh v2.0 format (http://www.geuz.org/gmsh/) and .xml, parser implemented as a state machine: 0 = read 'MeshFormat' 1 = read mesh format data 2 = read 'EndMeshFormat' 3 = read 'Nodes' 4 = read number of vertices 5 = read vertices 6 = read 'EndNodes' 7 = read 'Elements' 8 = read number of cells 9 = read cells 10 = done Afterwards, extract physical region numbers if they are defined in the mesh file as a mesh function. """ print "Converting from Gmsh format (.msh, .gmsh) to DOLFIN XML format" # The dimension of the gmsh element types supported here as well as the dolfin cell types for each dimension gmsh_dim = {1: 1, 2: 2, 4: 3} gmsh_cell_type = {1: "interval", 2: "triangle", 3: "tetrahedron"} # the gmsh element types supported for conversion supported_gmsh_element_types = [1, 2, 4] # Open files ifile = open(ifilename, "r") # Scan file for cell type cell_type = None highest_dim = 0 line = ifile.readline() while line: # Remove newline if line[-1] == "\n": line = line[:-1] # Read dimension if line.find("$Elements") == 0: line = ifile.readline() num_elements = int(line) num_cells_counted = 0 if num_elements == 0: _error("No elements found in gmsh file.") line = ifile.readline() # Now iterate through elements to find largest dimension. Gmsh # format might include elements of lower dimensions in the element list. # We also need to count number of elements of correct dimensions. # Also determine which vertices are not used. dim_count = {1: 0, 2: 0, 3: 0} vertices_used = {1: [], 2: [], 3: []} # Array used to store gmsh tags for 1D (type 1/line), 2D (type 2/triangular) elements and 3D (type 4/tet) elements tags_for_dim = {1: [], 2: [], 3: []} while line.find("$EndElements") == -1: element = line.split() elem_type = int(element[1]) num_tags = int(element[2]) if elem_type in supported_gmsh_element_types: dim = gmsh_dim[elem_type] if highest_dim < dim: highest_dim = dim node_num_list = [ int(node) for node in element[3 + num_tags:] ] vertices_used[dim].extend(node_num_list) if num_tags > 0: tags_for_dim[dim].append( tuple(int(tag) for tag in element[3:3 + num_tags])) dim_count[dim] += 1 else: #TODO: output a warning here. "gmsh element type %d not supported" % elem_type pass line = ifile.readline() else: # Read next line line = ifile.readline() # Check that we got the cell type and set num_cells_counted if highest_dim == 0: _error("Unable to find cells of supported type.") num_cells_counted = dim_count[highest_dim] vertex_set = set(vertices_used[highest_dim]) vertices_used[highest_dim] = None vertex_dict = {} for n, v in enumerate(vertex_set): vertex_dict[v] = n # Step to beginning of file ifile.seek(0) # Set mesh type handler.set_mesh_type(gmsh_cell_type[highest_dim], highest_dim) # Initialise node list (gmsh does not export all vertexes in order) nodelist = {} # Current state state = 0 # Write data num_vertices_read = 0 num_cells_read = 0 # Now handle the facet markings if len(tags_for_dim[highest_dim - 1]) > 0: # first construct the mesh from dolfin import MeshEditor, Mesh mesh = Mesh() me = MeshEditor() me.open(mesh, highest_dim, highest_dim) else: me = None while state != 10: # Read next line line = ifile.readline() if not line: break # Skip comments if line[0] == '#': continue # Remove newline if line[-1] == "\n": line = line[:-1] if state == 0: if line == "$MeshFormat": state = 1 elif state == 1: (version, file_type, data_size) = line.split() state = 2 elif state == 2: if line == "$EndMeshFormat": state = 3 elif state == 3: if line == "$Nodes": state = 4 elif state == 4: num_vertices = len(vertex_dict) handler.start_vertices(num_vertices) if me is not None: me.init_vertices(num_vertices) state = 5 elif state == 5: (node_no, x, y, z) = line.split() node_no = int(node_no) x, y, z = [float(xx) for xx in (x, y, z)] if vertex_dict.has_key(node_no): node_no = vertex_dict[node_no] else: continue nodelist[int(node_no)] = num_vertices_read handler.add_vertex(num_vertices_read, [x, y, z]) if me is not None: if highest_dim == 1: me.add_vertex(num_vertices_read, x) elif highest_dim == 2: me.add_vertex(num_vertices_read, x, y) elif highest_dim == 3: me.add_vertex(num_vertices_read, x, y, z) num_vertices_read += 1 if num_vertices == num_vertices_read: handler.end_vertices() state = 6 elif state == 6: if line == "$EndNodes": state = 7 elif state == 7: if line == "$Elements": state = 8 elif state == 8: handler.start_cells(num_cells_counted) if me is not None: me.init_cells(num_cells_counted) state = 9 elif state == 9: element = line.split() elem_type = int(element[1]) num_tags = int(element[2]) if elem_type in supported_gmsh_element_types: dim = gmsh_dim[elem_type] else: dim = 0 if dim == highest_dim: node_num_list = [ vertex_dict[int(node)] for node in element[3 + num_tags:] ] for node in node_num_list: if not node in nodelist: _error("Vertex %d of %s %d not previously defined." % (node, gmsh_cell_type[dim], num_cells_read)) cell_nodes = [nodelist[n] for n in node_num_list] handler.add_cell(num_cells_read, cell_nodes) if me is not None: me.add_cell(num_cells_read, *cell_nodes) num_cells_read += 1 if num_cells_counted == num_cells_read: handler.end_cells() if me is not None: me.close() state = 10 elif state == 10: break # Write mesh function based on the Physical Regions defined by # gmsh, but only if they are not all zero. All zero physical # regions indicate that no physical regions were defined. if highest_dim not in [1, 2, 3]: _error("Gmsh tags not supported for dimension %i. Probably a bug" % dim) tags = tags_for_dim[highest_dim] physical_regions = tuple(tag[0] for tag in tags) if not all(tag == 0 for tag in physical_regions): handler.start_meshfunction("physical_region", dim, num_cells_counted) for i, physical_region in enumerate(physical_regions): handler.add_entity_meshfunction(i, physical_region) handler.end_meshfunction() # Now process the facet markers tags = tags_for_dim[highest_dim - 1] if len(tags) > 0: print tags print vertices_used[highest_dim - 1] physical_regions = tuple(tag[0] for tag in tags) if not all(tag == 0 for tag in physical_regions): mesh.init(highest_dim - 1, 0) # Get the facet-node connectivity information (reshape as a row of node indices per facet) facets_as_nodes = mesh.topology()(highest_dim - 1, 0)().reshape( mesh.num_facets(), highest_dim) # from dolfin import MeshFunction # # Create and initialise the mesh function # facet_mark_function = MeshFunction ( 'uint', mesh, highest_dim-1 ) # facet_mark_function.set_all( 0 ) handler.start_meshfunction("facet_region", highest_dim - 1, mesh.num_facets()) facets_to_check = range(mesh.num_facets()) data = [int(0 * k) for k in range(len(facets_to_check))] for i, physical_region in enumerate(physical_regions): nodes = [ n - 1 for n in vertices_used[highest_dim - 1][2 * i:(2 * i + highest_dim)] ] nodes.sort() if physical_region != 0: found = False for j in range(len(facets_to_check)): index = facets_to_check[j] if all(facets_as_nodes[index, k] == nodes[k] for k in range(len(nodes))): found = True facets_to_check.pop(j) # set the value of the mesh function # facet_mark_function[index] = physical_region data[index] = physical_region break if not found: raise Exception( "The facet (%d) was not found to mark: %s" % (i, nodes)) # fname = os.path.splitext('tmp.xml')[0] # mesh_function_file = File("%s_%s.xml" % (fname, "facet_region")) # mesh_function_file << facet_mark_function for index, physical_region in enumerate(data): handler.add_entity_meshfunction(index, physical_region) handler.end_meshfunction() mf = MeshFunction('uint', mesh, 'tmp_facet_region.xml') plot(mf, interactive=True) # Check that we got all data if state == 10: print "Conversion done" else: _error( "Missing data, unable to convert \n\ Did you use version 2.0 of the gmsh file format?" ) # Close files ifile.close()