+++ /dev/null
-.. meta::
- :keywords: maillage, champ, manipulation, XMED
- :author: Guillaume Boulant
-
-%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-Démonstrateur XMED, documentation technique
-%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-
-Cette note fait la synthèse des développements effectués pour le
-maquettage des fonctions de manipulation de champs dans SALOME. Elle
-présente les principes retenus en matière de conception, c'est-à-dire
-concernant les mécanismes techniques sous-jacents, et en matière
-d'ergonomie, c'est-à-dire concernant les modalités d'utilisation dans
-l'environnement SALOME.
-
-Ces principes sont illustrés par des développements implantés dans le
-module XMED, développé pour les besoins de l'analyse, et dans le
-module MED distribué avec la plateforme SALOME.
-
-.. note:: la lecture de ce chapitre demande une connaissance de la
- structure de classes du module MED, en particulier la distinction
- entre les classes ``MEDMEM::*`` et les servants CORBA associés
- (classe ``SALOME_MED::*``).
-
-.. contents:: Sommaire
- :local:
- :backlinks: none
-
-Principes directeurs
-====================
-
-Objectif et motivation
-----------------------
-
-L'objectif de maquettage est de trouver une architecture technique qui
-permet d'exécuter le cas d'utilisation suivant:
-
-* Chargement d'un fichier med dans SALOME (a priori dans le module MED)
-* Sélection graphique des champs de l'étude à mettre à disposition
- dans la console utilisateur ("calculette" en mode texte qui
- concraitement correspond à l'interface python de SALOME).
-* Dans la calculette, exécution d'opérations algébriques (+,-,*,/)
- entre champs avec possibilité d'utiliser des scalaires dans des
- opérations de type transformation linéaire (y=ax+b ou y et x sont
- des champs et a et b des scalaires). Opérations pow, sqrt.
-* Possibilité de visualiser les champs produits avec VISU pour
- contrôle des résultats.
-* Possibilité d'exporter des champs produits dans un fichier med.
-
-Eléments de contexte
---------------------
-
-Les opérations de manipulation de champs sont en grande partie
-implémentées dans la bibliothèque MEDMEM. Pour illustration, le
-fragment de code ci-dessous montre comment une addition de champ peut
-être opérée en python:
-
-.. code-block:: python
-
- from libMEDMEM_Swig import MedDataManager
- from xmed.helper import readMed, writeMed
-
- # Load the medmem data structure from a med file
- med = readMed("/tmp/input.med")
- # Then create a med data manager to deal with the fields data
- dm = MedDataManager(med)
- # Get the timestamps (dt,it)=(-1,-1) of the fields "testfield1" and "testfield2"
- f1 = dm.getFieldDouble("testfield1",-1,-1)
- f2 = dm.getFieldDouble("testfield2",-1,-1)
-
- # Create a new field as the sum of f1 and f2
- r = f1 + f2
- # And add this new field to the med data structure
- med.addField(r)
-
- # Finally, write the whole data in an output med file
- writeMed(med,"/tmp/output.med")
-
-Ceci montre que les champs peuvent être manipulés avec une interface
-relativement ergonomique (une addition de deux champs f1 et f2 s'écrit
-f1+f2) tant que l'on manoeuvre des objets MEDMEM purs (classes C++ du
-package MEDMEM et wrapping python du package MEDMEM_SWIG).
-
-Par ailleurs, le fonctionnement actuel des modules SALOME qui
-manoeuvrent des données MED est d'instancier les structures de données
-MEDMEM au niveau de la partie serveur, c'est-à-dire au niveau des
-servants CORBA hébergés dans le processus ``SALOME_Container``, et de
-donner accés à ces données depuis l'étude SALOME au travers de
-pointeurs CORBA. Ce choix d'architecture présente l'avantage de
-centraliser au niveau serveur la gestion du cycle de vie des données
-informatiques et de pouvoir distribuer des "poignées" pour manipuler
-ces données depuis chaque point de l'application qui sait accéder au
-bus CORBA, l'interface graphique en particulier.
-
-
-Hypothèse de travail
---------------------
-
-Compte-tenu de l'objectif de maquettage et des éléments de contexte
-existant, on cherche une solution dans le cadre des hypothèses
-de travail suivantes:
-
-* La manipulation des champs se fait dans l'environement graphique de
- SALOME.
-* Dans cet environnement, on souhaite pouvoir sélectionner
- graphiquement les champs à considérer, puis manipuler ces champs
- dans l'interface texte au moyen de variables python avec une syntaxe
- aussi simple que celle définie dans le wrapping python de MEDMEM,
- c'est-à-dire que pour faire l'addition de 2 champs f1 et f2, on veut
- pouvoir écrire f1+f2.
-* Les données MED sont physiquement dans la partie serveur de SALOME
- et accessibles via des pointeurs CORBA (interface spécifiée dans
- MED.idl). On exclu la recopie de données au niveau du client
- graphique.
-
-Dans le cadre de ces hypothèses, la difficulté technique réside dans
-la mise au point d'une interface de communication entre des variables
-manipulées par l'utilisateur dans l'interface graphique (c'est-à-dire
-dans le processus ``SALOME_SessionServer``) et des objets MEDMEM
-instanciés dans le containeur des servants CORBA (c'est-à-dire dans le
-processus ``SALOME_Container``).
-
-
-Eléments de conception
-======================
-
-
-Implantation technique
-----------------------
-
-Le diagramme ci-dessous représente l'organisation des principaux
-paquets logiciels du module MED:
-
-.. image:: images/medmem-layers.png
- :align: center
-
-Les cadres bleus représentent le lieu d'implantation des
-développements effectués dans le module MED pour les besoins du
-maquettage. On notera en particulier les interventions aux niveaux
-suivants:
-
-* interfaces idl: ajout de l'interface MEDOP.idl
-* package MEDMEM_I: ajout du servant SALOME_MED::MEDOP qui implémente
- l'interface MEDOP.idl
-
-Architecture technique
-----------------------
-
-Les schéma ci-dessous représente les objets informatiques qui sont à
-l'oeuvre pour la réalisation des opérations sur les champs:
-
-.. image:: /images/xmed-architecture.png
- :align: center
- :alt: Objets mis en oeuvre dans l'interface de manipulation de champs
-
-On distingue les objets suivants:
-
-* Une instance de ``MEDMEM::MED``, correspondant à la structure de donnée
- MED chargée en mémoire.
-* Des instances de ``MEDMEM::FIELD`` qui représentent les champs med
- chargés en mémoire.
-* Une instances de ``SALOME_MED::MED`` et des instances de
- ``SALOME_MED::FIELD`` qui sont les servants CORBA respectivement de la
- structure med et des champs qui lui sont associés et chargés en
- mémoire.
-* Une instance de ``SALOME_MED::MEDOP`` qui est le servant CORBA qui
- centralise la mise en oeuvre des opérations de champs sur le serveur
- ``SALOME_Container``. Le servant MEDOP détient en attribut une référence
- sur la structure ``MEDMEM::MED``, ce qui lui permet d'accéder
- directement aux champs ``MEDMEM::FIELD`` à partir de leur nom et du pas
- de temps.
-* Des instances de ``FieldProxy`` qui correspondent aux variables
- manipulées au niveau de l'interface graphique et qui représentent
- les champs. Une instance de FieldProxy possède détient les
- références des servants ``SALOME_MED::MEDOP`` et
- ``SALOME_MED::FIELD`` sous la forme de pointeurs CORBA de noms
- ``medop_ptr`` et ``field_ptr`` respectivement.
-* Il existe également une instance de ``MedProxy`` non représentée
- dans ce diagramme. Cette instance correspond à une variable qui
- permet de manipuler la structure med.
-
-.. note:: Les éléments apportés par la maquette sont les classes
- ``SALOME_MED::MEDOP``, ``MedProxy`` et ``FieldProxy``. Les autres
- éléments ont pu être modifiés légèrement pour les besoins de
- l'intégration ou pour la correction de quelques bugs.
-
-Le cycle de vie de ces objets est le suivant.
-
-Pour ce qui concerne les instances de la structure ``MEDMEM::MED`` et
-des champs ``MEDMEM::FIELD``, la création est faite au moment du
-chargement du fichier med dans SALOME au moyen du module MED. A cette
-occasion, les servants CORBA associés ``SALOME_MED::MED`` et
-``SALOME_MED::FIELD`` sont créés et des références vers ces servants
-sont publiés dans l'étude. Ils peuvent donc être sélectionnés par
-l'utilisateur dans l'interface graphique. L'ensemble de ces données
-préexiste à la manipulation de champs.
-
-Les objets ``SALOME_MED::MEDOP`` sont instanciés au sein du servant
-``SALOME_MED::MED`` auquel ils sont associées. Le servant
-``SALOME_MED::MED`` possède une référence sur la structure
-``MEDMEM::MED`` et il la transmet à l'instance du servant
-``SALOME_MED::MEDOP`` qu'il construit. L'opérateur MEDOP est donc
-autonome par la suite pour manipuler les données MED, et les champs en
-particulier. Le code python ci-dessous montre comment un opérateur med
-``SALOME_MED::MEDOP`` peut être créé puis utilisé pour réaliser
-l'addition de deux champs:
-
-.. code-block:: python
-
- import salome
- salome.salome_init()
- import SALOME_MED
-
- medComp = salome.lcc.FindOrLoadComponent("FactoryServer", "MED")
- medObj = medComp.readStructFile("myfile.med",salome.myStudyName)
- medOp = medObj.createMedOperator()
-
- f1 = medObj.getField("testfield1",-1,-1)
- f2 = medObj.getField("testfield2",-1,-1)
-
- somme = medOp.add(f1,f2)
-
-Il est à noter qu'une instance de ``SALOME_MED::MEDOP`` est associé à
-une instance unique de ``SALOME_MED::MED`` (et donc indirectement de
-``MEDMED::MED``) pour toute la durée de son cycle de vie. Par contre,
-un servant ``SALOME_MED::MED`` peut être associé à plusieurs servants
-``SALOME_MED::MEDOP`` différents. Un servant ``SALOME_MED::MEDOP`` a
-une référence directe sur la structure ``MEDMEM::MED`` et peut la
-manoeuvrer pour demander des champs, faire des opérations avec ces
-champs, ajouter le champs résultat à la structure et enfin retourner
-un servant ``SALOME_MED::FIELD`` qui encapsule le champ résultat.
-
-Enfin, quelques éléments concernant la classe ``FieldProxy``. Une
-instance de ``FieldProxy`` est un objet python qui peut être
-manoeuvrée dans l'interpréteur SALOME et qui référence un champ MED
-localisé sur le serveur ``SALOME_Container`` (par le mécanisme décrit
-ci-dessus). C'est à ce niveau qu'on règle les détails d'ergonomie
-d'usage (cf. paragraphe ci-après). La création d'un objet
-``FieldProxy`` déclenche la création d'un opérateur med (instance de
-``SALOME_MED::MEDOP``) qui lui est associé et dont il conserve la
-référence CORBA en attribut (noté ``medop_ptr`` sur le diagramme). Cet
-opérateur ``medop_ptr`` peut être requêter pour exécuter toutes les
-opérations possibles sur ce champ, comme illustrer sur l'exemple
-ci-dessus.
-
-
-Rôle des objets proxy
----------------------
-
-Dans le modèle d'architecture présenté ci-dessus, on introduit deux
-types d'objets proxy:
-
-* Les objets de classe ``FieldProxy`` qui représentent des poignées de
- manipulation des champs ``MEDMEM::FIELD`` physiquement instanciés
- dans le container SALOME.
-* Les objets de classe ``MedProxy`` qui représentent des poignées de
- manipulation des structures ``MEDMEM::MED`` physiquement instanciées
- dans le container SALOME.
-
-Elles sont instanciées dans l'interpréteur python SALOME pour
-manipulation dans l'interface textuelle à partir de la donnée du
-pointeur vers le servant ``SALOME_MED::MED`` et de l'identifiant du
-champ (le nom du champ et le pas de temps défini par le numéro d'ordre
-et le numéro d'iteration:
-
-.. code-block:: python
-
- import salome
- salome.salome_init()
- import SALOME_MED
-
- medComp = salome.lcc.FindOrLoadComponent("FactoryServer", "MED")
- medObj = medComp.readStructFile("myfile.med",salome.myStudyName)
-
- from xmed import fieldproxy
- from xmed import medproxy
-
- f1 = fieldproxy.getFieldFromMed(medObj, "testfield1", -1, -1)
- f2 = fieldproxy.getFieldFromMed(medObj, "testfield2", -1, -1)
-
- field_somme = f1 + f2
- field_offset = f1 + 5.3
-
-Dans cet exemple, les variables ``f1``, ``f2``, ``field_somme`` et
-``field_offset`` sont des objets de classe ``FieldProxy``. Ils
-correspondent aux variables physiquement manipulées par
-l'utilisateur pour désigner les champs dans les opérations.
-
-Ces classes proxy sont conçues pour être le lieu d'implémentation de
-l'interprétation des commandes utilisateur et donc de l'ergonomie
-de manipulation des champs au niveau l'interface textuelle. Ce point
-est développé :ref:`plus bas <develguide_execFieldOperation>`.
-
-Programmation de l'interface textuelle
---------------------------------------
-
-Dans le cadre de la maquette, l'interface de manipulation des champs
-est l'interface textuelle python intégrée à SALOME. Dans la pratique,
-l'utilisateur manipule des variables python qui correspondent à des
-objets de classe ``FieldProxy`` équipées des fonctions requises et de
-l'ergonomie nécessaire à la mise en oeuvre des opérations (voir
-ci-dessus).
-
-Or, l'hypothèse de travail est que les données MED sont chargées dans
-SALOME et publiées dans l'étude pour point d'accés depuis l'interface
-graphique. L'utilisateur choisi un champs directement dans l'arbre
-d'étude (ou dans une interface graphique dédiée) puis demande qu'il
-soit mis à disposition dans l'interface python sous un nom de variable
-à choisir. Les captures d'écran ci-dessous montre la séquence
-graphique en images:
-
-.. |IMG_SELECT| image:: images/medop-gui-selectfield_scale.png
-.. |IMG_ALIAS| image:: images/medop-gui-aliasfield_scale.png
-
-+---------------+---------------+
-| |IMG_SELECT| | |IMG_ALIAS| |
-+---------------+---------------+
-
-L'image de gauche montre la sélection du pas de temps, l'image de
-droite la boîte de dialogue qui permet la saisie de l'alias avec
-lequel le champs sera manipulé dans l'interface textuelle. La
-validation de cette fenêtre doit mettre automatiquement le champ à
-disposition dans l'interface python SALOME et sous le nom de variable
-spécifié par l'alias saisi.
-
-Pour cela, il y a un couplage technique à programmer entre l'interface
-graphique et l'interface textuelle python, avec en particulier la
-transmission des pointeurs vers les servants CORBA mis en jeu dans la
-sélection.
-
-Ce couplage est implanté au niveau de la classe MEDGUI.cxx du module
-MED (où de la classe XMEDGUI.cxx du module XMED pour la maquette) qui
-implémente l'interface graphique du module. Pour rappel, l'interface
-graphique d'un module SALOME se présente sous la forme d'une classe
-centrale de nom ``<MODULE_NAME>GUI`` et qui spécialise la classe
-``SalomeApp_Module``. Cette classe possède une méthode ``getApp()``
-par laquelle on peut récupérer une instance de la console python
-embarquée (this->getApp()->pythonConsole()).
-
-Le code suivant illustre l'envoie d'une commande python par ce
-mécanisme. Dans cet example, on cherche à reconstituer dans le
-contexte de la console python un pointer vers un objet med instancié
-dans le contexte C++ de l'application graphique. Pour cela, on
-communique la référence de l'objet sous la forme sérialisé (IOR pour
-un objet CORBA):
-
-.. code-block:: cpp
-
- #include <PyConsole_Console.h>
- #include <QString>
- #include <QStringList>
- #include <SalomeApp_Application.h>
-
- // We suppose here that we have a CORBA object reference (object of
- // type *_ptr or *_var), for example a SALOME_MED::MED object.
- SALOME_MED::MED_ptr medObj = ... // anything to get this object
-
- // Get the IOR of this object
- QString medIOR = SalomeApp_Application::orb()->object_to_string(medObj);
-
- PyConsole_Console * pyConsole = getApp()->pythonConsole();
-
- QStringList commands;
- commands+="import salome";
- commands+=QString("med=salome.orb.string_to_object(\"%1\")").arg(medIOR);
-
- QStringListIterator it(commands);
- while (it.hasNext()) {
- pyConsole->exec(it.next());
- }
-
-Le code réel de la maquette est basé sur ce principe et transmet à la
-console python des lignes de commandes qui permettent de reconstruire:
-
-* un pointeur CORBA vers le servant ``SALOME_MED::MED`` associé au
- champ sélectionné;
-* une instance de ``FieldProxy`` qui correspond au champ sélectionné
- et avec pour nom de variable la valeur de l'alias saisi dans
- l'interface graphique.
-
-Au niveau du code C++ de la classe ``XMEDGUI.cxx``, cela se traduit
-par la fabrication de la liste de commandes suivante pour envoie à la
-console python par le mécanisme illustré plus haut:
-
-.. code-block:: cpp
-
- QStringList commands;
- commands+="from xmed.fieldproxy import getFieldFromMed";
- commands+="from xmed.medproxy import getMedProxy";
- commands+=QString("if not dir().__contains__('med'): med = getMedProxy(\"%1\")").arg(medIOR);
- commands+=QString("%1=getFieldFromMed(med,\"%3\",%4,%5)").arg(*alias).arg(fieldName).arg(orderIndex).arg(iterationIndex);
-
-Les variables ``medIOR``, ``fieldName``, ``orderIndex`` et
-``iterationIndex`` sont construites à partir du champ sélectionné par
-des techniques de programmation standard dans SALOME qu'on peut
-examiner en détail dans la classe ``XMEDGUI`` (voir méthode
-``XMEDGUI::LoadIntoPythonConsole()``). La variable ``alias`` est la
-chaîne saisie par l'utilisateur dans la fenêtre de dialogue.
-
-Le point important à noter ici est que les données à transmettre
-doivent être fournies sous forme de chaînes de caractères ou de types
-simples. C'est pourquoi la référence au servant CORBA
-``SALOME_MED::MED`` est transmise ici sous la forme de son IOR,
-c'est-à-dire une chaîne de caractères qui permet l'identification de
-l'objet au niveau du bus CORBA.
-
-Au niveau de la console python cela correspond à l'exécution des
-commandes suivantes:
-
-.. code-block:: python
-
- from xmed.fieldproxy import getFieldFromMed
- from xmed.medproxy import getMedProxy
-
- med = getMedProxy("IOR:010000001700000049444c3a53414c4f4d455f4d45442f4d45443a312e300000010000000000000064000000010102000e0000003133302e39382e37372e313733009e0a0e000000feadc4ca4c00003169000000001100000200000000000000080000000100000000545441010000001c00000001000000010001000100000001000105090101000100000009010100")
-
- f1=getFieldFromMed(med,"testfield1",-1,-1)
-
-Ce jeu d'instructions reconstitue un pointeur vers le servant CORBA
-``SALOME_MED::MED`` à partir de son identifiant IOR (voir la fonction
-``getMedProxy(...)``, puis crée une instance de ``FieldProxy``
-associée à ce servant (en fait associée au servant
-``SALOME_MED::MEDOP`` créé sur demande par le servant
-``SALOME_MED::MED``, voir la fonction ``getFieldFromMed(...)``).
-
-.. _develguide_execFieldOperation:
-
-Exécution des opérations sur le champs
---------------------------------------
-
-Les variables définies dans l'interface textuelle pour désigner les
-champs à manipuler sont des objets de classe ``FieldProxy``.
-
-Cette classe a une propriété remarquable, elle est construite sur un
-design pattern de type "Proxy" qui pointe vers un servant
-``SALOME_MED::FIELD``. Cela signifie que l'on ne peut pas accéder
-directement au servant vers lequel il pointe, mais que l'on passe
-systématiquement par une procédure de l'objet proxy qui fait "boîte
-aux lettres":
-
-.. code-block:: python
-
- class FieldProxy:
-
- def __getattr__( self, name ):
- """
- This method realizes the proxy pattern toward the servant
- SALOME_MED::FIELD.
- """
- return getattr( self.__field_ptr, name )
-
-Ce pattern permet l'implémentation de pré-traitement et/ou de
-post-traitement suivant le type d'accés que l'on cherche à faire.
-
-Il permet aussi et surtout de fournir un objet python qui présente
-l'interface de ``SALOME_MED::FIELD`` dotée d'extentions adhoc pour les
-operations de champs. Ici, python est ton ami, car il s'agit pour cela
-d'équiper la classe ``FieldProxy`` des automatismes prévus nativement
-par python pour les operations entre objets. En particulier, la
-re-définition des fonctions internes ``__add__`` (opérateur addition),
-``__sub__`` (opérateur soustraction), ``__mul__`` (opérateur
-multiplication) et ``__div__`` (opérateur division) au sein de la
-classe ``FieldProxy``, permet de prendre la main sur le comportement
-des opérations algébriques et de définir une ergonomie sur mesure. Par
-exemple, la méthode ``__add__`` peut gérer les variantes "f1+f2"
-(ajout de deux variables de type FieldProxy) et "f1+5.3" (ajout d'un
-réel à une variable de type FieldProxy):
-
-.. code-block:: python
-
- class FieldProxy:
-
- def __add__(self, operande):
- """
- This can process the addition of two fields or the addition of
- a scalar to a field. It depends weither the operande is a
- FieldProxy or a simple scalar numerical value.
- """
- if isinstance(operande, FieldProxy):
- # The operande is an other field
- otherField_ptr = operande.__field_ptr
- rfield_ptr = self.__medOp_ptr.add(self.__field_ptr, otherField_ptr)
- else:
- # The operande is a scalar numerical value that must be
- # considered as an offset in a linear transformation
- factor = 1
- offset = operande
- rfield_ptr = self.__medOp_ptr.lin(self.__field_ptr, factor, offset)
- return FieldProxy(self.__med_ptr, rfield_ptr)
-
-Il est à noter que dans les deux cas de figure (opérande=champ ou
-opérande=scalaire), la fonction délègue la réalisation concrète de
-l'opération au servant ``SALOME_MED::MEDOP`` (identifié ici par
-l'attribut ``self.__medOp_ptr`` et que l'on appelera l'*opérateur
-MEDOP* dans la suite pour simplifier), mais n'appelle pas le même
-service de calcul (l'addition entre champs dans le premier cas,
-l'application d'une transformation linéaire de type y=factor*x+offset
-dans le deuxième cas).
-
-Pour couvrir le cas des opérations algébriques, l'opérateur MEDOP
-présentre l'interface suivante (cf. fichier ``MEDOP.idl`` qui définie
-l'interface du servant ``SALOME_MED_MEDOP``):
-
-.. code-block:: cpp
-
- /*! Addition of the fields f1 and f2 ( f1+f2) */
- FIELD add(in FIELD f1, in FIELD f2) raises (SALOME::SALOME_Exception);
- /*! Substraction of the fields f1 and f2 (f1-f2) */
- FIELD sub(in FIELD f1, in FIELD f2) raises (SALOME::SALOME_Exception);
- /*! Multiplication of the fields f1 by f2 (f1*f2) */
- FIELD mul(in FIELD f1, in FIELD f2) raises (SALOME::SALOME_Exception);
- /*! Division of the fields f1 by f2 (f1/f2) */
- FIELD div(in FIELD f1, in FIELD f2) raises (SALOME::SALOME_Exception);
- /*! Power of the field f (f^power) */
- FIELD pow(in FIELD f, in long power) raises (SALOME::SALOME_Exception);
- /*! Linear transformation of the field f (factor*f+offset) */
- FIELD lin(in FIELD f, in double factor, in double offset) raises (SALOME::SALOME_Exception);
- /*! Dublication of the field f */
- FIELD dup(in FIELD f) raises (SALOME::SALOME_Exception);
-
-Cette interface est implémentée dans la classe C++ ``MEDOP_i`` du
-module MED (voir fichier ``MEDMEM_MedOp_i.hxx`` du package
-``MEDMEM_I``). C'est au sein des instances de cette classe que sont
-réalisées les opérations et que sont produites physiquement les
-données. Typiquement, les opérations présentées ici produisent un
-champ ``MEDMEM::FIELD`` sur la base duquel elle fabrique un servant
-``SALOME_MED::FIELD`` pour finalement retourner un pointeur CORBA sur
-ce servant.
-
-Ce mécanisme global peut être étendu sans limitation à tout les types
-d'opération qui sont envisagés dans les spécifications de manipulation
-des champs dans SALOME.
-
-
-Contrôle visuel des champs
---------------------------
-
-Les illustrations ci-dessous montrent qu'une fonction de visalisation
-est implémentée dans la maquette pour permettre le contrôle visuel
-d'un champ au moyen d'une représentation 3D (une carte spatiale du
-module du champ dans l'exemple implémenté par défaut):
-
-.. |IMG_VISU| image:: images/medop-gui-visufield_scale.png
-.. |IMG_RESULT| image:: images/medop-gui-result_scale.png
-
-+---------------+---------------+
-| |IMG_VISU| | |IMG_RESULT| |
-+---------------+---------------+
-
-Cette fonction répond au besoin de contrôle interactif des résultats
-produits par les opérations de manipulation de champs.
-
-Il s'agit là d'un usage classique de SALOME, dans lequel on demande au
-module VISU de faire une représentation 3D d'un champ spécifié par la
-donnée du servant ``SALOME_MED::FIELD`` qui lui est associé
-(représenté par la variable ``field_ptr`` dans l'exemple ci-dessous):
-
-.. code-block:: python
-
- import salome
- import VISU
-
- visuComp = salome.lcc.FindOrLoadComponent("FactoryServer", "VISU")
- visuComp.SetCurrentStudy(salome.myStudy)
-
- # Then we can import the specified field in the VISU module. This
- # creates an study entry in the VISU folder.
- result = visuComp.ImportMedField(field_ptr)
-
- meshName = field_ptr.getSupport().getMesh().getName()
- fieldName = field_ptr.getName()
- iterNumber = field_ptr.getIterationNumber()
- scalarmap = visuComp.ScalarMapOnField(result,
- meshName,
- visuEntityType,
- fieldName,
- iterNumber)
-
-Dans ce jeu d'instructions donné pour exemple (non fonctionnel, en
-particulier à cause de la non définition de la variable
-``visuEntityType``, voir remarque plus bas), le composant VISU
-désigné ici par la variable ``visuComp`` va chercher les données du
-champ en interrogeant le servant ``SALOME_MED::FIELD`` transmis en
-argument de la fonction ``ImportMedField``, puis produit une
-représentation de type "scalarmap".
-
-.. note:: Compte-tenu des propriétés de la classe FieldProxy décrites
- plus haut conférées par le pattern "Proxy", on peut transmettre ici
- aussi bien le servant CORBA que l'instance du proxy (la fonction
- ``ImportMedField`` n'y verra que du feu).
-
-Le code complet et fonctionnel de la fonction d'affichage est dans le
-corps du module python ``fieldproxy.py`` sous la forme d'une fonction
-de nom ``visuField``. Il convient de noter que cette fonction doit
-établir une correspondance entre le type des entités tel que défini
-dans MED et dans VISU:
-
-.. code-block:: python
-
- medEntityType = field_ptr.getSupport().getEntity()
- if (medEntityType == SALOME_MED.MED_CELL):
- visuEntityType = VISU.CELL
- elif (medEntityType == SALOME_MED.MED_NODE):
- visuEntityType = VISU.NODE
-
-
-Export des résultats de calcul
-------------------------------
-
-Tous les champs produits à l'occasion des opérations entre objets
-``FieldProxy`` sont automatiquement ajoutés à la structure med à
-laquelle is sont associés. Une convention d'attribution des noms est
-implémentée de sorte que par défaut aucune précision n'est demandée à
-l'utilisateur.
-
-La structure med peut être manipulée au moyen de la variable ``med``
-créée dans l'interface textuelle comme une instance de la classe
-``MedProxy``. La classe ``MedProxy`` fournit un objet qui présente
-l'interface du servant ``SALOME_MED::MED`` étendue de quelques
-fonctions utilitaires pour la gestion et le contrôle des données.
-
-En particulier, la sauvegarde de la structure dans un fichier est
-automatisée par la méthode ``save(medfilename)``:
-
-.. code-block:: python
-
- med = medproxy.MedProxy(medObj)
- med.save("/tmp/output.med")
-
-Cette méthode s'occupe de définir un driver d'écriture et de procéder
-à l'enregistrement des données de la structure med (les maillages, les
-champs présents au départ et tous les champs produits depuis la
-lecture initiale).
-
-Limitations
-===========
-
-L'implémentation de la maquette limite l'usage des opérations aux cas
-de figure suivants:
-
-* Seules les operations entre champs qui partagent le même support med
- sont possibles. Ceci est une contrainte imposé par la conception
- actuelle de MEDMEM.
-* Le résultat d'une opérations est calculé sur toutes les composantes
- et tout le domaine de définition des champs en opérande. Cette
- deuxième contrainte est juste parce que les usages plus fin,
- notemment avec la notion de domaine de définition, n'a pas encore
- été exéminée à ce jour.
-* Le nom d'un champ produit par une opération ne correspond pas au nom
- de la variable python par laquelle on le réceptionne et on le
- manipule. Le nom est attribué par une convention (ceci n'est pas
- vraiment une limitation mais une caractéristique à connaître).
-
-On note également les restriction techniques suivantes:
-
-* Les données MEDMEM sont supposées être chargées par le composant MED
- puis référencées dans l'étude SALOME (comme c'est fait aujourd'hui
- par le module MED).
-* Dans certain cas, python n'est pas ton ami. Pour que les opérateur
- de la classe ``FieldProxy`` soient pris en considération dans les
- opérations sur les champs, il est indispensable que le premier
- opérande d'une opération unitaire soit un champ (objet de classe
- ``FieldProxy``). Par exemple: "field_offset = field + 5.3"
- fonctionne alors que "field_offset = 5.3 + field" ne fonctionne pas
- car python tente de traiter la situation au moyen de la fonction
- ``__add__`` de la classe ``float`` (qui n'est pas modifiable).
-
-
-Notice informatique
-===================
-
-Gestion de configuration
-------------------------
-
-Les développements décrits dans ce chapitre sont répartis entre les
-modules MED et XMED (développé pour l'occasion). Cette séparation est
-faite par soucis de clarté et d'efficacité de développement, mais les
-éléménts du module XMED ont vocation à intégrer le module MED dans la
-mesure où les propositions techniques sont retenues pour le
-développement à venir.
-
-Le code source du module XMED peut être récupérés par la commande
-suivante::
-
- $ svn co svn://nepal.der.edf.fr/FIELD/XMED_SRC/trunk XMED_SRC
-
-Le pré-requis est la plate-forme SALOME version 5.1.4 (ou plus)
-équipée au minimum des modules KERNEL, GUI, MED (branche BR_medop) et
-VISU. Pour récupérer la branche BR_medop du module MED, taper la
-commande::
-
- $ cvs -d :pserver:anonymous@cvs.opencascade.com:2401/home/server/cvs/MED co -r BR_medop MED_SRC
-
-La configuration de référence est:
-
-* XMED: révision svn 41
-* MED: tag cvs BR_medop_20101025
-
-Moyens de tests
----------------
-
-Plusieurs types de tests unitaires sont définis (reste à les
-automatiser proprement):
-
-* Test des servants et utilitaires de manipulation python:
-
- - Dans XMED, package xmed/tests, utiliser le script
- ``test_medoperation.py`` dans un interpréteur python lancé dans
- une session shell SALOME. Ce script prépare des variables de test
- et fournit des fonctions de test unitaire (à exécuter ou pour s'en
- inspirer). Après avoir lancé SALOME via une application virtuelle,
- on peut taper::
-
- $ <APPLI_ROOT>/runSession
- [NS=venus:2810] $ python -i test_medoperation.py
- >>>
-
- - Ceci permet de tester en particulier l'interface ``MedOp`` et son
- utilisation dans le module python ``fieldproxy.py``.
-
-* Test des classes MEDMEM:
-
- - Test de MEDMEM::MedDataManager dans ``MEDMEM_MedDataManager_test.cxx``
-
-Un fichier de test basique (mais néanmoins suffisant) de nom
-``tesfield.med`` est fourni avec les sources dans le répertoire
-``<XMED_SRC>/resources/datafiles`` et dans l'installation au niveau du
-répertoire ``<INSTALLDIR>/share/salome/resources/xmed/datadir``. Il
-contient deux champs ``testfield1`` et ``testfield2`` définis sur un
-pas de temps unique (dt,it=-1,-1). Ces champs définissent des valeurs
-par éléments (MED_CELL).