Salome Python script for Hexahedral & Tetrahedral elements
Mesh a CFD field with Hexahedral & Tetrahedral elements
This short tutorial is based largely on contributions of others in the Salome forum. It is an elegant example of utilizing a python script to create a well structured hexahedral mesh around a tetrahedral mesh all in 3D. The script is posted at: http://www.salome-platform.org/forum/forum_10/612390121, but is reproduced here with extensive embedded comments for the python novice. You will also need the test.brep file contained in test.zip which should be saved to any convenient place such as /tmp as used for the demonstration here.
Download the zip file from the Salome forum http://www.salome-platform.org/forum/forum_10/612390121 or here: Salome-TUI-HexaTetra.zip (it was just renamed here for clarity, but the contents are the same as test.zip of the Salome forum. Extract the BREP file inside it to the /tmp subdirectory.
cd /tmp unzip <pathname>/Salome-TUI-HexaTetra.zip
Copy and paste the script below to any text editor (gedit, kedit, nedit, etc) then save it to any convenient location (say ~/ i.e. your home directory or even /tmp again)
Start Salome and open a new study in the GEOM module. Use File -> Load Script (or [Ctrl-T] and select the script from where you had saved it. Salome will process the script and when you switch to the MESH module's VTK display, you will see a mesh as seen below:
from smesh import *
# Setup the current study called 'myStudy' smesh.SetCurrentStudy(salome.myStudy)
# 1. Set the full path and name of the BREP file and # 2. Import it into Salome, # 3. then publish it so it will show up in the Object Browser window pane brep_file = "\/tmp\/test.brep" # *** Remove the 2 "\" above. Without it this website's Wiki page does not work! test_brep_1 = geompy.ImportBREP(brep_file) geompy.addToStudy(test_brep_1,"shape")
# 4. Explode the 3rd sub-solid of the object 'test_brep_1' # 5. and publish it in the Object Browser window pane as a child of 'test_brep_1' inner_box = geompy.SubShapeAllSorted(test_brep_1, geompy.ShapeType["SOLID"]) geompy.addToStudyInFather( test_brep_1, inner_box, "inner box" )
# 6. Explode all the sub-faces of the object test_brep_1 ff = geompy.SubShapeAllSorted(test_brep_1, geompy.ShapeType["FACE"])
# 7. Select specific faces which will be needed for local mesh # hypothesis using a 'for' loop inbox_tria_faces = [ ff[i] for i in [6,13,15,19,20,21]]
# 8. Make a compound using the list 'inbox_tria_faces' # 9. and publish it in the Object Browser window pane as a child of 'test_brep_1' inbox_tria_faces = geompy.MakeCompound(inbox_tria_faces) geompy.addToStudyInFather( test_brep_1, inbox_tria_faces, "inbox_tria_faces" )
# 10. Explode all the sub-edges of the object 'test_brep_1' ee = geompy.SubShapeAllSorted(test_brep_1, geompy.ShapeType["EDGE"])
# 11. Select specific edges which will be needed for local mesh # hypothesis using a 'for' loop inbox_edges = [ ee[i] for i in [12,13,14,15,24,25,26,27,28,29,30,31]]
# 12. Make a compound using the list inbox_edges # 13. and publish it in the Object Browser window pane as a child of 'test_brep_1' inbox_edges = geompy.MakeCompound(inbox_edges) geompy.addToStudyInFather( test_brep_1, inbox_edges, "inbox_edges" )
# 14. Define a mesh called 'Mesh' # 15. Set the global 1D hypothesis to 5 segments per edge # 16. Set the local 1D hypothesis to 15 segments per edge for # all edges in the list 'inbox_edges' # 17. Set the global algorithm as quadrangle # 18. Set the local 2D algorithm as triangles for # the faces in the list 'inbox_tria_faces # 19. Set the global 3D algorithm to hexahedron # 20. Set the local 3D algorithm to tetrahedron for # the solid 'inner_box' # 21. Finally compute the mesh ! mesh = Mesh(test_brep_1) mesh.Segment().NumberOfSegments(5) mesh.Segment(inbox_edges).NumberOfSegments(15) mesh.Quadrangle() mesh.Triangle(inbox_tria_faces) mesh.Hexahedron() mesh.Tetrahedron(inner_box) mesh.Compute()
1. The 'geompy.SubShapeAllSorted' is used in line 6 and 10 to repeatably and consistently get the indices of the sub-shapes of 'test_brep_1'. Furthermore according to S.Michael " ... because of instability of complex geometrical operations, an index of the same sub-shape can vary from launch to launch." and "The script I attached does not badly [meaning: really] need usage of geompy.SubShapeAllSorted() since sub-shape indices within a geometrical shape imported from a file are always the same, this is just to demonstrate a useful technique."
2. One might wonder how does one decide which indices of 'ff[i]' to include in the list 'inbox_tria_faces' or which of the 'ee[i]' should be in the list 'inbox_edges'. The script above does not make it clear. Here is the secret behind it. One can run the following just after the 10th line:
# --- These 2 lines are optional --------------------------------------- # 10a.Do this in order to see all the exploded edges of 'test_brep_1' # from which one can select the appropriate edges in step 11 below for i,e in enumerate(ee): geompy.addToStudyInFather( test_brep_1, e, "edge_%s"%i ) # Use a similar process for deciding which of the 'ff[i]' members # need to be included in 'inbox_tria_faces' # ----------------------------------------------------------------------
This will list all 44 edges ('edge_0' ~ 'edge_43') in the Object Browser window pane. Then click on each one and Salome will highlight it in the OCC Viewer. if you are old fashioned like me note down the numbers that constitute the edges that form the 'boat' shaped feature of 'test_brep_1' or just python code on the fly by typing into a text editor the numbers you have chosen correctly. The reason I still use the old fashioned method is I avoid using the mouse to switch from Salome to the text editor as I am trying to determine which edges are relevant, I don't have an intelligent enough cursor that follows where I am looking, yet!
3. Suppose one wants to alter the local 1D hypothesis a little we could experiment a bit:
inbox_edges = [ ee[i] for i in [12,13,14,15,24,25,26,27,28,29,30,31]]
inbox_edges = [ ee[i] for i in [12,13,24,25,26,27,29,30]] inbox_z_edges = [ ee[i] for i in [14,15,28,31]]
(Note that we are removing the 4 vertical edges from 'inbox_edges' and putting them into a separate list 'inbox_z_edges')
B) Right after:
geompy.addToStudyInFather( test_brep_1, inbox_edges, "inbox_edges" )
inbox_z_edges = geompy.MakeCompound(inbox_z_edges) geompy.addToStudyInFather( test_brep_1, inbox_z_edges, "inbox_z_edges" )
(Creating a new compound and making it a child of 'test_brep_1')
C) Just after:
(Adding an additional 1D local hypothesis)
Try it to see what you get...
This page was made possible by the wonderful help of S. Michael and the topic started by vaina, who provided the BREP and STEP files for the model. Thank you.
The script was tested and functional on Salome 5.1.4 under Ubuntu Jaunty 9.04 64bit installed from binaries.
Disclaimer: This page is still evolving and omissions or errors are a regrettable part of such a process. So user beware! -JMB