diff --git a/src/Mod/Fem/CMakeLists.txt b/src/Mod/Fem/CMakeLists.txt
index 6a12f99cf7..5d816ac362 100755
--- a/src/Mod/Fem/CMakeLists.txt
+++ b/src/Mod/Fem/CMakeLists.txt
@@ -259,6 +259,8 @@ SET(FemSolverElmer_SRCS
SET(FemSolverElmerEquations_SRCS
femsolver/elmer/equations/__init__.py
+ femsolver/elmer/equations/deformation.py
+ femsolver/elmer/equations/deformation_writer.py
femsolver/elmer/equations/elasticity.py
femsolver/elmer/equations/elasticity_writer.py
femsolver/elmer/equations/electricforce.py
diff --git a/src/Mod/Fem/Gui/Resources/Fem.qrc b/src/Mod/Fem/Gui/Resources/Fem.qrc
index 25860e232f..4c72952889 100755
--- a/src/Mod/Fem/Gui/Resources/Fem.qrc
+++ b/src/Mod/Fem/Gui/Resources/Fem.qrc
@@ -41,6 +41,7 @@
icons/FEM_ElementGeometry1D.svg
icons/FEM_ElementGeometry2D.svg
icons/FEM_ElementRotation1D.svg
+ icons/FEM_EquationDeformation.svg
icons/FEM_EquationElasticity.svg
icons/FEM_EquationElectricforce.svg
icons/FEM_EquationElectrostatic.svg
diff --git a/src/Mod/Fem/Gui/Resources/icons/FEM_EquationDeformation.svg b/src/Mod/Fem/Gui/Resources/icons/FEM_EquationDeformation.svg
new file mode 100644
index 0000000000..a4db53daa6
--- /dev/null
+++ b/src/Mod/Fem/Gui/Resources/icons/FEM_EquationDeformation.svg
@@ -0,0 +1,47 @@
+
+
diff --git a/src/Mod/Fem/Gui/Resources/icons/FEM_EquationElasticity.svg b/src/Mod/Fem/Gui/Resources/icons/FEM_EquationElasticity.svg
index 2e9bcbcb01..526ff547ca 100644
--- a/src/Mod/Fem/Gui/Resources/icons/FEM_EquationElasticity.svg
+++ b/src/Mod/Fem/Gui/Resources/icons/FEM_EquationElasticity.svg
@@ -1,11 +1,16 @@
diff --git a/src/Mod/Fem/Gui/Workbench.cpp b/src/Mod/Fem/Gui/Workbench.cpp
index 70c14c5a7f..789d97a1c2 100755
--- a/src/Mod/Fem/Gui/Workbench.cpp
+++ b/src/Mod/Fem/Gui/Workbench.cpp
@@ -180,6 +180,7 @@ Gui::ToolBarItem* Workbench::setupToolBars() const
<< "FEM_SolverZ88"
<< "Separator"
<< "FEM_EquationElasticity"
+ << "FEM_EquationDeformation"
<< "FEM_CompEmEquations"
<< "FEM_EquationFlow"
<< "FEM_EquationFlux"
@@ -348,6 +349,7 @@ Gui::MenuItem* Workbench::setupMenuBar() const
<< "FEM_SolverZ88"
<< "Separator"
<< "FEM_EquationElasticity"
+ << "FEM_EquationDeformation"
<< "FEM_CompEmEquations"
<< "FEM_EquationFlow"
<< "FEM_EquationFlux"
diff --git a/src/Mod/Fem/ObjectsFem.py b/src/Mod/Fem/ObjectsFem.py
index 91e9378d07..c496ed88eb 100644
--- a/src/Mod/Fem/ObjectsFem.py
+++ b/src/Mod/Fem/ObjectsFem.py
@@ -753,6 +753,20 @@ def makePostVtkResult(
# ********* solver objects ***********************************************************************
+def makeEquationDeformation(
+ doc,
+ base_solver=None,
+ name="Deformation"
+):
+ """makeEquationDeformation(document, [base_solver], [name]):
+ creates a FEM deformation (nonlinear elasticity) equation for a solver"""
+ from femsolver.elmer.equations import deformation
+ obj = deformation.create(doc, name)
+ if base_solver:
+ base_solver.addObject(obj)
+ return obj
+
+
def makeEquationElasticity(
doc,
base_solver=None,
diff --git a/src/Mod/Fem/femcommands/commands.py b/src/Mod/Fem/femcommands/commands.py
index 732b546249..9bc5a579e5 100644
--- a/src/Mod/Fem/femcommands/commands.py
+++ b/src/Mod/Fem/femcommands/commands.py
@@ -431,6 +431,23 @@ class _ElementRotation1D(CommandManager):
self.do_activated = "add_obj_on_gui_noset_edit"
+class _EquationDeformation(CommandManager):
+ "The FEM_EquationDeformation command definition"
+
+ def __init__(self):
+ super(_EquationDeformation, self).__init__()
+ self.menutext = Qt.QT_TRANSLATE_NOOP(
+ "FEM_EquationDeformation",
+ "Deformation equation"
+ )
+ self.tooltip = Qt.QT_TRANSLATE_NOOP(
+ "FEM_EquationDeformation",
+ "Creates a FEM equation for\n deformation (nonlinear elasticity)"
+ )
+ self.is_active = "with_solver_elmer"
+ self.do_activated = "add_obj_on_gui_selobj_noset_edit"
+
+
class _EquationElasticity(CommandManager):
"The FEM_EquationElasticity command definition"
@@ -442,7 +459,7 @@ class _EquationElasticity(CommandManager):
)
self.tooltip = Qt.QT_TRANSLATE_NOOP(
"FEM_EquationElasticity",
- "Creates a FEM equation for elasticity"
+ "Creates a FEM equation for\n elasticity (stress)"
)
self.is_active = "with_solver_elmer"
self.do_activated = "add_obj_on_gui_selobj_noset_edit"
@@ -1232,6 +1249,10 @@ FreeCADGui.addCommand(
"FEM_ElementRotation1D",
_ElementRotation1D()
)
+FreeCADGui.addCommand(
+ "FEM_EquationDeformation",
+ _EquationDeformation()
+)
FreeCADGui.addCommand(
"FEM_EquationElasticity",
_EquationElasticity()
diff --git a/src/Mod/Fem/femsolver/elmer/equations/deformation.py b/src/Mod/Fem/femsolver/elmer/equations/deformation.py
new file mode 100644
index 0000000000..2c79ece569
--- /dev/null
+++ b/src/Mod/Fem/femsolver/elmer/equations/deformation.py
@@ -0,0 +1,120 @@
+# ***************************************************************************
+# * Copyright (c) 2023 Uwe Stöhr *
+# * *
+# * 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. *
+# * *
+# * This program 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 this program; if not, write to the Free Software *
+# * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 *
+# * USA *
+# * *
+# ***************************************************************************
+
+__title__ = "FreeCAD FEM solver Elmer equation object Deformation"
+__author__ = "Uwe Stöhr"
+__url__ = "https://www.freecadweb.org"
+
+## \addtogroup FEM
+# @{
+
+from femtools import femutils
+from ... import equationbase
+from . import linear
+
+
+def create(doc, name="Deformation"):
+ return femutils.createObject(
+ doc, name, Proxy, ViewProxy)
+
+
+class Proxy(linear.Proxy, equationbase.DeformationProxy):
+
+ Type = "Fem::EquationElmerDeformation"
+
+ def __init__(self, obj):
+ super(Proxy, self).__init__(obj)
+
+ obj.addProperty(
+ "App::PropertyBool",
+ "CalculatePangle",
+ "Deformation",
+ "Compute principal stress angles"
+ )
+ obj.addProperty(
+ "App::PropertyBool",
+ "CalculatePrincipal",
+ "Deformation",
+ "Compute principal stress components"
+ )
+ obj.addProperty(
+ "App::PropertyBool",
+ "CalculateStrains",
+ "Deformation",
+ "Compute the strain tensor"
+ )
+ obj.addProperty(
+ "App::PropertyBool",
+ "CalculateStresses",
+ "Deformation",
+ "Compute stress tensor and vanMises"
+ )
+ obj.addProperty(
+ "App::PropertyBool",
+ "InitializeStateVariables",
+ "Deformation",
+ "See Elmer manual for info"
+ )
+ obj.addProperty(
+ "App::PropertyBool",
+ "MixedFormulation",
+ "Deformation",
+ "See Elmer manual for info"
+ )
+ obj.addProperty(
+ "App::PropertyBool",
+ "NeoHookeanMaterial",
+ "Deformation",
+ (
+ "Uses the neo-Hookean material model"
+ )
+ )
+ obj.addProperty(
+ "App::PropertyBool",
+ "PlaneStress",
+ "Equation",
+ (
+ "Computes solution according to plane\nstress situation.\n"
+ "Applies only for 2D geometry."
+ )
+ )
+ obj.addProperty(
+ "App::PropertyString",
+ "Variable",
+ "Deformation",
+ "Only for a 2D model change the '3' to '2'"
+ )
+
+ obj.Priority = 10
+ obj.CalculatePrincipal = True
+ # according to Elmer tutorial and forum, for stresses direct solving
+ # is recommended -> tests showed 10 times faster and even more accurate
+ obj.LinearSolverType = "Direct"
+ obj.LinearDirectMethod = "Umfpack"
+ obj.Variable = "-dofs 3 Displacement"
+
+
+class ViewProxy(linear.ViewProxy, equationbase.DeformationViewProxy):
+ pass
+
+## @}
diff --git a/src/Mod/Fem/femsolver/elmer/equations/deformation_writer.py b/src/Mod/Fem/femsolver/elmer/equations/deformation_writer.py
new file mode 100644
index 0000000000..c73809840e
--- /dev/null
+++ b/src/Mod/Fem/femsolver/elmer/equations/deformation_writer.py
@@ -0,0 +1,222 @@
+# ***************************************************************************
+# * Copyright (c) 2023 Uwe Stöhr *
+# * *
+# * 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. *
+# * *
+# * This program 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 this program; if not, write to the Free Software *
+# * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 *
+# * USA *
+# * *
+# ***************************************************************************
+
+__title__ = "FreeCAD FEM Elasticity Elmer writer"
+__author__ = "Uwe Stöhr"
+__url__ = "https://www.freecad.org"
+
+## \addtogroup FEM
+# @{
+
+from FreeCAD import Console
+from FreeCAD import Units
+
+from .. import sifio
+from .. import writer as general_writer
+from femtools import femutils
+
+class DeformationWriter:
+
+ def __init__(self, writer, solver):
+ self.write = writer
+ self.solver = solver
+
+ def getDeformationSolver(self, equation):
+ s = self.write.createLinearSolver(equation)
+ # output the equation parameters
+ s["Equation"] = "Nonlinear elasticity solver"
+ s["Procedure"] = sifio.FileAttr("ElasticSolve/ElasticSolver")
+ if equation.CalculateStrains is True:
+ s["Calculate Strains"] = equation.CalculateStrains
+ if equation.CalculateStresses is True:
+ s["Calculate Stresses"] = equation.CalculateStresses
+ if equation.CalculatePrincipal is True:
+ s["Calculate Principal"] = equation.CalculatePrincipal
+ if equation.CalculatePangle is True:
+ s["Calculate Pangle"] = equation.CalculatePangle
+ if equation.InitializeStateVariables is True:
+ s["Initialize State Variables"] = equation.InitializeStateVariables
+ if equation.MixedFormulation is True:
+ s["Mixed Formulation"] = equation.MixedFormulation
+ if equation.NeoHookeanMaterial is True:
+ s["Neo-Hookean Material"] = equation.NeoHookeanMaterial
+ s["Exec Solver"] = "Always"
+ s["Optimize Bandwidth"] = True
+ s["Stabilize"] = equation.Stabilize
+ s["Variable"] = equation.Variable
+ return s
+
+ def handleDeformationEquation(self, bodies, equation):
+ for b in bodies:
+ # not for bodies with fluid material
+ if not self.write.isBodyMaterialFluid(b):
+ if equation.PlaneStress:
+ self.write.equation(b, "Plane Stress", equation.PlaneStress)
+
+ def handleDeformationConstants(self):
+ pass
+
+ def handleDeformationBndConditions(self):
+ for obj in self.write.getMember("Fem::ConstraintPressure"):
+ if obj.References:
+ for name in obj.References[0][1]:
+ pressure = self.write.getFromUi(obj.Pressure, "MPa", "M/(L*T^2)")
+ if not obj.Reversed:
+ pressure *= -1
+ self.write.boundary(name, "Normal Force", pressure)
+ self.write.handled(obj)
+ for obj in self.write.getMember("Fem::ConstraintFixed"):
+ if obj.References:
+ for name in obj.References[0][1]:
+ self.write.boundary(name, "Displacement 1", 0.0)
+ self.write.boundary(name, "Displacement 2", 0.0)
+ self.write.boundary(name, "Displacement 3", 0.0)
+ self.write.handled(obj)
+ for obj in self.write.getMember("Fem::ConstraintForce"):
+ if obj.References:
+ for name in obj.References[0][1]:
+ force = self.write.getFromUi(obj.Force, "N", "M*L*T^-2")
+ self.write.boundary(name, "Force 1", obj.DirectionVector.x * force)
+ self.write.boundary(name, "Force 2", obj.DirectionVector.y * force)
+ self.write.boundary(name, "Force 3", obj.DirectionVector.z * force)
+ self.write.boundary(name, "Force 1 Normalize by Area", True)
+ self.write.boundary(name, "Force 2 Normalize by Area", True)
+ self.write.boundary(name, "Force 3 Normalize by Area", True)
+ self.write.handled(obj)
+ for obj in self.write.getMember("Fem::ConstraintDisplacement"):
+ if obj.References:
+ for name in obj.References[0][1]:
+ if not obj.xFree:
+ self.write.boundary(
+ name, "Displacement 1", obj.xDisplacement * 0.001)
+ elif obj.xFix:
+ self.write.boundary(name, "Displacement 1", 0.0)
+ if not obj.yFree:
+ self.write.boundary(
+ name, "Displacement 2", obj.yDisplacement * 0.001)
+ elif obj.yFix:
+ self.write.boundary(name, "Displacement 2", 0.0)
+ if not obj.zFree:
+ self.write.boundary(
+ name, "Displacement 3", obj.zDisplacement * 0.001)
+ elif obj.zFix:
+ self.write.boundary(name, "Displacement 3", 0.0)
+ self.write.handled(obj)
+
+ def handleDeformationInitial(self, bodies):
+ pass
+
+ def handleDeformationBodyForces(self, bodies):
+ obj = self.write.getSingleMember("Fem::ConstraintSelfWeight")
+ if obj is not None:
+ for name in bodies:
+ gravity = self.write.convert(self.write.constsdef["Gravity"], "L/T^2")
+ if self.write.getBodyMaterial(name) is None:
+ raise general_writer.WriteError(
+ "The body {} is not referenced in any material.\n\n".format(name)
+ )
+ m = self.write.getBodyMaterial(name).Material
+
+ densityQuantity = Units.Quantity(m["Density"])
+ dimension = "M/L^3"
+ if name.startswith("Edge"):
+ # not tested, bernd
+ # TODO: test
+ densityQuantity.Unit = Units.Unit(-2, 1)
+ dimension = "M/L^2"
+ density = self.write.convert(densityQuantity, dimension)
+
+ force1 = gravity * obj.Gravity_x * density
+ force2 = gravity * obj.Gravity_y * density
+ force3 = gravity * obj.Gravity_z * density
+ self.write.bodyForce(name, "Stress Bodyforce 1", force1)
+ self.write.bodyForce(name, "Stress Bodyforce 2", force2)
+ self.write.bodyForce(name, "Stress Bodyforce 3", force3)
+ self.write.handled(obj)
+
+ def handleDeformationMaterial(self, bodies):
+ # density
+ # is needed for self weight constraints and frequency analysis
+ density_needed = False
+ for equation in self.solver.Group:
+ if femutils.is_of_type(equation, "Fem::EquationElmerElasticity"):
+ if equation.EigenAnalysis is True:
+ density_needed = True
+ break # there could be a second equation without frequency
+ gravObj = self.write.getSingleMember("Fem::ConstraintSelfWeight")
+ if gravObj is not None:
+ density_needed = True
+ # temperature
+ tempObj = self.write.getSingleMember("Fem::ConstraintInitialTemperature")
+ if tempObj is not None:
+ refTemp = self.write.getFromUi(tempObj.initialTemperature, "K", "O")
+ for name in bodies:
+ self.write.material(name, "Reference Temperature", refTemp)
+ # get the material data for all bodies
+ for obj in self.write.getMember("App::MaterialObject"):
+ m = obj.Material
+ refs = (
+ obj.References[0][1]
+ if obj.References
+ else self.write.getAllBodies()
+ )
+ for name in (n for n in refs if n in bodies):
+ # don't evaluate fluid material
+ if self.write.isBodyMaterialFluid(name):
+ break
+ if "YoungsModulus" not in m:
+ Console.PrintMessage("m: {}\n".format(m))
+ # it is no fluid but also no solid
+ # -> user set no material reference at all
+ # that now material is known
+ raise general_writer.WriteError(
+ "There are two or more materials with empty references.\n\n"
+ "Set for the materials to what solid they belong to.\n"
+ )
+ self.write.material(name, "Name", m["Name"])
+ if density_needed is True:
+ self.write.material(
+ name, "Density",
+ self.write.getDensity(m)
+ )
+ self.write.material(
+ name, "Youngs Modulus",
+ self._getYoungsModulus(m)
+ )
+ self.write.material(
+ name, "Poisson ratio",
+ float(m["PoissonRatio"])
+ )
+ if tempObj:
+ self.write.material(
+ name, "Heat expansion Coefficient",
+ self.write.convert(m["ThermalExpansionCoefficient"], "O^-1")
+ )
+
+ def _getYoungsModulus(self, m):
+ youngsModulus = self.write.convert(m["YoungsModulus"], "M/(L*T^2)")
+ if self.write.getMeshDimension() == 2:
+ youngsModulus *= 1e3
+ return youngsModulus
+
+## @}
diff --git a/src/Mod/Fem/femsolver/elmer/equations/elasticity_writer.py b/src/Mod/Fem/femsolver/elmer/equations/elasticity_writer.py
index 63fbed1bb5..fabee1449a 100644
--- a/src/Mod/Fem/femsolver/elmer/equations/elasticity_writer.py
+++ b/src/Mod/Fem/femsolver/elmer/equations/elasticity_writer.py
@@ -36,7 +36,7 @@ from .. import writer as general_writer
from femtools import femutils
from . import elasticity
-class Elasticitywriter:
+class ElasticityWriter:
def __init__(self, writer, solver):
self.write = writer
diff --git a/src/Mod/Fem/femsolver/elmer/writer.py b/src/Mod/Fem/femsolver/elmer/writer.py
index 4cd3d4975d..8a6361e353 100644
--- a/src/Mod/Fem/femsolver/elmer/writer.py
+++ b/src/Mod/Fem/femsolver/elmer/writer.py
@@ -48,6 +48,7 @@ from femmesh import gmshtools
from femtools import constants
from femtools import femutils
from femtools import membertools
+from .equations import deformation_writer as DEF_writer
from .equations import elasticity_writer as EL_writer
from .equations import electricforce_writer as EF_writer
from .equations import electrostatic_writer as ES_writer
@@ -94,6 +95,7 @@ class Writer(object):
def write_solver_input(self):
self._handleRedifinedConstants()
self._handleSimulation()
+ self._handleDeformation()
self._handleElasticity()
self._handleElectricforce()
self._handleElectrostatic()
@@ -405,11 +407,39 @@ class Writer(object):
)
solver.TimestepSizes = [0.1]
+ #-------------------------------------------------------------------------------------------
+ # Deformation
+
+ def _handleDeformation(self):
+ DEFW = DEF_writer.DeformationWriter(self, self.solver)
+ activeIn = []
+ for equation in self.solver.Group:
+ if femutils.is_of_type(equation, "Fem::EquationElmerDeformation"):
+ if not self._haveMaterialSolid():
+ raise WriteError(
+ "The Deformation equation requires at least one body with a solid material!"
+ )
+ if equation.References:
+ activeIn = equation.References[0][1]
+ else:
+ activeIn = self.getAllBodies()
+ solverSection = DEFW.getDeformationSolver(equation)
+ for body in activeIn:
+ if not self.isBodyMaterialFluid(body):
+ self._addSolver(body, solverSection)
+ DEFW.handleDeformationEquation(activeIn, equation)
+ if activeIn:
+ DEFW.handleDeformationConstants()
+ DEFW.handleDeformationBndConditions()
+ DEFW.handleDeformationInitial(activeIn)
+ DEFW.handleDeformationBodyForces(activeIn)
+ DEFW.handleDeformationMaterial(activeIn)
+
#-------------------------------------------------------------------------------------------
# Elasticity
def _handleElasticity(self):
- ELW = EL_writer.Elasticitywriter(self, self.solver)
+ ELW = EL_writer.ElasticityWriter(self, self.solver)
activeIn = []
for equation in self.solver.Group:
if femutils.is_of_type(equation, "Fem::EquationElmerElasticity"):
diff --git a/src/Mod/Fem/femsolver/equationbase.py b/src/Mod/Fem/femsolver/equationbase.py
index a540c4165a..d926195e45 100644
--- a/src/Mod/Fem/femsolver/equationbase.py
+++ b/src/Mod/Fem/femsolver/equationbase.py
@@ -69,6 +69,16 @@ class BaseViewProxy(object):
return mode
+class DeformationProxy(BaseProxy):
+ pass
+
+
+class DeformationViewProxy(BaseViewProxy):
+
+ def getIcon(self):
+ return ":/icons/FEM_EquationDeformation.svg"
+
+
class ElasticityProxy(BaseProxy):
pass
diff --git a/src/Mod/Fem/femtest/app/test_object.py b/src/Mod/Fem/femtest/app/test_object.py
index a0123a499a..662f6eeccf 100644
--- a/src/Mod/Fem/femtest/app/test_object.py
+++ b/src/Mod/Fem/femtest/app/test_object.py
@@ -84,14 +84,14 @@ class TestObjectCreate(unittest.TestCase):
# thus they are not added to the analysis group ATM
# https://forum.freecadweb.org/viewtopic.php?t=25283
# thus they should not be counted
- # solver children: equations --> 8
+ # solver children: equations --> 9
# gmsh mesh children: group, region, boundary layer --> 3
# result children: mesh result --> 1
# post pipeline children: region, scalar, cut, wrap --> 5
# analysis itself is not in analysis group --> 1
- # thus: -18
+ # thus: -19
- self.assertEqual(len(doc.Analysis.Group), count_defmake - 18)
+ self.assertEqual(len(doc.Analysis.Group), count_defmake - 19)
self.assertEqual(len(doc.Objects), count_defmake)
fcc_print("doc objects count: {}, method: {}".format(
@@ -346,6 +346,10 @@ class TestObjectType(unittest.TestCase):
"Fem::SolverZ88",
type_of_obj(ObjectsFem.makeSolverZ88(doc))
)
+ self.assertEqual(
+ "Fem::EquationElmerDeformation",
+ type_of_obj(ObjectsFem.makeEquationDeformation(doc, solverelmer))
+ )
self.assertEqual(
"Fem::EquationElmerElasticity",
type_of_obj(ObjectsFem.makeEquationElasticity(doc, solverelmer))
@@ -589,6 +593,10 @@ class TestObjectType(unittest.TestCase):
ObjectsFem.makeSolverZ88(doc),
"Fem::SolverZ88"
))
+ self.assertTrue(is_of_type(
+ ObjectsFem.makeEquationDeformation(doc, solverelmer),
+ "Fem::EquationElmerDeformation"
+ ))
self.assertTrue(is_of_type(
ObjectsFem.makeEquationElasticity(doc, solverelmer),
"Fem::EquationElmerElasticity"
@@ -1371,6 +1379,21 @@ class TestObjectType(unittest.TestCase):
"Fem::SolverZ88"
))
+ # EquationElmerDeformation
+ equation_deformation = ObjectsFem.makeEquationDeformation(doc, solver_elmer)
+ self.assertTrue(is_derived_from(
+ equation_deformation,
+ "App::DocumentObject"
+ ))
+ self.assertTrue(is_derived_from(
+ equation_deformation,
+ "App::FeaturePython"
+ ))
+ self.assertTrue(is_derived_from(
+ equation_deformation,
+ "Fem::EquationElmerDeformation"
+ ))
+
# EquationElmerElasticity
equation_elasticity = ObjectsFem.makeEquationElasticity(doc, solver_elmer)
self.assertTrue(is_derived_from(
@@ -1744,6 +1767,12 @@ class TestObjectType(unittest.TestCase):
doc
).isDerivedFrom("Fem::FemSolverObjectPython")
)
+ self.assertTrue(
+ ObjectsFem.makeEquationDeformation(
+ doc,
+ solverelmer
+ ).isDerivedFrom("App::FeaturePython")
+ )
self.assertTrue(
ObjectsFem.makeEquationElasticity(
doc,
@@ -1868,6 +1897,7 @@ def create_all_fem_objects_doc(
analysis.addObject(ObjectsFem.makeSolverMystran(doc))
analysis.addObject(ObjectsFem.makeSolverZ88(doc))
+ ObjectsFem.makeEquationDeformation(doc, sol)
ObjectsFem.makeEquationElasticity(doc, sol)
ObjectsFem.makeEquationElectricforce(doc, sol)
ObjectsFem.makeEquationElectrostatic(doc, sol)