Add FEM Constraint Tutorial/fr: Difference between revisions

From FreeCAD Documentation
No edit summary
m (FuzzyBot moved page Add FEM constraint tutorial/fr to Add FEM Constraint Tutorial/fr without leaving a redirect: Part of translatable page "Add FEM constraint tutorial")
(35 intermediate revisions by 3 users not shown)
Line 1: Line 1:
<languages/>
<languages/>

{{TutorialInfo
{{TutorialInfo/fr
|Topic=
|Topic=Ajouter des contraintes FEM
|Level=
|Time=
|Level=
|Time=
|Author=[[User:M42kus|M42kus]]
|Author=[[User:M42kus|M42kus]]
|FCVersion=
|FCVersion=
|Files=
|Files=
}}
}}

[[Category:FEM/fr]]


Dans ce tutoriel, nous allons ajouter la contrainte de vitesse d'écoulement à FreeCAD et implémenter le support pour le solveur Elmer. Assurez-vous d'avoir lu et compris [[Extend_FEM_Module/fr|Module d'extension FEM]] avant de lire ce tutoriel.
Dans ce tutoriel, nous allons ajouter la contrainte de vitesse d'écoulement à FreeCAD et implémenter le support pour le solveur Elmer. Assurez-vous d'avoir lu et compris [[Extend_FEM_Module/fr|Module d'extension FEM]] avant de lire ce tutoriel.


Ce tutoriel explique uniquement comment implémenter des contraintes en Python. Contrairement aux solveurs et aux équations, les contraintes suivent la structure classique du module FEM. C'est-à-dire que tous les modules d'une contrainte ont leur place soit dans le paquet PyObjects soit dans PyGui.
Ce tutoriel explique uniquement comment implémenter des contraintes en Python. Contrairement aux solveurs et aux équations, les contraintes suivent la structure classique du module FEM. C'est-à-dire que tous les modules d'une contrainte ont leur place soit dans le paquet {{Incode|femobjects}} ou le paquet {{Incode|femviewprovider}}.


== Résumé ==
== Résumé ==
Line 23: Line 26:


Dans cette étape, nous allons modifier les fichiers suivants:
Dans cette étape, nous allons modifier les fichiers suivants:
* 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}}

et ajouter les fichiers suivants:
Et ajouter les fichiers suivants:
* src/Mod/Fem/PyObjects/_FemConstraintFlowVelocity.py
* src/Mod/Fem/PyGui/_ViewProviderFemConstraintFlowVelocity.py
* {{FileName|src/Mod/Fem/femobjects/constraint_flowvelocity.py}}
* {{FileName|src/Mod/Fem/femviewprovider/view_constraint_flowvelocity.py}}

Un document proxy et une vue proxy sont nécessaires pour la nouvelle contrainte. Ceux-ci sont dans des modules séparés. Le document proxy est dans femobjects et la vue proxy dans femviewprovider. Copiez simplement les modules à partir d'une contrainte existante, par exemple:
* {{FileName|femobjects/constraint_selfweight.py}}
* {{FileName|femviewprovider/view_constraint_selfweight.py}}


Un document proxy et une vue proxy sont nécessaires pour la nouvelle contrainte. Ceux-ci sont dans des modules séparés. Le document proxy est dans PyObjects et la vue proxy dans PyGui. Copiez simplement les modules à partir d'une contrainte existante, par exemple:
* PyObjects/_FemConstraintSelfWeight.py
* PyGui/_ViewProviderFemConstraintSelfWeight.py
Ajustez la variable Type et les propriétés à vos besoins. Le document proxy de la contrainte de flux a l'aspect suivant:
Ajustez la variable Type et les propriétés à vos besoins. Le document proxy de la contrainte de flux a l'aspect suivant:

<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")
}}

Le module contenant la vue proxy peut paraître un peu plus compliqué. Mais pour l'instant, ajustez simplement le chemin de l'icône. Nous allons revenir à ce fichier dans les prochaines étapes du tutoriel.
Le module contenant la vue proxy peut paraître un peu plus compliqué. Mais pour l'instant, ajustez simplement le chemin de l'icône. Nous allons revenir à ce fichier dans les prochaines étapes du tutoriel.

<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"
}}

