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
):
13 Return the OpenFOAM file header block as a string.
15 return '''/*--------------------------------*- C++ -*----------------------------------*\\
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 \\*---------------------------------------------------------------------------*/
29 // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
31 ''' % (className
, objectName
)
35 def __init__(self
, object = None, allEdges
= False):
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.
48 # =============================================================================
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
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()
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 # =============================================================================
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
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
)
113 for name
, ids
in patches
.iteritems():
115 if patchIds
[faceId
-1] == lastPatchId
:
116 patchIds
[faceId
-1] = patchId
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.')
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
137 # =============================================================================
138 # Process feature edges
141 for name
, ids
in featureEdgeSubsets
.iteritems():
144 edgeIds
= list(set(edgeIds
))
145 nEdges
= len(edgeIds
)
147 # Reverse mapping of edge ids since they aren't necessarily numbered 1..nEdges
149 edgeMap
= [-1] * max(edgeIds
)
154 for edgeId
in edgeIds
:
155 edgeMap
[edgeId
-1] = i
158 # =============================================================================
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
167 # =============================================================================
171 self
._nodeIds
= nodeIds
172 self
._edgeIds
= edgeIds
173 self
._faceIds
= faceIds
175 self
._nodeMap
= nodeMap
176 self
._edgeMap
= edgeMap
179 self
._patches
= patches
180 self
._pointSubsets
= pointSubsets
181 self
._featureEdgeSubsets
= featureEdgeSubsets
182 self
._faceSubsets
= {}
188 Return the number of nodes
190 return len(self
._nodeIds
)
194 Return the number of edges
196 return len(self
._edgeIds
)
200 Return the number of triangular facets
202 return len(self
._faceIds
)
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
))
223 def _writeNodes(self
, f
):
225 Write the nodes to file as an OpenFOAM pointField.
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
))
237 def _writeFeatureEdges(self
, f
):
239 Write the feature edges to file as an OpenFOAM edgeList.
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')
253 def _writeFacets(self
, f
):
255 Write the facets to file as an OpenFOAM List of labelledTri.
257 from itertools
import chain
260 nodeMap
= self
._nodeMap
261 patches
= self
._patches
263 f
.write('%d\n(\n' % sum([len(patch
) for patch
in patches
.itervalues()]))
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
)
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
])))
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
308 f
= open(fileName
, 'wb') # NOTE: file opened as binary to ensure unix-style line breaks
311 f
.write(foamHeader('edgeMesh', self
._mesh
.GetName()))
314 self
._writeFeatureEdges
(f
)
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
327 f
= open(fileName
, 'wb') # NOTE: file opened as binary to ensure unix-style line breaks
329 self
._writePatchDefs
(f
)
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
344 f
= open(fileName
, 'wb') # NOTE: file opened as binary to ensure unix-style line breaks
346 self
._writePatchDefs
(f
)
349 self
._writeFeatureEdges
(f
)
350 self
._writePointSubsets
(f
)
351 self
._writeFaceSubsets
(f
)
352 self
._writeFeatureEdgeSubsets
(f
)
356 print 'triSurf written to %s' % fileName
359 if __name__
== '__main__':
363 import SMESH
, SALOMEDS