From 37db5ab4289bd2d131fe8babd47fd6d20a73d77f Mon Sep 17 00:00:00 2001 From: Bernd Hahnebach Date: Mon, 28 Nov 2016 01:17:36 +0100 Subject: [PATCH 1/6] FEM: solver Z88, fix in object attributes --- src/Mod/Fem/_FemSolverZ88.py | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/src/Mod/Fem/_FemSolverZ88.py b/src/Mod/Fem/_FemSolverZ88.py index c9f05a46bc14..9ed12d1170f4 100644 --- a/src/Mod/Fem/_FemSolverZ88.py +++ b/src/Mod/Fem/_FemSolverZ88.py @@ -27,7 +27,7 @@ ## @package FemSolverZ88 # \ingroup FEM -import FreeCAD +# import FreeCAD import FemToolsZ88 @@ -42,15 +42,15 @@ def __init__(self, obj): obj.addProperty("App::PropertyString", "SolverType", "Base", "Type of the solver", 1) # the 1 set the property to ReadOnly obj.SolverType = str(self.Type) - fem_prefs = FreeCAD.ParamGet("User parameter:BaseApp/Preferences/Mod/Fem/General") + # fem_prefs = FreeCAD.ParamGet("User parameter:BaseApp/Preferences/Mod/Fem/General") # not needed ATM - obj.addProperty("App::PropertyPath", "WorkingDir", "Fem", "Working directory for calculations") - obj.WorkingDir = fem_prefs.GetString("WorkingDir", "") + obj.addProperty("App::PropertyPath", "WorkingDir", "Fem", "Working directory for calculations, will only be used it is left blank in preferences") + # the working directory is not set, the solver working directory is only used if the preferences working directory is left blank obj.addProperty("App::PropertyEnumeration", "AnalysisType", "Fem", "Type of the analysis") - obj.AnalysisType = FemToolsZ88.FemToolsZ88.known_analysis_types - analysis_type = fem_prefs.GetInt("AnalysisType", 0) - obj.AnalysisType = FemToolsZ88.FemToolsZ88.known_analysis_types[analysis_type] + known_analysis_types = FemToolsZ88.FemToolsZ88.known_analysis_types + obj.AnalysisType = known_analysis_types + obj.AnalysisType = known_analysis_types[0] def execute(self, obj): return From 299d3d120625f2b562616c6dd89f794466f7be26 Mon Sep 17 00:00:00 2001 From: Bernd Hahnebach Date: Mon, 28 Nov 2016 01:17:45 +0100 Subject: [PATCH 2/6] FEM: icons, rename some icons to better fit in FEM name scheme --- src/Mod/Fem/Gui/Command.cpp | 4 ++-- src/Mod/Fem/Gui/Resources/Fem.qrc | 8 ++++---- ...-poly.svg => fem-femmesh-create-node-by-poly.svg} | 2 +- ...esh-from-shape.svg => fem-femmesh-from-shape.svg} | 2 +- ...rom-shape.svg => fem-femmesh-gmsh-from-shape.svg} | 2 +- ...m-shape.svg => fem-femmesh-netgen-from-shape.svg} | 2 +- src/Mod/Fem/Gui/TaskAnalysisInfo.cpp | 2 +- src/Mod/Fem/Gui/TaskCreateNodeSet.cpp | 2 +- src/Mod/Fem/Gui/TaskDriver.cpp | 2 +- src/Mod/Fem/Gui/TaskObjectName.cpp | 2 +- src/Mod/Fem/Gui/TaskPostBoxes.cpp | 12 ++++++------ src/Mod/Fem/Gui/TaskTetParameter.cpp | 2 +- src/Mod/Fem/Gui/ViewProviderFemMesh.cpp | 2 +- src/Mod/Fem/Gui/ViewProviderFemPostObject.cpp | 2 +- src/Mod/Fem/_CommandMeshGmshFromShape.py | 2 +- src/Mod/Fem/_CommandMeshNetgenFromShape.py | 2 +- src/Mod/Fem/_ViewProviderFemMeshGmsh.py | 2 +- 17 files changed, 26 insertions(+), 26 deletions(-) rename src/Mod/Fem/Gui/Resources/icons/{fem-fem-mesh-create-node-by-poly.svg => fem-femmesh-create-node-by-poly.svg} (99%) rename src/Mod/Fem/Gui/Resources/icons/{fem-fem-mesh-from-shape.svg => fem-femmesh-from-shape.svg} (99%) rename src/Mod/Fem/Gui/Resources/icons/{fem-fem-mesh-gmsh-from-shape.svg => fem-femmesh-gmsh-from-shape.svg} (99%) rename src/Mod/Fem/Gui/Resources/icons/{fem-fem-mesh-netgen-from-shape.svg => fem-femmesh-netgen-from-shape.svg} (99%) diff --git a/src/Mod/Fem/Gui/Command.cpp b/src/Mod/Fem/Gui/Command.cpp index 4ca785c732c4..b5480e208cbf 100644 --- a/src/Mod/Fem/Gui/Command.cpp +++ b/src/Mod/Fem/Gui/Command.cpp @@ -975,7 +975,7 @@ CmdFemDefineNodesSet::CmdFemDefineNodesSet() sToolTipText = QT_TR_NOOP("Create node set by Poly"); sWhatsThis = "Create node set by Poly"; sStatusTip = QT_TR_NOOP("Create node set by Poly"); - sPixmap = "fem-fem-mesh-create-node-by-poly"; + sPixmap = "fem-femmesh-create-node-by-poly"; } void CmdFemDefineNodesSet::activated(int) @@ -1032,7 +1032,7 @@ CmdFemCreateNodesSet::CmdFemCreateNodesSet() sToolTipText = QT_TR_NOOP("Creates a FEM mesh nodes set"); sWhatsThis = "Fem_CreateNodesSet"; sStatusTip = sToolTipText; - sPixmap = "fem-fem-mesh-create-node-by-poly"; + sPixmap = "fem-femmesh-create-node-by-poly"; } void CmdFemCreateNodesSet::activated(int) diff --git a/src/Mod/Fem/Gui/Resources/Fem.qrc b/src/Mod/Fem/Gui/Resources/Fem.qrc index 1f914c0890bd..79eec3a0b7f0 100755 --- a/src/Mod/Fem/Gui/Resources/Fem.qrc +++ b/src/Mod/Fem/Gui/Resources/Fem.qrc @@ -25,10 +25,10 @@ icons/fem-control-solver.svg icons/fem-cylinder.svg icons/fem-data.png - icons/fem-fem-mesh-create-node-by-poly.svg - icons/fem-fem-mesh-from-shape.svg - icons/fem-fem-mesh-gmsh-from-shape.svg - icons/fem-fem-mesh-netgen-from-shape.svg + icons/fem-femmesh-create-node-by-poly.svg + icons/fem-femmesh-from-shape.svg + icons/fem-femmesh-gmsh-from-shape.svg + icons/fem-femmesh-netgen-from-shape.svg icons/fem-femmesh-to-mesh.svg icons/fem-frequency-analysis.svg icons/fem-inp-editor.svg diff --git a/src/Mod/Fem/Gui/Resources/icons/fem-fem-mesh-create-node-by-poly.svg b/src/Mod/Fem/Gui/Resources/icons/fem-femmesh-create-node-by-poly.svg similarity index 99% rename from src/Mod/Fem/Gui/Resources/icons/fem-fem-mesh-create-node-by-poly.svg rename to src/Mod/Fem/Gui/Resources/icons/fem-femmesh-create-node-by-poly.svg index 044191fe418b..1d56b643cb98 100644 --- a/src/Mod/Fem/Gui/Resources/icons/fem-fem-mesh-create-node-by-poly.svg +++ b/src/Mod/Fem/Gui/Resources/icons/fem-femmesh-create-node-by-poly.svg @@ -15,7 +15,7 @@ id="svg2860" sodipodi:version="0.32" inkscape:version="0.48.3.1 r9886" - sodipodi:docname="fem-fem-mesh-create-node-by-poly.svg" + sodipodi:docname="fem-femmesh-create-node-by-poly.svg" inkscape:output_extension="org.inkscape.output.svg.inkscape" version="1.1"> diff --git a/src/Mod/Fem/Gui/Resources/icons/fem-fem-mesh-gmsh-from-shape.svg b/src/Mod/Fem/Gui/Resources/icons/fem-femmesh-gmsh-from-shape.svg similarity index 99% rename from src/Mod/Fem/Gui/Resources/icons/fem-fem-mesh-gmsh-from-shape.svg rename to src/Mod/Fem/Gui/Resources/icons/fem-femmesh-gmsh-from-shape.svg index d9fd5d8cf4fb..b869f01cad3a 100644 --- a/src/Mod/Fem/Gui/Resources/icons/fem-fem-mesh-gmsh-from-shape.svg +++ b/src/Mod/Fem/Gui/Resources/icons/fem-femmesh-gmsh-from-shape.svg @@ -15,7 +15,7 @@ id="svg2860" sodipodi:version="0.32" inkscape:version="0.48.5 r10040" - sodipodi:docname="fem-fem-mesh-gmsh-from-shape.svg" + sodipodi:docname="fem-femmesh-gmsh-from-shape.svg" inkscape:output_extension="org.inkscape.output.svg.inkscape" version="1.1"> isDerivedFrom(ViewProviderFemPostFunction::getClassTypeId())); @@ -244,7 +244,7 @@ void TaskPostFunction::applyPythonCode() { //############################################################################################ TaskPostClip::TaskPostClip(ViewProviderDocumentObject* view, App::PropertyLink* function, QWidget* parent) - : TaskPostBox(view,Gui::BitmapFactory().pixmap("fem-fem-mesh-create-node-by-poly"), tr("Choose implicit function"), parent) { + : TaskPostBox(view,Gui::BitmapFactory().pixmap("fem-femmesh-create-node-by-poly"), tr("Choose implicit function"), parent) { assert(view->isDerivedFrom(ViewProviderFemPostClip::getClassTypeId())); assert(function); @@ -363,7 +363,7 @@ void TaskPostClip::on_InsideOut_toggled(bool val) { //############################################################################################ TaskPostScalarClip::TaskPostScalarClip(ViewProviderDocumentObject* view, QWidget* parent) : - TaskPostBox(view, Gui::BitmapFactory().pixmap("fem-fem-mesh-create-node-by-poly"), tr("Clip options"), parent) { + TaskPostBox(view, Gui::BitmapFactory().pixmap("fem-femmesh-create-node-by-poly"), tr("Clip options"), parent) { assert(view->isDerivedFrom(ViewProviderFemPostScalarClip::getClassTypeId())); @@ -455,7 +455,7 @@ void TaskPostScalarClip::on_InsideOut_toggled(bool val) { //############################################################################################ TaskPostWarpVector::TaskPostWarpVector(ViewProviderDocumentObject* view, QWidget* parent) : - TaskPostBox(view, Gui::BitmapFactory().pixmap("fem-fem-mesh-create-node-by-poly"), tr("Clip options"), parent) { + TaskPostBox(view, Gui::BitmapFactory().pixmap("fem-femmesh-create-node-by-poly"), tr("Clip options"), parent) { assert(view->isDerivedFrom(ViewProviderFemPostWarpVector::getClassTypeId())); @@ -540,7 +540,7 @@ void TaskPostWarpVector::on_Min_valueChanged(double v) { //############################################################################################ TaskPostCut::TaskPostCut(ViewProviderDocumentObject* view, App::PropertyLink* function, QWidget* parent) - : TaskPostBox(view,Gui::BitmapFactory().pixmap("fem-fem-mesh-create-node-by-poly"), tr("Choose implicit function"), parent) { + : TaskPostBox(view,Gui::BitmapFactory().pixmap("fem-femmesh-create-node-by-poly"), tr("Choose implicit function"), parent) { assert(view->isDerivedFrom(ViewProviderFemPostCut::getClassTypeId())); assert(function); diff --git a/src/Mod/Fem/Gui/TaskTetParameter.cpp b/src/Mod/Fem/Gui/TaskTetParameter.cpp index 2707b9e94b9f..2ac5298a8ccc 100644 --- a/src/Mod/Fem/Gui/TaskTetParameter.cpp +++ b/src/Mod/Fem/Gui/TaskTetParameter.cpp @@ -48,7 +48,7 @@ using namespace Gui; TaskTetParameter::TaskTetParameter(Fem::FemMeshShapeNetgenObject *pcObject,QWidget *parent) - : TaskBox(Gui::BitmapFactory().pixmap("fem-fem-mesh-create-node-by-poly"), + : TaskBox(Gui::BitmapFactory().pixmap("fem-femmesh-create-node-by-poly"), tr("Tet Parameter"), true, parent), diff --git a/src/Mod/Fem/Gui/ViewProviderFemMesh.cpp b/src/Mod/Fem/Gui/ViewProviderFemMesh.cpp index 689a96ecec1c..14b238ca550a 100644 --- a/src/Mod/Fem/Gui/ViewProviderFemMesh.cpp +++ b/src/Mod/Fem/Gui/ViewProviderFemMesh.cpp @@ -183,7 +183,7 @@ App::PropertyFloatConstraint::Constraints ViewProviderFemMesh::floatRange = {1.0 ViewProviderFemMesh::ViewProviderFemMesh() { - sPixmap = "fem-fem-mesh-from-shape"; + sPixmap = "fem-femmesh-from-shape"; ADD_PROPERTY(PointColor,(App::Color(0.7f,0.7f,0.7f))); ADD_PROPERTY(PointSize,(5.0f)); diff --git a/src/Mod/Fem/Gui/ViewProviderFemPostObject.cpp b/src/Mod/Fem/Gui/ViewProviderFemPostObject.cpp index 9c73dacfc3a5..fa8fedf2bf15 100644 --- a/src/Mod/Fem/Gui/ViewProviderFemPostObject.cpp +++ b/src/Mod/Fem/Gui/ViewProviderFemPostObject.cpp @@ -66,7 +66,7 @@ ViewProviderFemPostObject::ViewProviderFemPostObject() : m_blockPropertyChanges( ADD_PROPERTY_TYPE(VectorMode,((long)0), "Coloring", App::Prop_None, "Select what to show for a vector field"); ADD_PROPERTY(Transperency, (0)); - sPixmap = "fem-fem-mesh-from-shape"; + sPixmap = "fem-femmesh-from-shape"; //create the subnodes which do the visualization work m_shapeHints = new SoShapeHints(); diff --git a/src/Mod/Fem/_CommandMeshGmshFromShape.py b/src/Mod/Fem/_CommandMeshGmshFromShape.py index 5044fff6f512..a11ce896aec3 100644 --- a/src/Mod/Fem/_CommandMeshGmshFromShape.py +++ b/src/Mod/Fem/_CommandMeshGmshFromShape.py @@ -38,7 +38,7 @@ class _CommandMeshGmshFromShape(FemCommands): # the Fem_MeshGmshFromShape command definition def __init__(self): super(_CommandMeshGmshFromShape, self).__init__() - self.resources = {'Pixmap': 'fem-fem-mesh-gmsh-from-shape', + self.resources = {'Pixmap': 'fem-femmesh-gmsh-from-shape', 'MenuText': QtCore.QT_TRANSLATE_NOOP("Fem_MeshGmshFromShape", "FEM mesh from shape by GMSH"), 'ToolTip': QtCore.QT_TRANSLATE_NOOP("Fem_MeshGmshFromShape", "Create a FEM mesh from a shape by GMSH mesher")} self.is_active = 'with_part_feature' diff --git a/src/Mod/Fem/_CommandMeshNetgenFromShape.py b/src/Mod/Fem/_CommandMeshNetgenFromShape.py index 877687a5bb9f..f497fcb34986 100644 --- a/src/Mod/Fem/_CommandMeshNetgenFromShape.py +++ b/src/Mod/Fem/_CommandMeshNetgenFromShape.py @@ -37,7 +37,7 @@ class _CommandMeshNetgenFromShape(FemCommands): # the Fem_MeshNetgenFromShape command definition def __init__(self): super(_CommandMeshNetgenFromShape, self).__init__() - self.resources = {'Pixmap': 'fem-fem-mesh-netgen-from-shape', + self.resources = {'Pixmap': 'fem-femmesh-netgen-from-shape', 'MenuText': QtCore.QT_TRANSLATE_NOOP("Fem_MeshFromShape", "FEM mesh from shape by Netgen"), 'ToolTip': QtCore.QT_TRANSLATE_NOOP("Fem_MeshFromShape", "Create a FEM volume mesh from a solid or face shape by Netgen internal mesher")} self.is_active = 'with_part_feature' diff --git a/src/Mod/Fem/_ViewProviderFemMeshGmsh.py b/src/Mod/Fem/_ViewProviderFemMeshGmsh.py index 981bfeed624c..34d4239aa7e2 100644 --- a/src/Mod/Fem/_ViewProviderFemMeshGmsh.py +++ b/src/Mod/Fem/_ViewProviderFemMeshGmsh.py @@ -38,7 +38,7 @@ def __init__(self, vobj): vobj.Proxy = self def getIcon(self): - return ":/icons/fem-fem-mesh-from-shape.svg" + return ":/icons/fem-femmesh-from-shape.svg" def attach(self, vobj): self.ViewObject = vobj From f9bc29fbc51bc00818d6caff6693ee6c4360c69b Mon Sep 17 00:00:00 2001 From: Bernd Hahnebach Date: Mon, 28 Nov 2016 01:17:50 +0100 Subject: [PATCH 3/6] FEM: gmsh mesh tool, use gmsh names for properties --- src/Mod/Fem/FemGmshTools.py | 12 ++++++------ src/Mod/Fem/_FemMeshGmsh.py | 8 ++++---- src/Mod/Fem/_TaskPanelFemMeshGmsh.py | 8 ++++---- 3 files changed, 14 insertions(+), 14 deletions(-) diff --git a/src/Mod/Fem/FemGmshTools.py b/src/Mod/Fem/FemGmshTools.py index 26fd8d728f75..1923003c5159 100644 --- a/src/Mod/Fem/FemGmshTools.py +++ b/src/Mod/Fem/FemGmshTools.py @@ -48,13 +48,13 @@ def __init__(self, gmsh_mesh_obj, analysis=None): # part to mesh self.part_obj = self.mesh_obj.Part - # clmax, ElementSizeMax: float, 0.0 = 1e+22 - self.clmax = Units.Quantity(self.mesh_obj.ElementSizeMax).Value + # clmax, CharacteristicLengthMax: float, 0.0 = 1e+22 + self.clmax = Units.Quantity(self.mesh_obj.CharacteristicLengthMax).Value if self.clmax == 0.0: self.clmax = 1e+22 - # clmin, ElementSizeMin: float - self.clmin = Units.Quantity(self.mesh_obj.ElementSizeMin).Value + # clmin, CharacteristicLengthMin: float + self.clmin = Units.Quantity(self.mesh_obj.CharacteristicLengthMin).Value # order, ElementOrder: ['Auto', '1st', '2nd'] self.order = self.mesh_obj.ElementOrder @@ -71,8 +71,8 @@ def __init__(self, gmsh_mesh_obj, analysis=None): def create_mesh(self): print("\nWe gone start GMSH FEM mesh run!") print(' Part to mesh: Name --> ' + self.part_obj.Name + ', Label --> ' + self.part_obj.Label + ', ShapeType --> ' + self.part_obj.Shape.ShapeType) - print(' ElementSizeMax: ' + str(self.clmax)) - print(' ElementSizeMin: ' + str(self.clmin)) + print(' CharacteristicLengthMax: ' + str(self.clmax)) + print(' CharacteristicLengthMin: ' + str(self.clmin)) print(' ElementOrder: ' + self.order) self.get_dimension() self.get_tmp_file_paths() diff --git a/src/Mod/Fem/_FemMeshGmsh.py b/src/Mod/Fem/_FemMeshGmsh.py index ea29ad8a30d3..7e1279e04bdc 100644 --- a/src/Mod/Fem/_FemMeshGmsh.py +++ b/src/Mod/Fem/_FemMeshGmsh.py @@ -44,11 +44,11 @@ def __init__(self, obj): obj.addProperty("App::PropertyLink", "Part", "FEM Mesh", "Part object to mesh") obj.Part = None - obj.addProperty("App::PropertyLength", "ElementSizeMax", "FEM Mesh Params", "Max mesh element size (0.0 = infinity)") - obj.ElementSizeMax = 0.0 # will be 1e+22 + obj.addProperty("App::PropertyLength", "CharacteristicLengthMax", "FEM Mesh Params", "Max mesh element size (0.0 = infinity)") + obj.CharacteristicLengthMax = 0.0 # will be 1e+22 - obj.addProperty("App::PropertyLength", "ElementSizeMin", "FEM Mesh Params", "Min mesh element size") - obj.ElementSizeMin = 0.0 + obj.addProperty("App::PropertyLength", "CharacteristicLengthMin", "FEM Mesh Params", "Min mesh element size") + obj.CharacteristicLengthMin = 0.0 obj.addProperty("App::PropertyEnumeration", "ElementDimension", "FEM Mesh Params", "Dimension of mesh elements (Auto = according ShapeType of part to mesh)") obj.ElementDimension = _FemMeshGmsh.known_element_dimensions diff --git a/src/Mod/Fem/_TaskPanelFemMeshGmsh.py b/src/Mod/Fem/_TaskPanelFemMeshGmsh.py index 0a9d0a42a204..0b4b4913e896 100644 --- a/src/Mod/Fem/_TaskPanelFemMeshGmsh.py +++ b/src/Mod/Fem/_TaskPanelFemMeshGmsh.py @@ -78,14 +78,14 @@ def clicked(self, button): self.run_gmsh() def get_mesh_params(self): - self.clmax = self.mesh_obj.ElementSizeMax - self.clmin = self.mesh_obj.ElementSizeMin + self.clmax = self.mesh_obj.CharacteristicLengthMax + self.clmin = self.mesh_obj.CharacteristicLengthMin self.order = self.mesh_obj.ElementOrder self.dimension = self.mesh_obj.ElementDimension def set_mesh_params(self): - self.mesh_obj.ElementSizeMax = self.clmax - self.mesh_obj.ElementSizeMin = self.clmin + self.mesh_obj.CharacteristicLengthMax = self.clmax + self.mesh_obj.CharacteristicLengthMin = self.clmin self.mesh_obj.ElementOrder = self.order self.mesh_obj.ElementDimension = self.dimension From cb14a50aec08bc07c9a0b0dab59d598c2910bcd7 Mon Sep 17 00:00:00 2001 From: Bernd Hahnebach Date: Mon, 28 Nov 2016 01:17:54 +0100 Subject: [PATCH 4/6] FEM: gmsh mesh tool, add some more properties to adjust gmsh mesh --- src/Mod/Fem/FemGmshTools.py | 80 +++++++++++++++++++++++++++++++++---- src/Mod/Fem/_FemMeshGmsh.py | 38 ++++++++++++++---- 2 files changed, 103 insertions(+), 15 deletions(-) diff --git a/src/Mod/Fem/FemGmshTools.py b/src/Mod/Fem/FemGmshTools.py index 1923003c5159..8257a08f80de 100644 --- a/src/Mod/Fem/FemGmshTools.py +++ b/src/Mod/Fem/FemGmshTools.py @@ -56,18 +56,60 @@ def __init__(self, gmsh_mesh_obj, analysis=None): # clmin, CharacteristicLengthMin: float self.clmin = Units.Quantity(self.mesh_obj.CharacteristicLengthMin).Value - # order, ElementOrder: ['Auto', '1st', '2nd'] + # order + # known_element_orders = ['Automatic', '1st', '2nd'] self.order = self.mesh_obj.ElementOrder if self.order == '1st': self.order = '1' - elif self.order == 'Auto' or self.order == '2nd': + elif self.order == 'Automatic' or self.order == '2nd': self.order = '2' else: print('Error in order') - # dimension, ElementDimension: ['Auto', '1D', '2D', '3D'] + # dimension + # known_element_dimensions = ['Automatic', '1D', '2D', '3D'] self.dimension = self.mesh_obj.ElementDimension + # Algorithm2D + # known_mesh_algorithm_2D = ['Automatic', 'MeshAdapt', 'Delaunay', 'Frontal', 'BAMG', 'DelQuad'] + algo2D = self.mesh_obj.Algorithm2D + if algo2D == 'Automatic': + self.algorithm2D = '2' + elif algo2D == 'MeshAdapt': + self.algorithm2D = '1' + elif algo2D == 'Delaunay': + self.algorithm2D = '5' + elif algo2D == 'Frontal': + self.algorithm2D = '6' + elif algo2D == 'BAMG': + self.algorithm2D = '7' + elif algo2D == 'DelQuad': + self.algorithm2D = '8' + else: + self.algorithm2D = '2' + + # Algorithm3D + # known_mesh_algorithm_3D = ['Automatic', 'Delaunay', 'New Delaunay', 'Frontal', 'Frontal Delaunay', 'Frontal Hex', 'MMG3D', 'R-tree'] + algo3D = self.mesh_obj.Algorithm2D + if algo3D == 'Automatic': + self.algorithm3D = '1' + elif algo3D == 'Delaunay': + self.algorithm3D = '1' + elif algo3D == 'New Delaunay': + self.algorithm3D = '2' + elif algo3D == 'Frontal': + self.algorithm3D = '4' + elif algo3D == 'Frontal Delaunay': + self.algorithm3D = '5' + elif algo3D == 'Frontal Hex': + self.algorithm3D = '6' + elif algo3D == 'MMG3D': + self.algorithm3D = '7' + elif algo3D == 'R-tree': + self.algorithm3D = '9' + else: + self.algorithm3D = '1' + def create_mesh(self): print("\nWe gone start GMSH FEM mesh run!") print(' Part to mesh: Name --> ' + self.part_obj.Name + ', Label --> ' + self.part_obj.Label + ', ShapeType --> ' + self.part_obj.Shape.ShapeType) @@ -88,7 +130,7 @@ def get_dimension(self): # Dimension # GMSH uses the hightest availabe. # A use case for not auto would be a surface (2D) mesh of a solid or other 3d shape - if self.dimension == 'Auto': + if self.dimension == 'Automatic': shty = self.part_obj.Shape.ShapeType if shty == 'Solid' or shty == 'CompSolid': # print('Found: ' + shty) @@ -217,9 +259,33 @@ def write_geo(self): geo.write("Mesh.CharacteristicLengthMax = " + str(self.clmax) + ";\n") geo.write("Mesh.CharacteristicLengthMin = " + str(self.clmin) + ";\n") geo.write("Mesh.ElementOrder = " + self.order + ";\n") - geo.write("//Mesh.HighOrderOptimize = 1;\n") # but does not really work, in GUI it does - geo.write("Mesh.Algorithm3D = 1;\n") - geo.write("Mesh.Algorithm = 2;\n") + geo.write("\n") + geo.write("//optimize the mesh\n") + # GMSH tetra optimizer + if hasattr(self.mesh_obj, 'OptimizeStd') and self.mesh_obj.OptimizeStd is True: + geo.write("Mesh.Optimize = 1;\n") + else: + geo.write("Mesh.Optimize = 0;\n") + # Netgen optimizer in GMSH + if hasattr(self.mesh_obj, 'OptimizeNetgen') and self.mesh_obj.OptimizeNetgen is True: + geo.write("Mesh.OptimizeNetgen = 1;\n") + else: + geo.write("Mesh.OptimizeNetgen = 0;\n") + # hight order mesh optimizing + if hasattr(self.mesh_obj, 'OptimizeNetgen') and self.mesh_obj.OptimizeNetgen is True: + geo.write("Mesh.HighOrderOptimize = 1; //probably needs more lines off adjustment in geo file\n") + else: + geo.write("Mesh.HighOrderOptimize = 0; //probably needs more lines off adjustment in geo file\n") + geo.write("\n") + if hasattr(self.mesh_obj, 'RecombineAll') and self.mesh_obj.RecombineAll is True: + geo.write("//recombine\n") + geo.write("Mesh.RecombineAll = 1;\n") + geo.write("\n") + geo.write("//mesh algorithm\n") + geo.write("Mesh.Algorithm = " + self.algorithm2D + ";\n") + geo.write("Mesh.Algorithm3D = " + self.algorithm3D + ";\n") + geo.write("\n") + geo.write("//more\n") geo.write("Mesh " + self.dimension + ";\n") geo.write("Mesh.Format = 2;\n") # unv if self.analysis and self.group_elements: diff --git a/src/Mod/Fem/_FemMeshGmsh.py b/src/Mod/Fem/_FemMeshGmsh.py index 7e1279e04bdc..978749c9ef20 100644 --- a/src/Mod/Fem/_FemMeshGmsh.py +++ b/src/Mod/Fem/_FemMeshGmsh.py @@ -33,8 +33,10 @@ class _FemMeshGmsh(): """ # they will be used from the task panel too, thus they need to be outside of the __init__ - known_element_dimensions = ['Auto', '1D', '2D', '3D'] - known_element_orders = ['Auto', '1st', '2nd'] + known_element_dimensions = ['Automatic', '1D', '2D', '3D'] + known_element_orders = ['Automatic', '1st', '2nd'] + known_mesh_algorithm_2D = ['Automatic', 'MeshAdapt', 'Delaunay', 'Frontal', 'BAMG', 'DelQuad'] + known_mesh_algorithm_3D = ['Automatic', 'Delaunay', 'New Delaunay', 'Frontal', 'Frontal Delaunay', 'Frontal Hex', 'MMG3D', 'R-tree'] def __init__(self, obj): self.Type = "FemMeshGmsh" @@ -44,19 +46,39 @@ def __init__(self, obj): obj.addProperty("App::PropertyLink", "Part", "FEM Mesh", "Part object to mesh") obj.Part = None - obj.addProperty("App::PropertyLength", "CharacteristicLengthMax", "FEM Mesh Params", "Max mesh element size (0.0 = infinity)") + obj.addProperty("App::PropertyLength", "CharacteristicLengthMax", "FEM GMSH Mesh Params", "Max mesh element size (0.0 = infinity)") obj.CharacteristicLengthMax = 0.0 # will be 1e+22 - obj.addProperty("App::PropertyLength", "CharacteristicLengthMin", "FEM Mesh Params", "Min mesh element size") + obj.addProperty("App::PropertyLength", "CharacteristicLengthMin", "FEM GMSH Mesh Params", "Min mesh element size") obj.CharacteristicLengthMin = 0.0 - obj.addProperty("App::PropertyEnumeration", "ElementDimension", "FEM Mesh Params", "Dimension of mesh elements (Auto = according ShapeType of part to mesh)") + obj.addProperty("App::PropertyEnumeration", "ElementDimension", "FEM GMSH Mesh Params", "Dimension of mesh elements (Auto = according ShapeType of part to mesh)") obj.ElementDimension = _FemMeshGmsh.known_element_dimensions - obj.ElementDimension = 'Auto' # according ShapeType of Part to mesh + obj.ElementDimension = 'Automatic' # according ShapeType of Part to mesh - obj.addProperty("App::PropertyEnumeration", "ElementOrder", "FEM Mesh Params", "Order of mesh elements (Auto will be 2nd)") + obj.addProperty("App::PropertyEnumeration", "ElementOrder", "FEM GMSH Mesh Params", "Order of mesh elements (Auto will be 2nd)") obj.ElementOrder = _FemMeshGmsh.known_element_orders - obj.ElementOrder = 'Auto' # = 2nd + obj.ElementOrder = 'Automatic' # = 2nd + + obj.addProperty("App::PropertyBool", "OptimizeStd", "FEM GMSH Mesh Params", "Optimize tetra elements") + obj.OptimizeStd = False + + obj.addProperty("App::PropertyBool", "OptimizeNetgen", "FEM GMSH Mesh Params", "Optimize tetra elements by use of Netgen") + obj.OptimizeNetgen = False + + obj.addProperty("App::PropertyBool", "HighOrderOptimize", "FEM GMSH Mesh Params", "Optimize hight order meshes") + obj.HighOrderOptimize = False + + obj.addProperty("App::PropertyBool", "RecombineAll", "FEM GMSH Mesh Params", "Apply recombination algorithm to all surfaces") + obj.RecombineAll = False + + obj.addProperty("App::PropertyEnumeration", "Algorithm2D", "FEM GMSH Mesh Params", "mesh algorithm 2D") + obj.Algorithm2D = _FemMeshGmsh.known_mesh_algorithm_2D + obj.Algorithm2D = 'Automatic' # ? + + obj.addProperty("App::PropertyEnumeration", "Algorithm3D", "FEM GMSH Mesh Params", "mesh algorithm 3D") + obj.Algorithm3D = _FemMeshGmsh.known_mesh_algorithm_3D + obj.Algorithm3D = 'Automatic' # ? def execute(self, obj): return From ddef153ef1d674ce090d7bc597439111e8584971 Mon Sep 17 00:00:00 2001 From: Bernd Hahnebach Date: Mon, 28 Nov 2016 01:17:58 +0100 Subject: [PATCH 5/6] FEM: gmsh mesh tool, fix endless loop in task panel --- src/Mod/Fem/_TaskPanelFemMeshGmsh.py | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/src/Mod/Fem/_TaskPanelFemMeshGmsh.py b/src/Mod/Fem/_TaskPanelFemMeshGmsh.py index 0b4b4913e896..8aae5d84872b 100644 --- a/src/Mod/Fem/_TaskPanelFemMeshGmsh.py +++ b/src/Mod/Fem/_TaskPanelFemMeshGmsh.py @@ -141,7 +141,12 @@ def run_gmsh(self): import FemGmshTools gmsh_mesh = FemGmshTools.FemGmshTools(self.obj, self.analysis) self.console_log("Start GMSH ...") - error = gmsh_mesh.create_mesh() + error = '' + try: + error = gmsh_mesh.create_mesh() + except: + import sys + print("Unexpected error when creating mesh: ", sys.exc_info()[0]) if error: print(error) self.console_log('GMSH had warnings ...') From 9154825889c5a99aeb1b7167bd11d03d277ffd4a Mon Sep 17 00:00:00 2001 From: Bernd Hahnebach Date: Mon, 28 Nov 2016 01:18:08 +0100 Subject: [PATCH 6/6] FEM: gmsh mesh tool, add different mesh element size for Shape elements --- src/Mod/Fem/FemGmshTools.py | 27 ++++++++++++++++++++++- src/Mod/Fem/FemMeshTools.py | 43 +++++++++++++++++++++++++++++++++++++ src/Mod/Fem/_FemMeshGmsh.py | 2 ++ 3 files changed, 71 insertions(+), 1 deletion(-) diff --git a/src/Mod/Fem/FemGmshTools.py b/src/Mod/Fem/FemGmshTools.py index 8257a08f80de..22b3aef954fc 100644 --- a/src/Mod/Fem/FemGmshTools.py +++ b/src/Mod/Fem/FemGmshTools.py @@ -223,6 +223,23 @@ def get_group_data(self): print(self.group_elements) else: print(' NO group meshing.') + self.ele_length_map = self.mesh_obj.CharacteristicLengthMap + self.ele_node_map = {} + if self.ele_length_map: + import FemMeshTools + print(self.ele_length_map) + self.ele_node_map = {} + for e in self.ele_length_map: + if not e.startswith('Solid'): + # Face, Edge, Vertex + ele_shape = self.part_obj.Shape.getElement(e) + else: + # Solid + ele_shape_index = int(e.lstrip('Solid')) - 1 + ele_shape = self.part_obj.Shape.Solids[ele_shape_index] + ele_vertexes = FemMeshTools.get_vertexes_by_element(self.part_obj.Shape, ele_shape) + self.ele_node_map[e] = ele_vertexes + print(self.ele_node_map) def write_part_file(self): self.part_obj.Shape.exportBrep(self.temp_file_geometry) @@ -232,7 +249,7 @@ def write_geo(self): geo.write('Merge "' + self.temp_file_geometry + '";\n') geo.write("\n") if self.analysis and self.group_elements: - print(' We gone have found elements to make mesh groups for!') + print(' We gone have found elements to make mesh groups for.') geo.write("// group data\n") # we use the element name of FreeCAD which starts with 1 (example: 'Face1'), same as GMSH for group in self.group_elements: @@ -256,6 +273,14 @@ def write_geo(self): # print(ele_nr) geo.write('Physical ' + physical_type + '("' + group + '") = {' + ele_nr + '};\n') geo.write("\n") + if self.ele_length_map: + # we use the index FreeCAD which starts with 0, we need to add 1 for the index in GMSH + geo.write("// Characteristic Length according CharacteristicLengthMap\n") + for e in self.ele_length_map: + ele_nodes = (''.join((str(n + 1) + ', ') for n in self.ele_node_map[e])).rstrip(', ') + geo.write("// " + e + "\n") + geo.write("Characteristic Length { " + ele_nodes + " } = " + self.ele_length_map[e] + ";\n") + geo.write("\n") geo.write("Mesh.CharacteristicLengthMax = " + str(self.clmax) + ";\n") geo.write("Mesh.CharacteristicLengthMin = " + str(self.clmin) + ";\n") geo.write("Mesh.ElementOrder = " + self.order + ";\n") diff --git a/src/Mod/Fem/FemMeshTools.py b/src/Mod/Fem/FemMeshTools.py index 42ace7d64e26..25141ccab8d0 100644 --- a/src/Mod/Fem/FemMeshTools.py +++ b/src/Mod/Fem/FemMeshTools.py @@ -1162,6 +1162,49 @@ def find_element_in_shape(aShape, anElement): FreeCAD.Console.PrintError('Compound is not supported.\n') +def get_vertexes_by_element(aShape, anElement): + # we gone extent the method find_element_in_shape and return the vertexes + # import Part + ele_vertexes = [] + ele_st = anElement.ShapeType + if ele_st == 'Solid' or ele_st == 'CompSolid': + for index, solid in enumerate(aShape.Solids): + if is_same_geometry(solid, anElement): + for vele in aShape.Solids[index].Vertexes: + for i, v in enumerate(aShape.Vertexes): + if vele.isSame(v): # use isSame, because orientation could be different + ele_vertexes.append(i) + # print(' ' + str(sorted(ele_vertexes))) + return ele_vertexes + FreeCAD.Console.PrintError('Error, Solid ' + str(anElement) + ' not found in: ' + str(aShape) + '\n') + elif ele_st == 'Face' or ele_st == 'Shell': + for index, face in enumerate(aShape.Faces): + if is_same_geometry(face, anElement): + for vele in aShape.Faces[index].Vertexes: + for i, v in enumerate(aShape.Vertexes): + if vele.isSame(v): # use isSame, because orientation could be different + ele_vertexes.append(i) + # print(' ' + str(sorted(ele_vertexes))) + return ele_vertexes + elif ele_st == 'Edge' or ele_st == 'Wire': + for index, edge in enumerate(aShape.Edges): + if is_same_geometry(edge, anElement): + for vele in aShape.Edges[index].Vertexes: + for i, v in enumerate(aShape.Vertexes): + if vele.isSame(v): # use isSame, because orientation could be different + ele_vertexes.append(i) + # print(' ' + str(sorted(ele_vertexes))) + return ele_vertexes + elif ele_st == 'Vertex': + for index, vertex in enumerate(aShape.Vertexes): + if is_same_geometry(vertex, anElement): + ele_vertexes.append(index) + # print(' ' + str(sorted(ele_vertexes))) + return ele_vertexes + elif ele_st == 'Compound': + FreeCAD.Console.PrintError('Compound is not supported.\n') + + def is_same_geometry(shape1, shape2): # the vertexes and the CenterOfMass are compared # it is a hack, but I do not know any better ! diff --git a/src/Mod/Fem/_FemMeshGmsh.py b/src/Mod/Fem/_FemMeshGmsh.py index 978749c9ef20..5cfe46711a36 100644 --- a/src/Mod/Fem/_FemMeshGmsh.py +++ b/src/Mod/Fem/_FemMeshGmsh.py @@ -80,6 +80,8 @@ def __init__(self, obj): obj.Algorithm3D = _FemMeshGmsh.known_mesh_algorithm_3D obj.Algorithm3D = 'Automatic' # ? + obj.addProperty("App::PropertyMap", "CharacteristicLengthMap", "FEM GMSH Mesh Params", "Map of CharacteristicLength of Shape elements") + def execute(self, obj): return