Add FEM Constraint Tutorial/de: Difference between revisions

From FreeCAD Documentation
(Created page with "Der Ansichtproxy muss erweitert werden, um das Aufgabenpaneel zu unterstützen, das wir gerade implementiert haben. Der folgende erweiterte Ansichtproxy öffnet das Aufgabenpa...")
No edit summary
Tag: Manual revert
 
(26 intermediate revisions by 4 users not shown)
Line 1: Line 1:
<languages/>
<languages/>

{{TutorialInfo/de
{{TutorialInfo/de
|Topic= FEM Beschränkung hinzufügen
|Topic= FEM Beschränkung hinzufügen
Line 9: Line 10:
}}
}}


<span id="Introduction"></span>
In diesem Tutorium werden wir die Fließgeschwindigkeitsbeschränkung zu FreeCAD hinzufügen und Unterstützung für den Elmer Löser implementieren. Bitte stelle sicher, dass du [[Extend_FEM_Module/de|FEM Modul erweitern]] gelesen und verstanden hast, bevor du dieses Tutorial liest.
==Einleitung==

In dieser Anleitung werden wir FreeCAD die Randbedingung Strömungsgeschwindigkeit hinzufügen und die Unterstützung für den Löser Elmer implementieren. Bitte stelle sicher, dass du [[Extend_FEM_Module/de|FEM-Modul erweitern]] gelesen und verstanden hast, bevor du diese Anleitung liest.


Dieses Tutorium umfasst nur die Implementierung von Beschränkungen in Python. Im Gegensatz zu Löser und Gleichungsbeschränkungen folge der klassischen FEM Modulstruktur. Das heißt, alle Module einer Beschränkung haben dort entweder im {{incode|femobjects}} oder {{incode|femviewprovider}} Paket Platz.
Dieses Tutorium deckt nur die Implementierung von Randbedingungen in Python ab. Im Gegensatz zu Löser und Gleichungen folgen Randbedingungen der klassischen FEM-Modulstruktur. Das heißt, alle Module einer Randbedingung befinden sich entweder im Paket {{incode|femobjects}} oder im Paket {{incode|femviewprovider}}.


<span id="Summary"></span>
== Zusammenfassung ==
== Zusammenfassung ==


Line 20: Line 25:
# '''Erweitere Elmers Schreiber:''' Füge Unterstützung für die neue Beschränkung Elmer hinzu, durch erweitern seines sif Datei Exportierers.
# '''Erweitere Elmers Schreiber:''' Füge Unterstützung für die neue Beschränkung Elmer hinzu, durch erweitern seines sif Datei Exportierers.


<span id="Create_document_object"></span>
== Dokumentobjekt erstellen ==
== Dokument-Objekt erstellen ==


In diesem Schritt werden wir die folgenden Dateien modifizieren:
In diesem Schritt werden wir die folgenden Dateien modifizieren:
* src/Mod/Fem/CMakeLists.txt
* {{FileName|src/Mod/Fem/CMakeLists.txt}}
* src/Mod/Fem/App/CMakeLists.txt
* {{FileName|src/Mod/Fem/App/CMakeLists.txt}}
* src/Mod/Fem/ObjectsFem.py
* {{FileName|src/Mod/Fem/ObjectsFem.py}}

und füge die folgenden Dateien hinzu:
Und füge die folgenden Dateien hinzu:
* src/Mod/Fem/femobjects/constraint_flowvelocity.py
* src/Mod/Fem/femviewprovider/view_constraint_flowvelocity.py
* {{FileName|src/Mod/Fem/femobjects/constraint_flowvelocity.py}}
* {{FileName|src/Mod/Fem/femviewprovider/view_constraint_flowvelocity.py}}

Für die neue Beschränkung sind ein Dokument-Proxy und ein Ansicht-Proxy erforderlich. Diese liegen in separaten Modulen vor. Der Dokument-Proxy in femobjects und der Ansicht-Proxy in femviewprovider. Kopiere einfach die Module aus einer bestehenden Beschränkung, z.B.:
* {{FileName|femobjects/constraint_selfweight.py}}
* {{FileName|femviewprovider/view_constraint_selfweight.py}}


Für die neue Beschränkung sind ein Dokumentproxy und ein Ansichtproxy erforderlich. Diese liegen in separaten Modulen vor. Der Dokumentproxy in femobjects und der Ansichtproxy in femviewprovider. Kopiere einfach die Module aus einer bestehenden Beschränkung, z.B.
* femobjects/constraint_selfweight.py
* femviewprovider/view_constraint_selfweight.py
Passe die Typvariable und die Eigenschaften an deine Bedürfnisse an. Der Dokumentproxy der Fließbeschränkung sieht wie folgt aus:
Passe die Typvariable und die Eigenschaften an deine Bedürfnisse an. Der Dokumentproxy der Fließbeschränkung sieht wie folgt aus:

