1
# Copyright (C) 2006 Anders Logg
2
# Licensed under the GNU LGPL Version 2.1
4
# Modified by Garth N. Wells (gmsh function)
5
# Modified by Alexander H. Jarosch (gmsh fix)
6
# Modified by Angelo Simone (Gmsh and Medit fix)
7
# Modified by Andy R. Terrel (gmsh fix and triangle function)
8
# Modified by Magnus Vikstrom (metis and scotch function)
9
# Modified by Bartosz Sawicki (diffpack function)
10
# Modified by Gideon Simpson (Exodus II function)
11
# Modified by Arve Knudsen (make into module, abaqus support)
12
# Modified by Kent-Andre Mardal (Star-CD function)
13
# Modified by Nuno Lopes (fix for emc2 mesh format (medit version 0))
14
# Modified by Neilen Marais (add gmsh support for reading physical region)
15
""" Module for converting various mesh formats.
18
# NOTE: This module does not depend on (py)dolfin beeing installed.
19
# NOTE: If future additions need that please import dolfin in a try: except:
20
# NOTE: clause and tell the user to install dolfin if it is not installed.
24
from dolfin_utils.commands import getstatusoutput
29
def format_from_suffix(suffix):
30
"Return format for given suffix"
33
elif suffix == "mesh":
35
elif suffix == "gmsh":
43
elif suffix == "grid":
47
elif suffix == "ncdf":
53
elif suffix == "vrt" or suffix == "cel":
55
elif suffix == "ele" or suffix == "node":
58
_error("Sorry, unknown suffix %s." % suffix)
60
def mesh2xml(ifilename, ofilename):
61
"""Convert between .mesh and .xml, parser implemented as a
67
3 = read number of vertices
69
5 = read 'Triangles' or 'Tetrahedra'
70
6 = read number of cells
76
print "Converting from Medit format (.mesh) to DOLFIN XML format"
79
ifile = open(ifilename, "r")
80
ofile = open(ofilename, "w")
82
# Scan file for cell type
88
line = ifile.readline()
96
if line == "Dimension" or line == " Dimension":
97
line = ifile.readline()
100
cell_type = "triangle"
103
cell_type = "tetrahedron"
107
# Check that we got the cell type
108
if cell_type == None:
109
_error("Unable to find cell type.")
111
# Step to beginning of file
115
write_header_mesh(ofile, cell_type, dim)
121
num_vertices_read = 0
127
line = ifile.readline()
139
if line == "Dimension" or line == " Dimension":
145
if line == "Vertices" or line == " Vertices":
148
num_vertices = int(line)
149
write_header_vertices(ofile, num_vertices)
153
(x, y, tmp) = line.split()
158
(x, y, z, tmp) = line.split()
162
write_vertex(ofile, num_vertices_read, x, y, z)
163
num_vertices_read +=1
164
if num_vertices == num_vertices_read:
165
write_footer_vertices(ofile)
168
if (line == "Triangles" or line == " Triangles") and num_dims == 2:
170
if line == "Tetrahedra" and num_dims == 3:
173
num_cells = int(line)
174
write_header_cells(ofile, num_cells)
178
(n0, n1, n2, tmp) = line.split()
182
write_cell_triangle(ofile, num_cells_read, n0, n1, n2)
184
(n0, n1, n2, n3, tmp) = line.split()
189
write_cell_tetrahedron(ofile, num_cells_read, n0, n1, n2, n3)
191
if num_cells == num_cells_read:
192
write_footer_cells(ofile)
197
# Check that we got all data
199
print "Conversion done"
201
_error("Missing data, unable to convert")
204
write_footer_mesh(ofile)
210
def gmsh2xml(ifilename, handler):
211
"""Convert between .gmsh v2.0 format (http://www.geuz.org/gmsh/) and .xml,
212
parser implemented as a state machine:
214
0 = read 'MeshFormat'
215
1 = read mesh format data
216
2 = read 'EndMeshFormat'
218
4 = read number of vertices
222
8 = read number of cells
226
Afterwards, extract physical region numbers if they are defined in
227
the mesh file as a mesh function.
231
print "Converting from Gmsh format (.msh, .gmsh) to DOLFIN XML format"
234
ifile = open(ifilename, "r")
236
# Scan file for cell type
239
line = ifile.readline()
247
if line.find("$Elements") == 0:
249
line = ifile.readline()
250
num_cells = int(line)
251
num_cells_counted = 0
253
_error("No cells found in gmsh file.")
254
line = ifile.readline()
256
# Now iterate through elements to find largest dimension. Gmsh
257
# format might include elements of lower dimensions in the element list.
258
# We also need to count number of elements of correct dimensions.
259
# Also determine which vertices are not used.
263
# Array used to store gmsh tags for 2D (type 2/triangular) elements
265
# Array used to store gmsh tags for 3D (type 4/tet) elements
268
while line.find("$EndElements") == -1:
269
element = line.split()
270
elem_type = int(element[1])
271
num_tags = int(element[2])
274
cell_type = "triangle"
276
node_num_list = [int(node) for node in element[3 + num_tags:]]
277
vertices_2_used.extend(node_num_list)
279
tags_2.append(tuple(int(tag) for tag in element[3:3+num_tags]))
283
cell_type = "tetrahedron"
285
vertices_2_used = None
286
node_num_list = [int(node) for node in element[3 + num_tags:]]
287
vertices_3_used.extend(node_num_list)
289
tags_3.append(tuple(int(tag) for tag in element[3:3+num_tags]))
291
line = ifile.readline()
294
line = ifile.readline()
296
# Check that we got the cell type and set num_cells_counted
297
if cell_type == None:
298
_error("Unable to find cell type.")
300
num_cells_counted = dim_3_count
301
vertex_set = set(vertices_3_used)
302
vertices_3_used = None
304
num_cells_counted = dim_2_count
305
vertex_set = set(vertices_2_used)
306
vertices_2_used = None
309
for n,v in enumerate(vertex_set):
312
# Step to beginning of file
316
handler.set_mesh_type(cell_type, dim)
318
# Initialise node list (gmsh does not export all vertexes in order)
325
num_vertices_read = 0
331
line = ifile.readline()
343
if line == "$MeshFormat":
346
(version, file_type, data_size) = line.split()
349
if line == "$EndMeshFormat":
355
num_vertices = len(vertex_dict)
356
handler.start_vertices(num_vertices)
359
(node_no, x, y, z) = line.split()
360
node_no = int(node_no)
361
x,y,z = [float(xx) for xx in (x,y,z)]
362
if vertex_dict.has_key(node_no):
363
node_no = vertex_dict[node_no]
366
nodelist[int(node_no)] = num_vertices_read
367
handler.add_vertex(num_vertices_read, [x, y, z])
368
num_vertices_read +=1
370
if num_vertices == num_vertices_read:
371
handler.end_vertices()
374
if line == "$EndNodes":
377
if line == "$Elements":
380
handler.start_cells(num_cells_counted)
383
element = line.split()
384
elem_type = int(element[1])
385
num_tags = int(element[2])
386
if elem_type == 2 and dim == 2:
387
node_num_list = [vertex_dict[int(node)] for node in element[3 + num_tags:]]
388
for node in node_num_list:
389
if not node in nodelist:
390
_error("Vertex %d of triangle %d not previously defined." %
391
(node, num_cells_read))
392
cell_nodes = [nodelist[n] for n in node_num_list]
393
handler.add_cell(num_cells_read, cell_nodes)
395
elif elem_type == 4 and dim == 3:
396
node_num_list = [vertex_dict[int(node)] for node in element[3 + num_tags:]]
397
for node in node_num_list:
398
if not node in nodelist:
399
_error("Vertex %d of tetrahedron %d not previously defined." %
400
(node, num_cells_read))
401
# import pdb ; pdb.set_trace()
402
cell_nodes = [nodelist[n] for n in node_num_list]
403
handler.add_cell(num_cells_read, cell_nodes)
406
if num_cells_counted == num_cells_read:
412
# Write mesh function based on the Physical Regions defined by
413
# gmsh, but only if they are not all zero. All zero physical
414
# regions indicate that no physical regions were defined.
420
_error("Gmsh tags not supported for dimension %i. Probably a bug" % dim)
422
physical_regions = tuple(tag[0] for tag in tags)
423
if not all(tag == 0 for tag in tags):
424
handler.start_meshfunction("physical_region", dim, num_cells)
425
for i, physical_region in enumerate(physical_regions):
426
handler.add_entity_meshfunction(i, physical_region)
427
handler.end_meshfunction()
429
# Check that we got all data
431
print "Conversion done"
433
_error("Missing data, unable to convert \n\ Did you use version 2.0 of the gmsh file format?")
438
def triangle2xml(ifilename, ofilename):
439
"""Convert between triangle format (http://www.cs.cmu.edu/~quake/triangle.html) and .xml. The
440
given ifilename should be the prefix for the corresponding .node, and .ele files.
443
def get_next_line (fp):
444
"""Helper function for skipping comments and blank lines"""
447
_error("Hit end of file prematurely.")
449
if not (line.startswith('#') or line == ''):
451
return get_next_line(fp)
454
print "Converting from Triangle format {.node, .ele} to DOLFIN XML format"
457
for suffix in [".node", ".ele"]:
458
if suffix in ifilename and ifilename[-len(suffix):] == suffix:
459
ifilename = ifilename.replace(suffix, "")
460
node_file = open(ifilename+".node", "r")
461
ele_file = open(ifilename+".ele", "r")
462
ofile = open(ofilename, "w")
466
num_nodes, dim, attr, bound = map(int, get_next_line(node_file).split())
467
while len(nodes) < num_nodes:
468
node, x, y = get_next_line(node_file).split()[:3]
469
nodes[int(node)] = (float(x), float(y))
471
# Read all the triangles
473
num_tris, n_per_tri, attrs = map(int, get_next_line(ele_file).split())
474
while len(tris) < num_tris:
475
tri, n1, n2, n3 = map(int, get_next_line(ele_file).split()[:4])
476
tris[tri] = (n1, n2, n3)
478
# Write everything out
479
write_header_mesh(ofile, "triangle", 2)
480
write_header_vertices(ofile, num_nodes)
481
node_off = 0 if nodes.has_key(0) else -1
482
for node, node_t in nodes.iteritems():
483
write_vertex(ofile, node+node_off, node_t[0], node_t[1], 0.0)
484
write_footer_vertices(ofile)
485
write_header_cells(ofile, num_tris)
486
tri_off = 0 if tris.has_key(0) else -1
487
for tri, tri_t in tris.iteritems():
488
write_cell_triangle(ofile, tri+tri_off, tri_t[0] + node_off,
489
tri_t[1] + node_off, tri_t[2] + node_off)
490
write_footer_cells(ofile)
491
write_footer_mesh(ofile)
499
def xml_old2xml(ifilename, ofilename):
500
"Convert from old DOLFIN XML format to new."
502
print "Converting from old (pre DOLFIN 0.6.2) to new DOLFIN XML format..."
505
ifile = open(ifilename, "r")
506
ofile = open(ofilename, "w")
508
# Scan file for cell type (assuming there is just one)
514
line = ifile.readline()
518
if "<triangle" in line:
519
cell_type = "triangle"
522
elif "<tetrahedron" in line:
523
cell_type = "tetrahedron"
527
# Step to beginning of file
530
# Read lines and make changes
534
line = ifile.readline()
539
line = "<dolfin xmlns:dolfin=\"http://www.fenicsproject.org\">\n"
541
line = " <mesh celltype=\"%s\" dim=\"%d\">\n" % (cell_type, dim)
542
if dim == 2 and " z=\"0.0\"" in line:
543
line = line.replace(" z=\"0.0\"", "")
545
line = line.replace(" name=", " index=")
546
if " name =" in line:
547
line = line.replace(" name =", " index=")
549
line = line.replace("n0", "v0")
551
line = line.replace("n1", "v1")
553
line = line.replace("n2", "v2")
555
line = line.replace("n3", "v3")
563
print "Conversion done"
565
def metis_graph2graph_xml(ifilename, ofilename):
566
"Convert from Metis graph format to DOLFIN Graph XML."
568
print "Converting from Metis graph format to DOLFIN Graph XML."
571
ifile = open(ifilename, "r")
572
ofile = open(ofilename, "w")
574
# Read number of vertices and edges
575
line = ifile.readline()
579
(num_vertices, num_edges) = line.split()
581
write_header_graph(ofile, "directed")
582
write_header_vertices(ofile, int(num_vertices))
584
for i in range(int(num_vertices)):
585
line = ifile.readline()
587
write_graph_vertex(ofile, i, len(edges))
589
write_footer_vertices(ofile)
590
write_header_edges(ofile, 2*int(num_edges))
592
# Step to beginning of file and skip header info
595
for i in range(int(num_vertices)):
597
line = ifile.readline()
600
write_graph_edge(ofile, i, int(e))
602
write_footer_edges(ofile)
603
write_footer_graph(ofile)
609
def scotch_graph2graph_xml(ifilename, ofilename):
610
"Convert from Scotch graph format to DOLFIN Graph XML."
612
print "Converting from Scotch graph format to DOLFIN Graph XML."
615
ifile = open(ifilename, "r")
616
ofile = open(ofilename, "w")
618
# Skip graph file version number
621
# Read number of vertices and edges
622
line = ifile.readline()
626
(num_vertices, num_edges) = line.split()
628
# Read start index and numeric flag
629
# Start index is 0 or 1 (C/Fortran)
630
# Numeric flag is 3 bits where bit 1 enables vertex labels
631
# bit 2 enables edge weights and bit 3 enables vertex weights
633
line = ifile.readline()
634
(start_index, numeric_flag) = line.split()
636
# Handling not implented
637
if not numeric_flag == "000":
638
_error("Handling of scotch vertex labels, edge- and vertex weights not implemented")
640
write_header_graph(ofile, "undirected")
641
write_header_vertices(ofile, int(num_vertices))
643
# Read vertices and edges, first number gives number of edges from this vertex (not used)
644
for i in range(int(num_vertices)):
645
line = ifile.readline()
647
write_graph_vertex(ofile, i, len(edges)-1)
649
write_footer_vertices(ofile)
650
write_header_edges(ofile, int(num_edges))
653
# Step to beginning of file and skip header info
658
for i in range(int(num_vertices)):
659
line = ifile.readline()
662
for j in range(1, len(edges)):
663
write_graph_edge(ofile, i, int(edges[j]))
665
write_footer_edges(ofile)
666
write_footer_graph(ofile)
672
def write_header_meshfunction(ofile, dimensions, size):
673
header = """<?xml version="1.0" encoding="UTF-8"?>
674
<dolfin xmlns:dolfin="http://www.fenics.org/dolfin/">
675
<meshfunction type="uint" dim="%d" size="%d">
676
""" % (dimensions, size)
679
def write_entity_meshfunction(ofile, index, value):
680
ofile.write(""" <entity index=\"%d\" value=\"%d\"/>
681
""" % (index, value))
683
def write_footer_meshfunction(ofile):
684
ofile.write(""" </meshfunction>
687
def diffpack2xml(ifilename, ofilename):
688
"Convert from Diffpack tetrahedral grid format to DOLFIN XML."
690
print diffpack2xml.__doc__
692
# Format strings for MeshFunction XML files
693
meshfunction_header = """\
694
<?xml version="1.0" encoding="UTF-8"?>\n
695
<dolfin xmlns:dolfin="http://www.fenics.org/dolfin/">
696
<meshfunction type="uint" dim="%d" size="%d">\n"""
697
meshfunction_entity = " <entity index=\"%d\" value=\"%d\"/>\n"
698
meshfunction_footer = " </meshfunction>\n</dolfin>"
701
ifile = open(ifilename, "r")
702
ofile = open(ofilename, "w")
703
ofile_mat = open(ofilename.split(".")[0]+"_mat.xml", "w")
704
ofile_bi = open(ofilename.split(".")[0]+"_bi.xml", "w")
706
# Read and analyze header
708
line = ifile.readline()
713
if re.search(r"Number of elements", line):
714
num_cells = int(re.match(r".*\s(\d+).*", line).group(1))
715
if re.search(r"Number of nodes", line):
716
num_vertices = int(re.match(r".*\s(\d+).*", line).group(1))
718
write_header_mesh(ofile, "tetrahedron", 3)
719
write_header_vertices(ofile, num_vertices)
720
ofile_bi.write(meshfunction_header % (0, num_vertices))
721
ofile_mat.write(meshfunction_header % (3, num_cells))
723
# Read & write vertices
724
# Note that only first boundary indicator is rewriten into XML
725
for i in range(num_vertices):
726
line = ifile.readline()
727
m = re.match(r"^.*\(\s*(.*)\s*\).*\](.*)$", line)
728
x = re.split("[\s,]+", m.group(1))
729
write_vertex(ofile, i, x[0], x[1], x[2])
730
tmp = m.group(2).split()
735
ofile_bi.write(meshfunction_entity % (i, bi))
737
write_footer_vertices(ofile)
738
write_header_cells(ofile, num_cells)
740
# Ignore comment lines
742
line = ifile.readline()
749
for i in range(int(num_cells)):
750
line = ifile.readline()
752
if v[1] != "ElmT4n3D":
753
_error("Only tetrahedral elements (ElmT4n3D) are implemented.")
754
write_cell_tetrahedron(ofile, i, int(v[3])-1, int(v[4])-1, int(v[5])-1, int(v[6])-1)
755
ofile_mat.write(meshfunction_entity % (i, int(v[2])))
757
write_footer_cells(ofile)
758
write_footer_mesh(ofile)
759
ofile_bi.write(meshfunction_footer)
760
ofile_mat.write(meshfunction_footer)
768
class ParseError(Exception):
769
""" Error encountered in source file.
772
class DataHandler(object):
773
""" Baseclass for handlers of mesh data.
775
The actual handling of mesh data encountered in the source file is
776
delegated to a polymorfic object. Typically, the delegate will write the
778
@ivar _state: the state which the handler is in, one of State_*.
779
@ivar _cell_type: cell type in mesh. One of CellType_*.
780
@ivar _dim: mesh dimensions.
782
State_Invalid, State_Init, State_Vertices, State_Cells, State_MeshFunction = range(5)
783
CellType_Tetrahedron, CellType_Triangle = range(2)
786
self._state = self.State_Invalid
788
def set_mesh_type(self, cell_type, dim):
789
assert self._state == self.State_Invalid
790
self._state = self.State_Init
791
if cell_type == "tetrahedron":
792
self._cell_type = self.CellType_Tetrahedron
793
elif cell_type == "triangle":
794
self._cell_type = self.CellType_Triangle
797
def start_vertices(self, num_vertices):
798
assert self._state == self.State_Init
799
self._state = self.State_Vertices
801
def add_vertex(self, vertex, coords):
802
assert self._state == self.State_Vertices
804
def end_vertices(self):
805
assert self._state == self.State_Vertices
806
self._state = self.State_Init
808
def start_cells(self, num_cells):
809
assert self._state == self.State_Init
810
self._state = self.State_Cells
812
def add_cell(self, cell, nodes):
813
assert self._state == self.State_Cells
816
assert self._state == self.State_Cells
817
self._state = self.State_Init
819
def start_meshfunction(self, name, dim, size):
820
assert self._state == self.State_Init
821
self._state = self.State_MeshFunction
823
def add_entity_meshfunction(self, index, value):
824
assert self._state == self.State_MeshFunction
826
def end_meshfunction(self):
827
assert self._state == self.State_MeshFunction
828
self._state = self.State_Init
831
""" Issue warning during parse.
835
def error(self, msg):
836
""" Raise error during parse.
838
This method is expected to raise ParseError.
840
raise ParseError(msg)
843
self._state = self.State_Invalid
845
class XmlHandler(DataHandler):
846
""" Data handler class which writes to Dolfin XML.
848
def __init__(self, ofilename):
849
DataHandler.__init__(self)
850
self._ofilename = ofilename
851
self.__ofile = file(ofilename, "wb")
852
self.__ofile_meshfunc = None
854
def set_mesh_type(self, cell_type, dim):
855
DataHandler.set_mesh_type(self, cell_type, dim)
856
write_header_mesh(self.__ofile, cell_type, dim)
858
def start_vertices(self, num_vertices):
859
DataHandler.start_vertices(self, num_vertices)
860
write_header_vertices(self.__ofile, num_vertices)
862
def add_vertex(self, vertex, coords):
863
DataHandler.add_vertex(self, vertex, coords)
864
write_vertex(self.__ofile, vertex, *coords)
866
def end_vertices(self):
867
DataHandler.end_vertices(self)
868
write_footer_vertices(self.__ofile)
870
def start_cells(self, num_cells):
871
DataHandler.start_cells(self, num_cells)
872
write_header_cells(self.__ofile, num_cells)
874
def add_cell(self, cell, nodes):
875
DataHandler.add_cell(self, cell, nodes)
876
if self._cell_type == self.CellType_Tetrahedron:
877
func = write_cell_tetrahedron
878
elif self._cell_type == self.CellType_Triangle:
879
func = write_cell_triangle
881
func(self.__ofile, cell, *nodes)
884
DataHandler.end_cells(self)
885
write_footer_cells(self.__ofile)
887
def start_meshfunction(self, name, dim, size):
888
DataHandler.start_meshfunction(self, name, dim, size)
889
fname = os.path.splitext(self.__ofile.name)[0]
890
self.__ofile_meshfunc = file("%s_%s.xml" % (fname, name), "wb")
891
write_header_meshfunction(self.__ofile_meshfunc, dim, size)
893
def add_entity_meshfunction(self, index, value):
894
DataHandler.add_entity_meshfunction(self, index, value)
895
write_entity_meshfunction(self.__ofile_meshfunc, index, value)
897
def end_meshfunction(self):
898
DataHandler.end_meshfunction(self)
899
write_footer_meshfunction(self.__ofile_meshfunc)
900
self.__ofile_meshfunc.close()
901
self.__ofile_meshfunc = None
904
DataHandler.close(self)
905
if self.__ofile.closed:
907
write_footer_mesh(self.__ofile)
909
if self.__ofile_meshfunc is not None:
910
self.__ofile_meshfunc.close()
912
def _abaqus(ifilename, handler):
913
""" Convert from Abaqus.
915
The Abaqus format first defines a node block, then there should be a number
916
of elements containing these nodes.
919
ifile = file(ifilename, "rb")
920
handler.set_mesh_type("tetrahedron", 3)
924
def read_params(params_spec, pnames, lineno):
926
for p in params_spec:
927
m = re.match(r"(.+)=(.+)", p)
929
pname, val = m.groups()
931
handler.warn("Invalid parameter syntax on line %d: %s" % (lineno, p))
943
material2elsetids = {}
945
re_sect = re.compile(r"\*([^,]+)(?:,(.*))?")
946
re_node = re.compile(r"(\d+),\s*(.+),\s*(.+),\s*(.+)")
947
re_tetra = re.compile(r"(\d+),\s*(\d+),\s*(\d+),\s*(\d+),\s*(\d+)")
949
for lineno, l in enumerate(ifile):
950
l = l.strip().lower()
953
sect, params_str = m.groups()
954
params_spec = ([s.strip() for s in params_str.split(",")] if params_str
957
if sect == "element":
958
pnames = ("type", "elset")
959
params = read_params(params_spec, pnames, lineno)
960
if "type" not in params:
961
handler.error("Element on line %d doesn't declare TYPE" %
963
tp, elset = params["type"], params.get("elset")
964
if tp not in ("c3d4", "dc3d4"):
965
handler.warn("Unsupported element type '%s' on line %d" % (tp, lineno))
966
supported_elem = False
968
supported_elem = True
969
elif sect == "solid section":
970
pnames = ("material", "elset")
971
params = read_params(params_spec, pnames, lineno)
973
if pname not in params:
974
handler.error("Solid section on line %d doesn't "
975
"declare %s" % (lineno, pname.upper()))
976
matname = params["material"]
977
material2elsetids.setdefault(matname, []).append(params["elset"])
978
elif sect == "material":
979
name = read_params(params_spec, ["name"], lineno)["name"]
980
materials.append(name)
981
# We've read the section's heading, continue to next line
987
# Read node definition
990
handler.warn("Node on line %d is on unsupported format" % (lineno,))
992
idx, c0, c1, c2 = m.groups()
993
try: coords = [float(c) for c in (c0, c1, c2)]
995
handler.warn("Node on line %d contains non-numeric coordinates"
998
nodes[int(idx)] = coords
999
elif sect == "element":
1000
if not supported_elem:
1002
m = re_tetra.match(l)
1004
handler.error("Node on line %d badly specified (expected 3 "
1005
"coordinates)" % (lineno,))
1006
idx, n0, n1, n2, n3 = [int(x) for x in m.groups()]
1007
elems[idx] = (tp, n0, n1, n2, n3)
1008
eid2elset.setdefault(elset, set()).add(idx)
1012
# Note that vertices/cells must be consecutively numbered, which isn't
1013
# necessarily the case in Abaqus. Therefore we enumerate and translate
1014
# original IDs to sequence indexes.
1016
handler.start_vertices(len(nodes))
1017
nodeids = nodes.keys()
1019
for idx, nid in enumerate(nodeids):
1020
handler.add_vertex(idx, nodes[nid])
1021
handler.end_vertices()
1023
handler.start_cells(len(elems))
1024
elemids = elems.keys()
1026
for idx, eid in enumerate(elemids):
1030
for nid in elem[1:]:
1031
try: elemnodes.append(nodeids.index(nid))
1033
handler.error("Element %s references non-existent node %s" % (eid, nid))
1034
handler.add_cell(idx, elemnodes)
1037
# Define the material function for the cells
1040
for matname, elsetids in material2elsetids.items():
1041
if matname not in materials:
1042
handler.error("Unknown material %s referred to for element sets %s" %
1043
(matname, ", ".join(elsetids)))
1044
num_entities += len(elsetids)
1045
handler.start_meshfunction("material", 3, num_entities)
1046
# Each material is associated with a number of element sets
1047
for i, matname in enumerate(materials):
1048
try: elsetids = material2elsetids[matname]
1050
# No elements for this material
1052
# For each element set associated with this material
1054
for eid in elsetids:
1055
try: elsets.append(eid2elset[eid])
1057
handler.error("Material '%s' is assigned to undefined element "
1058
"set '%s'" % (matname, eid))
1059
for elset in elsets:
1060
for elemid in elset:
1061
handler.add_entity_meshfunction(elemids.index(elemid), i)
1062
handler.end_meshfunction()
1064
def netcdf2xml(ifilename,ofilename):
1065
"Convert from NetCDF format to DOLFIN XML."
1067
print "Converting from NetCDF format (.ncdf) to DOLFIN XML format"
1070
ifile = open(ifilename, "r")
1071
ofile = open(ofilename, "w")
1077
# Scan file for dimension, number of nodes, number of elements
1079
line = ifile.readline()
1081
_error("Empty file")
1082
if re.search(r"num_dim.*=", line):
1083
dim = int(re.match(".*\s=\s(\d+)\s;",line).group(1))
1084
if re.search(r"num_nodes.*=", line):
1085
num_vertices = int(re.match(".*\s=\s(\d+)\s;",line).group(1))
1086
if re.search(r"num_elem.*=", line):
1087
num_cells = int(re.match(".*\s=\s(\d+)\s;",line).group(1))
1088
if re.search(r"connect1 =",line):
1095
cell_type ="triangle"
1097
cell_type ="tetrahedron"
1099
# Check that we got the cell type
1100
if cell_type == None:
1101
_error("Unable to find cell type.")
1104
write_header_mesh(ofile, cell_type, dim)
1105
write_header_cells(ofile, num_cells)
1108
# Read and write cells
1111
line = ifile.readline()
1114
connect=re.split("[,;]",line)
1116
n0 = int(connect[0])-1
1117
n1 = int(connect[1])-1
1118
n2 = int(connect[2])-1
1119
write_cell_triangle(ofile, num_cells_read, n0, n1, n2)
1121
n0 = int(connect[0])-1
1122
n1 = int(connect[1])-1
1123
n2 = int(connect[2])-1
1124
n3 = int(connect[3])-1
1125
write_cell_tetrahedron(ofile, num_cells_read, n0, n1, n2, n3)
1127
if num_cells == num_cells_read:
1128
write_footer_cells(ofile)
1129
write_header_vertices(ofile, num_vertices)
1132
num_vertices_read = 0
1137
line = ifile.readline()
1139
_error("Missing data")
1140
if re.search(r"coord =",line):
1145
line = ifile.readline()
1149
if re.search(r"\A\s\s\S+,",line):
1152
print "Found x_"+str(coord)+" coordinates"
1153
coords[coord] += line.split()
1154
if re.search(r";",line):
1158
for i in range(num_vertices):
1160
x = float(re.split(",",coords[0].pop(0))[0])
1161
y = float(re.split(",",coords[1].pop(0))[0])
1164
x = float(re.split(",",coords[0].pop(0))[0])
1165
y = float(re.split(",",coords[1].pop(0))[0])
1166
z = float(re.split(",",coords[2].pop(0))[0])
1167
write_vertex(ofile, i, x, y, z)
1171
write_footer_vertices(ofile)
1172
write_footer_mesh(ofile)
1178
def exodus2xml(ifilename,ofilename):
1179
"Convert from Exodus II format to DOLFIN XML."
1181
print "Converting from Exodus II format to NetCDF format"
1183
name = ifilename.split(".")[0]
1184
netcdffilename = name +".ncdf"
1185
status, output = getstatusoutput('ncdump '+ifilename + ' > '+netcdffilename)
1187
raise IOError, "Something wrong while executing ncdump. Is ncdump "\
1188
"installed on the system?"
1189
netcdf2xml(netcdffilename, ofilename)
1192
def write_header_mesh(ofile, cell_type, dim):
1194
<?xml version=\"1.0\" encoding=\"UTF-8\"?>
1196
<dolfin xmlns:dolfin=\"http://www.fenics.org/dolfin/\">
1197
<mesh celltype="%s" dim="%d">
1198
""" % (cell_type, dim))
1200
# Write graph header
1201
def write_header_graph(ofile, graph_type):
1203
<?xml version=\"1.0\" encoding=\"UTF-8\"?>
1205
<dolfin xmlns:dolfin=\"http://www.fenics.org/dolfin/\">
1210
def write_footer_mesh(ofile):
1216
# Write graph footer
1217
def write_footer_graph(ofile):
1223
def write_header_vertices(ofile, num_vertices):
1224
"Write vertices header"
1225
print "Expecting %d vertices" % num_vertices
1226
ofile.write(" <vertices size=\"%d\">\n" % num_vertices)
1228
def write_footer_vertices(ofile):
1229
"Write vertices footer"
1230
ofile.write(" </vertices>\n")
1231
print "Found all vertices"
1233
def write_header_edges(ofile, num_edges):
1234
"Write edges header"
1235
print "Expecting %d edges" % num_edges
1236
ofile.write(" <edges size=\"%d\">\n" % num_edges)
1238
def write_footer_edges(ofile):
1239
"Write edges footer"
1240
ofile.write(" </edges>\n")
1241
print "Found all edges"
1243
def write_vertex(ofile, vertex, x, y, z):
1245
ofile.write(" <vertex index=\"%d\" x=\"%s\" y=\"%s\" z=\"%s\"/>\n" % \
1248
def write_graph_vertex(ofile, vertex, num_edges, weight = 1):
1249
"Write graph vertex"
1250
ofile.write(" <vertex index=\"%d\" num_edges=\"%d\" weight=\"%d\"/>\n" % \
1251
(vertex, num_edges, weight))
1253
def write_graph_edge(ofile, v1, v2, weight = 1):
1255
ofile.write(" <edge v1=\"%d\" v2=\"%d\" weight=\"%d\"/>\n" % \
1258
def write_header_cells(ofile, num_cells):
1259
"Write cells header"
1260
ofile.write(" <cells size=\"%d\">\n" % num_cells)
1261
print "Expecting %d cells" % num_cells
1263
def write_footer_cells(ofile):
1264
"Write cells footer"
1265
ofile.write(" </cells>\n")
1266
print "Found all cells"
1268
def write_cell_triangle(ofile, cell, n0, n1, n2):
1269
"Write cell (triangle)"
1270
ofile.write(" <triangle index=\"%d\" v0=\"%d\" v1=\"%d\" v2=\"%d\"/>\n" % \
1273
def write_cell_tetrahedron(ofile, cell, n0, n1, n2, n3):
1274
"Write cell (tetrahedron)"
1275
ofile.write(" <tetrahedron index=\"%d\" v0=\"%d\" v1=\"%d\" v2=\"%d\" v3=\"%d\"/>\n" % \
1276
(cell, n0, n1, n2, n3))
1278
def _error(message):
1279
"Write an error message"
1280
for line in message.split("\n"):
1281
print "*** %s" % line
1284
def convert2xml(ifilename, ofilename, iformat=None):
1285
""" Convert a file to the DOLFIN XML format.
1287
convert(ifilename, XmlHandler(ofilename), iformat=iformat)
1289
def convert(ifilename, handler, iformat=None):
1290
""" Convert a file using a provided data handler.
1292
Note that handler.close is called when this function finishes.
1293
@param ifilename: Name of input file.
1294
@param handler: The data handler (instance of L{DataHandler}).
1295
@param iformat: Format of input file.
1298
iformat = format_from_suffix(os.path.splitext(ifilename)[1][1:])
1299
# XXX: Backwards-compat
1300
if hasattr(handler, "_ofilename"):
1301
ofilename = handler._ofilename
1303
if iformat == "mesh":
1304
# Convert from mesh to xml format
1305
mesh2xml(ifilename, ofilename)
1306
elif iformat == "gmsh":
1307
# Convert from gmsh to xml format
1308
gmsh2xml(ifilename, handler)
1309
elif iformat == "Triangle":
1310
# Convert from Triangle to xml format
1311
triangle2xml(ifilename, ofilename)
1312
elif iformat == "xml-old":
1313
# Convert from old to new xml format
1314
xml_old2xml(ifilename, ofilename)
1315
elif iformat == "metis":
1316
# Convert from metis graph to dolfin graph xml format
1317
metis_graph2graph_xml(ifilename, ofilename)
1318
elif iformat == "scotch":
1319
# Convert from scotch graph to dolfin graph xml format
1320
scotch_graph2graph_xml(ifilename, ofilename)
1321
elif iformat == "diffpack":
1322
# Convert from Diffpack tetrahedral grid format to xml format
1323
diffpack2xml(ifilename, ofilename)
1324
elif iformat == "abaqus":
1325
# Convert from abaqus to xml format
1326
_abaqus(ifilename, handler)
1327
elif iformat == "NetCDF":
1328
# Convert from NetCDF generated from ExodusII format to xml format
1329
netcdf2xml(ifilename, ofilename)
1330
elif iformat =="ExodusII":
1331
# Convert from ExodusII format to xml format via NetCDF
1332
exodus2xml(ifilename, ofilename)
1333
elif iformat == "StarCD":
1334
# Convert from Star-CD tetrahedral grid format to xml format
1335
starcd2xml(ifilename, ofilename)
1337
_error("Sorry, cannot convert between %s and DOLFIN xml file formats." % iformat)
1339
# XXX: handler.close messes things for other input formats than abaqus or gmsh
1340
if iformat in ("abaqus", "gmsh"):
1343
def starcd2xml(ifilename, ofilename):
1344
"Convert from Star-CD tetrahedral grid format to DOLFIN XML."
1346
print starcd2xml.__doc__
1348
if not os.path.isfile(ifilename[:-3] + "vrt") or not os.path.isfile(ifilename[:-3] + "cel"):
1349
print "StarCD format requires one .vrt file and one .cel file"
1354
ofile = open(ofilename, "w")
1356
# Open file, the vertices are in a .vrt file
1357
ifile = open(ifilename[:-3] + "vrt", "r")
1359
write_header_mesh(ofile, "tetrahedron", 3)
1362
# Read & write vertices
1364
# first, read all lines (need to sweep to times through the file)
1365
lines = ifile.readlines()
1367
# second, find the number of vertices
1370
# nodenr_map is needed because starcd support node numbering like 1,2,4 (ie 3 is missing)
1373
nodenr = int(line[0:15])
1374
nodenr_map[nodenr] = counter
1376
num_vertices = counter
1378
# third, run over all vertices
1379
write_header_vertices(ofile, num_vertices)
1381
nodenr = int(line[0:15])
1382
vertex0 = float(line[15:31])
1383
vertex1 = float(line[31:47])
1384
vertex2 = float(line[47:63])
1385
write_vertex(ofile, nodenr_map[nodenr], float(vertex0), float(vertex1), float(vertex2))
1386
write_footer_vertices(ofile)
1388
# Open file, the cells are in a .cel file
1389
ifile = open(ifilename[:-3] + "cel", "r")
1391
# Read & write cells
1393
# first, read all lines (need to sweep to times through the file)
1394
lines = ifile.readlines()
1396
# second, find the number of cells
1400
l = [int(a) for a in line.split()]
1401
cellnr, node0, node1, node2, node3, node4, node5, node6, node7, tmp1, tmp2 = l
1403
if node2 == node3 and node4 == node5 and node5 == node6 and node6 == node7: # these nodes should be equal
1406
print "The file does contain cells that are not tetraheders. The cell number is ", cellnr, " the line read was ", line
1408
# triangles on the surface
1409
# print "The file does contain cells that are not tetraheders node4==0. The cell number is ", cellnr, " the line read was ", line
1415
# third, run over all cells
1416
write_header_cells(ofile, num_cells)
1419
l = [int(a) for a in line.split()]
1420
cellnr, node0, node1, node2, node3, node4, node5, node6, node7, tmp1, tmp2 = l
1422
if node2 == node3 and node4 == node5 and node5 == node6 and node6 == node7: # these nodes should be equal
1424
write_cell_tetrahedron(ofile, counter, nodenr_map[node0], nodenr_map[node1], nodenr_map[node2], nodenr_map[node4])
1428
write_footer_cells(ofile)
1429
write_footer_mesh(ofile)