Ajoutez les deux nouveaux modules au système de construction comme décrit dans [https://www.freecadweb.org/wiki/Extend_FEM_Module/fr Module d'extension FEM]. Localisez la bonne liste en recherchant les modules de contraintes.
Ajoutez les deux nouveaux modules au système de construction comme décrit dans [https://www.freecadweb.org/wiki/Extend_FEM_Module/fr Module d'extension FEM]. Localisez la bonne liste en recherchant les modules de contraintes.


Comme tous les objets de l'espace de travail FEM, la contrainte de vélocité doit être enregistrée dans <code>ObjectsFem.py</code>. La méthode suivante ajoute une contrainte de vélocité au document actif. Cette méthode sera utilisée par la commande GUI pour ajouter la contrainte. Elle doit être insérée quelque part dans <code>ObjectsFem.py</code>.
Comme tous les objets de l'espace de travail FEM, la contrainte de vélocité doit être enregistrée dans {{Incode|ObjectsFem.py}}. La méthode suivante ajoute une contrainte de vélocité au document actif. Cette méthode sera utilisée par la commande GUI pour ajouter la contrainte. Elle doit être insérée quelque part dans {{Incode|ObjectsFem.py}}.

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

== Création d'une commande graphique ==
== Création d'une commande graphique ==


Dans cette étape, nous allons modifier les fichiers suivants:
Dans cette étape, nous allons modifier les fichiers suivants:
* 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}}

et ajoutez le nouveau fichier suivant:
Et ajoutez le nouveau fichier suivant:
* src/Mod/Fem/PyGui/_CommandFemConstraintFlowVelocity.py
* {{FileName|src/Mod/Fem/femobjects/constraint_flowvelocity.py}}

La commande permet à l'utilisateur d'ajouter la contrainte à l'analyse active. Copiez simplement une commande à partir d'une contrainte existante. Les commandes sont dans le package {{Incode|femviewprovider}}. Ajustez l’attribut des ressources et la méthode de compilation appelée dans Activated selon vos besoins. Utilisez également un ID de commande différent dans l'appel addCommand au bas du module. La classe suivante est la classe de commande de la contrainte de vélocité.


