diff --git a/src/Mod/Fem/CMakeLists.txt b/src/Mod/Fem/CMakeLists.txt
index e327feb1cc..6a12f99cf7 100755
--- a/src/Mod/Fem/CMakeLists.txt
+++ b/src/Mod/Fem/CMakeLists.txt
@@ -78,6 +78,7 @@ SET(FemExamples_SRCS
femexamples/equation_electrostatics_capacitance_two_balls.py
femexamples/equation_electrostatics_electricforce_elmer_nongui6.py
femexamples/equation_flow_elmer_2D.py
+ femexamples/equation_flow_initial_elmer_2D.py
femexamples/equation_flow_turbulent_elmer_2D.py
femexamples/equation_flux_elmer.py
femexamples/equation_magnetodynamics_elmer.py
diff --git a/src/Mod/Fem/Gui/Resources/ui/InitialFlowVelocity.ui b/src/Mod/Fem/Gui/Resources/ui/InitialFlowVelocity.ui
index e034b3f3f7..de26fc3c75 100644
--- a/src/Mod/Fem/Gui/Resources/ui/InitialFlowVelocity.ui
+++ b/src/Mod/Fem/Gui/Resources/ui/InitialFlowVelocity.ui
@@ -6,40 +6,27 @@
0
0
- 400
- 300
+ 300
+ 174
Constraint Properties
-
-
- QFormLayout::AllNonFixedFieldsGrow
-
- -
-
-
- Velocity x:
-
-
-
- -
-
-
-
-
+
+
-
+
+
-
+
false
-
- 1.000000000000000
-
-
- m/s
+
+ formula
- -
+
-
unspecified
@@ -49,31 +36,52 @@
-
-
- -
-
-
- Velocity y:
-
-
-
- -
-
-
-
-
-
- false
-
-
- 1.000000000000000
-
-
- m/s
+
-
+
+
+ Velocity x:
- -
+
-
+
+
+ false
+
+
+
+ -
+
+
+ false
+
+
+
+
+
+
+
+
+ -
+
+
-
+
+
+ false
+
+
+ formula
+
+
+
+ -
+
+
+ Velocity y:
+
+
+
+ -
unspecified
@@ -83,31 +91,28 @@
-
-
- -
-
-
- Velocity z:
-
-
-
- -
-
-
-
-
+
-
+
false
-
- 1.000000000000000
+
+
+ -
+
+
+ false
- m/s
+
- -
+
+
+ -
+
+
-
unspecified
@@ -117,15 +122,49 @@
+ -
+
+
+ false
+
+
+ formula
+
+
+
+ -
+
+
+ Velocity z:
+
+
+
+ -
+
+
+ false
+
+
+
+ -
+
+
+ false
+
+
+
+
+
+
- Gui::InputField
- QLineEdit
-
+ Gui::QuantitySpinBox
+ QWidget
+
@@ -133,96 +172,48 @@
velocityXBox
toggled(bool)
- velocityXTxt
- setEnabled(bool)
-
-
- 230
- 44
-
-
- 230
- 18
-
-
-
-
- velocityXBox
- toggled(bool)
- velocityXTxt
+ formulaXCB
setDisabled(bool)
- 230
- 44
+ 351
+ 19
- 230
- 18
+ 351
+ 45
velocityYBox
toggled(bool)
- velocityYTxt
- setEnabled(bool)
-
-
- 347
- 53
-
-
- 184
- 53
-
-
-
-
- velocityYBox
- toggled(bool)
- velocityYTxt
+ formulaYCB
setDisabled(bool)
- 347
- 53
+ 351
+ 73
- 184
- 53
+ 351
+ 99
velocityZBox
toggled(bool)
- velocityZTxt
- setEnabled(bool)
-
-
- 347
- 87
-
-
- 184
- 87
-
-
-
-
- velocityZBox
- toggled(bool)
- velocityZTxt
+ formulaZCB
setDisabled(bool)
- 347
- 87
+ 351
+ 127
- 184
- 87
+ 351
+ 153
diff --git a/src/Mod/Fem/femexamples/equation_flow_elmer_2D.py b/src/Mod/Fem/femexamples/equation_flow_elmer_2D.py
index 60e71d5cb1..28b022b8e6 100644
--- a/src/Mod/Fem/femexamples/equation_flow_elmer_2D.py
+++ b/src/Mod/Fem/femexamples/equation_flow_elmer_2D.py
@@ -40,7 +40,7 @@ def get_information():
"name": "Flow - Elmer 2D",
"meshtype": "solid",
"meshelement": "Tet10",
- "constraints": ["initial pressure", "initial temperature", "initial velocity",
+ "constraints": ["initial pressure", "initial temperature",
"temperature", "velocity"],
"solvers": ["elmer"],
"material": "fluid",
@@ -179,10 +179,10 @@ def setup(doc=None, solvertype="elmer"):
# constraint inlet velocity
FlowVelocity_Inlet = ObjectsFem.makeConstraintFlowVelocity(doc, "FlowVelocity_Inlet")
FlowVelocity_Inlet.References = [(BooleanFragments, "Edge5")]
- FlowVelocity_Inlet.NormalDirection = Vector(-1, 0, 0)
FlowVelocity_Inlet.VelocityXFormula = "Variable Coordinate 2; Real MATC \"-0.01*(tx-1)*(2-tx)\""
FlowVelocity_Inlet.VelocityXUnspecified = False
FlowVelocity_Inlet.VelocityXHasFormula = True
+ FlowVelocity_Inlet.VelocityYUnspecified = False
analysis.addObject(FlowVelocity_Inlet)
# constraint wall velocity
@@ -192,7 +192,6 @@ def setup(doc=None, solvertype="elmer"):
(BooleanFragments, "Edge3"),
(BooleanFragments, "Edge4"),
(BooleanFragments, "Edge7")]
- FlowVelocity_Wall.NormalDirection = Vector(0, -1, 0)
FlowVelocity_Wall.VelocityXUnspecified = False
FlowVelocity_Wall.VelocityYUnspecified = False
analysis.addObject(FlowVelocity_Wall)
diff --git a/src/Mod/Fem/femexamples/equation_flow_initial_elmer_2D.py b/src/Mod/Fem/femexamples/equation_flow_initial_elmer_2D.py
new file mode 100644
index 0000000000..384575558a
--- /dev/null
+++ b/src/Mod/Fem/femexamples/equation_flow_initial_elmer_2D.py
@@ -0,0 +1,275 @@
+# ***************************************************************************
+# * 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 *
+# * *
+# ***************************************************************************
+
+import sys
+import FreeCAD
+from FreeCAD import Placement
+from FreeCAD import Rotation
+from FreeCAD import Vector
+
+import Draft
+import ObjectsFem
+
+from BOPTools import SplitFeatures
+from . import manager
+from .manager import get_meshname
+from .manager import init_doc
+
+def get_information():
+ return {
+ "name": "Initial Flow - Elmer 2D",
+ "meshtype": "solid",
+ "meshelement": "Tet10",
+ "constraints": ["initial pressure", "initial temperature", "initial velocity",
+ "temperature", "velocity"],
+ "solvers": ["elmer"],
+ "material": "fluid",
+ "equations": ["flow", "heat"]
+ }
+
+def get_explanation(header=""):
+ return header + """
+
+To run the example from Python console use:
+from femexamples.equation_flow_initial_elmer_2D import setup
+setup()
+
+Flow and Heat equation with initial velocity - Elmer solver
+
+"""
+
+def setup(doc=None, solvertype="elmer"):
+
+ # init FreeCAD document
+ if doc is None:
+ doc = init_doc()
+
+ # explanation object
+ # just keep the following line and change text string in get_explanation method
+ manager.add_explanation_obj(doc, get_explanation(manager.get_header(get_information())))
+
+ # geometric objects
+
+ # the wire defining the pipe volume in 2D
+ p1 = Vector(400, -50.000, 0)
+ p2 = Vector(400, -150.000, 0)
+ p3 = Vector(1200, -150.000, 0)
+ p4 = Vector(1200, 50.000, 0)
+ p5 = Vector(0, 50.000, 0)
+ p6 = Vector(0, -50.000, 0)
+ wire = Draft.make_wire([p1, p2, p3, p4, p5, p6], closed=True)
+ wire.Label = "Wire"
+
+ # the circle defining the heating rod
+ pCirc = Vector(160, 0, 0)
+ axisCirc = Vector(1, 0, 0)
+ placementCircle = Placement(pCirc, Rotation(axisCirc, 0))
+ circle = Draft.make_circle(10, placement=placementCircle)
+ circle.Label = "HeatingRod"
+ circle.ViewObject.Visibility = False
+
+ # a link of the circle
+ circleLink = doc.addObject("App::Link", "Link-HeatingRod")
+ circleLink.LinkTransform = True
+ circleLink.LinkedObject = circle
+
+ # cut rod from wire to get volume of fluid
+ cut = doc.addObject("Part::Cut", "Cut")
+ cut.Base = wire
+ cut.Tool = circleLink
+ cut.ViewObject.Visibility = False
+
+ # BooleanFregments object to combine cut with rod
+ BooleanFragments = SplitFeatures.makeBooleanFragments(name="BooleanFragments")
+ BooleanFragments.Objects = [cut, circle]
+
+ # set view
+ doc.recompute()
+ if FreeCAD.GuiUp:
+ BooleanFragments.ViewObject.Transparency = 50
+ BooleanFragments.ViewObject.Document.activeView().fitAll()
+
+ # analysis
+ analysis = ObjectsFem.makeAnalysis(doc, "Analysis")
+ if FreeCAD.GuiUp:
+ import FemGui
+ FemGui.setActiveAnalysis(analysis)
+
+ # solver
+ if solvertype == "elmer":
+ solver_obj = ObjectsFem.makeSolverElmer(doc, "SolverElmer")
+ solver_obj.CoordinateSystem = "Cartesian 2D"
+ equation_flow = ObjectsFem.makeEquationFlow(doc, solver_obj)
+ equation_heat = ObjectsFem.makeEquationHeat(doc, solver_obj)
+ else:
+ FreeCAD.Console.PrintWarning(
+ "Unknown or unsupported solver type: {}. "
+ "No solver object was created.\n".format(solvertype)
+ )
+ return doc
+ analysis.addObject(solver_obj)
+
+ # solver settings
+ equation_flow.IdrsParameter = 3
+ equation_flow.LinearIterativeMethod = "Idrs"
+ equation_flow.LinearPreconditioning = "ILU1"
+ equation_flow.NonlinearIterations = 20
+ equation_flow.NonlinearNewtonAfterIterations = 20
+ equation_flow.RelaxationFactor = 0.15
+ equation_flow.Variable = "Flow Solution[Velocity:2 Pressure:1]"
+ equation_heat.Convection = "Computed"
+ equation_heat.IdrsParameter = 3
+ equation_heat.LinearIterativeMethod = "Idrs"
+ equation_heat.LinearPreconditioning = "ILU1"
+ equation_heat.NonlinearIterations = 20
+ equation_heat.NonlinearNewtonAfterIterations = 20
+ equation_heat.Priority = 5
+ equation_heat.RelaxationFactor = 0.15
+ equation_heat.Stabilize = True
+
+ # material
+
+ # fluid
+ material_obj = ObjectsFem.makeMaterialFluid(doc, "Material_Fluid")
+ mat = material_obj.Material
+ mat["Name"] = "Carbon dioxide"
+ mat["Density"] = "1.8393 kg/m^3"
+ mat["DynamicViscosity"] = "14.7e-6 kg/m/s"
+ mat["ThermalConductivity"] = "0.016242 W/m/K"
+ mat["ThermalExpansionCoefficient"] = "0.00343 m/m/K"
+ mat["SpecificHeat"] = "0.846 kJ/kg/K"
+ material_obj.Material = mat
+ material_obj.References = [(BooleanFragments, "Face2")]
+ analysis.addObject(material_obj)
+
+ # tube wall
+ material_obj = ObjectsFem.makeMaterialSolid(doc, "Material_Wall")
+ mat = material_obj.Material
+ mat["Name"] = "Aluminum Generic"
+ mat["Density"] = "2700 kg/m^3"
+ mat["PoissonRatio"] = "0.35"
+ mat["ShearModulus"] = "25.0 GPa"
+ mat["UltimateTensileStrength"] = "310 MPa"
+ mat["YoungsModulus"] = "70000 MPa"
+ mat["ThermalConductivity"] = "237.0 W/m/K"
+ mat["ThermalExpansionCoefficient"] = "23.1 µm/m/K"
+ mat["SpecificHeat"] = "897.0 J/kg/K"
+ material_obj.Material = mat
+ material_obj.References = [(BooleanFragments, "Face1")]
+ analysis.addObject(material_obj)
+
+ # constraint inlet velocity
+ FlowVelocity_Inlet = ObjectsFem.makeConstraintFlowVelocity(doc, "FlowVelocity_Inlet")
+ FlowVelocity_Inlet.References = [(BooleanFragments, "Edge5")]
+ FlowVelocity_Inlet.VelocityX = "20.0 mm/s"
+ FlowVelocity_Inlet.VelocityXUnspecified = False
+ analysis.addObject(FlowVelocity_Inlet)
+
+ # constraint wall velocity
+ FlowVelocity_Wall = ObjectsFem.makeConstraintFlowVelocity(doc, "FlowVelocity_Wall")
+ FlowVelocity_Wall.References = [
+ (BooleanFragments, "Edge2"),
+ (BooleanFragments, "Edge3"),
+ (BooleanFragments, "Edge4"),
+ (BooleanFragments, "Edge7")]
+ FlowVelocity_Wall.VelocityXUnspecified = False
+ FlowVelocity_Wall.VelocityYUnspecified = False
+ analysis.addObject(FlowVelocity_Wall)
+
+ # constraint initial velocity
+ FlowVelocity_Initial = ObjectsFem.makeConstraintInitialFlowVelocity(doc, "FlowVelocity_Initial")
+ FlowVelocity_Initial.References = [(BooleanFragments, "Face2")]
+ FlowVelocity_Initial.VelocityX = "20.0 mm/s"
+ FlowVelocity_Initial.VelocityY = "-20.0 mm/s"
+ FlowVelocity_Initial.VelocityXUnspecified = False
+ FlowVelocity_Initial.VelocityYUnspecified = False
+ analysis.addObject(FlowVelocity_Initial)
+
+ # constraint initial temperature
+ Temperature_Initial = ObjectsFem.makeConstraintInitialTemperature(doc, "Temperature_Initial")
+ Temperature_Initial.initialTemperature = 300.0
+ analysis.addObject(Temperature_Initial)
+
+ # constraint wall temperature
+ Temperature_Wall = ObjectsFem.makeConstraintTemperature(doc, "Temperature_Wall")
+ Temperature_Wall.Temperature = 300.0
+ Temperature_Wall.NormalDirection = Vector(0, 0, -1)
+ Temperature_Wall.References = [
+ (BooleanFragments, "Edge2"),
+ (BooleanFragments, "Edge3"),
+ (BooleanFragments, "Edge4"),
+ (BooleanFragments, "Edge7")]
+ analysis.addObject(Temperature_Wall)
+
+ # constraint inlet temperature
+ Temperature_Inlet = ObjectsFem.makeConstraintTemperature(doc, "Temperature_Inlet")
+ Temperature_Inlet.Temperature = 350.0
+ Temperature_Inlet.NormalDirection = Vector(-1, 0, 0)
+ Temperature_Inlet.References = [(BooleanFragments, "Edge5")]
+ analysis.addObject(Temperature_Inlet)
+
+ # constraint heating rod temperature
+ Temperature_HeatingRod = ObjectsFem.makeConstraintTemperature(doc, "Temperature_HeatingRod")
+ Temperature_HeatingRod.Temperature = 373.0
+ Temperature_HeatingRod.NormalDirection = Vector(0, -1, 0)
+ Temperature_HeatingRod.References = [(BooleanFragments, "Edge1")]
+ analysis.addObject(Temperature_HeatingRod)
+
+ # constraint initial pressure
+ Pressure_Initial = ObjectsFem.makeConstraintInitialPressure(doc, "Pressure_Initial")
+ Pressure_Initial.Pressure = "100.0 kPa"
+ Pressure_Initial.NormalDirection = Vector(0, -1, 0)
+ Pressure_Initial.References = [(BooleanFragments, "Face2")]
+ analysis.addObject(Pressure_Initial)
+
+ # mesh
+ femmesh_obj = analysis.addObject(ObjectsFem.makeMeshGmsh(doc, get_meshname()))[0]
+ femmesh_obj.Part = BooleanFragments
+ femmesh_obj.ElementOrder = "1st"
+ femmesh_obj.CharacteristicLengthMax = "4 mm"
+ femmesh_obj.ViewObject.Visibility = False
+
+ # mesh_region
+ mesh_region = ObjectsFem.makeMeshRegion(doc, femmesh_obj, name="MeshRegion")
+ mesh_region.CharacteristicLength = "2 mm"
+ mesh_region.References = [
+ (BooleanFragments, "Edge1"),
+ (BooleanFragments, "Vertex2"),
+ (BooleanFragments, "Vertex4"),
+ (BooleanFragments, "Vertex6")]
+ 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(
+ "Unexpected error when creating mesh: {}\n"
+ .format(error)
+ )
+
+ 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 3e8e2c631c..a203da2160 100644
--- a/src/Mod/Fem/femexamples/equation_flow_turbulent_elmer_2D.py
+++ b/src/Mod/Fem/femexamples/equation_flow_turbulent_elmer_2D.py
@@ -40,7 +40,7 @@ def get_information():
"name": "Turbulent Flow - Elmer 2D",
"meshtype": "solid",
"meshelement": "Tet10",
- "constraints": ["initial pressure", "initial temperature", "initial velocity",
+ "constraints": ["initial pressure", "initial temperature",
"temperature", "velocity"],
"solvers": ["elmer"],
"material": "fluid",
@@ -54,7 +54,7 @@ To run the example from Python console use:
from femexamples.equation_flow_turbulent_elmer_2D import setup
setup()
-Flow and Heat equation - Elmer solver
+Flow and Heat equation in turbulent flow - Elmer solver
"""
@@ -136,8 +136,8 @@ def setup(doc=None, solvertype="elmer"):
equation_flow.setExpression("LinearTolerance", "1e-6")
equation_flow.NonlinearIterations = 30
equation_flow.NonlinearNewtonAfterIterations = 30
- equation_flow.setExpression("NonlinearTolerance", "1e-4")
equation_flow.RelaxationFactor = 0.1
+ equation_flow.setExpression("NonlinearTolerance", "1e-4")
equation_flow.Variable = "Flow Solution[Velocity:2 Pressure:1]"
equation_heat.Convection = "Computed"
equation_heat.IdrsParameter = 3
@@ -185,10 +185,8 @@ def setup(doc=None, solvertype="elmer"):
# constraint inlet velocity
FlowVelocity_Inlet = ObjectsFem.makeConstraintFlowVelocity(doc, "FlowVelocity_Inlet")
FlowVelocity_Inlet.References = [(BooleanFragments, "Edge5")]
- FlowVelocity_Inlet.NormalDirection = Vector(-1, 0, 0)
FlowVelocity_Inlet.VelocityX = "20.0 mm/s"
FlowVelocity_Inlet.VelocityXUnspecified = False
- FlowVelocity_Inlet.VelocityYUnspecified = False
analysis.addObject(FlowVelocity_Inlet)
# constraint wall velocity
@@ -198,7 +196,6 @@ def setup(doc=None, solvertype="elmer"):
(BooleanFragments, "Edge3"),
(BooleanFragments, "Edge4"),
(BooleanFragments, "Edge7")]
- FlowVelocity_Wall.NormalDirection = Vector(0, 0, -1)
FlowVelocity_Wall.VelocityXUnspecified = False
FlowVelocity_Wall.VelocityYUnspecified = False
analysis.addObject(FlowVelocity_Wall)
diff --git a/src/Mod/Fem/femexamples/manager.py b/src/Mod/Fem/femexamples/manager.py
index a0eda86964..a23316e7e8 100644
--- a/src/Mod/Fem/femexamples/manager.py
+++ b/src/Mod/Fem/femexamples/manager.py
@@ -71,6 +71,7 @@ def run_all():
run_example("equation_electrostatics_capacitance_two_balls", run_solver=True)
run_example("equation_electrostatics_electricforce_elmer_nongui6", run_solver=True)
run_example("equation_flow_elmer_2D", run_solver=True)
+ run_example("equation_flow_initial_elmer_2D", run_solver=True)
run_example("equation_flow_turbulent_elmer_2D", run_solver=True)
run_example("equation_flux_elmer", run_solver=True)
run_example("equation_magnetodynamics_elmer", run_solver=True)
@@ -109,6 +110,7 @@ def setup_all():
run_example("equation_electrostatics_capacitance_two_balls")
run_example("equation_electrostatics_electricforce_elmer_nongui6")
run_example("equation_flow_elmer_2D")
+ run_example("equation_flow_initial_elmer_2D")
run_example("equation_flow_turbulent_elmer_2D")
run_example("equation_flux_elmer")
run_example("equation_magnetodynamics_elmer")
diff --git a/src/Mod/Fem/femobjects/constraint_initialflowvelocity.py b/src/Mod/Fem/femobjects/constraint_initialflowvelocity.py
index 0598767641..097e390679 100644
--- a/src/Mod/Fem/femobjects/constraint_initialflowvelocity.py
+++ b/src/Mod/Fem/femobjects/constraint_initialflowvelocity.py
@@ -40,38 +40,79 @@ class ConstraintInitialFlowVelocity(base_fempythonobject.BaseFemPythonObject):
def __init__(self, obj):
super(ConstraintInitialFlowVelocity, self).__init__(obj)
obj.addProperty(
- "App::PropertyFloat",
+ "App::PropertyVelocity",
"VelocityX",
"Parameter",
"Velocity in x-direction"
)
+ obj.addProperty(
+ "App::PropertyString",
+ "VelocityXFormula",
+ "Parameter",
+ "Velocity formula in x-direction"
+ )
obj.addProperty(
"App::PropertyBool",
- "VelocityXEnabled",
+ "VelocityXUnspecified",
"Parameter",
"Use velocity in x-direction"
)
+ obj.VelocityXUnspecified = True
obj.addProperty(
- "App::PropertyFloat",
+ "App::PropertyBool",
+ "VelocityXHasFormula",
+ "Parameter",
+ "Use formula for velocity in x-direction"
+ )
+
+ obj.addProperty(
+ "App::PropertyVelocity",
"VelocityY",
"Parameter",
"Velocity in y-direction"
)
+ obj.addProperty(
+ "App::PropertyString",
+ "VelocityYFormula",
+ "Parameter",
+ "Velocity formula in y-direction"
+ )
obj.addProperty(
"App::PropertyBool",
- "VelocityYEnabled",
+ "VelocityYUnspecified",
"Parameter",
"Use velocity in y-direction"
)
+ obj.VelocityYUnspecified = True
obj.addProperty(
- "App::PropertyFloat",
+ "App::PropertyBool",
+ "VelocityYHasFormula",
+ "Parameter",
+ "Use formula for velocity in y-direction"
+ )
+
+ obj.addProperty(
+ "App::PropertyVelocity",
"VelocityZ",
"Parameter",
"Velocity in z-direction"
)
+ obj.addProperty(
+ "App::PropertyString",
+ "VelocityZFormula",
+ "Parameter",
+ "Velocity formula in z-direction"
+ )
obj.addProperty(
"App::PropertyBool",
- "VelocityZEnabled",
+ "VelocityZUnspecified",
"Parameter",
"Use velocity in z-direction"
)
+ obj.VelocityZUnspecified = True
+ obj.addProperty(
+ "App::PropertyBool",
+ "VelocityZHasFormula",
+ "Parameter",
+ "Use formula for velocity in z-direction"
+ )
diff --git a/src/Mod/Fem/femsolver/elmer/equations/flow_writer.py b/src/Mod/Fem/femsolver/elmer/equations/flow_writer.py
index 68dd68333c..176706a56d 100644
--- a/src/Mod/Fem/femsolver/elmer/equations/flow_writer.py
+++ b/src/Mod/Fem/femsolver/elmer/equations/flow_writer.py
@@ -193,14 +193,23 @@ class Flowwriter:
def _outputInitialVelocity(self, obj, name):
# flow only makes sense for fluid material
if self.write.isBodyMaterialFluid(name):
- if obj.VelocityXEnabled:
- velocity = self.write.getFromUi(obj.VelocityX, "m/s", "L/T")
+ if not obj.VelocityXUnspecified:
+ if not obj.VelocityXHasFormula:
+ velocity = float(obj.VelocityX.getValueAs("m/s"))
+ else:
+ velocity = obj.VelocityXFormula
self.write.initial(name, "Velocity 1", velocity)
- if obj.VelocityYEnabled:
- velocity = self.write.getFromUi(obj.VelocityY, "m/s", "L/T")
+ if not obj.VelocityYUnspecified:
+ if not obj.VelocityYHasFormula:
+ velocity = float(obj.VelocityY.getValueAs("m/s"))
+ else:
+ velocity = obj.VelocityYFormula
self.write.initial(name, "Velocity 2", velocity)
- if obj.VelocityZEnabled:
- velocity = self.write.getFromUi(obj.VelocityZ, "m/s", "L/T")
+ if not obj.VelocityZUnspecified:
+ if not obj.VelocityZHasFormula:
+ velocity = float(obj.VelocityZ.getValueAs("m/s"))
+ else:
+ velocity = obj.VelocityZFormula
self.write.initial(name, "Velocity 3", velocity)
def handleFlowInitialVelocity(self, bodies):
diff --git a/src/Mod/Fem/femtaskpanels/task_constraint_initialflowvelocity.py b/src/Mod/Fem/femtaskpanels/task_constraint_initialflowvelocity.py
index 91fafc536a..dcae4622f8 100644
--- a/src/Mod/Fem/femtaskpanels/task_constraint_initialflowvelocity.py
+++ b/src/Mod/Fem/femtaskpanels/task_constraint_initialflowvelocity.py
@@ -30,6 +30,8 @@ __url__ = "https://www.freecadweb.org"
# \ingroup FEM
# \brief task panel for constraint initial flow velocity object
+from PySide import QtCore
+
import FreeCAD
import FreeCADGui
from FreeCAD import Units
@@ -46,7 +48,6 @@ class _TaskPanel(object):
self._paramWidget = FreeCADGui.PySideUic.loadUi(
FreeCAD.getHomePath() + "Mod/Fem/Resources/ui/InitialFlowVelocity.ui")
- self._initParamWidget()
# geometry selection widget
# start with Solid in list!
@@ -70,6 +71,96 @@ class _TaskPanel(object):
self._partVisible = None
self._meshVisible = None
+ # connect unspecified option
+ QtCore.QObject.connect(
+ self._paramWidget.velocityXBox,
+ QtCore.SIGNAL("toggled(bool)"),
+ self._velocityXEnable
+ )
+ QtCore.QObject.connect(
+ self._paramWidget.velocityYBox,
+ QtCore.SIGNAL("toggled(bool)"),
+ self._velocityYEnable
+ )
+ QtCore.QObject.connect(
+ self._paramWidget.velocityZBox,
+ QtCore.SIGNAL("toggled(bool)"),
+ self._velocityZEnable
+ )
+
+ # connect formula option
+ QtCore.QObject.connect(
+ self._paramWidget.formulaXCB,
+ QtCore.SIGNAL("toggled(bool)"),
+ self._formulaXEnable
+ )
+ QtCore.QObject.connect(
+ self._paramWidget.formulaYCB,
+ QtCore.SIGNAL("toggled(bool)"),
+ self._formulaYEnable
+ )
+ QtCore.QObject.connect(
+ self._paramWidget.formulaZCB,
+ QtCore.SIGNAL("toggled(bool)"),
+ self._formulaZEnable
+ )
+
+ self._initParamWidget()
+
+ def _velocityXEnable(self, toggled):
+ if toggled:
+ self._paramWidget.formulaX.setDisabled(toggled)
+ self._paramWidget.velocityX.setDisabled(toggled)
+ else:
+ if self._paramWidget.formulaXCB.isChecked():
+ self._paramWidget.formulaX.setDisabled(toggled)
+ else:
+ self._paramWidget.velocityX.setDisabled(toggled)
+
+ def _velocityYEnable(self, toggled):
+ if toggled:
+ self._paramWidget.formulaY.setDisabled(toggled)
+ self._paramWidget.velocityY.setDisabled(toggled)
+ else:
+ if self._paramWidget.formulaYCB.isChecked():
+ self._paramWidget.formulaY.setDisabled(toggled)
+ else:
+ self._paramWidget.velocityY.setDisabled(toggled)
+
+ def _velocityZEnable(self, toggled):
+ if toggled:
+ self._paramWidget.formulaZ.setDisabled(toggled)
+ self._paramWidget.velocityZ.setDisabled(toggled)
+ else:
+ if self._paramWidget.formulaZCB.isChecked():
+ self._paramWidget.formulaZ.setDisabled(toggled)
+ else:
+ self._paramWidget.velocityZ.setDisabled(toggled)
+
+ def _formulaXEnable(self, toggled):
+ FreeCAD.Console.PrintMessage("_formulaXEnable\n")
+ if self._paramWidget.velocityXBox.isChecked():
+ FreeCAD.Console.PrintMessage("velocityXBox isChecked\n")
+ return
+ else:
+ FreeCAD.Console.PrintMessage("velocityXBox not checked\n")
+ self._paramWidget.formulaX.setEnabled(toggled)
+ self._paramWidget.velocityX.setDisabled(toggled)
+
+ def _formulaYEnable(self, toggled):
+ if self._paramWidget.velocityYBox.isChecked():
+ return
+ else:
+ self._paramWidget.formulaY.setEnabled(toggled)
+ self._paramWidget.velocityY.setDisabled(toggled)
+
+ def _formulaZEnable(self, toggled):
+ if self._paramWidget.velocitZXBox.isChecked():
+ return
+ else:
+ self._paramWidget.formulaZ.setEnabled(toggled)
+ self._paramWidget.velocityZ.setDisabled(toggled)
+
def open(self):
if self._mesh is not None and self._part is not None:
self._meshVisible = self._mesh.ViewObject.isVisible()
@@ -104,33 +195,75 @@ class _TaskPanel(object):
def _initParamWidget(self):
unit = "m/s"
- self._paramWidget.velocityXTxt.setText(
- str(self._obj.VelocityX) + unit)
- self._paramWidget.velocityYTxt.setText(
- str(self._obj.VelocityY) + unit)
- self._paramWidget.velocityZTxt.setText(
- str(self._obj.VelocityZ) + unit)
+ self._paramWidget.velocityX.setProperty('unit', unit)
+ self._paramWidget.velocityY.setProperty('unit', unit)
+ self._paramWidget.velocityZ.setProperty('unit', unit)
+
+ self._paramWidget.velocityX.setProperty(
+ 'value', self._obj.VelocityX)
+ FreeCADGui.ExpressionBinding(
+ self._paramWidget.velocityX).bind(self._obj, "VelocityX")
self._paramWidget.velocityXBox.setChecked(
- not self._obj.VelocityXEnabled)
+ self._obj.VelocityXUnspecified)
+ self._paramWidget.formulaX.setText(self._obj.VelocityXFormula)
+ self._paramWidget.formulaXCB.setChecked(
+ self._obj.VelocityXHasFormula)
+
+ self._paramWidget.velocityY.setProperty(
+ 'value', self._obj.VelocityY)
+ FreeCADGui.ExpressionBinding(
+ self._paramWidget.velocityY).bind(self._obj, "VelocityY")
self._paramWidget.velocityYBox.setChecked(
- not self._obj.VelocityYEnabled)
+ self._obj.VelocityYUnspecified)
+ self._paramWidget.formulaY.setText(self._obj.VelocityYFormula)
+ self._paramWidget.formulaYCB.setChecked(
+ self._obj.VelocityYHasFormula)
+
+ self._paramWidget.velocityZ.setProperty(
+ 'value', self._obj.VelocityZ)
+ FreeCADGui.ExpressionBinding(
+ self._paramWidget.velocityZ).bind(self._obj, "VelocityZ")
self._paramWidget.velocityZBox.setChecked(
- not self._obj.VelocityZEnabled)
+ self._obj.VelocityZUnspecified)
+ self._paramWidget.formulaZ.setText(self._obj.VelocityZFormula)
+ self._paramWidget.formulaZCB.setChecked(
+ self._obj.VelocityZHasFormula)
+
+ def _applyVelocityChanges(self, enabledBox, velocityQSB):
+ enabled = enabledBox.isChecked()
+ velocity = None
+ try:
+ velocity = velocityQSB.property('value')
+ except ValueError:
+ FreeCAD.Console.PrintMessage(
+ "Wrong input. Not recognised input: '{}' "
+ "Velocity has not been set.\n".format(velocityQSB.text())
+ )
+ velocity = '0.0 m/s'
+ return enabled, velocity
def _applyWidgetChanges(self):
- unit = "m/s"
- self._obj.VelocityXEnabled = \
- not self._paramWidget.velocityXBox.isChecked()
- if self._obj.VelocityXEnabled:
- quantity = Units.Quantity(self._paramWidget.velocityXTxt.text())
- self._obj.VelocityX = quantity.getValueAs(unit).Value
- self._obj.VelocityYEnabled = \
- not self._paramWidget.velocityYBox.isChecked()
- if self._obj.VelocityYEnabled:
- quantity = Units.Quantity(self._paramWidget.velocityYTxt.text())
- self._obj.VelocityY = quantity.getValueAs(unit).Value
- self._obj.VelocityZEnabled = \
- not self._paramWidget.velocityZBox.isChecked()
- if self._obj.VelocityZEnabled:
- quantity = Units.Quantity(self._paramWidget.velocityZTxt.text())
- self._obj.VelocityZ = quantity.getValueAs(unit).Value
+ # apply the velocities and their enabled state
+ self._obj.VelocityXUnspecified, self._obj.VelocityX = \
+ self._applyVelocityChanges(
+ self._paramWidget.velocityXBox,
+ self._paramWidget.velocityX
+ )
+ self._obj.VelocityXHasFormula = self._paramWidget.formulaXCB.isChecked()
+ self._obj.VelocityXFormula = self._paramWidget.formulaX.text()
+
+ self._obj.VelocityYUnspecified, self._obj.VelocityY = \
+ self._applyVelocityChanges(
+ self._paramWidget.velocityYBox,
+ self._paramWidget.velocityY
+ )
+ self._obj.VelocityYHasFormula = self._paramWidget.formulaYCB.isChecked()
+ self._obj.VelocityYFormula = self._paramWidget.formulaY.text()
+
+ self._obj.VelocityZUnspecified, self._obj.VelocityZ = \
+ self._applyVelocityChanges(
+ self._paramWidget.velocityZBox,
+ self._paramWidget.velocityZ
+ )
+ self._obj.VelocityZHasFormula = self._paramWidget.formulaZCB.isChecked()
+ self._obj.VelocityZFormula = self._paramWidget.formulaZ.text()