Python est un langage interprété (comme le shell unix, matlab, etc) qui ressemble un peu à l'interpréteur intégré dans Oofelie. Contrairement à ce dernier, il est très complet, rapide, orienté objet, utilisant le typage dynamique, interfaçable avec plus ou moins n'importe quoi. De plus, c'est maintenant une référence vu le nombre d'utilisateurs à travers le monde (scientifique ou non).
Pour moi, c'est LA solution idéale pour interfacer un code de calcul avec la ligne de commande.
Pour la petite histoire, Python a été inventé par Guido van Rossum en 1990 (c'est-à-dire plus ou moins quand Igor a inventé Oofelie). On peut dire que Python est ce que l'interpréteur Oofelie serait devenu si Igor avait continué à travailler dessus (et s'il avait trouvé quelques centaines de petites mains pour l'aider). Parmi les organisations qui utilisent Python, citons Google, Yahoo et RedHat. Parmi les codes EF, Code_Aster et Abaqus. N'oublions pas que VTK et Qt sont aussi interfacés avec Python.
Pour en savoir plus sur ce fabuleux langage (n'ayons pas peur des mots):
Le combat est assez inégal, et perdu d'avance pour OE:
OE | Python | |
---|---|---|
Extensible | via les I_, bon courage ! | oui (classes interprétées, API C). extension possible via des scripts (on peut dériver une classe interprétée d'une classe compilée) |
Modulaire | non - pas de notion de package - conflits de noms fréquents | namespaces (modules) |
Rapide | bof (pas de hashMap) | oui (fichiers compilés, portables .pyc, hashMaps intégrées) |
Gestion des erreurs | peu fiable. Il a la mauvaise habitude de ne pas s'arrêter lorsque des erreurs surviennent rendant difficile la localisation de celles-ci. | très fiable (exceptions - callstack). Impossible de louper une erreur de syntaxe. |
Extensions | absentes - à programmer soi même. | réseau, MPI, graphisme (Tcl, Qt), système… - voir p.expl ce site |
Syntaxe | pas claire (cfr “;”) | claire et fiable |
Gestion mémoire | absente ou catastrophique, au choix | compteurs de refs - destructeurs - entièrement customisable |
Portable | bof - chaque nouvelle machine nécessite un portage fastidieux. | oui - toute plateforme |
Maintenance | non négligeable (à chaque mise à jour) | quasi nulle pour nous |
Bugs | nombreux (nombre croissant) - corrigés par nous | très peu - corrigés par d'autres |
Debugueur | non | oui, intégré |
Licence | payant (pas pour nous mais…) | gratuit - même encore mieux: on peut le revendre! (voir licence python) |
Ajoutons à ca des petits “plus” comme l'éditeur IDLE qui permet, avec son “path browser”, de parcourir toutes les fonctions et les modules disponibles. L'interface Tk intégrée à la distribution est aussi très intéressante.
En fait, tout ce qui peut se faire avec l'interpréteur Oofelie peut se faire avec Python. J'ai donc essayé de recréer un environnement “Oofelie” sous Python avec la contrainte d'une syntaxe similaire (ce n'est pas simple parce que l'interpréteur OE cache souvent beaucoup de choses à l'utilisateur - comme des conversions implicites).
Une application très simple de la puissance de Python serait de programmer l'ouverture d'une fenêtre lors du chargement d'un jeu de données pour que l'utilisateur puisse entrer, charger/sauver ses paramètres et enfin pousser sur le bouton “start metafor”. C'est fait en quelques lignes sous Python et ça permet de créer rapidement une application “métier”. Il est même possible, dans ce cas, de ne distribuer que le fichier .pyc (version compilée et indépendante de la plateforme du .py
).
Parmi les nombreuses choses que nous avions demandé à OE et qui nous sont maintenant accessible, citons (dans le désordre) :
CurveDataFunct::castToFunct()
est inutile!).NULL
via l'objet PyNone
(expl: curveSet(5)
donne pyNone
si la courbe numéro 5 n'existe pas).En un mot, on a d'un coup tout ce que Igor prétend faire pour la fin du mois dans sa présentation d'Oofelie
Un exemple d'erreur (avec impression de la callstack):
Traceback (most recent call last): File "<stdin>", line 1, in ? File "/d50/users/boman/dev/oo_meta/toolbox/utilities.py", line 7, in meta module = __import__(domainTxt, globals(), locals(), ['getDomain']) File "/d50/users/boman/dev/oo_meta/apps/zqs/ale_5cotes.py", line 144, in ? excit.define(1,NODE_PO,Key(TX|GD|RE),0.0000000000E+00,ale_5cotes_fct1,EX_INCR); fixaset.define(1,NODE_PO,Key(TX)); NameError: name 'EX_INCR' is not defined
Python possède une API écrite en C qui permet d'écrire des “modules” (comme les packages en java, ou namespaces en C++). Metafor est donc un module de Python…. enfin, presque. En effet, n'oublions pas que grâce au magnifique travail d'Igor sur les matériaux et les éléments, il n'est pas possible d'initialiser correctement ceux-ci quand ils sont regroupés dans une lib. J'ai dû donc choisir d'intégrer Python dans l'exécutable Metafor.
Cette interface n'est pas simple à écrire parce que l'API Python est complexe. J'étais donc un peu découragé jusqu'au jour où j'ai vu le logiciel Swig (Simplified Wrapper and Interface Generator) qui se charge du boulot. Mieux encore, Swig crée des “shadow classes” qui permettent d'obtenir des objets Python malgré l'API écrite en C. Swig gère aussi tous les problèmes de cast (ce qui pose beaucoup de problèmes dans l'interpréteur Oofelie).
Swig n'est pas qu'un simple traducteur: il gère également la surcharge des fonctions membres (absentes dans Python puisque les types d'objets ne sont pas explicites) et l'héritage multiple. Tout ceci via un système de cast dynamique assez bien fait et relativement bien optimisé (j ai jeté un œil, c'est largement mieux fait que OE). Enfin, Swig gère correctement les variables globales (qui, elles, ne sont pas des références Python).
L'interface Python de Metafor se réduit donc à des fichiers input de Swig (fichiers .i
et .swg
). Les fichiers .i
donnent des .cpp
via Swig qui sont compilés un à un pour former des modules. Les fichiers .swg
sont des fichiers inclus par les .i
qui ne correspondent pas à un module. A l'heure actuelle, ces fichiers interfacent toutes les fonctions membres (publiques) des classes Metafor et Oofelie utilisées dans le célèbre cas-test “cont2
”.
Lorsqu'on lance Metafor
, on se retrouve en ligne de commande Python. Le module Metafor est déjà chargé en mémoire ainsi que le module utilitaire (toolbox.utilities
). Il est donc possible de lancer un cas-test (myTest.py
) par la simple commande:
meta('myTest')
Contrairement à Oofelie, Python ne va pas commencer à parcourir les répertoires pour trouver myTest.py
. J'ai pourtant reprogrammé cette fonction mais je trouve que c'est pas très intéressant vu les conflits possibles. J'ai donc choisi que pour lancer cont2.py
, par exemple, qui se trouve dans oo_meta/apps/qs
, on tape:
meta('apps.qs.cont2')
c'est propre et net!
Avoir une première interface est très simple. Le premier problème était les cast implicites cachés derrière les get_properties()
. Heureusement, Swig peut gérer ça facilement (un peu comme le I_::new_child_from_id()
de OE). J'ai dû aussi gérer les std::string
et les UserNo
via des “typemaps
” de Swig (un système qui permet de faire des casts implicites automatiques).
Après ceci, le premier résultat ne ressemblait pas trop à l'interpréteur Oofelie. Par exemple, les Lock
s étaient stockées dans une variable cvar
. Il fallait donc écrire:
loadingset.define(1,NODE_PO, Key(cvar.TX|cvar.GD|cvar.RE), 0, f)
ce qui est lourd. J'ai donc réussi à “descendre” les variables cvar dans chaque namespace (et ceci de manière automatique - sans écrire). Bref, si on ajoute une Lock
, ça marche tout seul).
Même remarque pour les noms d'éléments, de matériaux, de Elementproperties
, de MaterialProperties
, identificateurs, etc.
apps/qs/cont2.py
.e
aux .py
est presque immédiat.Pour démarrer:
execfile('fichier.py')
ou import fichier
dir(module)
: “status
” de matlabdir(variable)
: donne les fonctions membresPYTHONPATH
: équivaut au LIBOOFE
type(variable)
: donne le type de variableprint 'variable=', variable
: imprime variable = valeur
Différences par rapport à l'interpréteur OE:
import
(from wrap.oofelie import *
par expl)int typemat;
par exemple)Refer
est inutile).Domain dom;
devient dom = Domain()
)PhySet::get_properties()
doit être mentionné explicitement (pas de raccourcis avec les crochets)[]
⇒ ()
pour les numéros utilisateurs (= syntaxe C++ ; expl : curset(3).mesh(nx)
)LoadingSet.define()
, FixationSet.define()
prennent des Key
s au lieu de Lock
s. Utiliser Key(TO|RE)
au lieu de TO|RE
getDomain()
doit retourner le domaine pour chaque cas-test.{ }
” mais des blocs basés sur l'indentationCTRL-Z [ENTER]
sous windows et CTRL-D
sous Unix ou CTRL-C
sous Cygwin (ou quit()
)