{{Code|code=
La commande permet à l'utilisateur d'ajouter la contrainte à l'analyse active. Copiez simplement une commande à partir d'une contrainte existante. Les commandes sont dans le package <code>PyGui</code>. Ajustez l’attribut des ressources et la méthode de compilation appelée dans Activated selon vos besoins. Utilisez également un ID de commande différent dans l'appel addCommand au bas du module. La classe suivante est la classe de commande de la contrainte de vélocité.
<pre>class Command(FemCommands.FemCommands):
class Command(FemCommands.FemCommands):


def __init__(self):
def __init__(self):
Line 91: Line 111:
'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>
Ajoutez le nouveau fichier de commande au système de build comme décrit dans [https://www.freecadweb.org/wiki/Extend_FEM_Module/fr Module d'extension FEM]. Recherchez la liste appropriée en recherchant les modules de commande existants.
Ajoutez le nouveau fichier de commande au système de build comme décrit dans [https://www.freecadweb.org/wiki/Extend_FEM_Module/fr Module d'extension FEM]. Recherchez la liste appropriée en recherchant les modules de commande existants.


Line 114: Line 136:


Dans cette étape, nous allons modifier le fichier suivant:
Dans cette étape, nous allons modifier le fichier suivant:
* src/Mod/Fem/PyGui/_ViewProviderFemConstraintFlowVelocity.py
* {{FileName|src/Mod/Fem/femviewprovider/view_constraint_flowvelocity.py}}

Dans FreeCAD, les objets de contrainte bénéficient des panneaux de tâches. Les panneaux de tâches peuvent utiliser des widgets de saisie puissants donnant directement l’unité de valeurs entrées à l’utilisateur. La contrainte de vélocité nécessite l'utilisation d'un panneau de tâches. C'est le seul moyen de spécifier la ou les faces sur lesquels la contrainte doit être appliquée.
Dans FreeCAD, les objets de contrainte bénéficient des panneaux de tâches. Les panneaux de tâches peuvent utiliser des widgets de saisie puissants donnant directement l’unité de valeurs entrées à l’utilisateur. La contrainte de vélocité nécessite l'utilisation d'un panneau de tâches. C'est le seul moyen de spécifier la ou les faces sur lesquels la contrainte doit être appliquée.


Line 120: Line 143:


La plupart du temps, cela devrait suffire pour copier cette classe. Utilisez un fichier d'interface utilisateur approprié (au lieu de TaskPanelFemFlowVelocity.ui) et ajustez _initParamWidget() ainsi que _applyWidgetChanges(). Si la nouvelle contrainte nécessite des bodies pour référence plutôt que des limites, remplacez simplement l'objet BoundarySelector par SolidSelector.
La plupart du temps, cela devrait suffire pour copier cette classe. Utilisez un fichier d'interface utilisateur approprié (au lieu de TaskPanelFemFlowVelocity.ui) et ajustez _initParamWidget() ainsi que _applyWidgetChanges(). Si la nouvelle contrainte nécessite des bodies pour référence plutôt que des limites, remplacez simplement l'objet BoundarySelector par SolidSelector.

<pre>class _TaskPanel(object):
{{Code|code=
class _TaskPanel(object):


def __init__(self, obj):
def __init__(self, obj):
Line 128: Line 153:
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/PyGui/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 193:


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 210:


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 226:
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()
}}

La vue proxy doit être étendue pour prendre en charge le panneau de tâches que nous venons d'implémenter. La vue proxy étendue ouvre le panneau de tâches lorsque l'utilisateur clique deux fois sur l'objet de contrainte dans la vue arborescente.
La vue proxy doit être étendue pour prendre en charge le panneau de tâches que nous venons d'implémenter. La vue proxy étendue ouvre le panneau de tâches lorsque l'utilisateur clique deux fois sur l'objet de contrainte dans la vue arborescente.

<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 248:
Gui.Control.closeDialog()
Gui.Control.closeDialog()
Gui.ActiveDocument.setEdit(vobj.Object.Name)
Gui.ActiveDocument.setEdit(vobj.Object.Name)
return True</pre>
return True
}}

== Extension du fichier writer du solveur Elmer ==
== Extension du fichier writer du solveur Elmer ==


Dans cette étape, nous allons modifier le fichier suivant:
Dans cette étape, nous allons modifier le fichier suivant:
* src/Mod/Fem/FemSolver/Elmer/Writer.py
* {{FileName|src/Mod/Fem/femsolver/elmer/writer.py}}

Le module writer contient des méthodes pour tous les types d'équations. En fonction du type de constraintes, de la condition limite, de la condition initiale ou de la force body, il est nécessaire de modifier différentes méthodes. Pour notre vitesse d'écoulement, nous devons ajuster _handleFlowBndConditions (...).
Le module writer contient des méthodes de calcul pour tout type d'équations. En fonction du type de contraintes, de la condition limite, de la condition initiale ou de la force body, il est nécessaire de modifier ces différentes méthodes. Pour notre vitesse d'écoulement, nous devons ajuster {{Incode|_handleFlowBndConditions(...)}}.
<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)
}}




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

Revision as of 14:27, 3 November 2021

Tutoriel
Thème
Ajouter des contraintes FEM
Niveau
Temps d'exécution estimé
Auteurs
M42kus
Version de FreeCAD
Fichiers exemples
Voir aussi
None

Dans ce tutoriel, nous allons ajouter la contrainte de vitesse d'écoulement à FreeCAD et implémenter le support pour le solveur Elmer. Assurez-vous d'avoir lu et compris Module d'extension FEM avant de lire ce tutoriel.

Ce tutoriel explique uniquement comment implémenter des contraintes en Python. Contrairement aux solveurs et aux équations, les contraintes suivent la structure classique du module FEM. C'est-à-dire que tous les modules d'une contrainte ont leur place soit dans le paquet femobjects ou le paquet femviewprovider.

Résumé

  1. Créer un objet document: l'objet document soumis à l'analyse et où la contrainte peut être paramétrée et liée.
  2. Créer une commande graphique: ajoute une commande à l'atelier FEM laquelle permet d'ajouter une contrainte de flux à l'analyse active.
  3. Créer un panneau de tâches: le panneau de tâches est nécessaire pour permettre à l'utilisateur de définir les limites de la contrainte de vélocité. Cela rend également la saisie des paramètres un peu plus conviviale.
  4. Extension du fichier writer du solveur Elmer: ajoute le support pour la nouvelle contrainte au solveur Elmer en développant son exportateur de fichier sif.

Créer un objet document

Dans cette étape, nous allons modifier les fichiers suivants:

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

Et ajouter les fichiers suivants:

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

