diff --git a/src/Mod/Fem/FemGmshTools.py b/src/Mod/Fem/FemGmshTools.py index 2b14757360..8f3fbf8409 100644 --- a/src/Mod/Fem/FemGmshTools.py +++ b/src/Mod/Fem/FemGmshTools.py @@ -355,11 +355,15 @@ class FemGmshTools(): FreeCAD.Console.PrintError("The element " + elems + " of the mesh boundary layer " + mr_obj.Name + " has been added to another mesh boudary layer.\n") setting = {} setting['hwall_n'] = Units.Quantity(mr_obj.MinimumThickness).Value - setting['hwall_t'] = setting['hwall_n'] * 5 # tangetial cell dimension setting['ratio'] = mr_obj.GrowthRate - setting['thickness'] = sum([setting['hwall_n'] **i for i in range(mr_obj.NumberOfLayers)]) + setting['thickness'] = sum([setting['hwall_n'] * setting['ratio']**i for i in range(mr_obj.NumberOfLayers)]) + setting['hwall_t'] = setting['thickness'] #setting['hwall_n'] * 5 # tangetial cell dimension + # hfar: cell dimension outside boundary should be set later if some character length is set - setting['hfar'] = setting['thickness'] * 2 # set a value for safety, it may works as background mesh cell size + if self.clmax > setting['thickness'] * 0.8 and self.clmax < setting['thickness'] * 1.6: + setting['hfar'] = self.clmax + else: + setting['hfar'] = setting['thickness'] # set a value for safety, it may works as background mesh cell size # from face name -> face id is done in geo file write up #fan angle setup is not implemented yet if self.dimension == '2': @@ -450,11 +454,17 @@ class FemGmshTools(): geo.write("// " + e + "\n") geo.write("Characteristic Length { " + ele_nodes + " } = " + str(self.ele_length_map[e]) + ";\n") geo.write("\n") + + # boundary layer generation may need special setup of Gmsh properties, set them in Gmsh TaskPanel self.write_boundary_layer(geo) geo.write("// min, max Characteristic Length\n") geo.write("Mesh.CharacteristicLengthMax = " + str(self.clmax) + ";\n") - geo.write("Mesh.CharacteristicLengthMin = " + str(self.clmin) + ";\n") + if len(self.bl_setting_list): + # if minLength must smaller than first layer of boundary_layer, it is safer to set it as zero (defualt value) to avoid error + geo.write("Mesh.CharacteristicLengthMin = " + str(0) + ";\n") + else: + geo.write("Mesh.CharacteristicLengthMin = " + str(self.clmin) + ";\n") geo.write("\n") if hasattr(self.mesh_obj, 'RecombineAll') and self.mesh_obj.RecombineAll is True: geo.write("// other mesh options\n") @@ -480,12 +490,17 @@ class FemGmshTools(): geo.write("// mesh order\n") geo.write("Mesh.ElementOrder = " + self.order + ";\n") geo.write("\n") - geo.write("// mesh algorithm\n") + + geo.write("// mesh algorithm, only a few algorithms are usable with 3D boundary layer generation\n") geo.write("// 2D mesh algorithm (1=MeshAdapt, 2=Automatic, 5=Delaunay, 6=Frontal, 7=BAMG, 8=DelQuad)\n") - geo.write("Mesh.Algorithm = " + self.algorithm2D + ";\n") + if len(self.bl_setting_list) and self.dimension == 3: + geo.write("Mesh.Algorithm = " + 'DelQuad' + ";\n") # Frontal/DelQuad are tested + else: + geo.write("Mesh.Algorithm = " + self.algorithm2D + ";\n") geo.write("// 3D mesh algorithm (1=Delaunay, 2=New Delaunay, 4=Frontal, 5=Frontal Delaunay, 6=Frontal Hex, 7=MMG3D, 9=R-tree)\n") geo.write("Mesh.Algorithm3D = " + self.algorithm3D + ";\n") geo.write("\n") + geo.write("// meshing\n") # remove duplicate vertices, see https://forum.freecadweb.org/viewtopic.php?f=18&t=21571&start=20#p179443 if hasattr(self.mesh_obj, 'CoherenceMesh') and self.mesh_obj.CoherenceMesh is True: diff --git a/src/Mod/Fem/Gui/Resources/Fem.qrc b/src/Mod/Fem/Gui/Resources/Fem.qrc index 3d2b3165f0..ffe30f3ad8 100755 --- a/src/Mod/Fem/Gui/Resources/Fem.qrc +++ b/src/Mod/Fem/Gui/Resources/Fem.qrc @@ -28,6 +28,7 @@ icons/fem-control-solver.svg icons/fem-cylinder.svg icons/fem-data.svg + icons/fem-femmesh-boundary-layer.svg icons/fem-femmesh-clear-mesh.svg icons/fem-femmesh-create-node-by-poly.svg icons/fem-femmesh-from-shape.svg diff --git a/src/Mod/Fem/ObjectsFem.py b/src/Mod/Fem/ObjectsFem.py index bef52adbcf..589f1d2658 100644 --- a/src/Mod/Fem/ObjectsFem.py +++ b/src/Mod/Fem/ObjectsFem.py @@ -319,7 +319,7 @@ def makeSolverZ88(name="Z88"): if FreeCAD.GuiUp: import PyGui._ViewProviderFemSolverZ88 PyGui._ViewProviderFemSolverZ88._ViewProviderFemSolverZ88(obj.ViewObject) - return obj + return obj ''' diff --git a/src/Mod/Fem/PyGui/TaskPanelFemMeshBoundaryLayer.ui b/src/Mod/Fem/PyGui/TaskPanelFemMeshBoundaryLayer.ui index 66ab0c2f95..c32e8a6174 100644 --- a/src/Mod/Fem/PyGui/TaskPanelFemMeshBoundaryLayer.ui +++ b/src/Mod/Fem/PyGui/TaskPanelFemMeshBoundaryLayer.ui @@ -46,14 +46,14 @@ 0 - + 80 20 - 0.0 + 1.0 Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter @@ -108,7 +108,7 @@ 0.100000000000000 - 1.000000000000000 + 1.300000000000000 diff --git a/src/Mod/Fem/PyGui/_TaskPanelFemMeshBoundaryLayer.py b/src/Mod/Fem/PyGui/_TaskPanelFemMeshBoundaryLayer.py index 0460983367..3a5540d484 100644 --- a/src/Mod/Fem/PyGui/_TaskPanelFemMeshBoundaryLayer.py +++ b/src/Mod/Fem/PyGui/_TaskPanelFemMeshBoundaryLayer.py @@ -47,7 +47,7 @@ class _TaskPanelFemMeshBoundaryLayer: QtCore.QObject.connect(self.form.bl_number_of_layers, QtCore.SIGNAL("valueChanged(int)"), self.bl_number_of_layers_changed) QtCore.QObject.connect(self.form.bl_min_thickness, QtCore.SIGNAL("valueChanged(Base::Quantity)"), self.bl_min_thickness_changed) - QtCore.QObject.connect(self.form.bl_growth_rate, QtCore.SIGNAL("valueChanged(float)"), self.bl_growth_rate_changed) + QtCore.QObject.connect(self.form.bl_growth_rate, QtCore.SIGNAL("valueChanged(double)"), self.bl_growth_rate_changed) # becareful of signal signature for QDoubleSpinbox QtCore.QObject.connect(self.form.rb_standard, QtCore.SIGNAL("toggled(bool)"), self.choose_selection_mode_standard) QtCore.QObject.connect(self.form.rb_solid, QtCore.SIGNAL("toggled(bool)"), self.choose_selection_mode_solid) @@ -72,19 +72,17 @@ class _TaskPanelFemMeshBoundaryLayer: self.obj.MinimumThickness = self.bl_min_thickness self.obj.NumberOfLayers = self.bl_number_of_layers self.obj.GrowthRate = self.bl_growth_rate - self.obj.References = self.references def update(self): - 'fills the widgets with ' + 'fills the widgets with data' self.form.bl_min_thickness.setText(self.bl_min_thickness.UserString) self.form.bl_number_of_layers.setValue(self.bl_number_of_layers) self.form.bl_growth_rate.setValue(self.bl_growth_rate) - self.rebuild_list_References() def bl_min_thickness_changed(self, base_quantity_value): - self.bl_min_thicknes = base_quantity_value + self.bl_min_thickness = base_quantity_value def bl_number_of_layers_changed(self, value): self.bl_number_of_layers = value @@ -100,13 +98,14 @@ class _TaskPanelFemMeshBoundaryLayer: FreeCAD.ActiveDocument.recompute() return True - ############### identical to FemMeshRegion ############ def reject(self): if self.sel_server: FreeCADGui.Selection.removeObserver(self.sel_server) FreeCADGui.ActiveDocument.resetEdit() return True + ############### identical to FemMeshRegion ############ + def choose_selection_mode_standard(self, state): self.selection_mode_solid = not state if self.sel_server and not self.selection_mode_solid: diff --git a/src/Mod/Fem/PyObjects/_FemMeshBoundaryLayer.py b/src/Mod/Fem/PyObjects/_FemMeshBoundaryLayer.py index f248d10ff3..b9de1adb8c 100644 --- a/src/Mod/Fem/PyObjects/_FemMeshBoundaryLayer.py +++ b/src/Mod/Fem/PyObjects/_FemMeshBoundaryLayer.py @@ -31,18 +31,30 @@ __url__ = "http://www.freecadweb.org" class _FemMeshBoundaryLayer: "The FemMeshBoundaryLayer object" def __init__(self, obj): - obj.addProperty("App::PropertyInteger", "NumberOfLayers", "MeshBoundaryLayerProperties", + self.Type = "FemMeshBoundaryLayer" + self.Object = obj # keep a ref to the DocObj for nonGui usage + obj.Proxy = self # link between App::DocumentObject to this object + + obj.addProperty("App::PropertyInteger", "NumberOfLayers", "MeshBoundaryLayerProperties", "set number of inflation layers for this boundary") obj.NumberOfLayers = 3 - obj.addProperty("App::PropertyLength", "MinimumThickness", "MeshBoundaryLayerProperties", + + obj.addProperty("App::PropertyLength", "MinimumThickness", "MeshBoundaryLayerProperties", "set minimum thickness,usually the first inflation layer") - obj.addProperty("App::PropertyFloat", "GrowthRate", "MeshBoundaryLayerProperties", + # default to zero, user must specify a proper value for this property + + obj.addProperty("App::PropertyFloat", "GrowthRate", "MeshBoundaryLayerProperties", "set growth rate of inflation layers for smooth transition") - obj.GrowthRate = 1.0 + obj.GrowthRate = 1.5 obj.addProperty("App::PropertyLinkSubList", "References", "MeshBoundaryLayerShapes", "List of FEM mesh region shapes") - obj.Proxy = self - self.Type = "FemMeshBoundaryLayer" def execute(self, obj): return + + def __getstate__(self): + return self.Type + + def __setstate__(self, state): + if state: + self.Type = state