4 Mise sous forme d'objet interne
5 ===============================
7 .. index:: single: objet interne
9 Dans la suite de ce document, on supposera qu'un **objet interne** est un
10 **objet C++ ou python** qui fournit une première interface au code initial.
11 Suivant la forme du code initial (binaire exécutable, librairie statique ou
12 dynamique, fichiers sources f77, C, C++ ou python), cet objet aura différentes
13 formes et la communication objet interne --- code initial sera différente.
16 Méthodes et attributs de l'objet
17 --------------------------------
19 Dans chaque cas, il faudra définir les services et l'état interne de l'objet
20 interne. En particulier :
22 * choisir les différents services de cet objet
24 * pour chaque service, définir les données d'entrée et de sortie
26 * pour chaque entrée et chaque sortie, définir le type de la donnée et
27 éventuellement les pré-conditions et post-conditions associées (par exemple,
28 donnée d'entrée positive)
30 * définir l'état interne de l'objet et éventuellement sa valeur avant et après
31 l'appel aux différents services
33 Les **services** seront implémentés sous forme de **méthodes publiques** et
34 l'**état interne** sous forme d'**attributs**. Si le concepteur de l'objet
35 désire permettre à l'utilisateur d'accéder en lecture/écriture aux attributs,
36 il doit fournir des services accédant à ces attributs.
39 Routines fortran77/fonctions C/classes C++
40 ------------------------------------------
46 Dans le cas de routines fortran77, de fonctions C et de classes C++,
47 l'intégrateur ajoutera simplement une enveloppe C++ autour de ces fonctions
48 (voir figure :ref:`Objet interne C++ <figobjetinterne>`), pour obtenir l'objet interne. Chaque
51 * extrait, si nécessaire, l'information des paramètres d'entrée,
53 * appelle la ou les routines internes concernées,
55 * met en forme les résultats de ces routines internes dans les paramètres de
61 .. image:: images/objintcpp.png
74 Soient les routines fortran f77 suivantes effectuant des calculs d'algèbre
75 linéaire sur des tableaux unidimensionnels de flottants :
80 .. include:: ./exemples/exemple1/addvec.f
86 .. include:: ./exemples/exemple1/prdscl.f
89 ainsi qu'une classe C++ simulant un type vecteur (très) rudimentaire :
94 ``vecteur.hxx (interface C++)``
96 .. include:: ./exemples/exemple1/exec2/vecteur.hxx
100 ``vecteur.cxx (implémentation C++)``
102 .. include:: ./exemples/exemple1/exec2/vecteur.cxx
105 L'objet interne (i.e. la classe C++) dans l'exemple est :
110 .. include:: ./exemples/exemple1/exec2/alglin.hxx
116 .. include:: ./exemples/exemple1/exec2/alglin.cxx
121 #. Le choix des méthodes, du passage des paramètres et de leur type, est laissé
122 libre à l'intégrateur (conformément aux souhaits des utilisateurs de l'objet).
123 La correspondance entre les paramètres de l'objet interne et ceux des routines
124 du code initial est réalisée par l'implémentation (fichier ``alglin.cxx``, ci-
127 #. En particulier, si des structures MED [MED]_ sont passées en argument
128 d'entrée, le fichier d'implémentation C++, sera chargé d'extraire et mettre en
129 forme les informations à passer aux routines de calcul internes (sous forme de
130 tableaux simples et scalaires pour les routines fortran internes). Pour les
131 arguments de sortie au format MED, les résultats des routines internes seront
132 introduites par l'implémentation dans les objets MED à retourner.
134 Dans l'exemple ci-avant, remarquer :
136 * la declaration ``extern "C"`` devant les prototypes en C++ des fonctions
139 * le caractère "underscore" ajouté au nom C++ des fonctions fortran,
141 * le mode de passage des arguments, la règle étant : sauf exceptions (longueur
142 des chaînes de caractères), on passe des pointeurs. Pour les arguments
143 scalaires, on passe l'adresse de ces scalaires; pour des arguments pointeurs
144 (tableaux), on passe les pointeurs tels quels.
146 L'objet interne peut maintenant être utilisé dans un code C++ :
149 .. include:: ./exemples/exemple1/exec2/main_extraits.cxx
156 L'encapsulation C/fortran77 dans un code C++ suit la procédure standard
157 (formats des réels/entiers, nom des routines, passage des arguments). A ce
158 sujet, on pourra consulter, par exemple, [ForCpp]_ ou [ForCpp2]_.
161 Fonctions/Classes Python
162 ------------------------
168 Le principe d'encapsulation de fonctions/classes python dans un objet interne
169 (python) est le même que dans le cas précédent.
171 .. _figobjetinterne2:
174 .. image:: images/objintpy.png
185 Un exemple similaire au précédent part de fonctions python à encapsuler :
190 .. include:: ./exemples/exemple2/func.py
193 Il est facile d'intégrer ces fonctions dans une classe python :
198 .. include:: ./exemples/exemple2/compo.py
202 En fait, il n'est même pas nécessaire d'enrober les fonctions python de
203 ``func.py``, mais c'est plus "propre" (en particulier si l'objet possède un
204 état interne). Le script ci-après permet d'utiliser l'objet interne python
205 depuis un interpréteur python :
207 .. include:: ./exemples/exemple2/exmpl.py
211 Code initial sous forme d'exécutables
212 -------------------------------------
218 Ce cas se rencontre lorsqu'on ne dispose pas des sources du code interne (ou
219 lorsqu'on ne désire pas intégrer ces sources dans l'architecture interne).
220 On supposera que le code est sous forme d'un binaire exécutable par le système
221 d'exploitation. Les communications avec le code peuvent se faire,
225 * par un ou plusieurs fichiers,
226 * par la ligne de commande,
227 * en répondant au clavier à des questions du code
231 * par un ou plusieurs fichiers,
232 * à l'affichage écran.
234 La communication avec les exécutables se fait à l'aide des commandes
235 (disponibles en C++ et en python) :
237 * ``system`` : lancer un exécutable avec lequel on communique en entrée via
238 fichiers ou la ligne de commande, en sortie, via fichiers;
240 * ``popen`` : mêmes fonctionnalités que le cas précédent, avec en plus la
241 possibilité de récupérer la sortie standard (écran) de l'exécutable.
243 Les commandes ci-dessus sont rangées par ordre de complexité croissante (on
244 conseille d'utiliser autant que possible ``system``).
247 Exemple 3 : Objet interne python, connecté à des exécutables externes.
248 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
252 un objet "Systeme" qui possède 5 services :
254 * ``cd``, qui, à partir d'un chemin (chaîne de caractères), positionne un
257 * ``cp``, qui, à partir de 2 noms de fichiers, copie le premier fichier sur le
258 second dans le répertoire courant;
260 * ``touch``, qui, à partir d'un nom de fichier, met à jour la date du fichier
261 s'il existe, le crée sinon;
263 * ``rm``, qui, à partir d'un nom de fichier, détruit le fichier dans le
266 * ``dir``, qui liste les fichiers contenus dans le répertoire courant.
268 L'état interne de l'objet sera constitué du nom du répertoire courant dans
269 lequel travailleront les services de l'objet (qui est positionné par le
272 En python, la classe de l'objet pourrait s'écrire :
277 .. include:: ./exemples/exemple3/systeme.py
280 et son utilisation depuis l'interpréteur python :
283 .. include:: ./exemples/exemple3/use.py
289 #. Ceci est donné à titre d'exemple, python possède en standard tout ce qu'il
290 faut pour rendre ces services, sans passer par des commandes systèmes
291 (``system`` et ``popen``).
293 #. L'exemple illustre le passage d'arguments d'entrées par la ligne de
294 commandes (noms passés en argument) et la "capture" des sorties écran des
295 exécutables extérieurs (``system`` ne permet pas de récupérer simplement la
296 sortie standard de la commande unix ``ls``, on utilise ``popen`` dans ce cas).
301 Exemple 4 : Objet interne connecté à un exécutable externe.
302 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
303 Cet exemple montre une
304 interface (très) partielle d'un exécutable binaire *FreeFem* [FreeFem]_ sous la
305 forme d'un objet C++. L'interface donne accès à la définition d'une géométrie
306 2D par sa frontière ainsi que la résolution approchée d'une équation simple
307 (convection forcée) sur cette géométrie. Les différentes méthodes de l'objet
310 * une méthode qui enregistre la géométrie du domaine,
312 * une méthode qui enregistre le champs de vitesse convectante,
314 * la méthode de calcul qui reçoit la condition initiale (sous forme analytique
315 --- chaîne de caractères), le pas de temps et le nombre de pas de temps.
317 L'état interne de l'objet est constitué de la géométrie et du champs de
318 vitesse. La méthode de calcul crée un fichier à partir de ses paramètres et
319 de l'état interne, puis lance une boucle de calcul (par un appel système).
320 Les résultats du calcul ne sont pas récupérés par l'objet.
324 #. Une encapsulation complète de FreeFem demanderait un effort beaucoup plus
325 important, ceci n'est qu'un exemple.
327 #. On ne récupère pas ici de résultat dans l'objet C++ (l'évolution est
328 seulement visualisée par le moteur graphique interne de FreeFem). Si on
329 désirait le faire, il faudrait après l'appel système, relire le fichier produit
330 par le code externe, et renvoyer les résultats sous forme compréhensible par
331 l'utilisateur de l'objet interne
333 Deux versions (C++ et python) sont listées ci-après.
340 .. include:: ./exemples/exemple4/FreeFem.hxx
346 .. include:: ./exemples/exemple4/FreeFem.cxx
352 .. include:: ./exemples/exemple4/FreeFem.py
355 L'utilisation depuis un code C++ ou un interpréteur python est similaire dans
361 .. include:: ./exemples/exemple4/main.cxx
367 .. include:: ./exemples/exemple4/useFreeFem.py