Skip to content

Commit 9c3200b

Browse files
authored
change VTK output of rastermesh (#75)
* change VTK output of rastermesh * bump numpy * bump scipy * version bump, docs update
1 parent 44b6a65 commit 9c3200b

File tree

3 files changed

+130
-41
lines changed

3 files changed

+130
-41
lines changed

requirements.txt

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,10 +3,10 @@ matplotlib==3.3.4
33
pybind11==2.4.3
44
pygmsh==7.0.2
55
MeshPy==2018.2.1
6-
numpy==1.22.0
6+
numpy==1.23.2
77
pyquaternion==0.9.5
88
pyvoro-mmalahe==1.3.3
9-
scipy==1.7.2
9+
scipy==1.9.1
1010
xmltodict==0.12.0
1111
tox==3.14.0
1212
lsq-ellipse==2.0.1

src/microstructpy/__init__.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,4 +4,4 @@
44
import microstructpy.seeding
55
import microstructpy.verification
66

7-
__version__ = '1.5.4'
7+
__version__ = '1.5.5'

src/microstructpy/meshing/trimesh.py

Lines changed: 127 additions & 38 deletions
Original file line numberDiff line numberDiff line change
@@ -1019,6 +1019,8 @@ def write(self, filename, format='txt', seeds=None, polymesh=None):
10191019
See the :ref:`s_tri_file_io` section of the :ref:`c_file_formats`
10201020
guide for more details on these formats.
10211021
1022+
VTK files use the `RECTILINEAR_GRID` data type.
1023+
10221024
Args:
10231025
filename (str): The name of the file to write.
10241026
format (str): {'abaqus' | 'txt' | 'vtk'}
@@ -1166,51 +1168,138 @@ def write(self, filename, format='txt', seeds=None, polymesh=None):
11661168
n_kp = len(self.elements[0])
11671169
mesh_type = {4: 'Pixel', 8: 'Voxel'}[n_kp]
11681170
pt_fmt = '{: f} {: f} {: f}\n'
1171+
1172+
# Dimensions
1173+
coords = [list(set(ax)) for ax in zip(*self.points)]
1174+
if len(coords) < 3:
1175+
coords.append([0]) # force z=0 for 2D meshes
1176+
dims = [len(c) for c in coords]
1177+
n_dim = len(dims)
1178+
1179+
11691180
# write heading
11701181
vtk = '# vtk DataFile Version 2.0\n'
11711182
vtk += '{} mesh\n'.format(mesh_type)
11721183
vtk += 'ASCII\n'
1173-
vtk += 'DATASET UNSTRUCTURED_GRID\n'
1174-
1175-
# Write points
1176-
vtk += 'POINTS ' + str(len(self.points)) + ' float\n'
1177-
if len(self.points[0]) == 2:
1178-
vtk += ''.join([pt_fmt.format(x, y, 0) for x, y in
1179-
self.points])
1180-
else:
1181-
vtk += ''.join([pt_fmt.format(x, y, z) for x, y, z in
1182-
self.points])
1183-
1184-
# write elements
1185-
n_elem = len(self.elements)
1186-
cell_fmt = str(n_kp) + n_kp * ' {}' + '\n'
1187-
cell_sz = (1 + n_kp) * n_elem
1188-
vtk += '\nCELLS ' + str(n_elem) + ' ' + str(cell_sz) + '\n'
1189-
vtk += ''.join([cell_fmt.format(*el) for el in self.elements])
1190-
1191-
# write cell type
1192-
vtk += '\nCELL_TYPES ' + str(n_elem) + '\n'
1193-
cell_type = {4: '9', 8: '12'}[n_kp]
1194-
vtk += ''.join(n_elem * [cell_type + '\n'])
1184+
vtk += 'DATASET RECTILINEAR_GRID\n'
1185+
vtk += 'DIMENSIONS {} {} {}\n'.format(*dims)
1186+
1187+
# write points
1188+
for ind, ax in enumerate(['X', 'Y', 'Z']):
1189+
vtk += '{}_COORDINATES {} float\n'.format(ax, dims[ind])
1190+
line = ''
1191+
for x in coords[ind]:
1192+
x_str = '{:f}'.format(x)
1193+
if len(line) == 0:
1194+
line = x_str
1195+
elif len(line) + len(' ') + len(x_str) < 80:
1196+
line += ' ' + x_str
1197+
else:
1198+
vtk += line + '\n'
1199+
line = x_str
1200+
vtk += line + '\n'
11951201

11961202
# write element attributes
1197-
try:
1198-
int(self.element_attributes[0])
1199-
att_type = 'int'
1200-
except TypeError:
1201-
att_type = 'float'
1202-
1203-
vtk += '\nCELL_DATA ' + str(n_elem) + '\n'
1204-
vtk += 'SCALARS element_attributes ' + att_type + ' 1 \n'
1205-
vtk += 'LOOKUP_TABLE element_attributes\n'
1206-
vtk += ''.join([str(a) + '\n' for a in self.element_attributes])
1203+
vtk += 'CELL_DATA {}\n'.format(len(self.element_attributes))
1204+
vtk += 'SCALARS element_attributes float\n'
1205+
vtk += 'LOOKUP_TABLE default\n'
1206+
line = ''
1207+
phase_nums = ''
1208+
phase_line = ''
1209+
pts = np.array(self.points)
1210+
elems = np.sort(self.elements)
1211+
if len(coords[-1]) == 1: # 2D
1212+
for y_ind in range(len(coords[1][:-1])):
1213+
y_mask_ind = pts[:, 1] == coords[1][y_ind]
1214+
y_mask_ip1 = pts[:, 1] == coords[1][y_ind]
1215+
y_mask = y_mask_ind | y_mask_ip1
1216+
1217+
for x_ind in range(len(coords[0][:-1])):
1218+
# mask self.points
1219+
x_mask_ind = pts[:, 0] == coords[0][x_ind]
1220+
x_mask_ip1 = pts[:, 0] == coords[0][x_ind + 1]
1221+
x_mask = x_mask_ind | x_mask_ip1
1222+
1223+
mask = x_mask & y_mask
1224+
el = np.where(mask)
1225+
e_ind = np.where(np.all(elems == el, axis=1))[0][0]
1226+
1227+
# element attribute
1228+
att = self.element_attributes[e_ind]
1229+
att_str = '{:f}'.format(att)
1230+
if len(line) == 0:
1231+
line += att_str
1232+
elif len(line) + len(' ') + len(att_str) < 80:
1233+
line += ' ' + att_str
1234+
else:
1235+
vtk += line + '\n'
1236+
line = att_str
1237+
1238+
# phase number
1239+
if seeds is not None:
1240+
phase = seeds[att].phase
1241+
p_str = str(int(phase))
1242+
if len(phase_line) == 0:
1243+
phase_line = p_str
1244+
elif len(line) + len(' ') + len(p_str) < 80:
1245+
phase_line += ' ' + p_str
1246+
else:
1247+
phase_nums += phase_line + '\n'
1248+
phase_line = p_str
1249+
vtk += line + '\n'
1250+
if seeds is not None:
1251+
vtk += 'SCALARS phase_numbers int\n'
1252+
vtk += 'LOOKUP_TABLE default\n'
1253+
vtk += phase_nums + phase_line + '\n'
12071254

1208-
# Write phase numbers
1209-
if seeds is not None:
1210-
vtk += '\nSCALARS phase_numbers int 1 \n'
1211-
vtk += 'LOOKUP_TABLE phase_numbers\n'
1212-
vtk += ''.join([str(seeds[a].phase) + '\n' for a in
1213-
self.element_attributes])
1255+
else:
1256+
for z_ind in range(len(coords[2][:-1])):
1257+
z_mask_ind = pts[:, 2] == coords[2][z_ind]
1258+
z_mask_ip1 = pts[:, 2] == coords[2][z_ind + 1]
1259+
z_mask = z_mask_ind | z_mask_ip1
1260+
1261+
for y_ind in range(len(coords[1][:-1])):
1262+
y_mask_ind = pts[:, 1] == coords[1][y_ind]
1263+
y_mask_ip1 = pts[:, 1] == coords[1][y_ind + 1]
1264+
y_mask = y_mask_ind | y_mask_ip1
1265+
1266+
for x_ind in range(len(coords[0][:-1])):
1267+
# mask self.points
1268+
x_mask_ind = pts[:, 0] == coords[0][x_ind]
1269+
x_mask_ip1 = pts[:, 0] == coords[0][x_ind + 1]
1270+
x_mask = x_mask_ind | x_mask_ip1
1271+
1272+
mask = x_mask & y_mask & z_mask
1273+
el = np.where(mask)
1274+
e_ind = np.where(np.all(elems == el, axis=1))[0][0]
1275+
1276+
# element attribute
1277+
att = self.element_attributes[e_ind]
1278+
att_str = '{:f}'.format(att)
1279+
if len(line) == 0:
1280+
line += att_str
1281+
elif len(line) + len(' ') + len(att_str) < 80:
1282+
line += ' ' + att_str
1283+
else:
1284+
vtk += line + '\n'
1285+
line = att_str
1286+
1287+
# phase number
1288+
if seeds is not None:
1289+
phase = seeds[att].phase
1290+
p_str = str(int(phase))
1291+
if len(phase_line) == 0:
1292+
phase_line = p_str
1293+
elif len(line) + len(' ') + len(p_str) < 80:
1294+
phase_line += ' ' + p_str
1295+
else:
1296+
phase_nums += phase_line + '\n'
1297+
phase_line = p_str
1298+
vtk += line + '\n'
1299+
if seeds is not None:
1300+
vtk += 'SCALARS phase_numbers int\n'
1301+
vtk += 'LOOKUP_TABLE default\n'
1302+
vtk += phase_nums + phase_line + '\n'
12141303

12151304
with open(filename, 'w') as file:
12161305
file.write(vtk)

0 commit comments

Comments
 (0)