<pre>class Proxy(FemConstraint.Proxy):
{{Code|code=
Type = &quot;Fem::ConstraintFlowVelocity&quot;
class Proxy(FemConstraint.Proxy):
Type = "Fem::ConstraintFlowVelocity"
def __init__(self, obj):
def __init__(self, obj):
super(Proxy, self).__init__(obj)
super(Proxy, self).__init__(obj)
obj.addProperty(
obj.addProperty(
&quot;App::PropertyFloat&quot;, &quot;VelocityX&quot;,
"App::PropertyFloat", "VelocityX",
&quot;Parameter&quot;, &quot;Body heat flux&quot;)
"Parameter", "Body heat flux")
obj.addProperty(
obj.addProperty(
&quot;App::PropertyBool&quot;, &quot;VelocityXEnabled&quot;,
"App::PropertyBool", "VelocityXEnabled",
&quot;Parameter&quot;, &quot;Body heat flux&quot;)
"Parameter", "Body heat flux")
obj.addProperty(
obj.addProperty(
&quot;App::PropertyFloat&quot;, &quot;VelocityY&quot;,
"App::PropertyFloat", "VelocityY",
&quot;Parameter&quot;, &quot;Body heat flux&quot;)
"Parameter", "Body heat flux")
obj.addProperty(
obj.addProperty(
&quot;App::PropertyBool&quot;, &quot;VelocityYEnabled&quot;,
"App::PropertyBool", "VelocityYEnabled",
&quot;Parameter&quot;, &quot;Body heat flux&quot;)
"Parameter", "Body heat flux")
obj.addProperty(
obj.addProperty(
&quot;App::PropertyFloat&quot;, &quot;VelocityZ&quot;,
"App::PropertyFloat", "VelocityZ",
&quot;Parameter&quot;, &quot;Body heat flux&quot;)
"Parameter", "Body heat flux")
obj.addProperty(
obj.addProperty(
&quot;App::PropertyBool&quot;, &quot;VelocityZEnabled&quot;,
"App::PropertyBool", "VelocityZEnabled",
&quot;Parameter&quot;, &quot;Body heat flux&quot;)
"Parameter", "Body heat flux")
obj.addProperty(
obj.addProperty(
&quot;App::PropertyBool&quot;, &quot;NormalToBoundary&quot;,
"App::PropertyBool", "NormalToBoundary",
&quot;Parameter&quot;, &quot;Body heat flux&quot;)</pre>
"Parameter", "Body heat flux")
}}

Das Modul, das den Ansichtproxy enthält, könnte etwas komplizierter aussehen. Aber für den Moment passe einfach den Symbolpfad an. Wir werden in späteren Schritten des Tutoriums auf diese Datei zurückkommen.
Das Modul, das den Ansichtproxy enthält, könnte etwas komplizierter aussehen. Aber für den Moment passe einfach den Symbolpfad an. Wir werden in späteren Schritten des Tutoriums auf diese Datei zurückkommen.

<pre>class ViewProxy(FemConstraint.ViewProxy):
{{Code|code=
class ViewProxy(FemConstraint.ViewProxy):
def getIcon(self):
def getIcon(self):
return &quot;:/icons/fem-constraint-flow-velocity.svg&quot;</pre>
return ":/icons/fem-constraint-flow-velocity.svg"
}}

