@@ -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 += '\n CELLS ' + 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 += '\n CELL_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 += '\n CELL_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 += '\n SCALARS 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