Forward compatibility: flex
[foam-extend-3.2.git] / applications / utilities / mesh / generation / cfMesh / python / Salome / salomeTriSurf.py
blob40fcdcb25c68230b02feba8800a9875e625804b4
1 #!python
2 # =============================================================================
3 # Python module for writing OpenFOAM feature edge and triSurface files from
4 # within Salome platform.
5 # Tested on Salome 7.4.0 and python 2.7 on 64-bit Windows
7 # Author: Ivor Clifford <ivor.clifford@psi.ch>
9 # =============================================================================
11 def foamHeader(className, objectName):
12 '''
13 Return the OpenFOAM file header block as a string.
14 '''
15 return '''/*--------------------------------*- C++ -*----------------------------------*\\
16 | ========= | |
17 | \\\\ / F ield | OpenFOAM: The Open Source CFD Toolbox |
18 | \\\\ / O peration | Version: 2.2.1 |
19 | \\\\ / A nd | Web: www.OpenFOAM.org |
20 | \\\\/ M anipulation | |
21 \\*---------------------------------------------------------------------------*/
22 FoamFile
24 version 2.0;
25 format ascii;
26 class %s;
27 object %s;
29 // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
31 ''' % (className, objectName)
34 class triSurf:
35 def __init__(self, object = None, allEdges = False):
36 '''
37 Construct from the supplied Salome mesh.
39 object - the mesh object (must be a triangular surface mesh). If no
40 object is supplied, the current Salome selection is used.
41 allEdges - If true, all edges on the mesh are included as feature
42 edges, otherwise only edges contained in groups are included
44 NOTE: All face groups are assumed to represent patches. No face subsets
45 are written. All edge groups are added as feature edge subsets. All point
46 groups are added as point subsets.
47 '''
48 # =============================================================================
49 # Initialize salome
50 import salome
51 import SMESH, SALOMEDS
52 from salome.smesh import smeshBuilder
53 from operator import itemgetter
54 from collections import OrderedDict
56 import SMESH, SALOMEDS
58 # =============================================================================
59 # Get the Salome mesh object
60 if object is None:
61 selected = salome.sg.getAllSelected()
62 if len(selected) != 1:
63 raise RuntimeError('A single Salome mesh object must be selected.')
65 object = salome.myStudy.FindObjectID(selected[0]).GetObject()
67 try:
68 object.GetMesh()
69 except:
70 raise RuntimeError('Supplied object is not a Salome SMESH mesh.')
72 smesh = smeshBuilder.New(salome.myStudy)
73 mesh = smesh.Mesh(object)
75 print "Converting SMESH Mesh '%s'" % mesh.GetName()
77 # =============================================================================
78 # Get basic mesh info
79 nNodes = mesh.NbNodes()
80 nFaces = mesh.NbFaces()
81 nTris = mesh.NbTriangles()
82 nEdges = mesh.NbEdges()
83 nodeIds = mesh.GetNodesId()
84 faceIds = mesh.GetElementsByType(SMESH.FACE)
85 edgeIds = mesh.GetElementsByType(SMESH.EDGE)
87 # Check that mesh is strictly triangular
88 if nFaces != nTris:
89 raise RuntimeError('Mesh is not strictly triangular')
91 # Get patch and subset names & ids
92 # All SMESH.FACE groups are assumed to be patches
93 # All SMESH.EDGE groups are assumed to be feature subsets
94 # All SMESH.NODE groups are assumed to be point subsets
95 patches = OrderedDict()
96 pointSubsets = OrderedDict()
97 featureEdgeSubsets = OrderedDict()
99 for group in mesh.GetGroups():
100 if group.GetType() == SMESH.FACE:
101 patches[group.GetName()] = group.GetIDs()
102 elif group.GetType() == SMESH.EDGE:
103 featureEdgeSubsets[group.GetName()] = group.GetIDs()
104 elif group.GetType() == SMESH.NODE:
105 pointSubsets[group.GetName()] = group.GetIDs()
107 # =============================================================================
108 # Process faces and patches
109 # Get patchId for each face
110 lastPatchId = len(patches)
111 patchIds = [lastPatchId] * max(faceIds)
112 patchId = 0
113 for name, ids in patches.iteritems():
114 for faceId in ids:
115 if patchIds[faceId-1] == lastPatchId:
116 patchIds[faceId-1] = patchId
117 else:
118 print "Face %d is assigned to both groups %s and %s" % (faceId, name, patches.keys()[patchIds[faceId-1]])
119 raise RuntimeError('Groups of faces are not unique, i.e. they overlap.')
121 patchId += 1
123 # Compact and reorder patchIds to match faceIds
124 patchIds = [patchIds[faceId-1] for faceId in faceIds]
126 # Reorder faces by increasing group id
127 faceAndpatchIds = sorted(zip(faceIds, patchIds), key=itemgetter(1))
128 faceIds, patchIds = zip(*faceAndpatchIds)
130 # Add unused faces to the default patch
131 defaultFaces = [faceId for faceId, patchId in faceAndpatchIds if patchId == lastPatchId]
132 if len(defaultFaces) > 0:
133 patches['defaultFaces'] = defaultFaces
135 defaultFaces = None
137 # =============================================================================
138 # Process feature edges
139 if not allEdges:
140 edgeIds = []
141 for name, ids in featureEdgeSubsets.iteritems():
142 edgeIds += ids
144 edgeIds = list(set(edgeIds))
145 nEdges = len(edgeIds)
147 # Reverse mapping of edge ids since they aren't necessarily numbered 1..nEdges
148 if len(edgeIds):
149 edgeMap = [-1] * max(edgeIds)
150 else:
151 edgeMap = []
154 for edgeId in edgeIds:
155 edgeMap[edgeId-1] = i
156 i += 1
158 # =============================================================================
159 # Process nodes
160 # Reverse mapping of node ids since nodes aren't necessarily numbered 1..nNodes
161 nodeMap = [-1] * max(nodeIds)
163 for nodeId in nodeIds:
164 nodeMap[nodeId-1] = i
165 i += 1
167 # =============================================================================
169 self._mesh = mesh
171 self._nodeIds = nodeIds
172 self._edgeIds = edgeIds
173 self._faceIds = faceIds
175 self._nodeMap = nodeMap
176 self._edgeMap = edgeMap
177 self._faceMap = []
179 self._patches = patches
180 self._pointSubsets = pointSubsets
181 self._featureEdgeSubsets = featureEdgeSubsets
182 self._faceSubsets = {}
184 print 'Done'
186 def nNodes(self):
188 Return the number of nodes
190 return len(self._nodeIds)
192 def nEdges(self):
194 Return the number of edges
196 return len(self._edgeIds)
198 def nFacets(self):
200 Return the number of triangular facets
202 return len(self._faceIds)
204 def nPatches(self):
206 Return the number of patches
208 return len(self._patches)
210 def _writePatchDefs(self, f, typeName = 'wall'):
212 Write the patch definitions to file as an OpenFOAM geometricSurfacePatchList.
213 NOTE: All patches are assumed to be walls.
215 patches = self._patches
217 f.write('%d\n(\n' % len(patches))
218 for name in patches.iterkeys():
219 f.write('%s\t%s\n' % (name, typeName))
221 f.write(')\n')
223 def _writeNodes(self, f):
225 Write the nodes to file as an OpenFOAM pointField.
227 mesh = self._mesh
228 nodeIds = self._nodeIds
230 f.write('%d\n(\n' % len(nodeIds))
232 for x, y, z in [mesh.GetNodeXYZ(nodeId) for nodeId in nodeIds]:
233 f.write( '( %g %g %g )\n' % (x, y, z))
235 f.write(')\n')
237 def _writeFeatureEdges(self, f):
239 Write the feature edges to file as an OpenFOAM edgeList.
241 mesh = self._mesh
242 nodeMap = self._nodeMap
243 edgeIds = self._edgeIds
245 f.write('%d\n(\n' % len(edgeIds))
247 for edgeId in edgeIds:
248 nodes = mesh.GetElemNodes(edgeId)
249 f.write( '(' + ' '.join([str(nodeMap[nodeId-1]) for nodeId in nodes]) + ')\n')
251 f.write(')\n')
253 def _writeFacets(self, f):
255 Write the facets to file as an OpenFOAM List of labelledTri.
257 from itertools import chain
259 mesh = self._mesh
260 nodeMap = self._nodeMap
261 patches = self._patches
263 f.write('%d\n(\n' % sum([len(patch) for patch in patches.itervalues()]))
265 patchId = 0
266 for patchId, (patchName, faceIds) in enumerate(patches.iteritems()):
267 for faceId in faceIds:
268 nodes = mesh.GetElemNodes(faceId)
269 f.write( '((' + ' '.join([str(nodeMap[nodeId-1]) for nodeId in nodes]) + ') %d)\n' % patchId)
271 f.write(')\n')
273 def _writeSubsets(self, f, subsets, map, typeId):
275 General function to write a subset to file as an OpenFOAM Map<meshSubset>.
277 f.write('%d\n(\n' % len(subsets))
278 for name, ids in subsets.iteritems():
279 f.write('%s %s %d ( %s )\n' % (name, typeId, len(ids), ' '.join([str(map[id-1]) for id in ids])))
281 f.write(')\n')
283 def _writePointSubsets(self, f):
285 Write the point subsets to file as and OpenFOAM Map<meshSubset>.
287 self._writeSubsets(f, self._pointSubsets, self._nodeMap, '2')
289 def _writeFaceSubsets(self, f):
291 Write the face subsets to file as and OpenFOAM Map<meshSubset>.
293 self._writeSubsets(f, self._faceSubsets, self._faceMap, '4')
295 def _writeFeatureEdgeSubsets(self, f):
297 Write the feature edge subsets to file as and OpenFOAM Map<meshSubset>.
299 self._writeSubsets(f, self._featureEdgeSubsets, self._edgeMap, '8')
301 def writeEdgeMesh(self, fileName):
303 Write to file as an OpenFOAM edgeMesh
305 fileName - The file name to write
307 # Create file
308 f = open(fileName, 'wb') # NOTE: file opened as binary to ensure unix-style line breaks
310 # Write header
311 f.write(foamHeader('edgeMesh', self._mesh.GetName()))
313 self._writeNodes(f)
314 self._writeFeatureEdges(f)
316 f.close()
318 print 'edgeMesh written to %s' % fileName
320 def writeFtr(self, fileName):
322 Write to file as an OpenFOAM cfMesh FTR file
324 fileName - the file name to write
326 # Create file
327 f = open(fileName, 'wb') # NOTE: file opened as binary to ensure unix-style line breaks
329 self._writePatchDefs(f)
330 self._writeNodes(f)
331 self._writeFacets(f)
333 f.close()
335 print 'triSurf written to %s' % fileName
337 def writeFms(self, fileName):
339 Write to file as an OpenFOAM cfMesh FMS file
341 fileName - the file name to write
343 # Create file
344 f = open(fileName, 'wb') # NOTE: file opened as binary to ensure unix-style line breaks
346 self._writePatchDefs(f)
347 self._writeNodes(f)
348 self._writeFacets(f)
349 self._writeFeatureEdges(f)
350 self._writePointSubsets(f)
351 self._writeFaceSubsets(f)
352 self._writeFeatureEdgeSubsets(f)
354 f.close()
356 print 'triSurf written to %s' % fileName
359 if __name__ == '__main__':
360 import salome
361 salome.salome_init()
363 import SMESH, SALOMEDS