Füge die beiden neuen Module zum Bausystem hinzu, wie in [https://www.freecadweb.org/wiki/Extend_FEM_Module FEM Modul erweitern] beschrieben. Suche die richtige Liste auf, durch Suchen nach Beschränkungsmodulen.
Füge die beiden neuen Module zum Bausystem hinzu, wie in [https://www.freecadweb.org/wiki/Extend_FEM_Module FEM Modul erweitern] beschrieben. Suche die richtige Liste auf, durch Suchen nach Beschränkungsmodulen.


Wie alle Objekte des FEM Arbeitsbereiches muss die Geschwindigkeitsbeschränkung in <code>ObjectsFem.py</code> registriert werden. Die folgende Methode fügt dem aktiven Dokument eine Geschwindigkeitsbeschränkung hinzu. Diese Methode wird vom GUI Befehl verwendet, um die Beschränkung hinzuzufügen. Sie muss irgendwo in <code>ObjectsFem.py</code> eingefügt werden.
Wie alle Objekte des FEM-Arbeitsbereiches muss die Geschwindigkeitsbeschränkung in {{incode|ObjectsFem.py}} registriert werden. Die folgende Methode fügt dem aktiven Dokument eine Geschwindigkeitsbeschränkung hinzu. Diese Methode wird vom GUI-Befehl verwendet, um die Beschränkung hinzuzufügen. Sie muss irgendwo in {{incode|ObjectsFem.py}} eingefügt werden.

<pre>def makeConstraintFlowVelocity(name=&quot;FlowVelocity&quot;):
{{Code|code=
obj = FreeCAD.ActiveDocument.addObject(&quot;Fem::ConstraintPython&quot;, name)
def makeConstraintFlowVelocity(name="FlowVelocity"):
obj = FreeCAD.ActiveDocument.addObject("Fem::ConstraintPython", name)
import femobjects.constraint_flowvelocity
import femobjects.constraint_flowvelocity
femobjects.constraint_flowvelocity.Proxy(obj)
femobjects.constraint_flowvelocity.Proxy(obj)
Line 73: Line 91:
import femviewprovider.view_constraint_flowvelocity
import femviewprovider.view_constraint_flowvelocity
femviewprovider.view_constraint_flowvelocity.ViewProxy(obj.ViewObject)
femviewprovider.view_constraint_flowvelocity.ViewProxy(obj.ViewObject)
return obj</pre>
return obj
}}

<span id="Create_GUI_command"></span>
== GUI Befehl erstellen ==
== GUI Befehl erstellen ==


In diesem Schritt werden wir die folgenden Dateien modifizieren:
In diesem Schritt werden wir die folgenden Dateien modifizieren:
* src/Mod/Fem/CMakeLists.txt
* {{FileName|src/Mod/Fem/CMakeLists.txt}}
* src/Mod/Fem/App/CMakeLists.txt
* {{FileName|src/Mod/Fem/App/CMakeLists.txt}}
* src/Mod/Fem/Gui/Workbench.cpp
* {{FileName|src/Mod/Fem/Gui/Workbench.cpp}}
und die folgende neue Datei hinzufügen:
* src/Mod/Fem/femobjects/constraint_flowvelocity.py


Und die folgende neue Datei hinzufügen:
Der Befehl ermöglicht es dem Anwender, die Beschränkung tatsächlich zur aktiven Analyse hinzuzufügen. Kopiere einfach einen Befehl aus einer vorhandenen Beschränkung. Die Befehle befinden sich im Paket <code>femviewprovider</code>. Passe das Attribut resources und die in Activated aufgerufene make Methode deinen Bedürfnissen an. Verwende auch eine andere Befehls ID im addCommand Aufruf am unteren Ende des Moduls. Die folgende Klasse ist die Befehlsklasse der Geschwindigkeitsbeschränkung.
* {{FileName|src/Mod/Fem/femobjects/constraint_flowvelocity.py}}
<pre>class Command(FemCommands.FemCommands):

Der Befehl ermöglicht es dem Anwender, die Beschränkung tatsächlich zur aktiven Analyse hinzuzufügen. Kopiere einfach einen Befehl aus einer vorhandenen Beschränkung. Die Befehle befinden sich im Paket {{incode|femviewprovider}}. Passe das Attribut resources und die in Activated aufgerufene make-Methode deinen Bedürfnissen an. Verwende auch eine andere Befehls-ID im addCommand-Aufruf am unteren Ende des Moduls. Die folgende Klasse ist die Befehlsklasse der Geschwindigkeitsbeschränkung.

{{Code|code=
class Command(FemCommands.FemCommands):


def __init__(self):
def __init__(self):
Line 91: Line 115:
'Pixmap': 'fem-constraint-flow-velocity',
'Pixmap': 'fem-constraint-flow-velocity',
'MenuText': QtCore.QT_TRANSLATE_NOOP(
'MenuText': QtCore.QT_TRANSLATE_NOOP(
&quot;FEM_ConstraintFlowVelocity&quot;,
"FEM_ConstraintFlowVelocity",
&quot;Constraint Velocity&quot;),
"Constraint Velocity"),
'ToolTip': QtCore.QT_TRANSLATE_NOOP(
'ToolTip': QtCore.QT_TRANSLATE_NOOP(
&quot;FEM_ConstraintFlowVelocity&quot;,
"FEM_ConstraintFlowVelocity",
&quot;Creates a FEM constraint body heat flux&quot;)}
"Creates a FEM constraint body heat flux")}
self.is_active = 'with_analysis'
self.is_active = 'with_analysis'


def Activated(self):
def Activated(self):
App.ActiveDocument.openTransaction(
App.ActiveDocument.openTransaction(
&quot;Create FemConstraintFlowVelocity&quot;)
"Create FemConstraintFlowVelocity")
Gui.addModule(&quot;ObjectsFem&quot;)
Gui.addModule("ObjectsFem")
Gui.doCommand(
Gui.doCommand(
&quot;FemGui.getActiveAnalysis().Member += &quot;
"FemGui.getActiveAnalysis().Member += "
&quot;[ObjectsFem.makeConstraintFlowVelocity()]&quot;)
"[ObjectsFem.makeConstraintFlowVelocity()]")

Gui.addCommand('FEM_AddConstraintFlowVelocity', Command())
}}


