diff --git a/src/Mod/Fem/App/FemMeshShapeObject.cpp b/src/Mod/Fem/App/FemMeshShapeObject.cpp index e6d219a92d..c3558e41d4 100644 --- a/src/Mod/Fem/App/FemMeshShapeObject.cpp +++ b/src/Mod/Fem/App/FemMeshShapeObject.cpp @@ -46,6 +46,22 @@ FemMeshShapeBaseObject::FemMeshShapeBaseObject() Prop_None, "Geometry object, the mesh is made from. The geometry object has to have a Shape." ); + ADD_PROPERTY_TYPE( + Tool, + (Py::Object()), + "FEM Mesh", + App::PropertyType( + App::Prop_Transient | App::Prop_Hidden | App::Prop_ReadOnly | App::Prop_Output + ), + "Tool object for run the mesher" + ); + ADD_PROPERTY_TYPE( + WorkingDirectory, + (""), + "FEM Mesh", + App::PropertyType(App::Prop_Transient | App::Prop_Hidden | App::Prop_Output), + "Mesher working directory" + ); Shape.setScope(LinkScope::Global); } diff --git a/src/Mod/Fem/App/FemMeshShapeObject.h b/src/Mod/Fem/App/FemMeshShapeObject.h index adf08ee618..a9afb94a76 100644 --- a/src/Mod/Fem/App/FemMeshShapeObject.h +++ b/src/Mod/Fem/App/FemMeshShapeObject.h @@ -39,6 +39,8 @@ public: ~FemMeshShapeBaseObject() override; App::PropertyLink Shape; + App::PropertyPythonObject Tool; + App::PropertyPath WorkingDirectory; /// returns the type name of the ViewProvider const char* getViewProviderName() const override diff --git a/src/Mod/Fem/App/FemSolverObject.cpp b/src/Mod/Fem/App/FemSolverObject.cpp index 8a297b91fe..50672e481b 100644 --- a/src/Mod/Fem/App/FemSolverObject.cpp +++ b/src/Mod/Fem/App/FemSolverObject.cpp @@ -50,6 +50,15 @@ FemSolverObject::FemSolverObject() App::PropertyType(App::Prop_Transient | App::Prop_Hidden | App::Prop_Output), "Solver working directory" ); + ADD_PROPERTY_TYPE( + Tool, + (Py::Object()), + "Solver", + App::PropertyType( + App::Prop_Transient | App::Prop_Hidden | App::Prop_ReadOnly | App::Prop_Output + ), + "Tool for run the solver" + ); } FemSolverObject::~FemSolverObject() = default; diff --git a/src/Mod/Fem/App/FemSolverObject.h b/src/Mod/Fem/App/FemSolverObject.h index 191a47a1df..fc03e6652c 100644 --- a/src/Mod/Fem/App/FemSolverObject.h +++ b/src/Mod/Fem/App/FemSolverObject.h @@ -42,6 +42,7 @@ public: ~FemSolverObject() override; App::PropertyLinkList Results; + App::PropertyPythonObject Tool; App::PropertyPath WorkingDirectory; // Attributes are implemented in the FemSolverObjectPython diff --git a/src/Mod/Fem/CMakeLists.txt b/src/Mod/Fem/CMakeLists.txt index 083c07b367..55950ed466 100755 --- a/src/Mod/Fem/CMakeLists.txt +++ b/src/Mod/Fem/CMakeLists.txt @@ -116,6 +116,7 @@ SET(FemExamples_SRCS SET(FemExampleMeshes_SRCS femexamples/meshes/__init__.py + femexamples/meshes/generate_mesh.py femexamples/meshes/mesh_beamsimple_tetra10.py femexamples/meshes/mesh_boxanalysis_tetra10.py femexamples/meshes/mesh_boxes_2_vertikal_tetra10.py @@ -517,6 +518,7 @@ SET(FemTools_SRCS femtools/geomtools.py femtools/membertools.py femtools/migrate_app.py + femtools/objecttools.py femtools/tokrules.py ) diff --git a/src/Mod/Fem/femcommands/commands.py b/src/Mod/Fem/femcommands/commands.py index 3c7e3b0bfc..872e0afd72 100644 --- a/src/Mod/Fem/femcommands/commands.py +++ b/src/Mod/Fem/femcommands/commands.py @@ -29,9 +29,6 @@ __url__ = "https://www.freecad.org" # \ingroup FEM # \brief FreeCAD FEM command definitions -from PySide import QtCore -from PySide import QtGui - import FreeCAD import FreeCADGui from FreeCAD import Qt @@ -1184,51 +1181,11 @@ class _SolverRun(CommandManager): self.tool = None def Activated(self): - if self.selobj.Proxy.Type in ["Fem::SolverCalculiX", "Fem::SolverElmer"]: - try: - QtGui.QApplication.setOverrideCursor(QtCore.Qt.WaitCursor) - self._set_tool() - self._conn(self.tool) - self.tool.prepare() - self.tool.compute() - except Exception as e: - QtGui.QApplication.restoreOverrideCursor() - FreeCAD.Console.PrintError(e) - return + from femsolver.run import run_fem_solver - else: - from femsolver.run import run_fem_solver - - run_fem_solver(self.selobj) - FreeCADGui.Selection.clearSelection() - FreeCAD.ActiveDocument.recompute() - - def _set_tool(self): - match self.selobj.Proxy.Type: - case "Fem::SolverCalculiX": - from femsolver.calculix.calculixtools import CalculiXTools - - self.tool = CalculiXTools(self.selobj) - case "Fem::SolverElmer": - from femsolver.elmer.elmertools import ElmerTools - - self.tool = ElmerTools(self.selobj) - - def _conn(self, tool): - QtCore.QObject.connect( - tool.process, - QtCore.SIGNAL("finished(int, QProcess::ExitStatus)"), - self._process_finished, - ) - - def _process_finished(self, code, status): - if status == QtCore.QProcess.ExitStatus.NormalExit and code == 0: - self.tool.update_properties() - FreeCAD.ActiveDocument.recompute() - QtGui.QApplication.restoreOverrideCursor() - else: - QtGui.QApplication.restoreOverrideCursor() - FreeCAD.Console.PrintError("Process finished with errors. Result not updated\n") + run_fem_solver(self.selobj) + FreeCADGui.Selection.clearSelection() + FreeCAD.ActiveDocument.recompute() class _SolverZ88(CommandManager): diff --git a/src/Mod/Fem/femexamples/boxanalysis_base.py b/src/Mod/Fem/femexamples/boxanalysis_base.py index e90bfce7eb..4899c68f81 100644 --- a/src/Mod/Fem/femexamples/boxanalysis_base.py +++ b/src/Mod/Fem/femexamples/boxanalysis_base.py @@ -29,9 +29,10 @@ import ObjectsFem from .manager import get_meshname from .manager import init_doc +from .meshes import generate_mesh -def setup_boxanalysisbase(doc=None, solvertype="ccxtools"): +def setup_boxanalysisbase(doc=None, solvertype="ccxtools", test_mode=False): # init FreeCAD document if doc is None: @@ -62,21 +63,22 @@ def setup_boxanalysisbase(doc=None, solvertype="ccxtools"): analysis.addObject(material_obj) # mesh - from .meshes.mesh_boxanalysis_tetra10 import create_nodes, create_elements - - fem_mesh = Fem.FemMesh() - control = create_nodes(fem_mesh) - if not control: - FreeCAD.Console.PrintError("Error on creating nodes.\n") - control = create_elements(fem_mesh) - if not control: - FreeCAD.Console.PrintError("Error on creating elements.\n") femmesh_obj = analysis.addObject(ObjectsFem.makeMeshGmsh(doc, get_meshname()))[0] - femmesh_obj.FemMesh = fem_mesh femmesh_obj.Shape = geom_obj femmesh_obj.SecondOrderLinear = False femmesh_obj.CharacteristicLengthMin = "8.0 mm" femmesh_obj.ElementOrder = "2nd" + # generate the mesh + success = False + if not test_mode: + success = generate_mesh.mesh_from_mesher(femmesh_obj, "gmsh") + if not success: + # try to create from existing rough mesh + from .meshes.mesh_boxanalysis_tetra10 import create_nodes, create_elements + + fem_mesh = generate_mesh.mesh_from_existing(create_nodes, create_elements) + femmesh_obj.FemMesh = fem_mesh + doc.recompute() return doc diff --git a/src/Mod/Fem/femexamples/boxanalysis_frequency.py b/src/Mod/Fem/femexamples/boxanalysis_frequency.py index 67628832ac..096cf73c4c 100644 --- a/src/Mod/Fem/femexamples/boxanalysis_frequency.py +++ b/src/Mod/Fem/femexamples/boxanalysis_frequency.py @@ -58,7 +58,7 @@ See forum topic post: ) -def setup(doc=None, solvertype="ccxtools"): +def setup(doc=None, solvertype="ccxtools", test_mode=False): # init FreeCAD document if doc is None: @@ -69,7 +69,7 @@ def setup(doc=None, solvertype="ccxtools"): manager.add_explanation_obj(doc, get_explanation(manager.get_header(get_information()))) # setup box frequency, change solver attributes - doc = setup_boxanalysisbase(doc, solvertype) + doc = setup_boxanalysisbase(doc, solvertype, test_mode) analysis = doc.Analysis # solver diff --git a/src/Mod/Fem/femexamples/boxanalysis_static.py b/src/Mod/Fem/femexamples/boxanalysis_static.py index 3b4eee2c2c..71b7ac37a8 100644 --- a/src/Mod/Fem/femexamples/boxanalysis_static.py +++ b/src/Mod/Fem/femexamples/boxanalysis_static.py @@ -60,7 +60,7 @@ See forum topic post: ) -def setup(doc=None, solvertype="ccxtools"): +def setup(doc=None, solvertype="ccxtools", test_mode=False): # init FreeCAD document if doc is None: @@ -71,7 +71,7 @@ def setup(doc=None, solvertype="ccxtools"): manager.add_explanation_obj(doc, get_explanation(manager.get_header(get_information()))) # setup box static, add a fixed, force and a pressure constraint - doc = setup_boxanalysisbase(doc, solvertype) + doc = setup_boxanalysisbase(doc, solvertype, test_mode) geom_obj = doc.Box analysis = doc.Analysis diff --git a/src/Mod/Fem/femexamples/buckling_lateraltorsionalbuckling.py b/src/Mod/Fem/femexamples/buckling_lateraltorsionalbuckling.py index 49e86961c1..8c53202833 100644 --- a/src/Mod/Fem/femexamples/buckling_lateraltorsionalbuckling.py +++ b/src/Mod/Fem/femexamples/buckling_lateraltorsionalbuckling.py @@ -29,6 +29,7 @@ import ObjectsFem from . import manager from .manager import get_meshname from .manager import init_doc +from .meshes import generate_mesh def get_information(): @@ -177,13 +178,7 @@ def setup(doc=None, solvertype="ccxtools"): # mesh from .meshes.mesh_buckling_ibeam_tria6 import create_nodes, create_elements - fem_mesh = Fem.FemMesh() - control = create_nodes(fem_mesh) - if not control: - FreeCAD.Console.PrintError("Error on creating nodes.\n") - control = create_elements(fem_mesh) - if not control: - FreeCAD.Console.PrintError("Error on creating elements.\n") + fem_mesh = generate_mesh.mesh_from_existing(create_nodes, create_elements) femmesh_obj = analysis.addObject(ObjectsFem.makeMeshGmsh(doc, get_meshname()))[0] femmesh_obj.FemMesh = fem_mesh femmesh_obj.Shape = geom_obj diff --git a/src/Mod/Fem/femexamples/buckling_platebuckling.py b/src/Mod/Fem/femexamples/buckling_platebuckling.py index 0c029412cf..21cb489eb1 100644 --- a/src/Mod/Fem/femexamples/buckling_platebuckling.py +++ b/src/Mod/Fem/femexamples/buckling_platebuckling.py @@ -29,6 +29,7 @@ import ObjectsFem from . import manager from .manager import get_meshname from .manager import init_doc +from .meshes import generate_mesh def get_information(): @@ -150,13 +151,7 @@ def setup(doc=None, solvertype="ccxtools"): # mesh from .meshes.mesh_buckling_plate_tria6 import create_nodes, create_elements - fem_mesh = Fem.FemMesh() - control = create_nodes(fem_mesh) - if not control: - FreeCAD.Console.PrintError("Error on creating nodes.\n") - control = create_elements(fem_mesh) - if not control: - FreeCAD.Console.PrintError("Error on creating elements.\n") + fem_mesh = generate_mesh.mesh_from_existing(create_nodes, create_elements) femmesh_obj = analysis.addObject(ObjectsFem.makeMeshGmsh(doc, get_meshname()))[0] femmesh_obj.FemMesh = fem_mesh femmesh_obj.Shape = geom_obj diff --git a/src/Mod/Fem/femexamples/ccx_buckling_flexuralbuckling.py b/src/Mod/Fem/femexamples/ccx_buckling_flexuralbuckling.py index 9086a72981..84af90ce9a 100644 --- a/src/Mod/Fem/femexamples/ccx_buckling_flexuralbuckling.py +++ b/src/Mod/Fem/femexamples/ccx_buckling_flexuralbuckling.py @@ -30,6 +30,7 @@ import ObjectsFem from . import manager from .manager import get_meshname from .manager import init_doc +from .meshes import generate_mesh def get_information(): @@ -130,13 +131,7 @@ def setup(doc=None, solvertype="ccxtools"): # mesh from .meshes.mesh_flexural_buckling import create_nodes, create_elements - fem_mesh = Fem.FemMesh() - control = create_nodes(fem_mesh) - if not control: - FreeCAD.Console.PrintError("Error on creating nodes.\n") - control = create_elements(fem_mesh) - if not control: - FreeCAD.Console.PrintError("Error on creating elements.\n") + fem_mesh = generate_mesh.mesh_from_existing(create_nodes, create_elements) femmesh_obj = analysis.addObject(ObjectsFem.makeMeshGmsh(doc, get_meshname()))[0] femmesh_obj.FemMesh = fem_mesh femmesh_obj.Shape = geom_obj diff --git a/src/Mod/Fem/femexamples/ccx_cantilever_base_edge.py b/src/Mod/Fem/femexamples/ccx_cantilever_base_edge.py index c3642287cf..2318766682 100644 --- a/src/Mod/Fem/femexamples/ccx_cantilever_base_edge.py +++ b/src/Mod/Fem/femexamples/ccx_cantilever_base_edge.py @@ -29,6 +29,7 @@ import ObjectsFem from .manager import get_meshname from .manager import init_doc +from .meshes import generate_mesh def setup_cantilever_base_edge(doc=None, solvertype="ccxtools"): @@ -121,13 +122,7 @@ def setup_cantilever_base_edge(doc=None, solvertype="ccxtools"): # mesh from .meshes.mesh_canticcx_seg3 import create_nodes, create_elements - fem_mesh = Fem.FemMesh() - control = create_nodes(fem_mesh) - if not control: - FreeCAD.Console.PrintError("Error on creating nodes.\n") - control = create_elements(fem_mesh) - if not control: - FreeCAD.Console.PrintError("Error on creating elements.\n") + fem_mesh = generate_mesh.mesh_from_existing(create_nodes, create_elements) femmesh_obj = analysis.addObject(ObjectsFem.makeMeshGmsh(doc, get_meshname()))[0] femmesh_obj.FemMesh = fem_mesh femmesh_obj.Shape = geom_obj diff --git a/src/Mod/Fem/femexamples/ccx_cantilever_base_face.py b/src/Mod/Fem/femexamples/ccx_cantilever_base_face.py index 6a360c1dd3..b1fca7a92a 100644 --- a/src/Mod/Fem/femexamples/ccx_cantilever_base_face.py +++ b/src/Mod/Fem/femexamples/ccx_cantilever_base_face.py @@ -28,6 +28,7 @@ import ObjectsFem from .manager import get_meshname from .manager import init_doc +from .meshes import generate_mesh def setup_cantilever_base_face(doc=None, solvertype="ccxtools"): @@ -106,13 +107,7 @@ def setup_cantilever_base_face(doc=None, solvertype="ccxtools"): # mesh from .meshes.mesh_canticcx_tria6 import create_nodes, create_elements - fem_mesh = Fem.FemMesh() - control = create_nodes(fem_mesh) - if not control: - FreeCAD.Console.PrintError("Error on creating nodes.\n") - control = create_elements(fem_mesh) - if not control: - FreeCAD.Console.PrintError("Error on creating elements.\n") + fem_mesh = generate_mesh.mesh_from_existing(create_nodes, create_elements) femmesh_obj = analysis.addObject(ObjectsFem.makeMeshGmsh(doc, get_meshname()))[0] femmesh_obj.FemMesh = fem_mesh femmesh_obj.Shape = geom_obj diff --git a/src/Mod/Fem/femexamples/ccx_cantilever_base_solid.py b/src/Mod/Fem/femexamples/ccx_cantilever_base_solid.py index b2ddec593b..2b233279fe 100644 --- a/src/Mod/Fem/femexamples/ccx_cantilever_base_solid.py +++ b/src/Mod/Fem/femexamples/ccx_cantilever_base_solid.py @@ -29,9 +29,10 @@ import ObjectsFem from .manager import get_meshname from .manager import init_doc +from .meshes import generate_mesh -def setup_cantilever_base_solid(doc=None, solvertype="ccxtools"): +def setup_cantilever_base_solid(doc=None, solvertype="ccxtools", test_mode=False): # init FreeCAD document if doc is None: @@ -91,19 +92,20 @@ def setup_cantilever_base_solid(doc=None, solvertype="ccxtools"): analysis.addObject(con_fixed) # mesh - from .meshes.mesh_canticcx_tetra10 import create_nodes, create_elements - - fem_mesh = Fem.FemMesh() - control = create_nodes(fem_mesh) - if not control: - FreeCAD.Console.PrintError("Error on creating nodes.\n") - control = create_elements(fem_mesh) - if not control: - FreeCAD.Console.PrintError("Error on creating elements.\n") femmesh_obj = analysis.addObject(ObjectsFem.makeMeshGmsh(doc, get_meshname()))[0] - femmesh_obj.FemMesh = fem_mesh femmesh_obj.Shape = geom_obj femmesh_obj.SecondOrderLinear = False + # generate the mesh + success = False + if not test_mode: + success = generate_mesh.mesh_from_mesher(femmesh_obj, "gmsh") + if not success: + # try to create from existing rough mesh + from .meshes.mesh_canticcx_tetra10 import create_nodes, create_elements + + fem_mesh = generate_mesh.mesh_from_existing(create_nodes, create_elements) + femmesh_obj.FemMesh = fem_mesh + doc.recompute() return doc diff --git a/src/Mod/Fem/femexamples/ccx_cantilever_ele_hexa20.py b/src/Mod/Fem/femexamples/ccx_cantilever_ele_hexa20.py index 3ff22f19af..f28638f68d 100644 --- a/src/Mod/Fem/femexamples/ccx_cantilever_ele_hexa20.py +++ b/src/Mod/Fem/femexamples/ccx_cantilever_ele_hexa20.py @@ -30,6 +30,7 @@ from . import manager from .ccx_cantilever_faceload import setup as setup_with_faceload from .manager import get_meshname from .manager import init_doc +from .meshes import generate_mesh def get_information(): @@ -38,7 +39,7 @@ def get_information(): "meshtype": "solid", "meshelement": "Hexa20", "constraints": ["fixed", "force"], - "solvers": ["ccxtools", "elmer", "z88"], + "solvers": ["ccxtools", "z88"], # elmer disabled until mesh has groups "material": "solid", "equations": ["mechanical"], } @@ -84,16 +85,8 @@ def setup(doc=None, solvertype="ccxtools"): # load the hexa20 mesh from .meshes.mesh_canticcx_hexa20 import create_nodes, create_elements - new_fem_mesh = Fem.FemMesh() - control = create_nodes(new_fem_mesh) - if not control: - FreeCAD.Console.PrintError("Error on creating nodes.\n") - control = create_elements(new_fem_mesh) - if not control: - FreeCAD.Console.PrintError("Error on creating elements.\n") - - # overwrite mesh with the hexa20 mesh - femmesh_obj.FemMesh = new_fem_mesh + fem_mesh = generate_mesh.mesh_from_existing(create_nodes, create_elements) + femmesh_obj.FemMesh = fem_mesh doc.recompute() return doc diff --git a/src/Mod/Fem/femexamples/ccx_cantilever_ele_quad4.py b/src/Mod/Fem/femexamples/ccx_cantilever_ele_quad4.py index 213af6ea74..90906ec35c 100644 --- a/src/Mod/Fem/femexamples/ccx_cantilever_ele_quad4.py +++ b/src/Mod/Fem/femexamples/ccx_cantilever_ele_quad4.py @@ -29,6 +29,7 @@ from . import manager from .ccx_cantilever_base_face import setup_cantilever_base_face from .manager import get_meshname from .manager import init_doc +from .meshes import generate_mesh def get_information(): @@ -80,16 +81,10 @@ def setup(doc=None, solvertype="ccxtools"): # load the quad4 mesh from .meshes.mesh_canticcx_quad4 import create_nodes, create_elements - new_fem_mesh = Fem.FemMesh() - control = create_nodes(new_fem_mesh) - if not control: - FreeCAD.Console.PrintError("Error on creating nodes.\n") - control = create_elements(new_fem_mesh) - if not control: - FreeCAD.Console.PrintError("Error on creating elements.\n") + fem_mesh = generate_mesh.mesh_from_existing(create_nodes, create_elements) # overwrite mesh with the quad4 mesh - femmesh_obj.FemMesh = new_fem_mesh + femmesh_obj.FemMesh = fem_mesh # set mesh obj parameter femmesh_obj.Shape = geom_obj diff --git a/src/Mod/Fem/femexamples/ccx_cantilever_ele_quad8.py b/src/Mod/Fem/femexamples/ccx_cantilever_ele_quad8.py index 17e0706694..ed655832b4 100644 --- a/src/Mod/Fem/femexamples/ccx_cantilever_ele_quad8.py +++ b/src/Mod/Fem/femexamples/ccx_cantilever_ele_quad8.py @@ -29,6 +29,7 @@ from . import manager from .ccx_cantilever_base_face import setup_cantilever_base_face from .manager import get_meshname from .manager import init_doc +from .meshes import generate_mesh def get_information(): @@ -80,16 +81,10 @@ def setup(doc=None, solvertype="ccxtools"): # load the quad8 mesh from .meshes.mesh_canticcx_quad8 import create_nodes, create_elements - new_fem_mesh = Fem.FemMesh() - control = create_nodes(new_fem_mesh) - if not control: - FreeCAD.Console.PrintError("Error on creating nodes.\n") - control = create_elements(new_fem_mesh) - if not control: - FreeCAD.Console.PrintError("Error on creating elements.\n") + fem_mesh = generate_mesh.mesh_from_existing(create_nodes, create_elements) # overwrite mesh with the quad8 mesh - femmesh_obj.FemMesh = new_fem_mesh + femmesh_obj.FemMesh = fem_mesh # set mesh obj parameter femmesh_obj.Shape = geom_obj diff --git a/src/Mod/Fem/femexamples/ccx_cantilever_ele_seg2.py b/src/Mod/Fem/femexamples/ccx_cantilever_ele_seg2.py index e5565329f0..7b61d5dfff 100644 --- a/src/Mod/Fem/femexamples/ccx_cantilever_ele_seg2.py +++ b/src/Mod/Fem/femexamples/ccx_cantilever_ele_seg2.py @@ -29,6 +29,7 @@ from . import manager from .ccx_cantilever_base_edge import setup_cantilever_base_edge from .manager import get_meshname from .manager import init_doc +from .meshes import generate_mesh def get_information(): @@ -80,16 +81,10 @@ def setup(doc=None, solvertype="ccxtools"): # load the seg2 mesh from .meshes.mesh_canticcx_seg2 import create_nodes, create_elements - new_fem_mesh = Fem.FemMesh() - control = create_nodes(new_fem_mesh) - if not control: - FreeCAD.Console.PrintError("Error on creating nodes.\n") - control = create_elements(new_fem_mesh) - if not control: - FreeCAD.Console.PrintError("Error on creating elements.\n") + fem_mesh = generate_mesh.mesh_from_existing(create_nodes, create_elements) # overwrite mesh with the seg2 mesh - femmesh_obj.FemMesh = new_fem_mesh + femmesh_obj.FemMesh = fem_mesh # set mesh obj parameter femmesh_obj.Shape = geom_obj diff --git a/src/Mod/Fem/femexamples/ccx_cantilever_ele_tetra4.py b/src/Mod/Fem/femexamples/ccx_cantilever_ele_tetra4.py index 5e167354d3..b4879e8906 100644 --- a/src/Mod/Fem/femexamples/ccx_cantilever_ele_tetra4.py +++ b/src/Mod/Fem/femexamples/ccx_cantilever_ele_tetra4.py @@ -28,6 +28,7 @@ from . import manager from .ccx_cantilever_faceload import setup as setup_with_faceload from .manager import get_meshname from .manager import init_doc +from .meshes import generate_mesh def get_information(): @@ -52,8 +53,7 @@ from femexamples.ccx_cantilever_ele_tetra4 import setup setup() -Tetra4 elements. There are really a lot needed thus mesh is cleared. -Mesh before run the example. +Cantilever modeled with tetra4 volume elements ... """ @@ -89,5 +89,8 @@ def setup(doc=None, solvertype="ccxtools"): femmesh_obj.CharacteristicLengthMax = "150.0 mm" femmesh_obj.CharacteristicLengthMin = "150.0 mm" + # generate the mesh + generate_mesh.mesh_from_mesher(femmesh_obj, "gmsh") + doc.recompute() return doc diff --git a/src/Mod/Fem/femexamples/ccx_cantilever_ele_tria3.py b/src/Mod/Fem/femexamples/ccx_cantilever_ele_tria3.py index bbc17eacb6..844e70a368 100644 --- a/src/Mod/Fem/femexamples/ccx_cantilever_ele_tria3.py +++ b/src/Mod/Fem/femexamples/ccx_cantilever_ele_tria3.py @@ -29,6 +29,7 @@ from . import manager from .ccx_cantilever_base_face import setup_cantilever_base_face from .manager import get_meshname from .manager import init_doc +from .meshes import generate_mesh def get_information(): @@ -80,16 +81,10 @@ def setup(doc=None, solvertype="ccxtools"): # load the tria3 mesh from .meshes.mesh_canticcx_tria3 import create_nodes, create_elements - new_fem_mesh = Fem.FemMesh() - control = create_nodes(new_fem_mesh) - if not control: - FreeCAD.Console.PrintError("Error on creating nodes.\n") - control = create_elements(new_fem_mesh) - if not control: - FreeCAD.Console.PrintError("Error on creating elements.\n") + fem_mesh = generate_mesh.mesh_from_existing(create_nodes, create_elements) # overwrite mesh with the tria3 mesh - femmesh_obj.FemMesh = new_fem_mesh + femmesh_obj.FemMesh = fem_mesh # set mesh obj parameter femmesh_obj.Shape = geom_obj diff --git a/src/Mod/Fem/femexamples/ccx_cantilever_faceload.py b/src/Mod/Fem/femexamples/ccx_cantilever_faceload.py index 46658dcd9a..a6f7a39b28 100644 --- a/src/Mod/Fem/femexamples/ccx_cantilever_faceload.py +++ b/src/Mod/Fem/femexamples/ccx_cantilever_faceload.py @@ -58,7 +58,7 @@ See forum topic post: ) -def setup(doc=None, solvertype="ccxtools"): +def setup(doc=None, solvertype="ccxtools", test_mode=False): # init FreeCAD document if doc is None: @@ -69,7 +69,7 @@ def setup(doc=None, solvertype="ccxtools"): manager.add_explanation_obj(doc, get_explanation(manager.get_header(get_information()))) # setup CalculiX cantilever - doc = setup_cantilever_base_solid(doc, solvertype) + doc = setup_cantilever_base_solid(doc, solvertype, test_mode) analysis = doc.Analysis geom_obj = doc.Box diff --git a/src/Mod/Fem/femexamples/ccx_cantilever_nodeload.py b/src/Mod/Fem/femexamples/ccx_cantilever_nodeload.py index b2e2a30e8a..40ca90e1c6 100644 --- a/src/Mod/Fem/femexamples/ccx_cantilever_nodeload.py +++ b/src/Mod/Fem/femexamples/ccx_cantilever_nodeload.py @@ -58,7 +58,7 @@ See forum topic post: ) -def setup(doc=None, solvertype="ccxtools"): +def setup(doc=None, solvertype="ccxtools", test_mode=False): # init FreeCAD document if doc is None: @@ -69,7 +69,7 @@ def setup(doc=None, solvertype="ccxtools"): manager.add_explanation_obj(doc, get_explanation(manager.get_header(get_information()))) # setup CalculiX cantilever, apply 9 MN on the 4 nodes of the front end face - doc = setup_cantilever_base_solid(doc, solvertype) + doc = setup_cantilever_base_solid(doc, solvertype, test_mode) analysis = doc.Analysis geom_obj = doc.Box diff --git a/src/Mod/Fem/femexamples/ccx_cantilever_prescribeddisplacement.py b/src/Mod/Fem/femexamples/ccx_cantilever_prescribeddisplacement.py index 8ed6cdfde0..e453b2c3ef 100644 --- a/src/Mod/Fem/femexamples/ccx_cantilever_prescribeddisplacement.py +++ b/src/Mod/Fem/femexamples/ccx_cantilever_prescribeddisplacement.py @@ -58,7 +58,7 @@ See forum topic post: ) -def setup(doc=None, solvertype="ccxtools"): +def setup(doc=None, solvertype="ccxtools", test_mode=False): if solvertype == "z88": # constraint displacement is not supported for Z88 @@ -75,7 +75,7 @@ def setup(doc=None, solvertype="ccxtools"): # setup CalculiX cantilever # apply a prescribed displacement of 250 mm in -z on the front end face - doc = setup_cantilever_base_solid(doc, solvertype) + doc = setup_cantilever_base_solid(doc, solvertype, test_mode) analysis = doc.Analysis geom_obj = doc.Box diff --git a/src/Mod/Fem/femexamples/ccx_disc_cyclic_symm_centrif.py b/src/Mod/Fem/femexamples/ccx_disc_cyclic_symm_centrif.py index a9c3ed639e..8845c84fa7 100644 --- a/src/Mod/Fem/femexamples/ccx_disc_cyclic_symm_centrif.py +++ b/src/Mod/Fem/femexamples/ccx_disc_cyclic_symm_centrif.py @@ -30,6 +30,7 @@ import ObjectsFem from . import manager from .manager import get_meshname from .manager import init_doc +from .meshes import generate_mesh def get_information(): @@ -169,10 +170,7 @@ def setup(doc=None, solvertype="ccxtools"): femmesh_obj.ViewObject.Visibility = False # generate the mesh - from femmesh import gmshtools - - gmsh_mesh = gmshtools.GmshTools(femmesh_obj, analysis) - gmsh_mesh.create_mesh() + generate_mesh.mesh_from_mesher(femmesh_obj, "gmsh") doc.recompute() return doc diff --git a/src/Mod/Fem/femexamples/ccx_pipe_pressure_2D.py b/src/Mod/Fem/femexamples/ccx_pipe_pressure_2D.py index 7f05aa380e..58f6c08927 100644 --- a/src/Mod/Fem/femexamples/ccx_pipe_pressure_2D.py +++ b/src/Mod/Fem/femexamples/ccx_pipe_pressure_2D.py @@ -29,6 +29,7 @@ import ObjectsFem from . import manager from .manager import get_meshname from .manager import init_doc +from .meshes import generate_mesh def get_information(): @@ -144,10 +145,7 @@ def setup(doc=None, solvertype="ccxtools"): femmesh_obj.ViewObject.Visibility = False # generate the mesh - from femmesh import gmshtools - - gmsh_mesh = gmshtools.GmshTools(femmesh_obj, analysis) - gmsh_mesh.create_mesh() + generate_mesh.mesh_from_mesher(femmesh_obj, "gmsh") doc.recompute() return doc diff --git a/src/Mod/Fem/femexamples/ccx_rigid_body.py b/src/Mod/Fem/femexamples/ccx_rigid_body.py index 42241f0478..a392cdd1a1 100644 --- a/src/Mod/Fem/femexamples/ccx_rigid_body.py +++ b/src/Mod/Fem/femexamples/ccx_rigid_body.py @@ -30,6 +30,7 @@ import ObjectsFem from . import manager from .manager import get_meshname from .manager import init_doc +from .meshes import generate_mesh def get_information(): @@ -138,14 +139,7 @@ def setup(doc=None, solvertype="ccxtools"): femmesh_obj.ViewObject.Visibility = False # generate the mesh - from femmesh import gmshtools - - gmsh_mesh = gmshtools.GmshTools(femmesh_obj, analysis) - try: - error = gmsh_mesh.create_mesh() - except Exception: - error = sys.exc_info()[1] - FreeCAD.Console.PrintError(f"Unexpected error when creating mesh: {error}\n") + generate_mesh.mesh_from_mesher(femmesh_obj, "gmsh") doc.recompute() return doc diff --git a/src/Mod/Fem/femexamples/constraint_centrif.py b/src/Mod/Fem/femexamples/constraint_centrif.py index fd625ffeac..fd466c2e55 100644 --- a/src/Mod/Fem/femexamples/constraint_centrif.py +++ b/src/Mod/Fem/femexamples/constraint_centrif.py @@ -34,6 +34,7 @@ import ObjectsFem from . import manager from .manager import get_meshname from .manager import init_doc +from .meshes import generate_mesh def get_information(): @@ -184,13 +185,7 @@ def setup(doc=None, solvertype="ccxtools"): # mesh from .meshes.mesh_constraint_centrif_tetra10 import create_nodes, create_elements - fem_mesh = Fem.FemMesh() - control = create_nodes(fem_mesh) - if not control: - FreeCAD.Console.PrintError("Error on creating nodes.\n") - control = create_elements(fem_mesh) - if not control: - FreeCAD.Console.PrintError("Error on creating elements.\n") + fem_mesh = generate_mesh.mesh_from_existing(create_nodes, create_elements) femmesh_obj = analysis.addObject(ObjectsFem.makeMeshGmsh(doc, get_meshname()))[0] femmesh_obj.FemMesh = fem_mesh femmesh_obj.Shape = geom_obj diff --git a/src/Mod/Fem/femexamples/constraint_contact_shell_shell.py b/src/Mod/Fem/femexamples/constraint_contact_shell_shell.py index 55e6bf0af6..092494885b 100644 --- a/src/Mod/Fem/femexamples/constraint_contact_shell_shell.py +++ b/src/Mod/Fem/femexamples/constraint_contact_shell_shell.py @@ -33,6 +33,7 @@ import ObjectsFem from . import manager from .manager import get_meshname from .manager import init_doc +from .meshes import generate_mesh def get_information(): @@ -204,13 +205,7 @@ def setup(doc=None, solvertype="ccxtools"): # mesh from .meshes.mesh_contact_tube_tube_tria3 import create_nodes, create_elements - fem_mesh = Fem.FemMesh() - control = create_nodes(fem_mesh) - if not control: - FreeCAD.Console.PrintError("Error on creating nodes.\n") - control = create_elements(fem_mesh) - if not control: - FreeCAD.Console.PrintError("Error on creating elements.\n") + fem_mesh = generate_mesh.mesh_from_existing(create_nodes, create_elements) femmesh_obj = analysis.addObject(ObjectsFem.makeMeshGmsh(doc, get_meshname()))[0] femmesh_obj.FemMesh = fem_mesh femmesh_obj.Shape = geom_obj diff --git a/src/Mod/Fem/femexamples/constraint_contact_solid_solid.py b/src/Mod/Fem/femexamples/constraint_contact_solid_solid.py index 5f7ed8b8b8..9d1f06ba57 100644 --- a/src/Mod/Fem/femexamples/constraint_contact_solid_solid.py +++ b/src/Mod/Fem/femexamples/constraint_contact_solid_solid.py @@ -34,6 +34,7 @@ import ObjectsFem from . import manager from .manager import get_meshname from .manager import init_doc +from .meshes import generate_mesh def get_information(): @@ -189,13 +190,7 @@ def setup(doc=None, solvertype="ccxtools"): create_elements, ) - fem_mesh = Fem.FemMesh() - control = create_nodes(fem_mesh) - if not control: - FreeCAD.Console.PrintError("Error on creating nodes.\n") - control = create_elements(fem_mesh) - if not control: - FreeCAD.Console.PrintError("Error on creating elements.\n") + fem_mesh = generate_mesh.mesh_from_existing(create_nodes, create_elements) femmesh_obj = analysis.addObject(ObjectsFem.makeMeshGmsh(doc, get_meshname()))[0] femmesh_obj.FemMesh = fem_mesh femmesh_obj.Shape = geom_obj diff --git a/src/Mod/Fem/femexamples/constraint_section_print.py b/src/Mod/Fem/femexamples/constraint_section_print.py index c474b9b342..8174aa63c4 100644 --- a/src/Mod/Fem/femexamples/constraint_section_print.py +++ b/src/Mod/Fem/femexamples/constraint_section_print.py @@ -40,6 +40,7 @@ import ObjectsFem from . import manager from .manager import get_meshname from .manager import init_doc +from .meshes import generate_mesh def get_information(): @@ -263,13 +264,7 @@ def setup(doc=None, solvertype="ccxtools"): # mesh from .meshes.mesh_section_print_tetra10 import create_nodes, create_elements - fem_mesh = Fem.FemMesh() - control = create_nodes(fem_mesh) - if not control: - FreeCAD.Console.PrintError("Error on creating nodes.\n") - control = create_elements(fem_mesh) - if not control: - FreeCAD.Console.PrintError("Error on creating elements.\n") + fem_mesh = generate_mesh.mesh_from_existing(create_nodes, create_elements) femmesh_obj = analysis.addObject(ObjectsFem.makeMeshGmsh(doc, get_meshname()))[0] femmesh_obj.FemMesh = fem_mesh femmesh_obj.Shape = geom_obj diff --git a/src/Mod/Fem/femexamples/constraint_selfweight_cantilever.py b/src/Mod/Fem/femexamples/constraint_selfweight_cantilever.py index e56a79da18..752c1b8206 100644 --- a/src/Mod/Fem/femexamples/constraint_selfweight_cantilever.py +++ b/src/Mod/Fem/femexamples/constraint_selfweight_cantilever.py @@ -29,6 +29,7 @@ import ObjectsFem from . import manager from .manager import get_meshname from .manager import init_doc +from .meshes import generate_mesh def get_information(): @@ -64,7 +65,7 @@ max deformation = 576.8 mm ) -def setup(doc=None, solvertype="ccxtools"): +def setup(doc=None, solvertype="ccxtools", test_mode=False): # init FreeCAD document if doc is None: @@ -116,6 +117,7 @@ def setup(doc=None, solvertype="ccxtools"): mat["PoissonRatio"] = "0.30" mat["Density"] = "7900 kg/m^3" material_obj.Material = mat + material_obj.References = [(geom_obj, "Solid1")] analysis.addObject(material_obj) # constraint fixed @@ -129,19 +131,20 @@ def setup(doc=None, solvertype="ccxtools"): analysis.addObject(con_selfweight) # mesh - from .meshes.mesh_selfweight_cantilever_tetra10 import create_nodes, create_elements - - fem_mesh = Fem.FemMesh() - control = create_nodes(fem_mesh) - if not control: - FreeCAD.Console.PrintError("Error on creating nodes.\n") - control = create_elements(fem_mesh) - if not control: - FreeCAD.Console.PrintError("Error on creating elements.\n") femmesh_obj = analysis.addObject(ObjectsFem.makeMeshGmsh(doc, get_meshname()))[0] - femmesh_obj.FemMesh = fem_mesh femmesh_obj.Shape = geom_obj femmesh_obj.SecondOrderLinear = False + # generate the mesh + success = False + if not test_mode: + success = generate_mesh.mesh_from_mesher(femmesh_obj, "gmsh") + if not success: + # try to create from existing rough mesh + from .meshes.mesh_selfweight_cantilever_tetra10 import create_nodes, create_elements + + fem_mesh = generate_mesh.mesh_from_existing(create_nodes, create_elements) + femmesh_obj.FemMesh = fem_mesh + doc.recompute() return doc diff --git a/src/Mod/Fem/femexamples/constraint_tie.py b/src/Mod/Fem/femexamples/constraint_tie.py index 2001ad8ff7..6112e2b3e9 100644 --- a/src/Mod/Fem/femexamples/constraint_tie.py +++ b/src/Mod/Fem/femexamples/constraint_tie.py @@ -34,6 +34,7 @@ import ObjectsFem from . import manager from .manager import get_meshname from .manager import init_doc +from .meshes import generate_mesh def get_information(): @@ -160,13 +161,7 @@ def setup(doc=None, solvertype="ccxtools"): # mesh from .meshes.mesh_constraint_tie_tetra10 import create_nodes, create_elements - fem_mesh = Fem.FemMesh() - control = create_nodes(fem_mesh) - if not control: - FreeCAD.Console.PrintError("Error on creating nodes.\n") - control = create_elements(fem_mesh) - if not control: - FreeCAD.Console.PrintError("Error on creating elements.\n") + fem_mesh = generate_mesh.mesh_from_existing(create_nodes, create_elements) femmesh_obj = analysis.addObject(ObjectsFem.makeMeshGmsh(doc, get_meshname()))[0] femmesh_obj.FemMesh = fem_mesh femmesh_obj.Shape = geom_obj diff --git a/src/Mod/Fem/femexamples/constraint_transform_beam_hinged.py b/src/Mod/Fem/femexamples/constraint_transform_beam_hinged.py index e395909684..1d004cf2a1 100644 --- a/src/Mod/Fem/femexamples/constraint_transform_beam_hinged.py +++ b/src/Mod/Fem/femexamples/constraint_transform_beam_hinged.py @@ -34,6 +34,7 @@ import ObjectsFem from . import manager from .manager import get_meshname from .manager import init_doc +from .meshes import generate_mesh def get_information(): @@ -175,13 +176,7 @@ def setup(doc=None, solvertype="ccxtools"): # mesh from .meshes.mesh_transform_beam_hinged_tetra10 import create_nodes, create_elements - fem_mesh = Fem.FemMesh() - control = create_nodes(fem_mesh) - if not control: - FreeCAD.Console.PrintError("Error on creating nodes.\n") - control = create_elements(fem_mesh) - if not control: - FreeCAD.Console.PrintError("Error on creating elements.\n") + fem_mesh = generate_mesh.mesh_from_existing(create_nodes, create_elements) femmesh_obj = analysis.addObject(ObjectsFem.makeMeshGmsh(doc, get_meshname()))[0] femmesh_obj.FemMesh = fem_mesh femmesh_obj.Shape = geom_obj diff --git a/src/Mod/Fem/femexamples/constraint_transform_torque.py b/src/Mod/Fem/femexamples/constraint_transform_torque.py index 800d49e21e..0cff0050fc 100644 --- a/src/Mod/Fem/femexamples/constraint_transform_torque.py +++ b/src/Mod/Fem/femexamples/constraint_transform_torque.py @@ -42,6 +42,7 @@ from Part import makeLine from . import manager from .manager import get_meshname from .manager import init_doc +from .meshes import generate_mesh def get_information(): @@ -164,13 +165,7 @@ def setup(doc=None, solvertype="ccxtools"): # mesh from .meshes.mesh_transform_torque_tetra10 import create_nodes, create_elements - fem_mesh = Fem.FemMesh() - control = create_nodes(fem_mesh) - if not control: - FreeCAD.Console.PrintError("Error on creating nodes.\n") - control = create_elements(fem_mesh) - if not control: - FreeCAD.Console.PrintError("Error on creating elements.\n") + fem_mesh = generate_mesh.mesh_from_existing(create_nodes, create_elements) femmesh_obj = analysis.addObject(ObjectsFem.makeMeshGmsh(doc, get_meshname()))[0] femmesh_obj.FemMesh = fem_mesh femmesh_obj.Shape = geom_obj diff --git a/src/Mod/Fem/femexamples/elmer_nonguitutorial01_eigenvalue_of_elastic_beam.py b/src/Mod/Fem/femexamples/elmer_nonguitutorial01_eigenvalue_of_elastic_beam.py index 5104cd4200..343e6e51b5 100644 --- a/src/Mod/Fem/femexamples/elmer_nonguitutorial01_eigenvalue_of_elastic_beam.py +++ b/src/Mod/Fem/femexamples/elmer_nonguitutorial01_eigenvalue_of_elastic_beam.py @@ -29,6 +29,7 @@ import ObjectsFem from . import manager from .manager import get_meshname from .manager import init_doc +from .meshes import generate_mesh def get_information(): @@ -125,21 +126,19 @@ def setup(doc=None, solvertype="elmer"): analysis.addObject(con_fixed) # mesh - from .meshes.mesh_eigenvalue_of_elastic_beam_tetra10 import create_nodes - from .meshes.mesh_eigenvalue_of_elastic_beam_tetra10 import create_elements - - fem_mesh = Fem.FemMesh() - control = create_nodes(fem_mesh) - if not control: - FreeCAD.Console.PrintError("Error on creating nodes.\n") - control = create_elements(fem_mesh) - if not control: - FreeCAD.Console.PrintError("Error on creating elements.\n") femmesh_obj = analysis.addObject(ObjectsFem.makeMeshGmsh(doc, get_meshname()))[0] - femmesh_obj.FemMesh = fem_mesh femmesh_obj.Shape = geom_obj femmesh_obj.SecondOrderLinear = False femmesh_obj.CharacteristicLengthMax = "40.80 mm" + # generate the mesh + success = generate_mesh.mesh_from_mesher(femmesh_obj, "gmsh") + if not success: + # try to create from existing mesh + from .meshes.mesh_eigenvalue_of_elastic_beam_tetra10 import create_nodes, create_elements + + fem_mesh = generate_mesh.mesh_from_existing(create_nodes, create_elements) + femmesh_obj.FemMesh = fem_mesh + doc.recompute() return doc diff --git a/src/Mod/Fem/femexamples/equation_deformation_spring_elmer.py b/src/Mod/Fem/femexamples/equation_deformation_spring_elmer.py index 47497fb45a..c387252558 100644 --- a/src/Mod/Fem/femexamples/equation_deformation_spring_elmer.py +++ b/src/Mod/Fem/femexamples/equation_deformation_spring_elmer.py @@ -32,6 +32,7 @@ import Sketcher from . import manager from .manager import get_meshname from .manager import init_doc +from .meshes import generate_mesh def get_information(): @@ -198,14 +199,7 @@ def setup(doc=None, solvertype="elmer"): femmesh_obj.ViewObject.Visibility = False # generate the mesh - from femmesh import gmshtools - - gmsh_mesh = gmshtools.GmshTools(femmesh_obj, analysis) - try: - error = gmsh_mesh.create_mesh() - except Exception: - error = sys.exc_info()[1] - FreeCAD.Console.PrintError(f"Unexpected error when creating mesh: {error}\n") + generate_mesh.mesh_from_mesher(femmesh_obj, "gmsh") doc.recompute() return doc diff --git a/src/Mod/Fem/femexamples/equation_electrostatics_capacitance_two_balls.py b/src/Mod/Fem/femexamples/equation_electrostatics_capacitance_two_balls.py index 78eebc1fa4..e7e02cfe90 100644 --- a/src/Mod/Fem/femexamples/equation_electrostatics_capacitance_two_balls.py +++ b/src/Mod/Fem/femexamples/equation_electrostatics_capacitance_two_balls.py @@ -33,6 +33,7 @@ import ObjectsFem from . import manager from .manager import get_meshname from .manager import init_doc +from .meshes import generate_mesh def get_information(): @@ -177,28 +178,15 @@ def setup(doc=None, solvertype="elmer"): mesh_region.ViewObject.Visibility = False # generate the mesh - from femmesh import gmshtools - - gmsh_mesh = gmshtools.GmshTools(femmesh_obj, analysis) - try: - error = gmsh_mesh.create_mesh() - except Exception: - error = sys.exc_info()[1] - FreeCAD.Console.PrintError(f"Unexpected error when creating mesh: {error}\n") - if error: + success = generate_mesh.mesh_from_mesher(femmesh_obj, "gmsh") + if not success: # try to create from existing rough mesh from .meshes.mesh_capacitance_two_balls_tetra10 import ( create_nodes, create_elements, ) - fem_mesh = Fem.FemMesh() - control = create_nodes(fem_mesh) - if not control: - FreeCAD.Console.PrintError("Error on creating nodes.\n") - control = create_elements(fem_mesh) - if not control: - FreeCAD.Console.PrintError("Error on creating elements.\n") + fem_mesh = generate_mesh.mesh_from_existing(create_nodes, create_elements) femmesh_obj.FemMesh = fem_mesh doc.recompute() diff --git a/src/Mod/Fem/femexamples/equation_electrostatics_capacitance_two_balls_ccx.py b/src/Mod/Fem/femexamples/equation_electrostatics_capacitance_two_balls_ccx.py index f290873433..b421cb0506 100644 --- a/src/Mod/Fem/femexamples/equation_electrostatics_capacitance_two_balls_ccx.py +++ b/src/Mod/Fem/femexamples/equation_electrostatics_capacitance_two_balls_ccx.py @@ -34,6 +34,7 @@ import ObjectsFem from . import manager from .manager import get_meshname from .manager import init_doc +from .meshes import generate_mesh def get_information(): @@ -182,28 +183,15 @@ def setup(doc=None, solvertype="calculix"): mesh_region.ViewObject.Visibility = False # generate the mesh - from femmesh import gmshtools - - gmsh_mesh = gmshtools.GmshTools(femmesh_obj, analysis) - try: - error = gmsh_mesh.create_mesh() - except Exception: - error = sys.exc_info()[1] - FreeCAD.Console.PrintError(f"Unexpected error when creating mesh: {error}\n") - if error: + success = generate_mesh.mesh_from_mesher(femmesh_obj, "gmsh") + if not success: # try to create from existing rough mesh from .meshes.mesh_capacitance_two_balls_tetra10 import ( create_nodes, create_elements, ) - fem_mesh = Fem.FemMesh() - control = create_nodes(fem_mesh) - if not control: - FreeCAD.Console.PrintError("Error on creating nodes.\n") - control = create_elements(fem_mesh) - if not control: - FreeCAD.Console.PrintError("Error on creating elements.\n") + fem_mesh = generate_mesh.mesh_from_existing(create_nodes, create_elements) femmesh_obj.FemMesh = fem_mesh doc.recompute() diff --git a/src/Mod/Fem/femexamples/equation_electrostatics_electricforce_elmer_nongui6.py b/src/Mod/Fem/femexamples/equation_electrostatics_electricforce_elmer_nongui6.py index e69043aaa2..c3913efc60 100644 --- a/src/Mod/Fem/femexamples/equation_electrostatics_electricforce_elmer_nongui6.py +++ b/src/Mod/Fem/femexamples/equation_electrostatics_electricforce_elmer_nongui6.py @@ -36,6 +36,7 @@ import Sketcher from . import manager from .manager import get_meshname from .manager import init_doc +from .meshes import generate_mesh def get_information(): @@ -44,7 +45,7 @@ def get_information(): "meshtype": "solid", "meshelement": "Tet10", "constraints": ["electrostatic potential"], - "solvers": ["elmer"], + "solvers": ["calculix", "elmer"], "material": "fluid", "equations": ["electrostatic"], } @@ -178,6 +179,9 @@ def setup(doc=None, solvertype="elmer"): solver_obj = ObjectsFem.makeSolverElmer(doc, "SolverElmer") ObjectsFem.makeEquationElectrostatic(doc, solver_obj) ObjectsFem.makeEquationElectricforce(doc, solver_obj) + elif solvertype == "calculix": + solver_obj = ObjectsFem.makeSolverCalculiX(doc, "SolverCalculiX") + solver_obj.AnalysisType = "electromagnetic" else: FreeCAD.Console.PrintWarning( "Unknown or unsupported solver type: {}. " @@ -213,12 +217,7 @@ def setup(doc=None, solvertype="elmer"): # constraint potential 1V name_pot2 = "ElectrostaticPotential2" con_elect_pot2 = ObjectsFem.makeConstraintElectrostaticPotential(doc, name_pot2) - con_elect_pot2.References = [ - (geom_obj, "Face4"), - (geom_obj, "Face5"), - (geom_obj, "Face6"), - (geom_obj, "Face11"), - ] + con_elect_pot2.References = [(geom_obj, "Face4")] con_elect_pot2.Potential = "1 V" con_elect_pot2.CapacitanceBody = 2 con_elect_pot2.CapacitanceBodyEnabled = True @@ -245,29 +244,7 @@ def setup(doc=None, solvertype="elmer"): mesh_region.ViewObject.Visibility = False # generate the mesh - from femmesh import gmshtools - - gmsh_mesh = gmshtools.GmshTools(femmesh_obj, analysis) - try: - error = gmsh_mesh.create_mesh() - except Exception: - error = sys.exc_info()[1] - FreeCAD.Console.PrintError(f"Unexpected error when creating mesh: {error}\n") - if error: - # try to create from existing rough mesh - from .meshes.mesh_electricforce_elmer_nongui6_tetra10 import ( - create_nodes, - create_elements, - ) - - fem_mesh = Fem.FemMesh() - control = create_nodes(fem_mesh) - if not control: - FreeCAD.Console.PrintError("Error on creating nodes.\n") - control = create_elements(fem_mesh) - if not control: - FreeCAD.Console.PrintError("Error on creating elements.\n") - femmesh_obj.FemMesh = fem_mesh + generate_mesh.mesh_from_mesher(femmesh_obj, "gmsh") doc.recompute() return doc diff --git a/src/Mod/Fem/femexamples/equation_flow_elmer_2D.py b/src/Mod/Fem/femexamples/equation_flow_elmer_2D.py index df958bcb9c..e36e2d26cb 100644 --- a/src/Mod/Fem/femexamples/equation_flow_elmer_2D.py +++ b/src/Mod/Fem/femexamples/equation_flow_elmer_2D.py @@ -34,6 +34,7 @@ from BOPTools import SplitFeatures from . import manager from .manager import get_meshname from .manager import init_doc +from .meshes import generate_mesh def get_information(): @@ -269,14 +270,7 @@ def setup(doc=None, solvertype="elmer"): mesh_region.ViewObject.Visibility = False # generate the mesh - from femmesh import gmshtools - - gmsh_mesh = gmshtools.GmshTools(femmesh_obj, analysis) - try: - error = gmsh_mesh.create_mesh() - except Exception: - error = sys.exc_info()[1] - FreeCAD.Console.PrintError(f"Unexpected error when creating mesh: {error}\n") + generate_mesh.mesh_from_mesher(femmesh_obj, "gmsh") doc.recompute() return doc diff --git a/src/Mod/Fem/femexamples/equation_flow_initial_elmer_2D.py b/src/Mod/Fem/femexamples/equation_flow_initial_elmer_2D.py index 2b82ae1b89..2ecd0bc430 100644 --- a/src/Mod/Fem/femexamples/equation_flow_initial_elmer_2D.py +++ b/src/Mod/Fem/femexamples/equation_flow_initial_elmer_2D.py @@ -34,6 +34,7 @@ from BOPTools import SplitFeatures from . import manager from .manager import get_meshname from .manager import init_doc +from .meshes import generate_mesh def get_information(): @@ -277,14 +278,7 @@ def setup(doc=None, solvertype="elmer"): mesh_region.ViewObject.Visibility = False # generate the mesh - from femmesh import gmshtools - - gmsh_mesh = gmshtools.GmshTools(femmesh_obj, analysis) - try: - error = gmsh_mesh.create_mesh() - except Exception: - error = sys.exc_info()[1] - FreeCAD.Console.PrintError(f"Unexpected error when creating mesh: {error}\n") + generate_mesh.mesh_from_mesher(femmesh_obj, "gmsh") doc.recompute() return doc diff --git a/src/Mod/Fem/femexamples/equation_flow_turbulent_elmer_2D.py b/src/Mod/Fem/femexamples/equation_flow_turbulent_elmer_2D.py index 41965c1c11..f2ae46f297 100644 --- a/src/Mod/Fem/femexamples/equation_flow_turbulent_elmer_2D.py +++ b/src/Mod/Fem/femexamples/equation_flow_turbulent_elmer_2D.py @@ -34,6 +34,7 @@ from BOPTools import SplitFeatures from . import manager from .manager import get_meshname from .manager import init_doc +from .meshes import generate_mesh def get_information(): @@ -275,14 +276,7 @@ def setup(doc=None, solvertype="elmer"): mesh_region.ViewObject.Visibility = False # generate the mesh - from femmesh import gmshtools - - gmsh_mesh = gmshtools.GmshTools(femmesh_obj, analysis) - try: - error = gmsh_mesh.create_mesh() - except Exception: - error = sys.exc_info()[1] - FreeCAD.Console.PrintError(f"Unexpected error when creating mesh: {error}\n") + generate_mesh.mesh_from_mesher(femmesh_obj, "gmsh") doc.recompute() return doc diff --git a/src/Mod/Fem/femexamples/equation_flux_elmer.py b/src/Mod/Fem/femexamples/equation_flux_elmer.py index 67b38c99d0..5c43c11130 100644 --- a/src/Mod/Fem/femexamples/equation_flux_elmer.py +++ b/src/Mod/Fem/femexamples/equation_flux_elmer.py @@ -30,6 +30,7 @@ import ObjectsFem from . import manager from .manager import get_meshname from .manager import init_doc +from .meshes import generate_mesh def get_information(): @@ -158,14 +159,7 @@ def setup(doc=None, solvertype="elmer"): femmesh_obj.ViewObject.Visibility = False # generate the mesh - from femmesh import gmshtools - - gmsh_mesh = gmshtools.GmshTools(femmesh_obj, analysis) - try: - error = gmsh_mesh.create_mesh() - except Exception: - error = sys.exc_info()[1] - FreeCAD.Console.PrintError(f"Unexpected error when creating mesh: {error}\n") + generate_mesh.mesh_from_mesher(femmesh_obj, "gmsh") doc.recompute() return doc diff --git a/src/Mod/Fem/femexamples/equation_magnetodynamics_2D_elmer.py b/src/Mod/Fem/femexamples/equation_magnetodynamics_2D_elmer.py index 1571d16a39..5c70d93339 100644 --- a/src/Mod/Fem/femexamples/equation_magnetodynamics_2D_elmer.py +++ b/src/Mod/Fem/femexamples/equation_magnetodynamics_2D_elmer.py @@ -33,6 +33,7 @@ from BOPTools import SplitFeatures from . import manager from .manager import get_meshname from .manager import init_doc +from .meshes import generate_mesh def get_information(): @@ -274,14 +275,7 @@ def setup(doc=None, solvertype="elmer"): mesh_region.ViewObject.Visibility = False # generate the mesh - from femmesh import gmshtools - - gmsh_mesh = gmshtools.GmshTools(femmesh_obj, analysis) - try: - error = gmsh_mesh.create_mesh() - except Exception: - error = sys.exc_info()[1] - FreeCAD.Console.PrintError(f"Unexpected error when creating mesh: {error}\n") + generate_mesh.mesh_from_mesher(femmesh_obj, "gmsh") doc.recompute() return doc diff --git a/src/Mod/Fem/femexamples/equation_magnetodynamics_elmer.py b/src/Mod/Fem/femexamples/equation_magnetodynamics_elmer.py index fe5c592696..d47ab542d9 100644 --- a/src/Mod/Fem/femexamples/equation_magnetodynamics_elmer.py +++ b/src/Mod/Fem/femexamples/equation_magnetodynamics_elmer.py @@ -32,6 +32,7 @@ from BasicShapes import Shapes from . import manager from .manager import get_meshname from .manager import init_doc +from .meshes import generate_mesh def get_information(): @@ -211,29 +212,7 @@ def setup(doc=None, solvertype="elmer"): mesh_region.ViewObject.Visibility = False # generate the mesh - from femmesh import gmshtools - - gmsh_mesh = gmshtools.GmshTools(femmesh_obj, analysis) - try: - error = gmsh_mesh.create_mesh() - except Exception: - error = sys.exc_info()[1] - FreeCAD.Console.PrintError(f"Unexpected error when creating mesh: {error}\n") - if error: - # try to create from existing rough mesh - from .meshes.mesh_capacitance_two_balls_tetra10 import ( - create_nodes, - create_elements, - ) - - fem_mesh = Fem.FemMesh() - control = create_nodes(fem_mesh) - if not control: - FreeCAD.Console.PrintError("Error on creating nodes.\n") - control = create_elements(fem_mesh) - if not control: - FreeCAD.Console.PrintError("Error on creating elements.\n") - femmesh_obj.FemMesh = fem_mesh + generate_mesh.mesh_from_mesher(femmesh_obj, "gmsh") doc.recompute() return doc diff --git a/src/Mod/Fem/femexamples/equation_magnetostatics_2D_elmer.py b/src/Mod/Fem/femexamples/equation_magnetostatics_2D_elmer.py index b9d4aeda90..7852e67169 100644 --- a/src/Mod/Fem/femexamples/equation_magnetostatics_2D_elmer.py +++ b/src/Mod/Fem/femexamples/equation_magnetostatics_2D_elmer.py @@ -25,7 +25,6 @@ import sys import FreeCAD from FreeCAD import Vector -import Draft import ObjectsFem import Part @@ -33,6 +32,7 @@ from BOPTools import SplitFeatures from . import manager from .manager import get_meshname from .manager import init_doc +from .meshes import generate_mesh def get_information(): @@ -79,9 +79,8 @@ def setup(doc=None, solvertype="elmer"): p2 = Vector(200.0, -200.0, 0.0) p3 = Vector(200.0, -100.0, 0.0) p4 = Vector(0.0, -100.0, 0.0) - Horseshoe_lower = Draft.make_wire([p1, p2, p3, p4], closed=True) - Horseshoe_lower.MakeFace = True - Horseshoe_lower.Label = "Lower_End" + Horseshoe_lower = doc.addObject("Part::Feature", "Lower_End") + Horseshoe_lower.Shape = Part.makeFace(Part.makePolygon([p1, p2, p3, p4, p1])) Horseshoe_lower.ViewObject.Visibility = False # wire defining the upper horse shoe end @@ -89,9 +88,8 @@ def setup(doc=None, solvertype="elmer"): p2 = Vector(200.0, 100.0, 0.0) p3 = Vector(200.0, 200.0, 0.0) p4 = Vector(0.0, 200.0, 0.0) - Horseshoe_upper = Draft.make_wire([p1, p2, p3, p4], closed=True) - Horseshoe_upper.MakeFace = True - Horseshoe_upper.Label = "Upper_End" + Horseshoe_upper = doc.addObject("Part::Feature", "Upper_End") + Horseshoe_upper.Shape = Part.makeFace(Part.makePolygon([p1, p2, p3, p4, p1])) Horseshoe_upper.ViewObject.Visibility = False # the U-part of the horse shoe @@ -275,14 +273,7 @@ def setup(doc=None, solvertype="elmer"): mesh_region.ViewObject.Visibility = False # generate the mesh - from femmesh import gmshtools - - gmsh_mesh = gmshtools.GmshTools(femmesh_obj, analysis) - try: - error = gmsh_mesh.create_mesh() - except Exception: - error = sys.exc_info()[1] - FreeCAD.Console.PrintError(f"Unexpected error when creating mesh: {error}\n") + generate_mesh.mesh_from_mesher(femmesh_obj, "gmsh") doc.recompute() return doc diff --git a/src/Mod/Fem/femexamples/equation_staticcurrent_elmer.py b/src/Mod/Fem/femexamples/equation_staticcurrent_elmer.py index 44e686ee08..fee0c183f8 100644 --- a/src/Mod/Fem/femexamples/equation_staticcurrent_elmer.py +++ b/src/Mod/Fem/femexamples/equation_staticcurrent_elmer.py @@ -38,6 +38,7 @@ from BasicShapes import Shapes from . import manager from .manager import get_meshname from .manager import init_doc +from .meshes import generate_mesh def get_information(): @@ -159,14 +160,7 @@ def setup(doc=None, solvertype="elmer"): femmesh_obj.ViewObject.Visibility = False # generate the mesh - from femmesh import gmshtools - - gmsh_mesh = gmshtools.GmshTools(femmesh_obj, analysis) - try: - error = gmsh_mesh.create_mesh() - except Exception: - error = sys.exc_info()[1] - FreeCAD.Console.PrintError(f"Unexpected error when creating mesh: {error}\n") + generate_mesh.mesh_from_mesher(femmesh_obj, "gmsh") doc.recompute() return doc diff --git a/src/Mod/Fem/femexamples/examplesgui.py b/src/Mod/Fem/femexamples/examplesgui.py index 5f24bac2b3..d8d2a020e6 100644 --- a/src/Mod/Fem/femexamples/examplesgui.py +++ b/src/Mod/Fem/femexamples/examplesgui.py @@ -239,7 +239,7 @@ class FemExamples(QtGui.QWidget): FreeCADGui.doCommand("from femexamples.manager import run_example") if solver is not None: FreeCADGui.doCommand( - f'run_example("{str(example)}", solver="{str(solver)}", run_solver=True)' + f'run_example("{str(example)}", solver="{str(solver)}", run_solver=True, blocking=False)' ) else: FreeCADGui.doCommand(f'run_example("{str(example)}", run_solver=True)') diff --git a/src/Mod/Fem/femexamples/frequency_beamsimple.py b/src/Mod/Fem/femexamples/frequency_beamsimple.py index d016873806..f84e03d94d 100644 --- a/src/Mod/Fem/femexamples/frequency_beamsimple.py +++ b/src/Mod/Fem/femexamples/frequency_beamsimple.py @@ -29,6 +29,7 @@ import ObjectsFem from . import manager from .manager import get_meshname from .manager import init_doc +from .meshes import generate_mesh def get_information(): @@ -141,13 +142,7 @@ def setup(doc=None, solvertype="ccxtools"): # mesh from .meshes.mesh_beamsimple_tetra10 import create_nodes, create_elements - fem_mesh = Fem.FemMesh() - control = create_nodes(fem_mesh) - if not control: - FreeCAD.Console.PrintError("Error on creating nodes.\n") - control = create_elements(fem_mesh) - if not control: - FreeCAD.Console.PrintError("Error on creating elements.\n") + fem_mesh = generate_mesh.mesh_from_existing(create_nodes, create_elements) femmesh_obj = analysis.addObject(ObjectsFem.makeMeshGmsh(doc, get_meshname()))[0] femmesh_obj.FemMesh = fem_mesh femmesh_obj.Shape = geom_obj diff --git a/src/Mod/Fem/femexamples/magnetic_shielding_2D.py b/src/Mod/Fem/femexamples/magnetic_shielding_2D.py index b042fbb368..fee70caf29 100644 --- a/src/Mod/Fem/femexamples/magnetic_shielding_2D.py +++ b/src/Mod/Fem/femexamples/magnetic_shielding_2D.py @@ -36,6 +36,7 @@ import Materials import Part from . import manager +from .meshes import generate_mesh def get_information(): @@ -150,14 +151,7 @@ def setup(doc=None, solvertype="elmer"): mesh_region.ViewObject.Visibility = False # generate the mesh - from femmesh import gmshtools - - gmsh_mesh = gmshtools.GmshTools(femmesh_obj, analysis) - try: - gmsh_mesh.create_mesh() - except Exception: - error = sys.exc_info()[1] - FreeCAD.Console.PrintError(f"Unexpected error when creating mesh: {error}\n") + generate_mesh.mesh_from_mesher(femmesh_obj, "gmsh") doc.recompute() return doc diff --git a/src/Mod/Fem/femexamples/manager.py b/src/Mod/Fem/femexamples/manager.py index 4df4fb4c8f..8bf64b6332 100644 --- a/src/Mod/Fem/femexamples/manager.py +++ b/src/Mod/Fem/femexamples/manager.py @@ -127,7 +127,7 @@ def setup_all(): run_example("thermomech_bimetal") -def run_analysis(doc, base_name, filepath="", run_solver=False): +def run_analysis(doc, base_name, filepath="", run_solver=False, blocking=True): from os.path import join, exists from os import makedirs @@ -168,13 +168,13 @@ def run_analysis(doc, base_name, filepath="", run_solver=False): from femsolver.run import run_fem_solver if run_solver is True: - run_fem_solver(solver, working_dir) + run_fem_solver(solver, working_dir, blocking=blocking) # save doc once again with results doc.save() -def run_example(example, solver=None, base_name=None, run_solver=False): +def run_example(example, solver=None, base_name=None, run_solver=False, blocking=True): from importlib import import_module @@ -192,7 +192,7 @@ def run_example(example, solver=None, base_name=None, run_solver=False): base_name = example if solver is not None: base_name += "_" + solver - run_analysis(doc, base_name, run_solver=run_solver) + run_analysis(doc, base_name, run_solver=run_solver, blocking=blocking) doc.recompute() return doc diff --git a/src/Mod/Fem/femexamples/material_multiple_bendingbeam_fiveboxes.py b/src/Mod/Fem/femexamples/material_multiple_bendingbeam_fiveboxes.py index 1ccd05783e..d0250fd9b6 100644 --- a/src/Mod/Fem/femexamples/material_multiple_bendingbeam_fiveboxes.py +++ b/src/Mod/Fem/femexamples/material_multiple_bendingbeam_fiveboxes.py @@ -32,6 +32,7 @@ import ObjectsFem from . import manager from .manager import get_meshname from .manager import init_doc +from .meshes import generate_mesh def get_information(): @@ -192,13 +193,7 @@ def setup(doc=None, solvertype="ccxtools"): # mesh from .meshes.mesh_multibodybeam_tetra10 import create_nodes, create_elements - fem_mesh = Fem.FemMesh() - control = create_nodes(fem_mesh) - if not control: - FreeCAD.Console.PrintError("Error on creating nodes.\n") - control = create_elements(fem_mesh) - if not control: - FreeCAD.Console.PrintError("Error on creating elements.\n") + fem_mesh = generate_mesh.mesh_from_existing(create_nodes, create_elements) femmesh_obj = analysis.addObject(ObjectsFem.makeMeshGmsh(doc, get_meshname()))[0] femmesh_obj.FemMesh = fem_mesh femmesh_obj.Shape = geom_obj diff --git a/src/Mod/Fem/femexamples/material_multiple_bendingbeam_fivefaces.py b/src/Mod/Fem/femexamples/material_multiple_bendingbeam_fivefaces.py index 451983314c..a83c7f7c10 100644 --- a/src/Mod/Fem/femexamples/material_multiple_bendingbeam_fivefaces.py +++ b/src/Mod/Fem/femexamples/material_multiple_bendingbeam_fivefaces.py @@ -30,6 +30,7 @@ import ObjectsFem from . import manager from .manager import get_meshname from .manager import init_doc +from .meshes import generate_mesh def get_information(): @@ -185,13 +186,7 @@ def setup(doc=None, solvertype="ccxtools"): # mesh from .meshes.mesh_multibodybeam_tria6 import create_nodes, create_elements - fem_mesh = Fem.FemMesh() - control = create_nodes(fem_mesh) - if not control: - FreeCAD.Console.PrintError("Error on creating nodes.\n") - control = create_elements(fem_mesh) - if not control: - FreeCAD.Console.PrintError("Error on creating elements.\n") + fem_mesh = generate_mesh.mesh_from_existing(create_nodes, create_elements) femmesh_obj = analysis.addObject(ObjectsFem.makeMeshGmsh(doc, get_meshname()))[0] femmesh_obj.FemMesh = fem_mesh femmesh_obj.Shape = geom_obj diff --git a/src/Mod/Fem/femexamples/material_multiple_tensionrod_twoboxes.py b/src/Mod/Fem/femexamples/material_multiple_tensionrod_twoboxes.py index 7d04aa70ed..728e72f53d 100644 --- a/src/Mod/Fem/femexamples/material_multiple_tensionrod_twoboxes.py +++ b/src/Mod/Fem/femexamples/material_multiple_tensionrod_twoboxes.py @@ -33,6 +33,7 @@ import ObjectsFem from . import manager from .manager import get_meshname from .manager import init_doc +from .meshes import generate_mesh def get_information(): @@ -161,13 +162,7 @@ def setup(doc=None, solvertype="ccxtools"): # mesh from .meshes.mesh_boxes_2_vertikal_tetra10 import create_nodes, create_elements - fem_mesh = Fem.FemMesh() - control = create_nodes(fem_mesh) - if not control: - FreeCAD.Console.PrintError("Error on creating nodes.\n") - control = create_elements(fem_mesh) - if not control: - FreeCAD.Console.PrintError("Error on creating elements.\n") + fem_mesh = generate_mesh.mesh_from_existing(create_nodes, create_elements) femmesh_obj = analysis.addObject(ObjectsFem.makeMeshGmsh(doc, get_meshname()))[0] femmesh_obj.FemMesh = fem_mesh femmesh_obj.Shape = geom_obj diff --git a/src/Mod/Fem/femexamples/material_nl_platewithhole.py b/src/Mod/Fem/femexamples/material_nl_platewithhole.py index 192b12915d..67be0f16dc 100644 --- a/src/Mod/Fem/femexamples/material_nl_platewithhole.py +++ b/src/Mod/Fem/femexamples/material_nl_platewithhole.py @@ -41,6 +41,7 @@ import ObjectsFem from . import manager from .manager import get_meshname from .manager import init_doc +from .meshes import generate_mesh def get_information(): @@ -169,13 +170,7 @@ def setup(doc=None, solvertype="ccxtools"): # mesh from .meshes.mesh_platewithhole_tetra10 import create_nodes, create_elements - fem_mesh = Fem.FemMesh() - control = create_nodes(fem_mesh) - if not control: - FreeCAD.Console.PrintError("Error on creating nodes.\n") - control = create_elements(fem_mesh) - if not control: - FreeCAD.Console.PrintError("Error on creating elements.\n") + fem_mesh = generate_mesh.mesh_from_existing(create_nodes, create_elements) femmesh_obj = analysis.addObject(ObjectsFem.makeMeshGmsh(doc, get_meshname()))[0] femmesh_obj.FemMesh = fem_mesh femmesh_obj.Shape = geom_obj diff --git a/src/Mod/Fem/femexamples/meshes/generate_mesh.py b/src/Mod/Fem/femexamples/meshes/generate_mesh.py new file mode 100644 index 0000000000..1bfe3a96d2 --- /dev/null +++ b/src/Mod/Fem/femexamples/meshes/generate_mesh.py @@ -0,0 +1,66 @@ +# SPDX-License-Identifier: LGPL-2.1-or-later + +# *************************************************************************** +# * Copyright (c) 2026 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 * +# * . * +# * * +# *************************************************************************** + +import sys +from FreeCAD import Console +import Fem + + +def mesh_from_mesher(femmesh_obj, mesher=""): + tool = None + success = False + match mesher: + case "netgen": + from femmesh import netgentools + tool = netgentools.NetgenTools(femmesh_obj) + case "gmsh" | "": + from femmesh import gmshtools + tool = gmshtools.GmshTools(femmesh_obj) + case _: + raise ValueError(f"Invalid mesher: {mesher}") + + # Redirect process error to report view + print_error = lambda: Console.PrintError( + tool.process.readAllStandardError().data().decode("utf-8") + ) + tool.process.readyReadStandardError.connect(print_error) + + # generate the mesh + try: + success = tool.run(blocking=True) + except Exception as e: + error = sys.exc_info()[1] + Console.PrintError(f"Unexpected error when creating mesh: {error}\n") + + return success + +def mesh_from_existing(create_nodes, create_elements): + fem_mesh = Fem.FemMesh() + control = create_nodes(fem_mesh) + if not control: + Console.PrintError("Error on creating nodes.\n") + control = create_elements(fem_mesh) + if not control: + Console.PrintError("Error on creating elements.\n") + + return fem_mesh diff --git a/src/Mod/Fem/femexamples/mystran_plate.py b/src/Mod/Fem/femexamples/mystran_plate.py index d25c9f0e85..2e96c6c98b 100644 --- a/src/Mod/Fem/femexamples/mystran_plate.py +++ b/src/Mod/Fem/femexamples/mystran_plate.py @@ -31,6 +31,7 @@ import ObjectsFem from . import manager from .manager import get_meshname from .manager import init_doc +from .meshes import generate_mesh def get_information(): @@ -39,7 +40,7 @@ def get_information(): "meshtype": "face", "meshelement": "Quad4", "constraints": ["fixed", "force"], - "solvers": ["ccxtools", "elmer", "mystran"], + "solvers": ["ccxtools", "mystran"], # elmer disabled until mesh has groups "material": "solid", "equations": ["mechanical"], } @@ -179,13 +180,7 @@ def setup(doc=None, solvertype="ccxtools"): # mesh from .meshes.mesh_plate_mystran_quad4 import create_nodes, create_elements - fem_mesh = Fem.FemMesh() - control = create_nodes(fem_mesh) - if not control: - FreeCAD.Console.PrintError("Error on creating nodes.\n") - control = create_elements(fem_mesh) - if not control: - FreeCAD.Console.PrintError("Error on creating elements.\n") + fem_mesh = generate_mesh.mesh_from_existing(create_nodes, create_elements) femmesh_obj = analysis.addObject(ObjectsFem.makeMeshGmsh(doc, get_meshname()))[0] femmesh_obj.FemMesh = fem_mesh femmesh_obj.Shape = geom_obj diff --git a/src/Mod/Fem/femexamples/rc_wall_2d.py b/src/Mod/Fem/femexamples/rc_wall_2d.py index d7659fef9c..fbed5fe48f 100644 --- a/src/Mod/Fem/femexamples/rc_wall_2d.py +++ b/src/Mod/Fem/femexamples/rc_wall_2d.py @@ -34,6 +34,7 @@ import ObjectsFem from . import manager from .manager import get_meshname from .manager import init_doc +from .meshes import generate_mesh def get_information(): @@ -167,13 +168,7 @@ def setup(doc=None, solvertype="ccxtools"): # mesh from .meshes.mesh_rc_wall_2d_tria6 import create_nodes, create_elements - fem_mesh = Fem.FemMesh() - control = create_nodes(fem_mesh) - if not control: - FreeCAD.Console.PrintError("Error on creating nodes.\n") - control = create_elements(fem_mesh) - if not control: - FreeCAD.Console.PrintError("Error on creating elements.\n") + fem_mesh = generate_mesh.mesh_from_existing(create_nodes, create_elements) femmesh_obj = analysis.addObject(ObjectsFem.makeMeshGmsh(doc, get_meshname()))[0] femmesh_obj.FemMesh = fem_mesh femmesh_obj.Shape = geom_obj diff --git a/src/Mod/Fem/femexamples/square_pipe_end_twisted_edgeforces.py b/src/Mod/Fem/femexamples/square_pipe_end_twisted_edgeforces.py index 9fed8cb4bc..fc2b08e99d 100644 --- a/src/Mod/Fem/femexamples/square_pipe_end_twisted_edgeforces.py +++ b/src/Mod/Fem/femexamples/square_pipe_end_twisted_edgeforces.py @@ -33,6 +33,7 @@ import ObjectsFem from . import manager from .manager import get_meshname from .manager import init_doc +from .meshes import generate_mesh def get_information(): @@ -169,13 +170,7 @@ def setup(doc=None, solvertype="ccxtools"): # mesh from .meshes.mesh_square_pipe_end_twisted_tria6 import create_nodes, create_elements - fem_mesh = Fem.FemMesh() - control = create_nodes(fem_mesh) - if not control: - FreeCAD.Console.PrintError("Error on creating nodes.\n") - control = create_elements(fem_mesh) - if not control: - FreeCAD.Console.PrintError("Error on creating elements.\n") + fem_mesh = generate_mesh.mesh_from_existing(create_nodes, create_elements) femmesh_obj = analysis.addObject(ObjectsFem.makeMeshGmsh(doc, get_meshname()))[0] femmesh_obj.FemMesh = fem_mesh femmesh_obj.Shape = geom_obj diff --git a/src/Mod/Fem/femexamples/square_pipe_end_twisted_nodeforces.py b/src/Mod/Fem/femexamples/square_pipe_end_twisted_nodeforces.py index 4297d41f57..b587e896d3 100644 --- a/src/Mod/Fem/femexamples/square_pipe_end_twisted_nodeforces.py +++ b/src/Mod/Fem/femexamples/square_pipe_end_twisted_nodeforces.py @@ -33,6 +33,7 @@ import ObjectsFem from . import manager from .manager import get_meshname from .manager import init_doc +from .meshes import generate_mesh def get_information(): @@ -439,13 +440,7 @@ def setup(doc=None, solvertype="ccxtools"): # mesh from .meshes.mesh_square_pipe_end_twisted_tria6 import create_nodes, create_elements - fem_mesh = Fem.FemMesh() - control = create_nodes(fem_mesh) - if not control: - FreeCAD.Console.PrintError("Error on creating nodes.\n") - control = create_elements(fem_mesh) - if not control: - FreeCAD.Console.PrintError("Error on creating elements.\n") + fem_mesh = generate_mesh.mesh_from_existing(create_nodes, create_elements) femmesh_obj = analysis.addObject(ObjectsFem.makeMeshGmsh(doc, get_meshname()))[0] femmesh_obj.FemMesh = fem_mesh femmesh_obj.Shape = geom_obj diff --git a/src/Mod/Fem/femexamples/thermomech_bimetal.py b/src/Mod/Fem/femexamples/thermomech_bimetal.py index f7725a343e..39707cbd88 100644 --- a/src/Mod/Fem/femexamples/thermomech_bimetal.py +++ b/src/Mod/Fem/femexamples/thermomech_bimetal.py @@ -41,6 +41,7 @@ import ObjectsFem from . import manager from .manager import get_meshname from .manager import init_doc +from .meshes import generate_mesh def get_information(): @@ -78,7 +79,7 @@ this file has 7.15 mm max deflection ) -def setup(doc=None, solvertype="ccxtools"): +def setup(doc=None, solvertype="ccxtools", test_mode=False): # init FreeCAD document if doc is None: @@ -206,19 +207,21 @@ def setup(doc=None, solvertype="ccxtools"): analysis.addObject(con_temp) # mesh - from .meshes.mesh_thermomech_bimetal_tetra10 import create_nodes, create_elements - - fem_mesh = Fem.FemMesh() - control = create_nodes(fem_mesh) - if not control: - FreeCAD.Console.PrintError("Error on creating nodes.\n") - control = create_elements(fem_mesh) - if not control: - FreeCAD.Console.PrintError("Error on creating elements.\n") femmesh_obj = analysis.addObject(ObjectsFem.makeMeshGmsh(doc, get_meshname()))[0] - femmesh_obj.FemMesh = fem_mesh femmesh_obj.Shape = geom_obj femmesh_obj.SecondOrderLinear = False + femmesh_obj.CharacteristicLengthMax = "2 mm" + + # generate the mesh + success = False + if not test_mode: + success = generate_mesh.mesh_from_mesher(femmesh_obj, "gmsh") + if not success: + # try to create from existing rough mesh + from .meshes.mesh_thermomech_bimetal_tetra10 import create_nodes, create_elements + + fem_mesh = generate_mesh.mesh_from_existing(create_nodes, create_elements) + femmesh_obj.FemMesh = fem_mesh doc.recompute() return doc diff --git a/src/Mod/Fem/femexamples/truss_3d_cs_circle_ele_seg2.py b/src/Mod/Fem/femexamples/truss_3d_cs_circle_ele_seg2.py index 3419cd0212..18cf0f7574 100644 --- a/src/Mod/Fem/femexamples/truss_3d_cs_circle_ele_seg2.py +++ b/src/Mod/Fem/femexamples/truss_3d_cs_circle_ele_seg2.py @@ -28,6 +28,7 @@ import Fem from .truss_3d_cs_circle_ele_seg3 import setup as setup_truss_seg3 from .manager import get_meshname from .manager import init_doc +from .meshes import generate_mesh def get_information(): @@ -59,13 +60,7 @@ def setup(doc=None, solvertype="z88"): # mesh from .meshes.mesh_truss_crane_seg2 import create_nodes, create_elements - fem_mesh = Fem.FemMesh() - control = create_nodes(fem_mesh) - if not control: - FreeCAD.Console.PrintError("Error on creating nodes.\n") - control = create_elements(fem_mesh) - if not control: - FreeCAD.Console.PrintError("Error on creating elements.\n") + fem_mesh = generate_mesh.mesh_from_existing(create_nodes, create_elements) # overwrite mesh with the hexa20 mesh femmesh_obj.FemMesh = fem_mesh diff --git a/src/Mod/Fem/femexamples/truss_3d_cs_circle_ele_seg3.py b/src/Mod/Fem/femexamples/truss_3d_cs_circle_ele_seg3.py index 333f0add1f..e3ed28b35d 100644 --- a/src/Mod/Fem/femexamples/truss_3d_cs_circle_ele_seg3.py +++ b/src/Mod/Fem/femexamples/truss_3d_cs_circle_ele_seg3.py @@ -33,6 +33,7 @@ import ObjectsFem from . import manager from .manager import get_meshname from .manager import init_doc +from .meshes import generate_mesh def get_information(): @@ -452,13 +453,7 @@ def setup(doc=None, solvertype="ccxtools"): # mesh from .meshes.mesh_truss_crane_seg3 import create_nodes, create_elements - fem_mesh = Fem.FemMesh() - control = create_nodes(fem_mesh) - if not control: - FreeCAD.Console.PrintError("Error on creating nodes.\n") - control = create_elements(fem_mesh) - if not control: - FreeCAD.Console.PrintError("Error on creating elements.\n") + fem_mesh = generate_mesh.mesh_from_existing(create_nodes, create_elements) femmesh_obj = analysis.addObject(ObjectsFem.makeMeshGmsh(doc, get_meshname()))[0] femmesh_obj.FemMesh = fem_mesh femmesh_obj.Shape = geom_obj diff --git a/src/Mod/Fem/femmesh/gmshtools.py b/src/Mod/Fem/femmesh/gmshtools.py index 2ce06baa47..2b072a53b2 100644 --- a/src/Mod/Fem/femmesh/gmshtools.py +++ b/src/Mod/Fem/femmesh/gmshtools.py @@ -41,32 +41,21 @@ import Fem from . import meshtools from femtools import femutils from femtools import geomtools +from femtools.objecttools import ObjectTools class GmshError(Exception): pass -class GmshTools: +class GmshTools(ObjectTools): name = "Gmsh" - def __init__(self, gmsh_mesh_obj, analysis=None): - - # mesh obj - self.mesh_obj = gmsh_mesh_obj - - self.process = QProcess() - # analysis - self.analysis = None - if analysis: - self.analysis = analysis - else: - for i in self.mesh_obj.InList: - if i.isDerivedFrom("Fem::FemAnalysis"): - self.analysis = i - break - + def __init__(self, obj): + super().__init__(obj) + self.mesh_obj = obj + self.analysis = obj.getParentGroup() self.load_properties() self.error = False @@ -232,10 +221,8 @@ class GmshTools: self.rename_groups() def create_mesh(self): - self.prepare() - p = self.compute() - p.waitForFinished() - self.update_properties() + # for backward compatibility only + self.run(True) def start_logs(self): Console.PrintLog("\nGmsh FEM mesh run is being started.\n") diff --git a/src/Mod/Fem/femmesh/netgentools.py b/src/Mod/Fem/femmesh/netgentools.py index 1ca99f430c..25a08b78b2 100644 --- a/src/Mod/Fem/femmesh/netgentools.py +++ b/src/Mod/Fem/femmesh/netgentools.py @@ -34,9 +34,10 @@ from PySide.QtCore import QProcess, QThread, QProcessEnvironment import FreeCAD import Fem from freecad import utils +from femtools.objecttools import ObjectTools -class NetgenTools: +class NetgenTools(ObjectTools): # to change order of nodes from netgen to smesh order_edge = { @@ -73,11 +74,9 @@ class NetgenTools: __param_grp = FreeCAD.ParamGet("User parameter:BaseApp/Preferences/Mod/Fem/Netgen") def __init__(self, obj): - self.obj = obj + super().__init__(obj) self.fem_mesh = None - self.process = None self.tmpdir = "" - self.process = QProcess() self.mesh_params = {} def write_geom(self): @@ -267,6 +266,9 @@ def run_netgen( np.save(result_file, [result, groups]) +# remove traceback +sys.excepthook = lambda type, value, traceback: print(value) + run_netgen(**{kwds}) """ diff --git a/src/Mod/Fem/femsolver/calculix/calculixtools.py b/src/Mod/Fem/femsolver/calculix/calculixtools.py index a9921ca122..1c23edd666 100644 --- a/src/Mod/Fem/femsolver/calculix/calculixtools.py +++ b/src/Mod/Fem/femsolver/calculix/calculixtools.py @@ -37,42 +37,18 @@ import Fem from . import writer from .. import settings -# from feminout import importCcxDatResults from femmesh import meshsetsgetter from femtools import membertools +from femtools.objecttools import ObjectTools -class CalculiXTools: +class CalculiXTools(ObjectTools): name = "CalculiX" def __init__(self, obj): - self.obj = obj - self.process = QProcess() + super().__init__(obj) self.model_file = "" - self.analysis = obj.getParentGroup() - self.fem_param = FreeCAD.ParamGet("User parameter:BaseApp/Preferences/Mod/Fem") - self._create_working_directory(obj) - - def _create_working_directory(self, obj): - """ - Create working directory according to preferences - """ - if not os.path.isdir(obj.WorkingDirectory): - gen_param = self.fem_param.GetGroup("General") - if gen_param.GetBool("UseTempDirectory"): - self.obj.WorkingDirectory = tempfile.mkdtemp(prefix="fem_") - elif gen_param.GetBool("UseBesideDirectory"): - root, ext = os.path.splitext(obj.Document.FileName) - if root: - self.obj.WorkingDirectory = os.path.join(root, obj.Label) - os.makedirs(self.obj.WorkingDirectory, exist_ok=True) - else: - # file not saved, use temporary - self.obj.WorkingDirectory = tempfile.mkdtemp(prefix="fem_") - elif gen_param.GetBool("UseCustomDirectory"): - self.obj.WorkingDirectory = gen_param.GetString("CustomDirectoryPath") - os.makedirs(self.obj.WorkingDirectory, exist_ok=True) def prepare(self): from femtools.checksanalysis import check_member_for_solver_calculix diff --git a/src/Mod/Fem/femsolver/elmer/elmertools.py b/src/Mod/Fem/femsolver/elmer/elmertools.py index 2587a9d687..622ced738e 100644 --- a/src/Mod/Fem/femsolver/elmer/elmertools.py +++ b/src/Mod/Fem/femsolver/elmer/elmertools.py @@ -27,7 +27,6 @@ __url__ = "https://www.freecad.org" from PySide.QtCore import QProcess, QProcessEnvironment -import tempfile import os import re import shutil @@ -38,41 +37,18 @@ from . import writer from .. import settings from femtools import membertools +from femtools.objecttools import ObjectTools -class ElmerTools: +class ElmerTools(ObjectTools): name = "Elmer" def __init__(self, obj): - self.obj = obj - self.process = QProcess() + super().__init__(obj) self.model_file = "" - self.analysis = obj.getParentGroup() - self.fem_param = FreeCAD.ParamGet("User parameter:BaseApp/Preferences/Mod/Fem") - self._create_working_directory(obj) self._result_format = "" - def _create_working_directory(self, obj): - """ - Create working directory according to preferences - """ - if not os.path.isdir(obj.WorkingDirectory): - gen_param = self.fem_param.GetGroup("General") - if gen_param.GetBool("UseTempDirectory"): - self.obj.WorkingDirectory = tempfile.mkdtemp(prefix="fem_") - elif gen_param.GetBool("UseBesideDirectory"): - root, ext = os.path.splitext(obj.Document.FileName) - if root: - self.obj.WorkingDirectory = os.path.join(root, obj.Label) - os.makedirs(self.obj.WorkingDirectory, exist_ok=True) - else: - # file not saved, use temporary - self.obj.WorkingDirectory = tempfile.mkdtemp(prefix="fem_") - elif gen_param.GetBool("UseCustomDirectory"): - self.obj.WorkingDirectory = gen_param.GetString("CustomDirectoryPath") - os.makedirs(self.obj.WorkingDirectory, exist_ok=True) - def prepare(self): w = writer.Writer(self.obj, self.obj.WorkingDirectory) w.write_solver_input() @@ -91,7 +67,7 @@ class ElmerTools: p.setWorkingDirectory(self.obj.WorkingDirectory) grid_args = ["8", "2", mesh_file, "-out", self.obj.WorkingDirectory] p.start(grid_bin, grid_args) - p.waitForFinished() + p.waitForFinished(-1) num_proc = self.fem_param.GetGroup("Elmer").GetInt("NumberOfTasks", 1) if num_proc > 1: # MPI parallel computing version diff --git a/src/Mod/Fem/femsolver/run.py b/src/Mod/Fem/femsolver/run.py index d3fcb18f4e..fa7fcb3baf 100644 --- a/src/Mod/Fem/femsolver/run.py +++ b/src/Mod/Fem/femsolver/run.py @@ -40,6 +40,7 @@ import os import os.path import shutil import tempfile +from PySide import QtCore # import threading # not used ATM @@ -48,6 +49,8 @@ import FreeCAD as App from . import settings from . import signal from . import task +from femsolver.elmer import elmertools +from femsolver.calculix import calculixtools from femtools import femutils from femtools import membertools from femtools.errors import DirectoryDoesNotExistError @@ -69,7 +72,7 @@ _machines = {} _dirTypes = {} -def run_fem_solver(solver, working_dir=None): +def run_fem_solver(solver, working_dir=None, blocking=False): """Execute *solver* of the solver framework. Uses :meth:`getMachine ` to obtain a @@ -100,6 +103,35 @@ def run_fem_solver(solver, working_dir=None): use a :class:`Machine`. """ + tool = None + if working_dir: + solver.WorkingDirectory = working_dir + + match solver.Proxy.Type: + case "Fem::SolverElmer": + tool = elmertools.ElmerTools(solver) + case "Fem::SolverCalculiX": + tool = calculixtools.CalculiXTools(solver) + + if tool is not None: + # Redirect process error to report view + print_error = lambda: App.Console.PrintError( + tool.process.readAllStandardError().data().decode("utf-8") + ) + tool.process.readyReadStandardError.connect(print_error) + tool.process.finished.connect(_solver_finish(solver)) + try: + if App.GuiUp: + QtGui.QApplication.setOverrideCursor(QtCore.Qt.WaitCursor) + tool.run(blocking) + except Exception as e: + if App.GuiUp: + QtGui.QApplication.restoreOverrideCursor() + raise e + return + + # code for old solver implementations + if solver.Proxy.Type == "Fem::SolverCcxTools": from femtools.ccxtools import CcxTools as ccx @@ -192,6 +224,17 @@ def getMachine(solver, path=None): return m +def _solver_finish(obj): + def receiver(code, status): + if status != QtCore.QProcess.ExitStatus.NormalExit or code != 0: + App.Console.PrintError("Solver finished with errors. Result not updated\n") + if App.GuiUp: + QtGui.QApplication.restoreOverrideCursor() + obj.Document.recompute() + + return receiver + + def _isPathValid(m, path): t = _dirTypes.get(m.directory) # setting default None setting = settings.get_dir_setting() diff --git a/src/Mod/Fem/femtaskpanels/base_femlogtaskpanel.py b/src/Mod/Fem/femtaskpanels/base_femlogtaskpanel.py index 740ad10566..90072f39de 100644 --- a/src/Mod/Fem/femtaskpanels/base_femlogtaskpanel.py +++ b/src/Mod/Fem/femtaskpanels/base_femlogtaskpanel.py @@ -138,7 +138,6 @@ class _BaseLogTaskPanel(base_femtaskpanel._BaseTaskPanel, ABC): QtGui.QColor(getOutputWinColor("Error")), ) return - self.tool.update_properties() self.write_log("Process finished\n", QtGui.QColor(getOutputWinColor("Text"))) def process_started(self): diff --git a/src/Mod/Fem/femtest/app/test_ccxtools.py b/src/Mod/Fem/femtest/app/test_ccxtools.py index a74e6c4f4d..4fd7000149 100644 --- a/src/Mod/Fem/femtest/app/test_ccxtools.py +++ b/src/Mod/Fem/femtest/app/test_ccxtools.py @@ -76,7 +76,7 @@ class TestCcxTools(unittest.TestCase): # set up from femexamples.boxanalysis_frequency import setup - setup(self.document, "ccxtools") + setup(self.document, "ccxtools", test_mode=True) base_name = get_namefromdef("test_") res_obj_name = "CCX_EigenMode_1_Results" analysis_dir = testtools.get_fem_test_tmp_dir(self.pre_dir_name + base_name) @@ -100,7 +100,7 @@ class TestCcxTools(unittest.TestCase): # set up from femexamples.boxanalysis_static import setup - setup(self.document, "ccxtools") + setup(self.document, "ccxtools", test_mode=True) base_name = get_namefromdef("test_") res_obj_name = "CCX_Results" analysis_dir = testtools.get_fem_test_tmp_dir(self.pre_dir_name + base_name) @@ -201,21 +201,21 @@ class TestCcxTools(unittest.TestCase): def test_ccx_cantilever_faceload(self): from femexamples.ccx_cantilever_faceload import setup - setup(self.document, "ccxtools") + setup(self.document, "ccxtools", test_mode=True) self.input_file_writing_test(get_namefromdef("test_")) # ******************************************************************************************** def test_ccx_cantilever_nodeload(self): from femexamples.ccx_cantilever_nodeload import setup - setup(self.document, "ccxtools") + setup(self.document, "ccxtools", test_mode=True) self.input_file_writing_test(get_namefromdef("test_")) # ******************************************************************************************** def test_ccx_cantilever_prescribeddisplacement(self): from femexamples.ccx_cantilever_prescribeddisplacement import setup - setup(self.document, "ccxtools") + setup(self.document, "ccxtools", test_mode=True) self.input_file_writing_test(get_namefromdef("test_")) # ******************************************************************************************** @@ -256,7 +256,7 @@ class TestCcxTools(unittest.TestCase): def test_constraint_selfweight_cantilever(self): from femexamples.constraint_selfweight_cantilever import setup - setup(self.document, "ccxtools") + setup(self.document, "ccxtools", test_mode=True) self.input_file_writing_test(get_namefromdef("test_")) # ******************************************************************************************** @@ -333,7 +333,7 @@ class TestCcxTools(unittest.TestCase): def test_thermomech_bimetal(self): from femexamples.thermomech_bimetal import setup - setup(self.document, "ccxtools") + setup(self.document, "ccxtools", test_mode=True) self.input_file_writing_test(get_namefromdef("test_")) # ******************************************************************************************** diff --git a/src/Mod/Fem/femtest/app/test_solver_z88.py b/src/Mod/Fem/femtest/app/test_solver_z88.py index 8087b23c53..5df40676d5 100644 --- a/src/Mod/Fem/femtest/app/test_solver_z88.py +++ b/src/Mod/Fem/femtest/app/test_solver_z88.py @@ -89,14 +89,14 @@ class TestSolverZ88(unittest.TestCase): def test_ccx_cantilever_faceload(self): from femexamples.ccx_cantilever_faceload import setup - setup(self.document, "z88") + setup(self.document, "z88", test_mode=True) self.inputfile_writing_test(get_namefromdef("test_")) # ******************************************************************************************** def test_ccx_cantilever_nodeload(self): from femexamples.ccx_cantilever_nodeload import setup - setup(self.document, "z88") + setup(self.document, "z88", test_mode=True) self.inputfile_writing_test(get_namefromdef("test_")) # ******************************************************************************************** diff --git a/src/Mod/Fem/femtools/objecttools.py b/src/Mod/Fem/femtools/objecttools.py new file mode 100644 index 0000000000..685145d839 --- /dev/null +++ b/src/Mod/Fem/femtools/objecttools.py @@ -0,0 +1,91 @@ +# SPDX-License-Identifier: LGPL-2.1-or-later + +# *************************************************************************** +# * Copyright (c) 2026 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__ = "Abstract base class for the work with solvers and meshers" +__author__ = "Mario Passaglia" +__url__ = "https://www.freecad.org" + + +from PySide.QtCore import QProcess +from abc import ABC, abstractmethod +import os +import tempfile + +import FreeCAD + + +class ObjectTools(ABC): + """Abstract base class for the work with solvers and meshers""" + + def __init__(self, obj): + obj.Tool = self + self.obj = obj + self.process = QProcess() + self.analysis = obj.getParentGroup() + self.fem_param = FreeCAD.ParamGet("User parameter:BaseApp/Preferences/Mod/Fem") + self._create_working_directory(obj) + + self.process.finished.connect(self._process_finished) + + def _create_working_directory(self, obj): + """ + Create working directory according to preferences + """ + if not os.path.isdir(obj.WorkingDirectory): + gen_param = self.fem_param.GetGroup("General") + if gen_param.GetBool("UseTempDirectory"): + self.obj.WorkingDirectory = tempfile.mkdtemp(prefix="fem_") + elif gen_param.GetBool("UseBesideDirectory"): + root, ext = os.path.splitext(obj.Document.FileName) + if root: + self.obj.WorkingDirectory = os.path.join(root, obj.Label) + os.makedirs(self.obj.WorkingDirectory, exist_ok=True) + else: + # file not saved, use temporary + self.obj.WorkingDirectory = tempfile.mkdtemp(prefix="fem_") + elif gen_param.GetBool("UseCustomDirectory"): + self.obj.WorkingDirectory = gen_param.GetString("CustomDirectoryPath") + os.makedirs(self.obj.WorkingDirectory, exist_ok=True) + + @abstractmethod + def prepare(self): + pass + + @abstractmethod + def compute(self): + pass + + @abstractmethod + def update_properties(self): + pass + + def run(self, blocking=False): + self.prepare() + self.compute() + if blocking: + return self.process.waitForFinished(-1) + return None + + def _process_finished(self, code, status): + if status == QProcess.ExitStatus.NormalExit and code == 0: + self.update_properties()