[FEM] Elmer add support for nonlinear elasticity solver
- adds new equation "Deformation" (this name since the stress solver got in FreeCAD the misleading name "elasticity") - this way change icon of elastic solver to make the difference clear
This commit is contained in:
@@ -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
|
||||
|
||||
@@ -41,6 +41,7 @@
|
||||
<file>icons/FEM_ElementGeometry1D.svg</file>
|
||||
<file>icons/FEM_ElementGeometry2D.svg</file>
|
||||
<file>icons/FEM_ElementRotation1D.svg</file>
|
||||
<file>icons/FEM_EquationDeformation.svg</file>
|
||||
<file>icons/FEM_EquationElasticity.svg</file>
|
||||
<file>icons/FEM_EquationElectricforce.svg</file>
|
||||
<file>icons/FEM_EquationElectrostatic.svg</file>
|
||||
|
||||
47
src/Mod/Fem/Gui/Resources/icons/FEM_EquationDeformation.svg
Normal file
47
src/Mod/Fem/Gui/Resources/icons/FEM_EquationDeformation.svg
Normal file
@@ -0,0 +1,47 @@
|
||||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||
<svg version="1.1" id="svg2" height="64" width="64" xmlns:xlink="http://www.w3.org/1999/xlink" xmlns="http://www.w3.org/2000/svg" xmlns:svg="http://www.w3.org/2000/svg" xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#" xmlns:cc="http://creativecommons.org/ns#" xmlns:dc="http://purl.org/dc/elements/1.1/">
|
||||
<defs id="defs4">
|
||||
<linearGradient id="linearGradient3802">
|
||||
<stop id="stop3804" offset="0" style="stop-color:black;stop-opacity:1;" />
|
||||
<stop id="stop3806" offset="1" style="stop-color:#555753;stop-opacity:1" />
|
||||
</linearGradient>
|
||||
<linearGradient gradientUnits="userSpaceOnUse" y2="42" x2="47" y1="58" x1="49" id="linearGradient3808" xlink:href="#linearGradient3802" />
|
||||
</defs>
|
||||
<metadata id="metadata7">
|
||||
<rdf:RDF>
|
||||
<cc:Work rdf:about="">
|
||||
<dc:format>image/svg+xml</dc:format>
|
||||
<dc:type rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
|
||||
<dc:creator>
|
||||
<cc:Agent>
|
||||
<dc:title>[Alexander Gryson]</dc:title>
|
||||
</cc:Agent>
|
||||
</dc:creator>
|
||||
<dc:date>2017-03-11</dc:date>
|
||||
<dc:relation>http://www.freecadweb.org/wiki/index.php?title=Artwork</dc:relation>
|
||||
<dc:publisher>
|
||||
<cc:Agent>
|
||||
<dc:title>FreeCAD</dc:title>
|
||||
</cc:Agent>
|
||||
</dc:publisher>
|
||||
<dc:identifier>FreeCAD/src/Mod/</dc:identifier>
|
||||
<dc:rights>
|
||||
<cc:Agent>
|
||||
<dc:title>FreeCAD LGPL2+</dc:title>
|
||||
</cc:Agent>
|
||||
</dc:rights>
|
||||
<cc:license>https://www.gnu.org/copyleft/lesser.html</cc:license>
|
||||
<dc:contributor>
|
||||
<cc:Agent>
|
||||
<dc:title>[agryson] Alexander Gryson</dc:title>
|
||||
</cc:Agent>
|
||||
</dc:contributor>
|
||||
</cc:Work>
|
||||
</rdf:RDF>
|
||||
</metadata>
|
||||
<g transform="translate(0,-988.36218)" id="layer1">
|
||||
<rect transform="translate(0,988.36218)" y="39" x="3" height="22" width="58" id="rect2987" style="fill:url(#linearGradient3808);stroke:#172a04;stroke-width:2;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:9.6;fill-opacity:1" />
|
||||
<rect y="1029.3622" x="5" height="18" width="54" id="rect2987-6" style="fill:none;stroke:#555753;stroke-width:2;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:9.6;stroke-opacity:1" />
|
||||
<path id="rect2987-3" d="m 3,1027.3622 c 18,0 24,-20 30,-32.00002 l 20,10.00002 c -4,8 -18,44 -50,44 z" style="fill:#ffc000;stroke:#172a04;stroke-width:2;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dashoffset:9.6;fill-opacity:1" />
|
||||
</g>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 2.6 KiB |
@@ -1,11 +1,16 @@
|
||||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||
<svg version="1.1" id="svg2" height="64" width="64" xmlns:xlink="http://www.w3.org/1999/xlink" xmlns="http://www.w3.org/2000/svg" xmlns:svg="http://www.w3.org/2000/svg" xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#" xmlns:cc="http://creativecommons.org/ns#" xmlns:dc="http://purl.org/dc/elements/1.1/">
|
||||
<defs id="defs4">
|
||||
<linearGradient id="linearGradient1124">
|
||||
<stop style="stop-color:#555753;stop-opacity:1;" offset="0.46724442" id="stop1120" />
|
||||
<stop style="stop-color:red;stop-opacity:1;" offset="1" id="stop1122" />
|
||||
</linearGradient>
|
||||
<linearGradient id="linearGradient3802">
|
||||
<stop id="stop3804" offset="0" style="stop-color:#2e3436;stop-opacity:1" />
|
||||
<stop id="stop3806" offset="1" style="stop-color:#555753;stop-opacity:1" />
|
||||
</linearGradient>
|
||||
<linearGradient gradientUnits="userSpaceOnUse" y2="42" x2="47" y1="58" x1="49" id="linearGradient3808" xlink:href="#linearGradient3802" />
|
||||
<linearGradient gradientUnits="userSpaceOnUse" y2="42" x2="47" y1="58" x1="49" id="linearGradient3808" xlink:href="#linearGradient3802" gradientTransform="translate(-1.7637803,1024.9528)" />
|
||||
<linearGradient xlink:href="#linearGradient1124" id="linearGradient1126" x1="3.2795276" y1="1022.3502" x2="60.972441" y2="1022.3502" gradientUnits="userSpaceOnUse" />
|
||||
</defs>
|
||||
<metadata id="metadata7">
|
||||
<rdf:RDF>
|
||||
@@ -17,7 +22,6 @@
|
||||
<dc:title>[Alexander Gryson]</dc:title>
|
||||
</cc:Agent>
|
||||
</dc:creator>
|
||||
<dc:title>fem-warp</dc:title>
|
||||
<dc:date>2017-03-11</dc:date>
|
||||
<dc:relation>http://www.freecadweb.org/wiki/index.php?title=Artwork</dc:relation>
|
||||
<dc:publisher>
|
||||
@@ -41,8 +45,6 @@
|
||||
</rdf:RDF>
|
||||
</metadata>
|
||||
<g transform="translate(0,-988.36218)" id="layer1">
|
||||
<rect transform="translate(0,988.36218)" y="39" x="3" height="22" width="58" id="rect2987" style="fill:url(#linearGradient3808);stroke:#172a04;stroke-width:2;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:9.6;fill-opacity:1" />
|
||||
<rect y="1029.3622" x="5" height="18" width="54" id="rect2987-6" style="fill:none;stroke:#555753;stroke-width:2;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:9.6;stroke-opacity:1" />
|
||||
<path id="rect2987-3" d="m 3,1027.3622 c 18,0 24,-20 30,-32.00002 l 20,10.00002 c -4,8 -18,44 -50,44 z" style="fill:#888a85;stroke:#172a04;stroke-width:2;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dashoffset:9.6;fill-opacity:1" />
|
||||
<path style="fill:url(#linearGradient1126);stroke:#172a04;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;fill-opacity:1" d="M 60.472441,1037.496 C 60.472441,1037.496 45.227698,1029.6494 3.7795276,1029.937 L 3.7795276,1007.2598 C 45.354331,1007.2598 60.472441,1014.8189 60.472441,1014.8189 V 1037.496" id="path484" />
|
||||
</g>
|
||||
</svg>
|
||||
|
||||
|
Before Width: | Height: | Size: 2.7 KiB After Width: | Height: | Size: 2.6 KiB |
@@ -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"
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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()
|
||||
|
||||
120
src/Mod/Fem/femsolver/elmer/equations/deformation.py
Normal file
120
src/Mod/Fem/femsolver/elmer/equations/deformation.py
Normal file
@@ -0,0 +1,120 @@
|
||||
# ***************************************************************************
|
||||
# * Copyright (c) 2023 Uwe Stöhr <uwestoehr@lyx.org> *
|
||||
# * *
|
||||
# * 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
|
||||
|
||||
## @}
|
||||
222
src/Mod/Fem/femsolver/elmer/equations/deformation_writer.py
Normal file
222
src/Mod/Fem/femsolver/elmer/equations/deformation_writer.py
Normal file
@@ -0,0 +1,222 @@
|
||||
# ***************************************************************************
|
||||
# * Copyright (c) 2023 Uwe Stöhr <uwestoehr@lyx.org> *
|
||||
# * *
|
||||
# * 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
|
||||
|
||||
## @}
|
||||
@@ -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
|
||||
|
||||
@@ -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"):
|
||||
|
||||
@@ -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
|
||||
|
||||
|
||||
@@ -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)
|
||||
|
||||
Reference in New Issue
Block a user