Un document proxy et une vue proxy sont nécessaires pour la nouvelle contrainte. Ceux-ci sont dans des modules séparés. Le document proxy est dans femobjects et la vue proxy dans femviewprovider. Copiez simplement les modules à partir d'une contrainte existante, par exemple:

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

Ajustez la variable Type et les propriétés à vos besoins. Le document proxy de la contrainte de flux a l'aspect suivant:

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")

Le module contenant la vue proxy peut paraître un peu plus compliqué. Mais pour l'instant, ajustez simplement le chemin de l'icône. Nous allons revenir à ce fichier dans les prochaines étapes du tutoriel.

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

Ajoutez les deux nouveaux modules au système de construction comme décrit dans Module d'extension FEM. Localisez la bonne liste en recherchant les modules de contraintes.

Comme tous les objets de l'espace de travail FEM, la contrainte de vélocité doit être enregistrée dans ObjectsFem.py. La méthode suivante ajoute une contrainte de vélocité au document actif. Cette méthode sera utilisée par la commande GUI pour ajouter la contrainte. Elle doit être insérée quelque part dans ObjectsFem.py.

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

Création d'une commande graphique

Dans cette étape, nous allons modifier les fichiers suivants:

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

Et ajoutez le nouveau fichier suivant:

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

La commande permet à l'utilisateur d'ajouter la contrainte à l'analyse active. Copiez simplement une commande à partir d'une contrainte existante. Les commandes sont dans le package femviewprovider. Ajustez l’attribut des ressources et la méthode de compilation appelée dans Activated selon vos besoins. Utilisez également un ID de commande différent dans l'appel addCommand au bas du module. La classe suivante est la classe de commande de la contrainte de vélocité.

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())

Ajoutez le nouveau fichier de commande au système de build comme décrit dans Module d'extension FEM. Recherchez la liste appropriée en recherchant les modules de commande existants.

Placez la commande dans Gui/Workbench.cpp pour l’ajouter à la barre d’outils et au menu. Recherchez une contrainte existante de la même catégorie que la nouvelle (par exemple, Flow), faites copier/coller et ajustez l'ID de la commande. Cela devrait être fait deux fois, une fois pour le menu et une pour la barre d'outils.

Créer un panneau de tâches

Dans cette étape, nous allons modifier le fichier suivant:

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

Dans FreeCAD, les objets de contrainte bénéficient des panneaux de tâches. Les panneaux de tâches peuvent utiliser des widgets de saisie puissants donnant directement l’unité de valeurs entrées à l’utilisateur. La contrainte de vélocité nécessite l'utilisation d'un panneau de tâches. C'est le seul moyen de spécifier la ou les faces sur lesquels la contrainte doit être appliquée.

L'emplacement du module dans lequel les panneaux de tâches sont implémentés n'est pas strictement défini. Pour la contrainte de vitesse, nous allons simplement placer le panneau de tâches dans le même module que la vue proxy. Le panneau de tâches est assez compliqué. Il utilise le FemSolectionWidgets.BoundarySelector(). C'est un widget QT qui permet à l'utilisateur de sélectionner les limites sur lesquelles la contrainte doit être appliquée. En plus de ce widget, il en génère un autre en chargeant un fichier d'interface utilisateur créé spécifiquement pour la contrainte de vélocité. Via ce widget, le vecteur de vitesse peut être spécifié.

La plupart du temps, cela devrait suffire pour copier cette classe. Utilisez un fichier d'interface utilisateur approprié (au lieu de TaskPanelFemFlowVelocity.ui) et ajustez _initParamWidget() ainsi que _applyWidgetChanges(). Si la nouvelle contrainte nécessite des bodies pour référence plutôt que des limites, remplacez simplement l'objet BoundarySelector par SolidSelector.

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()

La vue proxy doit être étendue pour prendre en charge le panneau de tâches que nous venons d'implémenter. La vue proxy étendue ouvre le panneau de tâches lorsque l'utilisateur clique deux fois sur l'objet de contrainte dans la vue arborescente.

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

Extension du fichier writer du solveur Elmer

Dans cette étape, nous allons modifier le fichier suivant:

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

Le module writer contient des méthodes de calcul pour tout type d'équations. En fonction du type de contraintes, de la condition limite, de la condition initiale ou de la force body, il est nécessaire de modifier ces différentes méthodes. Pour notre vitesse d'écoulement, nous devons ajuster _handleFlowBndConditions(...).

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)