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::*
).
Sommaire
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:
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:

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:

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 deSALOME_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 serveurSALOME_Container
. Le servant MEDOP détient en attribut une référence sur la structureMEDMEM::MED
, ce qui lui permet d’accéder directement aux champsMEDMEM::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 servantsSALOME_MED::MEDOP
etSALOME_MED::FIELD
sous la forme de pointeurs CORBA de nomsmedop_ptr
etfield_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:
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 champsMEDMEM::FIELD
physiquement instanciés dans le container SALOME.Les objets de classe
MedProxy
qui représentent des poignées de manipulation des structuresMEDMEM::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:
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é plus bas.
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:
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):
#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:
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:
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(...)
).
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 »:
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):
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
):
/*! 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);
/*! Duplication 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):
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):
import salome
import VISU
visuComp = salome.lcc.FindOrLoadComponent("FactoryServer", "VISU")
# 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:
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)
:
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 classeFieldProxy
). 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 classefloat
(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 pythonfieldproxy.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).