1 #-*-coding:iso-8859-1-*-
3 # Copyright (C) 2008-2009 EDF R&D
5 # This library is free software; you can redistribute it and/or
6 # modify it under the terms of the GNU Lesser General Public
7 # License as published by the Free Software Foundation; either
8 # version 2.1 of the License.
10 # This library is distributed in the hope that it will be useful,
11 # but WITHOUT ANY WARRANTY; without even the implied warranty of
12 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 # Lesser General Public License for more details.
15 # You should have received a copy of the GNU Lesser General Public
16 # License along with this library; if not, write to the Free Software
17 # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
19 # See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com
22 Définit les outils généraux élémentaires.
24 Ce module est destiné à etre appelée par AssimilationStudy pour constituer
25 les objets élémentaires de l'algorithme.
27 __author__ = "Jean-Philippe ARGAUD - Mars 2008"
31 import Logging ; Logging.Logging() # A importer en premier
33 from BasicObjects import Operator
35 # ==============================================================================
36 class AssimilationStudy:
38 Cette classe sert d'interface pour l'utilisation de l'assimilation de
39 données. Elle contient les méthodes ou accesseurs nécessaires à la
40 construction d'un calcul d'assimilation.
42 def __init__(self, name=""):
44 Prévoit de conserver l'ensemble des variables nécssaires à un algorithme
45 élémentaire. Ces variables sont ensuite disponibles pour implémenter un
46 algorithme élémentaire particulier.
48 Background............: vecteur Xb
49 Observation...........: vecteur Y (potentiellement temporel)
51 State.................: vecteur d'état dont une partie est le vecteur de
52 contrôle. Cette information n'est utile que si l'on veut faire des
53 calculs sur l'état complet, mais elle n'est pas indispensable pour
55 Control...............: vecteur X contenant toutes les variables de
56 contrôle, i.e. les paramètres ou l'état dont on veut estimer la
57 valeur pour obtenir les observations
58 ObservationOperator...: opérateur d'observation H
60 Les observations présentent une erreur dont la matrice de covariance est
61 R. L'ébauche du vecteur de contrôle présente une erreur dont la matrice
64 self.__name = str(name)
73 self.__X = Persistence.OneVector()
74 self.__Parameters = {}
75 self.__StoredDiagnostics = {}
77 # Variables temporaires
79 self.__algorithmFile = None
80 self.__algorithmName = None
81 self.__diagnosticFile = None
83 # Récupère le chemin du répertoire parent et l'ajoute au path
84 # (Cela complète l'action de la classe PathManagement dans PlatformInfo,
85 # qui est activée dans Persistence)
86 self.__parent = os.path.abspath(os.path.join(os.path.dirname(__file__),".."))
87 sys.path.insert(0, self.__parent)
88 sys.path = list(set(sys.path)) # Conserve en unique exemplaire chaque chemin
90 # ---------------------------------------------------------
91 def setBackground(self,
93 asPersistentVector = None,
97 Permet de définir l'estimation a priori :
98 - asVector : entrée des données, comme un vecteur compatible avec le
99 constructeur de numpy.matrix
100 - asPersistentVector : entrée des données, comme un vecteur de type
101 persistent contruit avec la classe ad-hoc "Persistence"
102 - Scheduler est le contrôle temporel des données
104 if asVector is not None:
105 if type( asVector ) is type( numpy.matrix([]) ):
106 self.__Xb = numpy.matrix( asVector.A1, numpy.float ).T
108 self.__Xb = numpy.matrix( asVector, numpy.float ).T
109 elif asPersistentVector is not None:
110 self.__Xb = asPersistentVector
112 raise ValueError("Error: improperly defined background")
115 def setBackgroundError(self, asCovariance=None):
117 Permet de définir la covariance des erreurs d'ébauche :
118 - asCovariance : entrée des données, comme une matrice compatible avec
119 le constructeur de numpy.matrix
121 self.__B = numpy.matrix( asCovariance, numpy.float )
124 # -----------------------------------------------------------
125 def setObservation(self,
127 asPersistentVector = None,
131 Permet de définir les observations :
132 - asVector : entrée des données, comme un vecteur compatible avec le
133 constructeur de numpy.matrix
134 - asPersistentVector : entrée des données, comme un vecteur de type
135 persistent contruit avec la classe ad-hoc "Persistence"
136 - Scheduler est le contrôle temporel des données disponibles
138 if asVector is not None:
139 if type( asVector ) is type( numpy.matrix([]) ):
140 self.__Y = numpy.matrix( asVector.A1, numpy.float ).T
142 self.__Y = numpy.matrix( asVector, numpy.float ).T
143 elif asPersistentVector is not None:
144 self.__Y = asPersistentVector
146 raise ValueError("Error: improperly defined observations")
149 def setObservationError(self, asCovariance=None):
151 Permet de définir la covariance des erreurs d'observations :
152 - asCovariance : entrée des données, comme une matrice compatible avec
153 le constructeur de numpy.matrix
155 self.__R = numpy.matrix( asCovariance, numpy.float )
158 def setObservationOperator(self,
159 asFunction = {"Direct":None, "Tangent":None, "Adjoint":None},
164 Permet de définir un opérateur d'observation H. L'ordre de priorité des
165 définitions et leur sens sont les suivants :
166 - si asFunction["Tangent"] et asFunction["Adjoint"] ne sont pas None
167 alors on définit l'opérateur à l'aide de fonctions. Si la fonction
168 "Direct" n'est pas définie, on prend la fonction "Tangent".
169 - si les fonctions ne sont pas disponibles et si asMatrix n'est pas
170 None, alors on définit l'opérateur "Direct" et "Tangent" à l'aide de
171 la matrice, et l'opérateur "Adjoint" à l'aide de la transposée. La
172 matrice fournie doit être sous une forme compatible avec le
173 constructeur de numpy.matrix.
174 - si l'argument "appliedToX" n'est pas None, alors on définit, pour des
175 X divers, l'opérateur par sa valeur appliquée à cet X particulier,
176 sous la forme d'un dictionnaire appliedToX[NAME] avec NAME un nom.
177 L'opérateur doit néanmoins déjà avoir été défini comme d'habitude.
179 if (type(asFunction) is type({})) and (asFunction["Tangent"] is not None) and (asFunction["Adjoint"] is not None):
180 if not asFunction.has_key("Direct") or (asFunction["Direct"] is None):
181 self.__H["Direct"] = Operator( fromMethod = asFunction["Tangent"] )
183 self.__H["Direct"] = Operator( fromMethod = asFunction["Direct"] )
184 self.__H["Tangent"] = Operator( fromMethod = asFunction["Tangent"] )
185 self.__H["Adjoint"] = Operator( fromMethod = asFunction["Adjoint"] )
186 elif asMatrix is not None:
187 mat = numpy.matrix( asMatrix, numpy.float )
188 self.__H["Direct"] = Operator( fromMatrix = mat )
189 self.__H["Tangent"] = Operator( fromMatrix = mat )
190 self.__H["Adjoint"] = Operator( fromMatrix = mat.T )
192 raise ValueError("Error: improperly defined observation operator")
194 if appliedToX is not None:
195 self.__H["AppliedToX"] = {}
196 if type(appliedToX) is not dict:
197 raise ValueError("Error: observation operator defined by \"appliedToX\" need a dictionary as argument.")
198 for key in appliedToX.keys():
199 if type( appliedToX[key] ) is type( numpy.matrix([]) ):
200 # Pour le cas où l'on a une vraie matrice
201 self.__H["AppliedToX"][key] = numpy.matrix( appliedToX[key].A1, numpy.float ).T
202 elif type( appliedToX[key] ) is type( numpy.array([]) ) and len(appliedToX[key].shape) > 1:
203 # Pour le cas où l'on a un vecteur représenté en array avec 2 dimensions
204 self.__H["AppliedToX"][key] = numpy.matrix( appliedToX[key].reshape(len(appliedToX[key]),), numpy.float ).T
206 self.__H["AppliedToX"][key] = numpy.matrix( appliedToX[key], numpy.float ).T
208 self.__H["AppliedToX"] = None
212 # -----------------------------------------------------------
213 def setEvolutionModel(self,
214 asFunction = {"Direct":None, "Tangent":None, "Adjoint":None},
219 Permet de définir un opérateur d'évolution M. L'ordre de priorité des
220 définitions et leur sens sont les suivants :
221 - si asFunction["Tangent"] et asFunction["Adjoint"] ne sont pas None
222 alors on définit l'opérateur à l'aide de fonctions. Si la fonction
223 "Direct" n'est pas définie, on prend la fonction "Tangent".
224 - si les fonctions ne sont pas disponibles et si asMatrix n'est pas
225 None, alors on définit l'opérateur "Direct" et "Tangent" à l'aide de
226 la matrice, et l'opérateur "Adjoint" à l'aide de la transposée. La
227 matrice fournie doit être sous une forme compatible avec le
228 constructeur de numpy.matrix.
230 if (type(asFunction) is type({})) and (asFunction["Tangent"] is not None) and (asFunction["Adjoint"] is not None):
231 if not asFunction.has_key("Direct") or (asFunction["Direct"] is None):
232 self.__M["Direct"] = Operator( fromMethod = asFunction["Tangent"] )
234 self.__M["Direct"] = Operator( fromMethod = asFunction["Direct"] )
235 self.__M["Tangent"] = Operator( fromMethod = asFunction["Tangent"] )
236 self.__M["Adjoint"] = Operator( fromMethod = asFunction["Adjoint"] )
237 elif asMatrix is not None:
238 matrice = numpy.matrix( asMatrix, numpy.float )
239 self.__M["Direct"] = Operator( fromMatrix = matrice )
240 self.__M["Tangent"] = Operator( fromMatrix = matrice )
241 self.__M["Adjoint"] = Operator( fromMatrix = matrice.T )
243 raise ValueError("Error: improperly defined evolution operator")
246 def setEvolutionError(self, asCovariance=None):
248 Permet de définir la covariance des erreurs de modèle :
249 - asCovariance : entrée des données, comme une matrice compatible avec
250 le constructeur de numpy.matrix
252 self.__Q = numpy.matrix( asCovariance, numpy.float )
255 # -----------------------------------------------------------
256 def setControls (self, asVector = None ):
258 Permet de définir la valeur initiale du vecteur X contenant toutes les
259 variables de contrôle, i.e. les paramètres ou l'état dont on veut
260 estimer la valeur pour obtenir les observations. C'est utile pour un
261 algorithme itératif/incrémental
262 - asVector : entrée des données, comme un vecteur compatible avec le
263 constructeur de numpy.matrix.
265 if asVector is not None:
266 self.__X.store( asVector )
269 # -----------------------------------------------------------
270 def setAlgorithm(self, choice = None ):
272 Permet de sélectionner l'algorithme à utiliser pour mener à bien l'étude
273 d'assimilation. L'argument est un champ caractère se rapportant au nom
274 d'un fichier contenu dans "../daAlgorithms" et réalisant l'opération
275 d'assimilation sur les arguments (Xb,Y,H,R,B,Xa).
278 raise ValueError("Error: algorithm choice has to be given")
279 if self.__algorithmName is not None:
280 raise ValueError("Error: algorithm choice has already been done as \"%s\", it can't be changed."%self.__algorithmName)
281 daDirectory = "daAlgorithms"
283 # Recherche explicitement le fichier complet
284 # ------------------------------------------
286 for directory in sys.path:
287 if os.path.isfile(os.path.join(directory, daDirectory, str(choice)+'.py')):
288 module_path = os.path.abspath(os.path.join(directory, daDirectory))
289 if module_path is None:
290 raise ImportError("No algorithm module named \"%s\" was found in a \"%s\" subdirectory\n The search path is %s"%(choice, daDirectory, sys.path))
292 # Importe le fichier complet comme un module
293 # ------------------------------------------
295 sys_path_tmp = sys.path ; sys.path.insert(0,module_path)
296 self.__algorithmFile = __import__(str(choice), globals(), locals(), [])
297 self.__algorithmName = str(choice)
298 sys.path = sys_path_tmp ; del sys_path_tmp
299 except ImportError, e:
300 raise ImportError("The module named \"%s\" was found, but is incorrect at the import stage.\n The import error message is: %s"%(choice,e))
302 # Instancie un objet du type élémentaire du fichier
303 # -------------------------------------------------
304 self.__algorithm = self.__algorithmFile.ElementaryAlgorithm()
307 def setAlgorithmParameters(self, asDico=None):
309 Permet de définir les paramètres de l'algorithme, sous la forme d'un
312 self.__Parameters = dict( asDico )
315 # -----------------------------------------------------------
316 def setDiagnostic(self, choice = None, name = "", unit = "", basetype = None, parameters = {} ):
318 Permet de sélectionner un diagnostic a effectuer.
321 raise ValueError("Error: diagnostic choice has to be given")
322 daDirectory = "daDiagnostics"
324 # Recherche explicitement le fichier complet
325 # ------------------------------------------
327 for directory in sys.path:
328 if os.path.isfile(os.path.join(directory, daDirectory, str(choice)+'.py')):
329 module_path = os.path.abspath(os.path.join(directory, daDirectory))
330 if module_path is None:
331 raise ImportError("No diagnostic module named \"%s\" was found in a \"%s\" subdirectory\n The search path is %s"%(choice, daDirectory, sys.path))
333 # Importe le fichier complet comme un module
334 # ------------------------------------------
336 sys_path_tmp = sys.path ; sys.path.insert(0,module_path)
337 self.__diagnosticFile = __import__(str(choice), globals(), locals(), [])
338 sys.path = sys_path_tmp ; del sys_path_tmp
339 except ImportError, e:
340 raise ImportError("The module named \"%s\" was found, but is incorrect at the import stage.\n The import error message is: %s"%(choice,e))
342 # Instancie un objet du type élémentaire du fichier
343 # -------------------------------------------------
344 if self.__StoredDiagnostics.has_key(name):
345 raise ValueError("A diagnostic with the same name already exists")
347 self.__StoredDiagnostics[name] = self.__diagnosticFile.ElementaryDiagnostic(
351 parameters = parameters )
354 # -----------------------------------------------------------
355 def shape_validate(self):
357 Validation de la correspondance correcte des tailles des variables et
358 des matrices s'il y en a.
360 if self.__Xb is None: __Xb_shape = (0,)
361 elif hasattr(self.__Xb,"shape"):
362 if type(self.__Xb.shape) is tuple: __Xb_shape = self.__Xb.shape
363 else: __Xb_shape = self.__Xb.shape()
364 else: raise TypeError("Xb has no attribute of shape: problem !")
366 if self.__Y is None: __Y_shape = (0,)
367 elif hasattr(self.__Y,"shape"):
368 if type(self.__Y.shape) is tuple: __Y_shape = self.__Y.shape
369 else: __Y_shape = self.__Y.shape()
370 else: raise TypeError("Y has no attribute of shape: problem !")
372 if self.__B is None: __B_shape = (0,0)
373 elif hasattr(self.__B,"shape"):
374 if type(self.__B.shape) is tuple: __B_shape = self.__B.shape
375 else: __B_shape = self.__B.shape()
376 else: raise TypeError("B has no attribute of shape: problem !")
378 if self.__R is None: __R_shape = (0,0)
379 elif hasattr(self.__R,"shape"):
380 if type(self.__R.shape) is tuple: __R_shape = self.__R.shape
381 else: __R_shape = self.__R.shape()
382 else: raise TypeError("R has no attribute of shape: problem !")
384 if self.__Q is None: __Q_shape = (0,0)
385 elif hasattr(self.__Q,"shape"):
386 if type(self.__Q.shape) is tuple: __Q_shape = self.__Q.shape
387 else: __Q_shape = self.__Q.shape()
388 else: raise TypeError("Q has no attribute of shape: problem !")
390 if len(self.__H) == 0: __H_shape = (0,0)
391 elif type(self.__H) is type({}): __H_shape = (0,0)
392 elif hasattr(self.__H["Direct"],"shape"):
393 if type(self.__H["Direct"].shape) is tuple: __H_shape = self.__H["Direct"].shape
394 else: __H_shape = self.__H["Direct"].shape()
395 else: raise TypeError("H has no attribute of shape: problem !")
397 if len(self.__M) == 0: __M_shape = (0,0)
398 elif type(self.__M) is type({}): __M_shape = (0,0)
399 elif hasattr(self.__M["Direct"],"shape"):
400 if type(self.__M["Direct"].shape) is tuple: __M_shape = self.__M["Direct"].shape
401 else: __M_shape = self.__M["Direct"].shape()
402 else: raise TypeError("M has no attribute of shape: problem !")
404 # Vérification des conditions
405 # ---------------------------
406 if not( len(__Xb_shape) == 1 or min(__Xb_shape) == 1 ):
407 raise ValueError("Shape characteristic of Xb is incorrect: \"%s\""%(__Xb_shape,))
408 if not( len(__Y_shape) == 1 or min(__Y_shape) == 1 ):
409 raise ValueError("Shape characteristic of Y is incorrect: \"%s\""%(__Y_shape,))
411 if not( min(__B_shape) == max(__B_shape) ):
412 raise ValueError("Shape characteristic of B is incorrect: \"%s\""%(__B_shape,))
413 if not( min(__R_shape) == max(__R_shape) ):
414 raise ValueError("Shape characteristic of R is incorrect: \"%s\""%(__R_shape,))
415 if not( min(__Q_shape) == max(__Q_shape) ):
416 raise ValueError("Shape characteristic of Q is incorrect: \"%s\""%(__Q_shape,))
417 if not( min(__M_shape) == max(__M_shape) ):
418 raise ValueError("Shape characteristic of M is incorrect: \"%s\""%(__M_shape,))
420 if len(self.__H) > 0 and not(type(self.__H) is type({})) and not( __H_shape[1] == max(__Xb_shape) ):
421 raise ValueError("Shape characteristic of H \"%s\" and X \"%s\" are incompatible"%(__H_shape,__Xb_shape))
422 if len(self.__H) > 0 and not(type(self.__H) is type({})) and not( __H_shape[0] == max(__Y_shape) ):
423 raise ValueError("Shape characteristic of H \"%s\" and Y \"%s\" are incompatible"%(__H_shape,__Y_shape))
424 if len(self.__H) > 0 and not(type(self.__H) is type({})) and len(self.__B) > 0 and not( __H_shape[1] == __B_shape[0] ):
425 raise ValueError("Shape characteristic of H \"%s\" and B \"%s\" are incompatible"%(__H_shape,__B_shape))
426 if len(self.__H) > 0 and not(type(self.__H) is type({})) and len(self.__R) > 0 and not( __H_shape[0] == __R_shape[1] ):
427 raise ValueError("Shape characteristic of H \"%s\" and R \"%s\" are incompatible"%(__H_shape,__R_shape))
429 if len(self.__B) > 0 and not( __B_shape[1] == max(__Xb_shape) ):
430 raise ValueError("Shape characteristic of B \"%s\" and Xb \"%s\" are incompatible"%(__B_shape,__Xb_shape))
432 if len(self.__R) > 0 and not( __R_shape[1] == max(__Y_shape) ):
433 raise ValueError("Shape characteristic of R \"%s\" and Y \"%s\" are incompatible"%(__R_shape,__Y_shape))
435 if len(self.__M) > 0 and not(type(self.__M) is type({})) and not( __M_shape[1] == max(__Xb_shape) ):
436 raise ValueError("Shape characteristic of M \"%s\" and X \"%s\" are incompatible"%(__M_shape,__Xb_shape))
440 # -----------------------------------------------------------
443 Permet de lancer le calcul d'assimilation.
445 Le nom de la méthode à activer est toujours "run". Les paramètres en
446 arguments de la méthode sont fixés. En sortie, on obtient les résultats
447 dans la variable de type dictionnaire "StoredVariables", qui contient en
448 particulier des objets de Persistence pour les analyses, OMA...
450 self.shape_validate()
452 self.__algorithm.run(
460 Par = self.__Parameters,
464 # -----------------------------------------------------------
465 def get(self, key=None):
467 Renvoie les résultats disponibles après l'exécution de la méthode
468 d'assimilation, ou les diagnostics disponibles. Attention, quand un
469 diagnostic porte le même nom qu'un variable stockée, c'est la variable
470 stockée qui est renvoyée, et le diagnostic est inatteignable.
473 if self.__algorithm.has_key(key):
474 return self.__algorithm.get( key )
475 elif self.__StoredDiagnostics.has_key(key):
476 return self.__StoredDiagnostics[key]
478 raise ValueError("The requested key \"%s\" does not exists as a diagnostic or as a stored variable."%key)
480 allvariables = self.__algorithm.get()
481 allvariables.update( self.__StoredDiagnostics )
484 def get_available_algorithms(self):
486 Renvoie la liste des algorithmes identifiés par les chaînes de
490 for directory in sys.path:
491 if os.path.isdir(os.path.join(directory,"daAlgorithms")):
492 for fname in os.listdir(os.path.join(directory,"daAlgorithms")):
493 root, ext = os.path.splitext(fname)
494 if ext == '.py' and root != '__init__':
499 def get_available_diagnostics(self):
501 Renvoie la liste des diagnostics identifiés par les chaînes de
505 for directory in sys.path:
506 if os.path.isdir(os.path.join(directory,"daDiagnostics")):
507 for fname in os.listdir(os.path.join(directory,"daDiagnostics")):
508 root, ext = os.path.splitext(fname)
509 if ext == '.py' and root != '__init__':
514 # -----------------------------------------------------------
515 def get_algorithms_main_path(self):
517 Renvoie le chemin pour le répertoire principal contenant les algorithmes
518 dans un sous-répertoire "daAlgorithms"
522 def add_algorithms_path(self, asPath=None):
524 Ajoute au chemin de recherche des algorithmes un répertoire dans lequel
525 se trouve un sous-répertoire "daAlgorithms"
527 Remarque : si le chemin a déjà été ajouté pour les diagnostics, il n'est
528 pas indispensable de le rajouter ici.
530 if not os.path.isdir(asPath):
531 raise ValueError("The given "+asPath+" argument must exist as a directory")
532 if not os.path.isdir(os.path.join(asPath,"daAlgorithms")):
533 raise ValueError("The given \""+asPath+"\" argument must contain a subdirectory named \"daAlgorithms\"")
534 if not os.path.isfile(os.path.join(asPath,"daAlgorithms","__init__.py")):
535 raise ValueError("The given \""+asPath+"/daAlgorithms\" path must contain a file named \"__init__.py\"")
536 sys.path.insert(0, os.path.abspath(asPath))
537 sys.path = list(set(sys.path)) # Conserve en unique exemplaire chaque chemin
540 def get_diagnostics_main_path(self):
542 Renvoie le chemin pour le répertoire principal contenant les diagnostics
543 dans un sous-répertoire "daDiagnostics"
547 def add_diagnostics_path(self, asPath=None):
549 Ajoute au chemin de recherche des algorithmes un répertoire dans lequel
550 se trouve un sous-répertoire "daDiagnostics"
552 Remarque : si le chemin a déjà été ajouté pour les algorithmes, il n'est
553 pas indispensable de le rajouter ici.
555 if not os.path.isdir(asPath):
556 raise ValueError("The given "+asPath+" argument must exist as a directory")
557 if not os.path.isdir(os.path.join(asPath,"daDiagnostics")):
558 raise ValueError("The given \""+asPath+"\" argument must contain a subdirectory named \"daDiagnostics\"")
559 if not os.path.isfile(os.path.join(asPath,"daDiagnostics","__init__.py")):
560 raise ValueError("The given \""+asPath+"/daDiagnostics\" path must contain a file named \"__init__.py\"")
561 sys.path.insert(0, os.path.abspath(asPath))
562 sys.path = list(set(sys.path)) # Conserve en unique exemplaire chaque chemin
565 def prepare_to_pickle(self):
566 self.__algorithmFile = None
567 self.__diagnosticFile = None
570 # ==============================================================================
571 if __name__ == "__main__":
572 print '\n AUTODIAGNOSTIC \n'
574 ADD = AssimilationStudy("Ma premiere etude BLUE")
576 ADD.setBackground (asVector = [0, 1, 2])
577 ADD.setBackgroundError (asCovariance = "1 0 0;0 1 0;0 0 1")
578 ADD.setObservation (asVector = [0.5, 1.5, 2.5])
579 ADD.setObservationError (asCovariance = "1 0 0;0 1 0;0 0 1")
580 ADD.setObservationOperator(asMatrix = "1 0 0;0 1 0;0 0 1")
582 ADD.setAlgorithm(choice="Blue")
586 print "Nombre d'analyses :", ADD.get("Analysis").stepnumber()
587 print "Analyse résultante :", ADD.get("Analysis").valueserie(0)
588 print "Innovation :", ADD.get("Innovation").valueserie(0)
591 print "Algorithmes disponibles :", ADD.get_available_algorithms()
592 # print " Chemin des algorithmes :", ADD.get_algorithms_main_path()
593 print "Diagnostics disponibles :", ADD.get_available_diagnostics()
594 # print " Chemin des diagnostics :", ADD.get_diagnostics_main_path()
597 ADD.setDiagnostic("RMS", "Ma RMS")
599 liste = ADD.get().keys()
601 print "Variables et diagnostics disponibles :", liste