Gui.addCommand('FEM_AddConstraintFlowVelocity', Command())</pre>
Füge die neue Befehlsdatei zum Bausystem hinzu, wie in [https://www.freecadweb.org/wiki/Extend_FEM_Module FEM Modul erweitern] beschrieben. Ermittle die richtige Liste, durch Suchen nach vorhandenen Befehlsmodulen.
Füge die neue Befehlsdatei zum Bausystem hinzu, wie in [https://www.freecadweb.org/wiki/Extend_FEM_Module FEM Modul erweitern] beschrieben. Ermittle die richtige Liste, durch Suchen nach vorhandenen Befehlsmodulen.


Gib den Befehl in Gui/Workbench.cpp ein, um ihn der Symbolleiste und dem Menü hinzuzufügen. Suche nach einer vorhandenen Beschränkung der gleichen Kategorie wie die neue (z.B. Flow), kopiere und füge sie ein und passe die Befehls ID an. Dies sollte zweimal durchgeführt werden. Einmal für das Menü und noch einmal für die Werkzeugleiste.
Gib den Befehl in Gui/Workbench.cpp ein, um ihn der Symbolleiste und dem Menü hinzuzufügen. Suche nach einer vorhandenen Beschränkung der gleichen Kategorie wie die neue (z.B. Flow), kopiere und füge sie ein und passe die Befehls ID an. Dies sollte zweimal durchgeführt werden. Einmal für das Menü und noch einmal für die Werkzeugleiste.


<span id="Create_a_task_panel"></span>
== Erstelle ein Aufgabenpaneel ==
== Erstelle ein Aufgabenpaneel ==


In diesem Schritt werden wir die folgenden Dateien modifizieren:
In diesem Schritt werden wir die folgenden Dateien modifizieren:
* src/Mod/Fem/femviewprovider/view_constraint_flowvelocity.py
* {{FileName|src/Mod/Fem/femviewprovider/view_constraint_flowvelocity.py}}
In FreeCAD constraint objects benefit greatly from task panels. Task panels can make use of more powerful input widgets which expose the unit of entered values directely to the user. The velocity constraint even requires the use of a task panel since a task panel is the only way of specifieing the face(s) on which the constraint shall be applied.


In FreeCAD profitieren Beschränkungsobjekte stark von Aufgabenpaneels. Aufgabenpaneels können leistungsfähigere Eingabebedienelemente verwenden, die dem Benutzer die Einheit der eingegebenen Werte direkt anzeigen. Die Geschwindigkeitsbeschränkung erfordert sogar die Verwendung eines Aufgabenpaneels, da ein Aufgabenpaneel die einzige Möglichkeit ist, die Fläche(n) zu spezifizieren, auf die die Beschränkung angewendet werden soll.
The location of the module in which task panels are implemented is not strictely defined. For the velocity constraint we are just going to put the task panel in the same module we put the view proxy. The task panel is quite complicated. It makes use of the FemSolectionWidgets.BoundarySelector(). Thats a qt widget which allows the user to select the boundaries on which the constraint shall be applied. In addition to this widget it generates another one by loading a ui file specifically created for the velocity constraint. Via this widget the velocity vector can be specified.


Der Standort des Moduls, in dem die Aufgabenpanels implementiert werden, ist nicht streng definiert. Für die Geschwindigkeitsbeschränkung werden wir das Aufgabenpaneel einfach in dasselbe Modul setzen, in das wir den Ansichtsproxy setzen. Das Aufgabenpaneel ist ziemlich kompliziert. Es verwendet die Funktion FemSolectionWidgets.BoundarySelector(). Dabei handelt es sich um ein qt Bedienelement, mit dem der Benutzer die Grenzen auswählen kann, auf die die Beschränkung angewendet werden soll. Zusätzlich zu diesem Bedienelement erzeugt es ein weiteres, indem es eine speziell für die Geschwindigkeitsbeschränkung erstellte ui Datei lädt. Über dieses Bedienelement kann der Geschwindigkeitsvektor spezifiziert werden.
Most of the time is should be sufficient to just copy this class, use a suitable ui file (instead of TaskPanelFemFlowVelocity.ui) and adjust _initParamWidget() as well as _applyWidgetChanges(). If the new constraint requires bodies as references instead of boundaries just replace the BoundarySelector object with the SolidSelector.

<pre>class _TaskPanel(object):
Die meiste Zeit sollte ausreichen, diese Klasse einfach zu kopieren, eine geeignete ui Datei zu verwenden (anstelle von TaskPanelFemFlowVelocity.ui) und _initParamWidget() sowie _applyWidgetChanges() anzupassen. Wenn die neue Beschränkung Körper als Referenzen anstelle von Begrenzungen erfordert, ersetze einfach das BoundarySelector Objekt durch das SolidSelector Objekt.

{{Code|code=
class _TaskPanel(object):


def __init__(self, obj):
def __init__(self, obj):
Line 128: Line 158:
self._refWidget.setReferences(obj.References)
self._refWidget.setReferences(obj.References)
self._paramWidget = Gui.PySideUic.loadUi(
self._paramWidget = Gui.PySideUic.loadUi(
App.getHomePath() + &quot;Mod/Fem/femviewprovider/TaskPanelFemFlowVelocity.ui&quot;)
App.getHomePath() + "Mod/Fem/femviewprovider/TaskPanelFemFlowVelocity.ui")
self._initParamWidget()
self._initParamWidget()
self.form = [self._refWidget, self._paramWidget]
self.form = [self._refWidget, self._paramWidget]
analysis = FemMisc.findAnalysisOfMember(obj)
analysis = FemMisc.findAnalysisOfMember(obj)
self._mesh = FemMisc.getSingleMember(analysis, &quot;Fem::FemMeshObject&quot;)
self._mesh = FemMisc.getSingleMember(analysis, "Fem::FemMeshObject")
self._part = self._mesh.Part if self._mesh is not None else None
self._part = self._mesh.Part if self._mesh is not None else None
self._partVisible = None
self._partVisible = None
Line 168: Line 198:


def _initParamWidget(self):
def _initParamWidget(self):
unit = &quot;m/s&quot;
unit = "m/s"
self._paramWidget.velocityXTxt.setText(
self._paramWidget.velocityXTxt.setText(
str(self._obj.VelocityX) + unit)
str(self._obj.VelocityX) + unit)
Line 185: Line 215:


def _applyWidgetChanges(self):
def _applyWidgetChanges(self):
unit = &quot;m/s&quot;
unit = "m/s"
self._obj.VelocityXEnabled = \
self._obj.VelocityXEnabled = \
not self._paramWidget.velocityXBox.isChecked()
not self._paramWidget.velocityXBox.isChecked()
Line 201: Line 231:
quantity = Units.Quantity(self._paramWidget.velocityZTxt.text())
quantity = Units.Quantity(self._paramWidget.velocityZTxt.text())
self._obj.VelocityZ = float(quantity.getValueAs(unit))
self._obj.VelocityZ = float(quantity.getValueAs(unit))
self._obj.NormalToBoundary = self._paramWidget.normalBox.isChecked()</pre>
self._obj.NormalToBoundary = self._paramWidget.normalBox.isChecked()
}}

Der Ansichtproxy muss erweitert werden, um das Aufgabenpaneel zu unterstützen, das wir gerade implementiert haben. Der folgende erweiterte Ansichtproxy öffnet das Aufgabenpaneel, wenn der Anwender einen Doppelklick auf das Beschränkungsobjekt in der Baumansicht macht.
Der Ansichtproxy muss erweitert werden, um das Aufgabenpaneel zu unterstützen, das wir gerade implementiert haben. Der folgende erweiterte Ansichtproxy öffnet das Aufgabenpaneel, wenn der Anwender einen Doppelklick auf das Beschränkungsobjekt in der Baumansicht macht.

<pre>class ViewProxy(FemConstraint.ViewProxy):
{{Code|code=
class ViewProxy(FemConstraint.ViewProxy):


def getIcon(self):
def getIcon(self):
return &quot;:/icons/fem-constraint-flow-velocity.svg&quot;
return ":/icons/fem-constraint-flow-velocity.svg"


def setEdit(self, vobj, mode=0):
def setEdit(self, vobj, mode=0):
Line 219: Line 253:
Gui.Control.closeDialog()
Gui.Control.closeDialog()
Gui.ActiveDocument.setEdit(vobj.Object.Name)
Gui.ActiveDocument.setEdit(vobj.Object.Name)
return True</pre>
return True
}}

<span id="Extend_Elmer&#039;s_writer"></span>
== Elmers Schreiber erweitern ==
== Elmers Schreiber erweitern ==


In diesem Schritt werden wir die folgenden Dateien modifizieren:
In diesem Schritt werden wir die folgenden Dateien modifizieren:
* src/Mod/Fem/femsolver/elmer/writer.py
* {{FileName|src/Mod/Fem/femsolver/elmer/writer.py}}

Das Schreiber Modul enthält Methoden für alle Gleichungstypen. Je nach Art der Beschränkung, Randbedingung, Anfangsbedingung oder Körperkraft muss man unterschiedliche Methoden modifizieren. Für unsere Strömungsgeschwindigkeit müssen wir _handleFlowBndConditions(...) anpassen.
Das Schreiber Modul enthält Methoden für alle Gleichungstypen. Je nach Art der Beschränkung, Randbedingung, Anfangsbedingung oder Körperkraft muss man unterschiedliche Methoden modifizieren. Für unsere Strömungsgeschwindigkeit müssen wir {{incode|_handleFlowBndConditions(...)}} anpassen.
<pre>def _handleFlowBndConditions(self):

for obj in self._getMember(&quot;Fem::ConstraintFlowVelocity&quot;):
{{Code|code=
def _handleFlowBndConditions(self):
for obj in self._getMember("Fem::ConstraintFlowVelocity"):
if obj.References:
if obj.References:
for name in obj.References[0][1]:
for name in obj.References[0][1]:
if obj.VelocityXEnabled:
if obj.VelocityXEnabled:
velocity = getFromUi(obj.VelocityX, &quot;m/s&quot;, &quot;L/T&quot;)
velocity = getFromUi(obj.VelocityX, "m/s", "L/T")
self._boundary(name, &quot;Velocity 1&quot;, velocity)
self._boundary(name, "Velocity 1", velocity)
if obj.VelocityYEnabled:
if obj.VelocityYEnabled:
velocity = getFromUi(obj.VelocityY, &quot;m/s&quot;, &quot;L/T&quot;)
velocity = getFromUi(obj.VelocityY, "m/s", "L/T")
self._boundary(name, &quot;Velocity 2&quot;, velocity)
self._boundary(name, "Velocity 2", velocity)
if obj.VelocityZEnabled:
if obj.VelocityZEnabled:
velocity = getFromUi(obj.VelocityZ, &quot;m/s&quot;, &quot;L/T&quot;)
velocity = getFromUi(obj.VelocityZ, "m/s", "L/T")
self._boundary(name, &quot;Velocity 3&quot;, velocity)
self._boundary(name, "Velocity 3", velocity)
if obj.NormalToBoundary:
if obj.NormalToBoundary:
self._boundary(name, &quot;Normal-Tangential Velocity&quot;, True)
self._boundary(name, "Normal-Tangential Velocity", True)
self._handled(obj)</pre>
self._handled(obj)
}}



{{clear}}


[[Category:FEM{{#translation:}}]]
[[Category:FEM{{#translation:}}]]

Latest revision as of 13:29, 8 May 2023

Tutorium
Thema
FEM Beschränkung hinzufügen
Niveau
Zeit zum Abschluss
Autoren
M42kus
FreeCAD-Version
Beispieldateien
Siehe auch
None

Einleitung

In dieser Anleitung werden wir FreeCAD die Randbedingung Strömungsgeschwindigkeit hinzufügen und die Unterstützung für den Löser Elmer implementieren. Bitte stelle sicher, dass du FEM-Modul erweitern gelesen und verstanden hast, bevor du diese Anleitung liest.

Dieses Tutorium deckt nur die Implementierung von Randbedingungen in Python ab. Im Gegensatz zu Löser und Gleichungen folgen Randbedingungen der klassischen FEM-Modulstruktur. Das heißt, alle Module einer Randbedingung befinden sich entweder im Paket femobjects oder im Paket femviewprovider.

Zusammenfassung

  1. Erstelle Dokumentobjekt: Das Dokumentobjekt, das sich innerhalb der Analyse befindet und durch das die Beschränkung parametrisiert und an Grenzen angehängt werden kann.
  2. Erstelle GUI Befehl: Füge dem FEM Arbeitsbereich einen Befehl hinzu, der der aktiven Analyse eine Durchflussbeschränkung hinzufügt.
  3. Erstelle ein Aufgabenpaneel: Das Aufgabenpaneel ist erforderlich, um dem Anwender die Möglichkeit zu gewähren, die Grenzen festzulegen, an denen er die Geschwindigkeitsbeschränkung festlegen möchte. Es macht auch die Eingabe der Parameter etwas benutzerfreundlicher.
  4. Erweitere Elmers Schreiber: Füge Unterstützung für die neue Beschränkung Elmer hinzu, durch erweitern seines sif Datei Exportierers.

Dokument-Objekt erstellen

In diesem Schritt werden wir die folgenden Dateien modifizieren:

  • src/Mod/Fem/CMakeLists.txt
  • src/Mod/Fem/App/CMakeLists.txt
  • src/Mod/Fem/ObjectsFem.py

Und füge die folgenden Dateien hinzu:

  • src/Mod/Fem/femobjects/constraint_flowvelocity.py
  • src/Mod/Fem/femviewprovider/view_constraint_flowvelocity.py

Für die neue Beschränkung sind ein Dokument-Proxy und ein Ansicht-Proxy erforderlich. Diese liegen in separaten Modulen vor. Der Dokument-Proxy in femobjects und der Ansicht-Proxy in femviewprovider. Kopiere einfach die Module aus einer bestehenden Beschränkung, z.B.:

  • femobjects/constraint_selfweight.py
  • femviewprovider/view_constraint_selfweight.py

Passe die Typvariable und die Eigenschaften an deine Bedürfnisse an. Der Dokumentproxy der Fließbeschränkung sieht wie folgt aus:

class Proxy(FemConstraint.Proxy):
    Type = "Fem::ConstraintFlowVelocity"
    def __init__(self, obj):
        super(Proxy, self).__init__(obj)
        obj.addProperty(
            "App::PropertyFloat", "VelocityX",
            "Parameter", "Body heat flux")
        obj.addProperty(
            "App::PropertyBool", "VelocityXEnabled",
            "Parameter", "Body heat flux")
        obj.addProperty(
            "App::PropertyFloat", "VelocityY",
            "Parameter", "Body heat flux")
        obj.addProperty(
            "App::PropertyBool", "VelocityYEnabled",
            "Parameter", "Body heat flux")
        obj.addProperty(
            "App::PropertyFloat", "VelocityZ",
            "Parameter", "Body heat flux")
        obj.addProperty(
            "App::PropertyBool", "VelocityZEnabled",
            "Parameter", "Body heat flux")
        obj.addProperty(
            "App::PropertyBool", "NormalToBoundary",
            "Parameter", "Body heat flux")

Das Modul, das den Ansichtproxy enthält, könnte etwas komplizierter aussehen. Aber für den Moment passe einfach den Symbolpfad an. Wir werden in späteren Schritten des Tutoriums auf diese Datei zurückkommen.

class ViewProxy(FemConstraint.ViewProxy):
    def getIcon(self):
        return ":/icons/fem-constraint-flow-velocity.svg"

Füge die beiden neuen Module zum Bausystem hinzu, wie in FEM Modul erweitern beschrieben. Suche die richtige Liste auf, durch Suchen nach Beschränkungsmodulen.

Wie alle Objekte des FEM-Arbeitsbereiches muss die Geschwindigkeitsbeschränkung in ObjectsFem.py registriert werden. Die folgende Methode fügt dem aktiven Dokument eine Geschwindigkeitsbeschränkung hinzu. Diese Methode wird vom GUI-Befehl verwendet, um die Beschränkung hinzuzufügen. Sie muss irgendwo in ObjectsFem.py eingefügt werden.

def makeConstraintFlowVelocity(name="FlowVelocity"):
    obj = FreeCAD.ActiveDocument.addObject("Fem::ConstraintPython", name)
    import femobjects.constraint_flowvelocity
    femobjects.constraint_flowvelocity.Proxy(obj)
    if FreeCAD.GuiUp:
        import femviewprovider.view_constraint_flowvelocity
        femviewprovider.view_constraint_flowvelocity.ViewProxy(obj.ViewObject)
    return obj

GUI Befehl erstellen

In diesem Schritt werden wir die folgenden Dateien modifizieren:

  • src/Mod/Fem/CMakeLists.txt
  • src/Mod/Fem/App/CMakeLists.txt
  • src/Mod/Fem/Gui/Workbench.cpp

Und die folgende neue Datei hinzufügen:

  • src/Mod/Fem/femobjects/constraint_flowvelocity.py

Der Befehl ermöglicht es dem Anwender, die Beschränkung tatsächlich zur aktiven Analyse hinzuzufügen. Kopiere einfach einen Befehl aus einer vorhandenen Beschränkung. Die Befehle befinden sich im Paket femviewprovider. Passe das Attribut resources und die in Activated aufgerufene make-Methode deinen Bedürfnissen an. Verwende auch eine andere Befehls-ID im addCommand-Aufruf am unteren Ende des Moduls. Die folgende Klasse ist die Befehlsklasse der Geschwindigkeitsbeschränkung.

class Command(FemCommands.FemCommands):

    def __init__(self):
        super(Command, self).__init__()
        self.resources = {
            'Pixmap': 'fem-constraint-flow-velocity',
            'MenuText': QtCore.QT_TRANSLATE_NOOP(
                "FEM_ConstraintFlowVelocity",
                "Constraint Velocity"),
            'ToolTip': QtCore.QT_TRANSLATE_NOOP(
                "FEM_ConstraintFlowVelocity",
                "Creates a FEM constraint body heat flux")}
        self.is_active = 'with_analysis'

    def Activated(self):
        App.ActiveDocument.openTransaction(
            "Create FemConstraintFlowVelocity")
        Gui.addModule("ObjectsFem")
        Gui.doCommand(
            "FemGui.getActiveAnalysis().Member += "
            "[ObjectsFem.makeConstraintFlowVelocity()]")

Gui.addCommand('FEM_AddConstraintFlowVelocity', Command())

Füge die neue Befehlsdatei zum Bausystem hinzu, wie in FEM Modul erweitern beschrieben. Ermittle die richtige Liste, durch Suchen nach vorhandenen Befehlsmodulen.

Gib den Befehl in Gui/Workbench.cpp ein, um ihn der Symbolleiste und dem Menü hinzuzufügen. Suche nach einer vorhandenen Beschränkung der gleichen Kategorie wie die neue (z.B. Flow), kopiere und füge sie ein und passe die Befehls ID an. Dies sollte zweimal durchgeführt werden. Einmal für das Menü und noch einmal für die Werkzeugleiste.

Erstelle ein Aufgabenpaneel

In diesem Schritt werden wir die folgenden Dateien modifizieren:

  • src/Mod/Fem/femviewprovider/view_constraint_flowvelocity.py

In FreeCAD profitieren Beschränkungsobjekte stark von Aufgabenpaneels. Aufgabenpaneels können leistungsfähigere Eingabebedienelemente verwenden, die dem Benutzer die Einheit der eingegebenen Werte direkt anzeigen. Die Geschwindigkeitsbeschränkung erfordert sogar die Verwendung eines Aufgabenpaneels, da ein Aufgabenpaneel die einzige Möglichkeit ist, die Fläche(n) zu spezifizieren, auf die die Beschränkung angewendet werden soll.

Der Standort des Moduls, in dem die Aufgabenpanels implementiert werden, ist nicht streng definiert. Für die Geschwindigkeitsbeschränkung werden wir das Aufgabenpaneel einfach in dasselbe Modul setzen, in das wir den Ansichtsproxy setzen. Das Aufgabenpaneel ist ziemlich kompliziert. Es verwendet die Funktion FemSolectionWidgets.BoundarySelector(). Dabei handelt es sich um ein qt Bedienelement, mit dem der Benutzer die Grenzen auswählen kann, auf die die Beschränkung angewendet werden soll. Zusätzlich zu diesem Bedienelement erzeugt es ein weiteres, indem es eine speziell für die Geschwindigkeitsbeschränkung erstellte ui Datei lädt. Über dieses Bedienelement kann der Geschwindigkeitsvektor spezifiziert werden.

Die meiste Zeit sollte ausreichen, diese Klasse einfach zu kopieren, eine geeignete ui Datei zu verwenden (anstelle von TaskPanelFemFlowVelocity.ui) und _initParamWidget() sowie _applyWidgetChanges() anzupassen. Wenn die neue Beschränkung Körper als Referenzen anstelle von Begrenzungen erfordert, ersetze einfach das BoundarySelector Objekt durch das SolidSelector Objekt.

class _TaskPanel(object):

    def __init__(self, obj):
        self._obj = obj
        self._refWidget = FemSelectionWidgets.BoundarySelector()
        # self._refWidget = FemSelectionWidgets.SolidSelector()
        self._refWidget.setReferences(obj.References)
        self._paramWidget = Gui.PySideUic.loadUi(
            App.getHomePath() + "Mod/Fem/femviewprovider/TaskPanelFemFlowVelocity.ui")
        self._initParamWidget()
        self.form = [self._refWidget, self._paramWidget]
        analysis = FemMisc.findAnalysisOfMember(obj)
        self._mesh = FemMisc.getSingleMember(analysis, "Fem::FemMeshObject")
        self._part = self._mesh.Part if self._mesh is not None else None
        self._partVisible = None
        self._meshVisible = None

    def open(self):
        if self._mesh is not None and self._part is not None:
            self._meshVisible = self._mesh.ViewObject.isVisible()
            self._partVisible = self._part.ViewObject.isVisible()
            self._mesh.ViewObject.hide()
            self._part.ViewObject.show()

    def reject(self):
        self._restoreVisibility()
        return True

    def accept(self):
        if self._obj.References != self._refWidget.references():
            self._obj.References = self._refWidget.references()
        self._applyWidgetChanges()
        self._obj.Document.recompute()
        self._restoreVisibility()
        return True

    def _restoreVisibility(self):
        if self._mesh is not None and self._part is not None:
            if self._meshVisible:
                self._mesh.ViewObject.show()
            else:
                self._mesh.ViewObject.hide()
            if self._partVisible:
                self._part.ViewObject.show()
            else:
                self._part.ViewObject.hide()

    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.velocityXBox.setChecked(
            not self._obj.VelocityXEnabled)
        self._paramWidget.velocityYBox.setChecked(
            not self._obj.VelocityYEnabled)
        self._paramWidget.velocityZBox.setChecked(
            not self._obj.VelocityZEnabled)
        self._paramWidget.normalBox.setChecked(
            self._obj.NormalToBoundary)

    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 = float(quantity.getValueAs(unit))
        self._obj.VelocityYEnabled = \
            not self._paramWidget.velocityYBox.isChecked()
        if self._obj.VelocityYEnabled:
            quantity = Units.Quantity(self._paramWidget.velocityYTxt.text())
            self._obj.VelocityY = float(quantity.getValueAs(unit))
        self._obj.VelocityZEnabled = \
            not self._paramWidget.velocityZBox.isChecked()
        if self._obj.VelocityZEnabled:
            quantity = Units.Quantity(self._paramWidget.velocityZTxt.text())
            self._obj.VelocityZ = float(quantity.getValueAs(unit))
        self._obj.NormalToBoundary = self._paramWidget.normalBox.isChecked()

Der Ansichtproxy muss erweitert werden, um das Aufgabenpaneel zu unterstützen, das wir gerade implementiert haben. Der folgende erweiterte Ansichtproxy öffnet das Aufgabenpaneel, wenn der Anwender einen Doppelklick auf das Beschränkungsobjekt in der Baumansicht macht.

class ViewProxy(FemConstraint.ViewProxy):

    def getIcon(self):
        return ":/icons/fem-constraint-flow-velocity.svg"

    def setEdit(self, vobj, mode=0):
        task = _TaskPanel(vobj.Object)
        Gui.Control.showDialog(task)

    def unsetEdit(self, vobj, mode=0):
        Gui.Control.closeDialog()

    def doubleClicked(self, vobj):
        if Gui.Control.activeDialog():
            Gui.Control.closeDialog()
        Gui.ActiveDocument.setEdit(vobj.Object.Name)
        return True

Elmers Schreiber erweitern

In diesem Schritt werden wir die folgenden Dateien modifizieren:

  • src/Mod/Fem/femsolver/elmer/writer.py

Das Schreiber Modul enthält Methoden für alle Gleichungstypen. Je nach Art der Beschränkung, Randbedingung, Anfangsbedingung oder Körperkraft muss man unterschiedliche Methoden modifizieren. Für unsere Strömungsgeschwindigkeit müssen wir _handleFlowBndConditions(...) anpassen.

def _handleFlowBndConditions(self):
    for obj in self._getMember("Fem::ConstraintFlowVelocity"):
        if obj.References:
            for name in obj.References[0][1]:
                if obj.VelocityXEnabled:
                    velocity = getFromUi(obj.VelocityX, "m/s", "L/T")
                    self._boundary(name, "Velocity 1", velocity)
                if obj.VelocityYEnabled:
                    velocity = getFromUi(obj.VelocityY, "m/s", "L/T")
                    self._boundary(name, "Velocity 2", velocity)
                if obj.VelocityZEnabled:
                    velocity = getFromUi(obj.VelocityZ, "m/s", "L/T")
                    self._boundary(name, "Velocity 3", velocity)
                if obj.NormalToBoundary:
                    self._boundary(name, "Normal-Tangential Velocity", True)
            self._handled(obj)