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/InputField.h
+ Gui::QuantitySpinBox + QWidget +
Gui/QuantitySpinBox.h
@@ -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()