# SPDX-License-Identifier: LGPL-2.1-or-later # *************************************************************************** # * Copyright (c) 2024 Mario Passaglia * # * * # * This file is part of FreeCAD. * # * * # * FreeCAD is free software: you can redistribute it and/or modify it * # * under the terms of the GNU Lesser General Public License as * # * published by the Free Software Foundation, either version 2.1 of the * # * License, or (at your option) any later version. * # * * # * FreeCAD is distributed in the hope that it will be useful, but * # * WITHOUT ANY WARRANTY; without even the implied warranty of * # * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * # * Lesser General Public License for more details. * # * * # * You should have received a copy of the GNU Lesser General Public * # * License along with FreeCAD. If not, see * # * . * # * * # *************************************************************************** __title__ = "FreeCAD FEM mesh netgen document object" __author__ = "Mario Passaglia" __url__ = "https://www.freecad.org" ## @package mesh_netgen # \ingroup FEM # \brief mesh gmsh object from FreeCAD import Base from . import base_fempythonobject _PropHelper = base_fempythonobject._PropHelper class MeshNetgen(base_fempythonobject.BaseFemPythonObject): """ A Fem::FemMeshShapeBaseObject python type, add Netgen specific properties """ Type = "Fem::FemMeshNetgen" def __init__(self, obj): super().__init__(obj) for prop in self._get_properties(): prop.add_to_object(obj) def _get_properties(self): prop = [] prop.append( _PropHelper( type="App::PropertyLinkList", name="MeshRegionList", group="Base", doc="Refinements of the mesh", value=[], ) ) # mesh parameters prop.append( _PropHelper( type="App::PropertyString", name="Optimize3d", group="Mesh Parameters", doc="3d optimization strategy.\n" + "m: move nodes, M: move nodes, cheap functional\n" + "s: swap faces, c: combine elements, d: divide elements,\n" + "D: divide and join opposite edges, remove element,\n" + "p: plot, no pause, P: plot, Pause,\n" + "h: Histogramm, no pause, H: Histogramm, pause", value="cmdDmustm", ) ) prop.append( _PropHelper( type="App::PropertyIntegerConstraint", name="OptimizationSteps3d", group="Mesh Parameters", doc="Number of 3d optimization steps", value={"value": 3, "min": 0}, ) ) prop.append( _PropHelper( type="App::PropertyString", name="Optimize2d", group="Mesh Parameters", doc="2d optimization strategy.\n" + "s: swap opt 6 lines/node, S: swap optimal elements,\n" + "m: move nodes, p: plot, no pause\n" + "P: plot, pause, c: combine", value="smcmSmcmSmcm", ) ) prop.append( _PropHelper( type="App::PropertyIntegerConstraint", name="OptimizationSteps2d", group="Mesh Parameters", doc="Number of 2d optimization steps", value={"value": 3, "min": 0}, ) ) prop.append( _PropHelper( type="App::PropertyFloat", name="OptimizationErrorPower", group="Mesh Parameters", doc="Power of error to approximate max error optimization", value=2.0, ) ) prop.append( _PropHelper( type="App::PropertyBool", name="BlockFill", group="Mesh Parameters", doc="Do block filling", value=True, ) ) prop.append( _PropHelper( type="App::PropertyLength", name="FillDistance", group="Mesh Parameters", doc="Block filling up to distance", value=0.1, ) ) prop.append( _PropHelper( type="App::PropertyFloatConstraint", name="Safety", group="Mesh Parameters", doc="Radius of local environment (times h)", value={"value": 5.0, "min": 0, "step": 0.1}, ) ) prop.append( _PropHelper( type="App::PropertyFloatConstraint", name="RelinnerSafety", group="Mesh Parameters", doc="Radius of active environment (times h)", value={"value": 3.0, "min": 0, "step": 0.1}, ) ) prop.append( _PropHelper( type="App::PropertyBool", name="LocalH", group="Mesh Parameters", doc="Use local h", value=True, ) ) prop.append( _PropHelper( type="App::PropertyBool", name="UseLocalH", group="Mesh Parameters", doc="Use local H", value=True, ) ) prop.append( _PropHelper( type="App::PropertyFloatConstraint", name="GrowthRate", group="Mesh Parameters", doc="Grading for local h", value={"value": 0.3, "min": 0, "step": 0.1}, ) ) prop.append( _PropHelper( type="App::PropertyBool", name="Delaunay", group="Mesh Parameters", doc="Use Delaunay for 3d meshing", value=True, ) ) prop.append( _PropHelper( type="App::PropertyBool", name="Delaunay2d", group="Mesh Parameters", doc="Use Delaunay for 2d meshing", value=False, ) ) prop.append( _PropHelper( type="App::PropertyLength", name="MaxSize", group="Mesh Parameters", doc="Maximal mesh size", value="1000 mm", ) ) prop.append( _PropHelper( type="App::PropertyLength", name="MinSize", group="Mesh Parameters", doc="Minimal mesh size", value="0 mm", ) ) prop.append( _PropHelper( type="App::PropertyFloatConstraint", name="CloseEdgeFactor", group="Mesh Parameters", doc="Factor to restrict meshing based on close edges", value={"value": 2.0, "min": 0, "step": 0.1}, ) ) prop.append( _PropHelper( type="App::PropertyBool", name="StartInSurface", group="Mesh Parameters", doc="Start surface meshing from everywhere in surface", value=False, ) ) prop.append( _PropHelper( type="App::PropertyBool", name="CheckOverlap", group="Mesh Parameters", doc="Check overlapping surfaces", value=True, ) ) prop.append( _PropHelper( type="App::PropertyBool", name="CheckOverlappingBoundary", group="Mesh Parameters", doc="Check overlapping surface mesh before volume meshing", value=True, ) ) prop.append( _PropHelper( type="App::PropertyBool", name="CheckChartBoundary", group="Mesh Parameters", doc="Check chart boundary", value=True, ) ) prop.append( _PropHelper( type="App::PropertyFloatConstraint", name="CurvatureSafety", group="Mesh Parameters", doc="Safety factor for curvatures (elements per radius)", value={"value": 2.0, "min": 0, "step": 0.1}, ) ) prop.append( _PropHelper( type="App::PropertyFloatConstraint", name="SegmentsPerEdge", group="Mesh Parameters", doc="Minimal number of segments per edge", value={"value": 2.0, "min": 0, "step": 0.1}, ) ) prop.append( _PropHelper( type="App::PropertyFloatConstraint", name="ElementSizeWeight", group="Mesh Parameters", doc="Weight of element size respect to element shape", value={"value": 0.2, "min": 0, "step": 0.1}, ) ) # Netgen meshing steps meshing_step = [ "AnalyzeGeometry", "MeshEdges", "MeshSurface", "OptimizeSurface", "MeshVolume", "OptimizeVolume", ] prop.append( _PropHelper( type="App::PropertyEnumeration", name="StartStep", group="Mesh Parameters", doc="First step", value=meshing_step, ) ) prop.append( _PropHelper( type="App::PropertyEnumeration", name="EndStep", group="Mesh Parameters", doc="Last step", value=meshing_step, ) ) prop.append( _PropHelper( type="App::PropertyIntegerConstraint", name="GiveUpTolerance2d", group="Mesh Parameters", doc="Give up quality class, 2d meshing", value={"value": 200, "min": 0}, ) ) prop.append( _PropHelper( type="App::PropertyIntegerConstraint", name="GiveUpTolerance", group="Mesh Parameters", doc="Give up quality class, 3d meshing", value={"value": 10, "min": 0}, ) ) prop.append( _PropHelper( type="App::PropertyIntegerConstraint", name="GiveUpToleranceOpenQuads", group="Mesh Parameters", doc="Give up quality class, for closing open quads, greater than 100 for free pyramids", value={"value": 15, "min": 0}, ) ) prop.append( _PropHelper( type="App::PropertyIntegerConstraint", name="MaxOuterSteps", group="Mesh Parameters", doc="Maximal outer steps", value={"value": 10, "min": 0}, ) ) prop.append( _PropHelper( type="App::PropertyIntegerConstraint", name="StarShapeClass", group="Mesh Parameters", doc="Class starting star-shape filling", value={"value": 5, "min": 0}, ) ) prop.append( _PropHelper( type="App::PropertyInteger", name="BaseElementNp", group="Mesh Parameters", doc="If non-zero, baseelement must have BaseElementlNp points", value=0, ) ) prop.append( _PropHelper( type="App::PropertyIntegerConstraint", name="Sloppy", group="Mesh Parameters", doc="Quality tolerances are handled less careful", value={"value": 10, "min": 0}, ) ) prop.append( _PropHelper( type="App::PropertyFloatConstraint", name="BadElementLimit", group="Mesh Parameters", doc="Limit for max element angle (150-180)", value={"value": 175, "min": 0}, ) ) prop.append( _PropHelper( type="App::PropertyBool", name="CheckImpossible", group="Mesh Parameters", doc="", value=False, ) ) prop.append( _PropHelper( type="App::PropertyInteger", name="Only3dDomainNr", group="Mesh Parameters", doc="", value=0, ) ) prop.append( _PropHelper( type="App::PropertyBool", name="SecondOrder", group="Mesh Parameters", doc="Second order element meshing", value=True, ) ) prop.append( _PropHelper( type="App::PropertyBool", name="SecondOrderLinear", group="Mesh Parameters", doc="Second order nodes are created by linear interpolation", value=False, ) ) prop.append( _PropHelper( type="App::PropertyIntegerConstraint", name="ElementOrder", group="Mesh Parameters", doc="High order element curvature", value={"value": 1, "min": 1}, ) ) prop.append( _PropHelper( type="App::PropertyBool", name="QuadDominated", group="Mesh Parameters", doc="Quad-dominated surface meshing", value=False, ) ) prop.append( _PropHelper( type="App::PropertyBool", name="TryHexes", group="Mesh Parameters", doc="Try hexahedral elements", value=False, ) ) prop.append( _PropHelper( type="App::PropertyBool", name="InvertTets", group="Mesh Parameters", doc="", value=False, ) ) prop.append( _PropHelper( type="App::PropertyBool", name="InvertTrigs", group="Mesh Parameters", doc="", value=False, ) ) prop.append( _PropHelper( type="App::PropertyEnumeration", name="ZRefine", group="Mesh Parameters", doc="Z-refinement for extruded shapes", value=["No", "Regular", "Custom"], ) ) prop.append( _PropHelper( type="App::PropertyVector", name="ZRefineDirection", group="Mesh Parameters", doc="Z-refinement direction", value=Base.Vector(0, 0, 1), ) ) prop.append( _PropHelper( type="App::PropertyFloatList", name="ZRefineSize", group="Mesh Parameters", doc="Z-refinement size given as a fraction of the shape size.\n" + "For a regular partition only one value is needed", value=[ 0.1, ], ) ) prop.append( _PropHelper( type="App::PropertyBool", name="ParallelMeshing", group="Mesh Parameters", doc="Use parallel meshing", value=True, ) ) prop.append( _PropHelper( type="App::PropertyBool", name="HealShape", group="Mesh Parameters", doc="Heal shape before meshing", value=False, ) ) prop.append( _PropHelper( type="App::PropertyBool", name="Glue", group="Mesh Parameters", doc="Glue shapes to get a conformal mesh", value=True, ) ) prop.append( _PropHelper( type="App::PropertyEnumeration", name="Fineness", group="Mesh Parameters", doc="Mesh granularity.\n" + "If differs from UserDefined, uses specific values\n" + "for CurvatureSafety, SegmentsPerEdge, GrowthRate,\n" + "CloseEdgeFactor and OptimizationSteps3d", value=["VeryCoarse", "Coarse", "Moderate", "Fine", "VeryFine", "UserDefined"], ) ) return prop def onChanged(self, obj, prop): if prop == "Fineness": if obj.Fineness != "UserDefined": p = self.get_predef_fineness_params(obj.Fineness) obj.CurvatureSafety = p["curvaturesafety"] obj.SegmentsPerEdge = p["segmentsperedge"] obj.GrowthRate = p["grading"] obj.CloseEdgeFactor = p["closeedgefac"] obj.OptimizationSteps3d = p["optsteps3d"] obj.setPropertyStatus("CurvatureSafety", "ReadOnly") obj.setPropertyStatus("SegmentsPerEdge", "ReadOnly") obj.setPropertyStatus("GrowthRate", "ReadOnly") obj.setPropertyStatus("CloseEdgeFactor", "ReadOnly") obj.setPropertyStatus("OptimizationSteps3d", "ReadOnly") else: obj.setPropertyStatus("CurvatureSafety", "-ReadOnly") obj.setPropertyStatus("SegmentsPerEdge", "-ReadOnly") obj.setPropertyStatus("GrowthRate", "-ReadOnly") obj.setPropertyStatus("CloseEdgeFactor", "-ReadOnly") obj.setPropertyStatus("OptimizationSteps3d", "-ReadOnly") def onDocumentRestored(self, obj): # update old project with new properties for prop in self._get_properties(): try: obj.getPropertyByName(prop.name) except Base.PropertyError: prop.add_to_object(obj) # for StartStep and EndStep set enumeration index from old integer value if prop.name == "StartStep" or prop.name == "EndStep": prop.handle_change_type( obj, "App::PropertyInteger", lambda x: 0 if x <= 1 else 5 if x >= 6 else x - 1 ) # update enum values setattr(obj, prop.name, prop.value) def get_predef_fineness_params(self, fineness): # set specific parameters by fineness params = {} if fineness == "VeryCoarse": params["curvaturesafety"] = 1 params["segmentsperedge"] = 0.3 params["grading"] = 0.7 params["closeedgefac"] = 0.5 params["optsteps3d"] = 5 elif fineness == "Coarse": params["curvaturesafety"] = 1.5 params["segmentsperedge"] = 0.5 params["grading"] = 0.5 params["closeedgefac"] = 1 params["optsteps3d"] = 5 elif fineness == "Moderate": params["curvaturesafety"] = 2 params["segmentsperedge"] = 1 params["grading"] = 0.3 params["closeedgefac"] = 2 params["optsteps3d"] = 5 elif fineness == "Fine": params["curvaturesafety"] = 3 params["segmentsperedge"] = 2 params["grading"] = 0.2 params["closeedgefac"] = 3.5 params["optsteps3d"] = 5 elif fineness == "VeryFine": params["curvaturesafety"] = 5 params["segmentsperedge"] = 3 params["grading"] = 0.1 params["closeedgefac"] = 5 params["optsteps3d"] = 5 elif fineness == "UserDefined": params["curvaturesafety"] = 2 params["segmentsperedge"] = 2 params["grading"] = 0.3 params["closeedgefac"] = 2 params["optsteps3d"] = 3 return params