diff --git a/src/Mod/Fem/CMakeLists.txt b/src/Mod/Fem/CMakeLists.txt index 160f672d7d..24cf9d129c 100755 --- a/src/Mod/Fem/CMakeLists.txt +++ b/src/Mod/Fem/CMakeLists.txt @@ -35,6 +35,7 @@ SET(FemCommands_SRCS SET(FemExamples_SRCS femexamples/__init__.py + femexamples/boxanalysis.py femexamples/ccx_cantilever_std.py femexamples/manager.py femexamples/multimaterial_twoboxes.py diff --git a/src/Mod/Fem/femexamples/boxanalysis.py b/src/Mod/Fem/femexamples/boxanalysis.py new file mode 100644 index 0000000000..b39eb75794 --- /dev/null +++ b/src/Mod/Fem/femexamples/boxanalysis.py @@ -0,0 +1,182 @@ +# *************************************************************************** +# * Copyright (c) 2019 Bernd Hahnebach * +# * * +# * This file is part of the FreeCAD CAx development system. * +# * * +# * This program is free software; you can redistribute it and/or modify * +# * it under the terms of the GNU Lesser General Public License (LGPL) * +# * as published by the Free Software Foundation; either version 2 of * +# * the License, or (at your option) any later version. * +# * for detail see the LICENCE text file. * +# * * +# * 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 Library General Public License for more details. * +# * * +# * You should have received a copy of the GNU Library General Public * +# * License along with FreeCAD; if not, write to the Free Software * +# * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 * +# * USA * +# * * +# *************************************************************************** + + +import FreeCAD +import ObjectsFem +import Fem + +mesh_name = "Mesh" # needs to be Mesh to work with unit tests + + +def init_doc(doc=None): + if doc is None: + doc = FreeCAD.newDocument() + return doc + + +def setup_base(doc=None, solver="ccxtools"): + # setup box base model + + if doc is None: + doc = init_doc() + + # part + box_obj = doc.addObject("Part::Box", "Box") + box_obj.Height = box_obj.Width = box_obj.Length = 10 + doc.recompute() + + if FreeCAD.GuiUp: + import FreeCADGui + FreeCADGui.ActiveDocument.activeView().viewAxonometric() + FreeCADGui.SendMsgToActiveView("ViewFit") + + # analysis + analysis = ObjectsFem.makeAnalysis(doc, "Analysis") + + # material + material_object = analysis.addObject( + ObjectsFem.makeMaterialSolid(doc, "MechanicalMaterial") + )[0] + mat = material_object.Material + mat["Name"] = "Steel-Generic" + mat["YoungsModulus"] = "200000 MPa" + mat["PoissonRatio"] = "0.30" + mat["Density"] = "7900 kg/m^3" + material_object.Material = mat + + # mesh + # from .meshes.mesh_canticcx_tetra10 import create_nodes, create_elements + from femtest.data.ccx.cube_mesh import create_nodes_cube as create_nodes + from femtest.data.ccx.cube_mesh import create_elements_cube as 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( + doc.addObject("Fem::FemMeshObject", mesh_name) + )[0] + femmesh_obj.FemMesh = fem_mesh + + doc.recompute() + return doc + + +def setup_static(doc=None, solver="ccxtools"): + # setup box static, add a fixed, force and a pressure constraint + + doc = setup_base(doc, solver) + box_obj = doc.Box + analysis = doc.Analysis + + # solver + # TODO How to pass multiple solver for one analysis in one doc + if solver == "calculix": + solver_object = analysis.addObject( + ObjectsFem.makeSolverCalculix(doc, "SolverCalculiX") + )[0] + elif solver == "ccxtools": + solver_object = analysis.addObject( + ObjectsFem.makeSolverCalculixCcxTools(doc, "CalculiXccxTools") + )[0] + solver_object.WorkingDir = u"" + elif solver == "elmer": + analysis.addObject(ObjectsFem.makeSolverElmer(doc, "SolverElmer")) + elif solver == "z88": + analysis.addObject(ObjectsFem.makeSolverZ88(doc, "SolverZ88")) + if solver == "calculix" or solver == "ccxtools": + solver_object.AnalysisType = "static" + solver_object.GeometricalNonlinearity = "linear" + solver_object.ThermoMechSteadyState = False + solver_object.MatrixSolverType = "default" + solver_object.IterationsControlParameterTimeUse = False + + # fixed_constraint + fixed_constraint = analysis.addObject( + ObjectsFem.makeConstraintFixed(doc, name="FemConstraintFixed") + )[0] + fixed_constraint.References = [(box_obj, "Face1")] + + # force_constraint + force_constraint = analysis.addObject( + ObjectsFem.makeConstraintForce(doc, name="FemConstraintForce") + )[0] + force_constraint.References = [(box_obj, "Face6")] + force_constraint.Force = 40000.0 + force_constraint.Direction = (box_obj, ["Edge5"]) + force_constraint.Reversed = True + + # pressure_constraint + pressure_constraint = analysis.addObject( + ObjectsFem.makeConstraintPressure(doc, name="FemConstraintPressure") + )[0] + pressure_constraint.References = [(box_obj, "Face2")] + pressure_constraint.Pressure = 1000.0 + pressure_constraint.Reversed = False + + doc.recompute() + return doc + + +def setup_frequency(doc=None, solver="ccxtools"): + # setup box frequency, change solver attributes + + doc = setup_base(doc, solver) + analysis = doc.Analysis + + # solver + # TODO How to pass multiple solver for one analysis in one doc + if solver == "calculix": + solver_object = analysis.addObject( + ObjectsFem.makeSolverCalculix(doc, "SolverCalculiX") + )[0] + elif solver == "ccxtools": + solver_object = analysis.addObject( + ObjectsFem.makeSolverCalculixCcxTools(doc, "CalculiXccxTools") + )[0] + solver_object.WorkingDir = u"" + if solver == "calculix" or solver == "ccxtools": + solver_object.AnalysisType = "frequency" + solver_object.GeometricalNonlinearity = "linear" + solver_object.ThermoMechSteadyState = False + solver_object.MatrixSolverType = "default" + solver_object.IterationsControlParameterTimeUse = False + solver_object.EigenmodesCount = 10 + solver_object.EigenmodeHighLimit = 1000000.0 + solver_object.EigenmodeLowLimit = 0.01 + + doc.recompute() + return doc + + +""" +from femexamples import boxanalysis as box + +box.setup_base() +box.setup_static() +box.setup_frequency() + +""" diff --git a/src/Mod/Fem/femtest/app/test_ccxtools.py b/src/Mod/Fem/femtest/app/test_ccxtools.py index 3d3974a70c..ffbddf0a6e 100644 --- a/src/Mod/Fem/femtest/app/test_ccxtools.py +++ b/src/Mod/Fem/femtest/app/test_ccxtools.py @@ -23,10 +23,8 @@ # * * # ***************************************************************************/ -import Fem from femtools import ccxtools import FreeCAD -import ObjectsFem import unittest from . import support_utils as testtools from .support_utils import fcc_print @@ -75,123 +73,12 @@ class TestCcxTools(unittest.TestCase): ): fcc_print("\n--------------- Start of FEM ccxtools static analysis test ---------------") - box = self.active_doc.addObject("Part::Box", "Box") + # set up the static analysis example + from femexamples import boxanalysis as box + box.setup_static(self.active_doc, "ccxtools") - fcc_print("Checking FEM new analysis...") - analysis = ObjectsFem.makeAnalysis( - self.active_doc, - "Analysis" - ) - self.assertTrue( - analysis, - "FemTest of new analysis failed" - ) - - fcc_print("Checking FEM new solver...") - solver_object = ObjectsFem.makeSolverCalculixCcxTools( - self.active_doc, - "CalculiX" - ) - solver_object.AnalysisType = "static" - solver_object.GeometricalNonlinearity = "linear" - solver_object.ThermoMechSteadyState = False - solver_object.MatrixSolverType = "default" - solver_object.IterationsControlParameterTimeUse = False - solver_object.EigenmodesCount = 10 - solver_object.EigenmodeHighLimit = 1000000.0 - solver_object.EigenmodeLowLimit = 0.0 - self.assertTrue( - solver_object, - "FemTest of new solver failed" - ) - analysis.addObject(solver_object) - - fcc_print("Checking FEM new material...") - material_object = ObjectsFem.makeMaterialSolid( - self.active_doc, - "MechanicalMaterial" - ) - mat = material_object.Material - mat["Name"] = "Steel-Generic" - mat["YoungsModulus"] = "200000 MPa" - mat["PoissonRatio"] = "0.30" - mat["Density"] = "7900 kg/m^3" - material_object.Material = mat - self.assertTrue( - material_object, - "FemTest of new material failed" - ) - analysis.addObject(material_object) - - fcc_print("Checking FEM new fixed constraint...") - fixed_constraint = self.active_doc.addObject( - "Fem::ConstraintFixed", - "FemConstraintFixed" - ) - fixed_constraint.References = [(box, "Face1")] - self.assertTrue( - fixed_constraint, - "FemTest of new fixed constraint failed" - ) - analysis.addObject(fixed_constraint) - - fcc_print("Checking FEM new force constraint...") - force_constraint = self.active_doc.addObject( - "Fem::ConstraintForce", - "FemConstraintForce" - ) - force_constraint.References = [(box, "Face6")] - force_constraint.Force = 40000.0 - force_constraint.Direction = (box, ["Edge5"]) - self.active_doc.recompute() - force_constraint.Reversed = True - self.active_doc.recompute() - self.assertTrue( - force_constraint, - "FemTest of new force constraint failed" - ) - analysis.addObject(force_constraint) - - fcc_print("Checking FEM new pressure constraint...") - pressure_constraint = self.active_doc.addObject( - "Fem::ConstraintPressure", - "FemConstraintPressure" - ) - pressure_constraint.References = [(box, "Face2")] - pressure_constraint.Pressure = 1000.0 - pressure_constraint.Reversed = False - self.assertTrue( - pressure_constraint, - "FemTest of new pressure constraint failed" - ) - analysis.addObject(pressure_constraint) - - fcc_print("Checking FEM new mesh...") - from ..data.ccx.cube_mesh import create_nodes_cube - from ..data.ccx.cube_mesh import create_elements_cube - mesh = Fem.FemMesh() - ret = create_nodes_cube(mesh) - self.assertTrue( - ret, - "Import of mesh nodes failed" - ) - ret = create_elements_cube(mesh) - self.assertTrue( - ret, - "Import of mesh volumes failed" - ) - mesh_object = self.active_doc.addObject( - "Fem::FemMeshObject", - self.mesh_name - ) - mesh_object.FemMesh = mesh - self.assertTrue( - mesh, - "FemTest of new mesh failed" - ) - analysis.addObject(mesh_object) - - self.active_doc.recompute() + analysis = self.active_doc.Analysis + solver_object = self.active_doc.CalculiXccxTools static_analysis_dir = testtools.get_unit_test_tmp_dir( self.temp_dir, @@ -341,71 +228,12 @@ class TestCcxTools(unittest.TestCase): ): fcc_print("\n--------------- Start of FEM ccxtools frequency analysis test ------------") - self.active_doc.addObject("Part::Box", "Box") + # set up the static analysis example + from femexamples import boxanalysis as box + box.setup_frequency(self.active_doc, "ccxtools") - fcc_print("Checking FEM new analysis...") - analysis = ObjectsFem.makeAnalysis( - self.active_doc, - "Analysis" - ) - self.assertTrue( - analysis, - "FemTest of new analysis failed" - ) - - fcc_print("Checking FEM new solver...") - solver_object = ObjectsFem.makeSolverCalculixCcxTools( - self.active_doc, - "CalculiX" - ) - solver_object.AnalysisType = "frequency" - solver_object.GeometricalNonlinearity = "linear" - solver_object.ThermoMechSteadyState = False - solver_object.MatrixSolverType = "default" - solver_object.IterationsControlParameterTimeUse = False - solver_object.EigenmodesCount = 10 - solver_object.EigenmodeHighLimit = 1000000.0 - solver_object.EigenmodeLowLimit = 0.01 - self.assertTrue( - solver_object, - "FemTest of new solver failed" - ) - analysis.addObject(solver_object) - - fcc_print("Checking FEM new material...") - material_object = ObjectsFem.makeMaterialSolid( - self.active_doc, - "MechanicalMaterial" - ) - mat = material_object.Material - mat["Name"] = "Steel-Generic" - mat["YoungsModulus"] = "200000 MPa" - mat["PoissonRatio"] = "0.30" - mat["Density"] = "7900 kg/m^3" - material_object.Material = mat - self.assertTrue( - material_object, - "FemTest of new material failed" - ) - analysis.addObject(material_object) - - fcc_print("Checking FEM new mesh...") - from ..data.ccx.cube_mesh import create_nodes_cube - from ..data.ccx.cube_mesh import create_elements_cube - mesh = Fem.FemMesh() - ret = create_nodes_cube(mesh) - self.assertTrue(ret, "Import of mesh nodes failed") - ret = create_elements_cube(mesh) - self.assertTrue(ret, "Import of mesh volumes failed") - mesh_object = self.active_doc.addObject( - "Fem::FemMeshObject", - self.mesh_name - ) - mesh_object.FemMesh = mesh - self.assertTrue(mesh, "FemTest of new mesh failed") - analysis.addObject(mesh_object) - - self.active_doc.recompute() + analysis = self.active_doc.Analysis + solver_object = self.active_doc.CalculiXccxTools frequency_analysis_dir = testtools.get_unit_test_tmp_dir( self.temp_dir,