Salome HOME
Improving and simplifying result variables access methods
[modules/adao.git] / src / daComposant / daCore / Persistence.py
1 #-*-coding:iso-8859-1-*-
2 #
3 # Copyright (C) 2008-2013 EDF R&D
4 #
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.
9 #
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.
14 #
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
18 #
19 # See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com
20 #
21 # Author: Jean-Philippe Argaud, jean-philippe.argaud@edf.fr, EDF R&D
22
23 __doc__ = """
24     Définit des outils de persistence et d'enregistrement de séries de valeurs
25     pour analyse ultérieure ou utilisation de calcul.
26 """
27 __author__ = "Jean-Philippe ARGAUD"
28
29 import numpy, copy
30
31 from PlatformInfo import PathManagement ; PathManagement()
32
33 # ==============================================================================
34 class Persistence:
35     """
36     Classe générale de persistence définissant les accesseurs nécessaires
37     (Template)
38     """
39     def __init__(self, name="", unit="", basetype=str):
40         """
41         name : nom courant
42         unit : unité
43         basetype : type de base de l'objet stocké à chaque pas
44         
45         La gestion interne des données est exclusivement basée sur les variables
46         initialisées ici (qui ne sont pas accessibles depuis l'extérieur des
47         objets comme des attributs) :
48         __basetype : le type de base de chaque valeur, sous la forme d'un type
49                      permettant l'instanciation ou le casting Python 
50         __values : les valeurs de stockage. Par défaut, c'est None
51         """
52         self.__name = str(name)
53         self.__unit = str(unit)
54         #
55         self.__basetype = basetype
56         #
57         self.__values = []
58         self.__tags   = []
59         #
60         self.__dynamic  = False
61         #
62         self.__dataobservers = []
63     
64     def basetype(self, basetype=None):
65         """
66         Renvoie ou met en place le type de base des objets stockés
67         """
68         if basetype is None:
69             return self.__basetype
70         else:
71             self.__basetype = basetype
72
73     def store(self, value=None, **kwargs):
74         """
75         Stocke une valeur avec ses informations de filtrage.
76         """
77         if value is None: raise ValueError("Value argument required")
78         #
79         self.__values.append(self.__basetype(value))
80         self.__tags.append(kwargs)
81         #
82         if self.__dynamic: self.__replots()
83         __step = len(self.__values) - 1
84         for hook, parameters, scheduler in self.__dataobservers:
85             if __step in scheduler:
86                 hook( self, parameters )
87
88     def pop(self, item=None):
89         """
90         Retire une valeur enregistree par son index de stockage. Sans argument,
91         retire le dernier objet enregistre.
92         """
93         if item is not None:
94             __index = int(item)
95             self.__values.pop(__index)
96             self.__tags.pop(__index)
97         else:
98             self.__values.pop()
99             self.__tags.pop()
100     
101     def shape(self):
102         """
103         Renvoie la taille sous forme numpy du dernier objet stocké. Si c'est un
104         objet numpy, renvoie le shape. Si c'est un entier, un flottant, un
105         complexe, renvoie 1. Si c'est une liste ou un dictionnaire, renvoie la
106         longueur. Par défaut, renvoie 1.
107         """
108         if len(self.__values) > 0:
109             if self.__basetype in [numpy.matrix, numpy.array, numpy.ravel]:
110                 return self.__values[-1].shape
111             elif self.__basetype in [int, float]:
112                 return (1,)
113             elif self.__basetype in [list, dict]:
114                 return (len(self.__values[-1]),)
115             else:
116                 return (1,)
117         else:
118             raise ValueError("Object has no shape before its first storage")
119
120     # ---------------------------------------------------------
121     def __str__(self):
122         msg  = "   Index        Value   Tags\n"
123         for i,v in enumerate(self.__values):
124             msg += "  i=%05i  %10s   %s\n"%(i,v,self.__tags[i])
125         return msg
126     
127     def __len__(self):
128         return len(self.__values)
129     
130     def __getitem__(self, index=None ):
131         return copy.copy(self.__values[index])
132     
133     def count(self, value):
134         return self.__values.count(value)
135     
136     def index(self, value, start=0, stop=None):
137         if stop is None : stop = len(self.__values)
138         return self.__values.index(value, start, stop)
139
140     # ---------------------------------------------------------
141     def __filteredIndexes(self, **kwargs):
142         __indexOfFilteredItems = range(len(self.__tags))
143         __filteringKwTags = kwargs.keys()
144         if len(__filteringKwTags) > 0:
145             for tagKey in __filteringKwTags:
146                 __tmp = []
147                 for i in __indexOfFilteredItems:
148                     if self.__tags[i].has_key(tagKey):
149                         if self.__tags[i][tagKey] == kwargs[tagKey]:
150                             __tmp.append( i )
151                         elif isinstance(kwargs[tagKey],(list,tuple)) and self.__tags[i][tagKey] in kwargs[tagKey]:
152                             __tmp.append( i )
153                 __indexOfFilteredItems = __tmp
154                 if len(__indexOfFilteredItems) == 0: break
155         return __indexOfFilteredItems
156
157     # ---------------------------------------------------------
158     def values(self, **kwargs):
159         __indexOfFilteredItems = self.__filteredIndexes(**kwargs)
160         return [self.__values[i] for i in __indexOfFilteredItems]
161
162     def keys(self, keyword=None , **kwargs):
163         __indexOfFilteredItems = self.__filteredIndexes(**kwargs)
164         __keys = []
165         for i in __indexOfFilteredItems:
166             if self.__tags[i].has_key( keyword ):
167                 __keys.append( self.__tags[i][keyword] )
168             else:
169                 __keys.append( None )
170         return __keys
171
172     def items(self, keyword=None , **kwargs):
173         __indexOfFilteredItems = self.__filteredIndexes(**kwargs)
174         __pairs = []
175         for i in __indexOfFilteredItems:
176             if self.__tags[i].has_key( keyword ):
177                 __pairs.append( [self.__tags[i][keyword], self.__values[i]] )
178             else:
179                 __pairs.append( [None, self.__values[i]] )
180         return __pairs
181
182     def tagkeys(self):
183         __allKeys = []
184         for dicotags in self.__tags:
185             __allKeys.extend( dicotags.keys() )
186         __allKeys = list(set(__allKeys))
187         __allKeys.sort()
188         return __allKeys
189
190     # def valueserie(self, item=None, allSteps=True, **kwargs):
191     #     if item is not None:
192     #         return self.__values[item]
193     #     else:
194     #         __indexOfFilteredItems = self.__filteredIndexes(**kwargs)
195     #         if not allSteps and len(__indexOfFilteredItems) > 0:
196     #             return self.__values[__indexOfFilteredItems[0]]
197     #         else:
198     #             return [self.__values[i] for i in __indexOfFilteredItems]
199
200     def tagserie(self, item=None, withValues=False, outputTag=None, **kwargs):
201         if item is None:
202             __indexOfFilteredItems = self.__filteredIndexes(**kwargs)
203         else:
204             __indexOfFilteredItems = [item,]
205         #
206         # Dans le cas où la sortie donne les valeurs d'un "outputTag"
207         if outputTag is not None and type(outputTag) is str :
208             outputValues = []
209             for index in __indexOfFilteredItems:
210                 if outputTag in self.__tags[index].keys():
211                     outputValues.append( self.__tags[index][outputTag] )
212             outputValues = list(set(outputValues))
213             outputValues.sort()
214             return outputValues
215         #
216         # Dans le cas où la sortie donne les tags satisfaisants aux conditions
217         else:
218             if withValues:
219                 return [self.__tags[index] for index in __indexOfFilteredItems]
220             else:
221                 allTags = {}
222                 for index in __indexOfFilteredItems:
223                     allTags.update( self.__tags[index] )
224                 allKeys = allTags.keys()
225                 allKeys.sort()
226                 return allKeys
227
228     # ---------------------------------------------------------
229     # Pour compatibilite
230     def stepnumber(self):
231         return len(self.__values)
232
233     # Pour compatibilite
234     def stepserie(self, **kwargs):
235         __indexOfFilteredItems = self.__filteredIndexes(**kwargs)
236         return __indexOfFilteredItems
237
238     # ---------------------------------------------------------
239     def means(self):
240         """
241         Renvoie la série, contenant à chaque pas, la valeur moyenne des données
242         au pas. Il faut que le type de base soit compatible avec les types
243         élémentaires numpy.
244         """
245         try:
246             return [numpy.matrix(item).mean() for item in self.__values]
247         except:
248             raise TypeError("Base type is incompatible with numpy")
249
250     def stds(self, ddof=0):
251         """
252         Renvoie la série, contenant à chaque pas, l'écart-type des données
253         au pas. Il faut que le type de base soit compatible avec les types
254         élémentaires numpy.
255         
256         ddof : c'est le nombre de degrés de liberté pour le calcul de
257                l'écart-type, qui est dans le diviseur. Inutile avant Numpy 1.1
258         """
259         try:
260             if numpy.version.version >= '1.1.0':
261                 return [numpy.matrix(item).std(ddof=ddof) for item in self.__values]
262             else:
263                 return [numpy.matrix(item).std() for item in self.__values]
264         except:
265             raise TypeError("Base type is incompatible with numpy")
266
267     def sums(self):
268         """
269         Renvoie la série, contenant à chaque pas, la somme des données au pas.
270         Il faut que le type de base soit compatible avec les types élémentaires
271         numpy.
272         """
273         try:
274             return [numpy.matrix(item).sum() for item in self.__values]
275         except:
276             raise TypeError("Base type is incompatible with numpy")
277
278     def mins(self):
279         """
280         Renvoie la série, contenant à chaque pas, le minimum des données au pas.
281         Il faut que le type de base soit compatible avec les types élémentaires
282         numpy.
283         """
284         try:
285             return [numpy.matrix(item).min() for item in self.__values]
286         except:
287             raise TypeError("Base type is incompatible with numpy")
288
289     def maxs(self):
290         """
291         Renvoie la série, contenant à chaque pas, la maximum des données au pas.
292         Il faut que le type de base soit compatible avec les types élémentaires
293         numpy.
294         """
295         try:
296             return [numpy.matrix(item).max() for item in self.__values]
297         except:
298             raise TypeError("Base type is incompatible with numpy")
299
300     def __preplots(self,
301             title    = "",
302             xlabel   = "",
303             ylabel   = "",
304             ltitle   = None,
305             geometry = "600x400",
306             persist  = False,
307             pause    = True,
308             ):
309         #
310         # Vérification de la disponibilité du module Gnuplot
311         try:
312             import Gnuplot
313             self.__gnuplot = Gnuplot
314         except:
315             raise ImportError("The Gnuplot module is required to plot the object.")
316         #
317         # Vérification et compléments sur les paramètres d'entrée
318         if persist:
319             self.__gnuplot.GnuplotOpts.gnuplot_command = 'gnuplot -persist -geometry '+geometry
320         else:
321             self.__gnuplot.GnuplotOpts.gnuplot_command = 'gnuplot -geometry '+geometry
322         if ltitle is None:
323             ltitle = ""
324         self.__g = self.__gnuplot.Gnuplot() # persist=1
325         self.__g('set terminal '+self.__gnuplot.GnuplotOpts.default_term)
326         self.__g('set style data lines')
327         self.__g('set grid')
328         self.__g('set autoscale')
329         self.__g('set xlabel "'+str(xlabel).encode('ascii','replace')+'"')
330         self.__g('set ylabel "'+str(ylabel).encode('ascii','replace')+'"')
331         self.__title  = title
332         self.__ltitle = ltitle
333         self.__pause  = pause
334
335     def plots(self, item=None, step=None,
336             steps    = None,
337             title    = "",
338             xlabel   = "",
339             ylabel   = "",
340             ltitle   = None,
341             geometry = "600x400",
342             filename = "",
343             dynamic  = False,
344             persist  = False,
345             pause    = True,
346             ):
347         """
348         Renvoie un affichage de la valeur à chaque pas, si elle est compatible
349         avec un affichage Gnuplot (donc essentiellement un vecteur). Si
350         l'argument "step" existe dans la liste des pas de stockage effectués,
351         renvoie l'affichage de la valeur stockée à ce pas "step". Si l'argument
352         "item" est correct, renvoie l'affichage de la valeur stockée au numéro
353         "item". Par défaut ou en l'absence de "step" ou "item", renvoie un
354         affichage successif de tous les pas.
355
356         Arguments :
357             - step     : valeur du pas à afficher
358             - item     : index de la valeur à afficher
359             - steps    : liste unique des pas de l'axe des X, ou None si c'est
360                          la numérotation par défaut
361             - title    : base du titre général, qui sera automatiquement
362                          complétée par la mention du pas
363             - xlabel   : label de l'axe des X
364             - ylabel   : label de l'axe des Y
365             - ltitle   : titre associé au vecteur tracé
366             - geometry : taille en pixels de la fenêtre et position du coin haut
367                          gauche, au format X11 : LxH+X+Y (défaut : 600x400)
368             - filename : base de nom de fichier Postscript pour une sauvegarde,
369                          qui est automatiquement complétée par le numéro du
370                          fichier calculé par incrément simple de compteur
371             - dynamic  : effectue un affichage des valeurs à chaque stockage
372                          (au-delà du second). La méthode "plots" permet de
373                          déclarer l'affichage dynamique, et c'est la méthode
374                          "__replots" qui est utilisée pour l'effectuer
375             - persist  : booléen indiquant que la fenêtre affichée sera
376                          conservée lors du passage au dessin suivant
377                          Par défaut, persist = False
378             - pause    : booléen indiquant une pause après chaque tracé, et
379                          attendant un Return
380                          Par défaut, pause = True
381         """
382         import os
383         if not self.__dynamic:
384             self.__preplots(title, xlabel, ylabel, ltitle, geometry, persist, pause )
385             if dynamic:
386                 self.__dynamic = True
387                 if len(self.__values) == 0: return 0
388         #
389         # Tracé du ou des vecteurs demandés
390         indexes = []
391         if step is not None and step < len(self.__values):
392             indexes.append(step)
393         elif item is not None and item < len(self.__values):
394             indexes.append(item)
395         else:
396             indexes = indexes + range(len(self.__values))
397         #
398         i = -1
399         for index in indexes:
400             self.__g('set title  "'+str(title).encode('ascii','replace')+' (pas '+str(index)+')"')
401             if ( type(steps) is list ) or ( type(steps) is type(numpy.array([])) ):
402                 Steps = list(steps)
403             else:
404                 Steps = range(len(self.__values[index]))
405             #
406             self.__g.plot( self.__gnuplot.Data( Steps, self.__values[index], title=ltitle ) )
407             #
408             if filename != "":
409                 i += 1
410                 stepfilename = "%s_%03i.ps"%(filename,i)
411                 if os.path.isfile(stepfilename):
412                     raise ValueError("Error: a file with this name \"%s\" already exists."%stepfilename)
413                 self.__g.hardcopy(filename=stepfilename, color=1)
414             if self.__pause:
415                 raw_input('Please press return to continue...\n')
416
417     def __replots(self):
418         """
419         Affichage dans le cas du suivi dynamique de la variable
420         """
421         if self.__dynamic and len(self.__values) < 2: return 0
422         #
423         self.__g('set title  "'+str(self.__title).encode('ascii','replace'))
424         Steps = range(len(self.__values))
425         self.__g.plot( self.__gnuplot.Data( Steps, self.__values, title=self.__ltitle ) )
426         #
427         if self.__pause:
428             raw_input('Please press return to continue...\n')
429
430     # ---------------------------------------------------------
431     def mean(self):
432         """
433         Renvoie la moyenne sur toutes les valeurs sans tenir compte de la
434         longueur des pas. Il faut que le type de base soit compatible avec
435         les types élémentaires numpy.
436         """
437         try:
438             if self.__basetype in [int, float]:
439                 return float( numpy.array(self.__values).mean() )
440             else:
441                 return numpy.array(self.__values).mean(axis=0)
442         except:
443             raise TypeError("Base type is incompatible with numpy")
444
445     def std(self, ddof=0):
446         """
447         Renvoie l'écart-type de toutes les valeurs sans tenir compte de la
448         longueur des pas. Il faut que le type de base soit compatible avec
449         les types élémentaires numpy.
450         
451         ddof : c'est le nombre de degrés de liberté pour le calcul de
452                l'écart-type, qui est dans le diviseur. Inutile avant Numpy 1.1
453         """
454         try:
455             if numpy.version.version >= '1.1.0':
456                 return numpy.array(self.__values).std(ddof=ddof,axis=0)
457             else:
458                 return numpy.array(self.__values).std(axis=0)
459         except:
460             raise TypeError("Base type is incompatible with numpy")
461
462     def sum(self):
463         """
464         Renvoie la somme de toutes les valeurs sans tenir compte de la
465         longueur des pas. Il faut que le type de base soit compatible avec
466         les types élémentaires numpy.
467         """
468         try:
469             return numpy.array(self.__values).sum(axis=0)
470         except:
471             raise TypeError("Base type is incompatible with numpy")
472
473     def min(self):
474         """
475         Renvoie le minimum de toutes les valeurs sans tenir compte de la
476         longueur des pas. Il faut que le type de base soit compatible avec
477         les types élémentaires numpy.
478         """
479         try:
480             return numpy.array(self.__values).min(axis=0)
481         except:
482             raise TypeError("Base type is incompatible with numpy")
483
484     def max(self):
485         """
486         Renvoie le maximum de toutes les valeurs sans tenir compte de la
487         longueur des pas. Il faut que le type de base soit compatible avec
488         les types élémentaires numpy.
489         """
490         try:
491             return numpy.array(self.__values).max(axis=0)
492         except:
493             raise TypeError("Base type is incompatible with numpy")
494
495     def cumsum(self):
496         """
497         Renvoie la somme cumulée de toutes les valeurs sans tenir compte de la
498         longueur des pas. Il faut que le type de base soit compatible avec
499         les types élémentaires numpy.
500         """
501         try:
502             return numpy.array(self.__values).cumsum(axis=0)
503         except:
504             raise TypeError("Base type is incompatible with numpy")
505
506     # On pourrait aussi utiliser les autres attributs d'une "matrix", comme
507     # "tofile", "min"...
508
509     def plot(self,
510             steps    = None,
511             title    = "",
512             xlabel   = "",
513             ylabel   = "",
514             ltitle   = None,
515             geometry = "600x400",
516             filename = "",
517             persist  = False,
518             pause    = True,
519             ):
520         """
521         Renvoie un affichage unique pour l'ensemble des valeurs à chaque pas, si
522         elles sont compatibles avec un affichage Gnuplot (donc essentiellement
523         un vecteur). Si l'argument "step" existe dans la liste des pas de
524         stockage effectués, renvoie l'affichage de la valeur stockée à ce pas
525         "step". Si l'argument "item" est correct, renvoie l'affichage de la
526         valeur stockée au numéro "item".
527
528         Arguments :
529             - steps    : liste unique des pas de l'axe des X, ou None si c'est
530                          la numérotation par défaut
531             - title    : base du titre général, qui sera automatiquement
532                          complétée par la mention du pas
533             - xlabel   : label de l'axe des X
534             - ylabel   : label de l'axe des Y
535             - ltitle   : titre associé au vecteur tracé
536             - geometry : taille en pixels de la fenêtre et position du coin haut
537                          gauche, au format X11 : LxH+X+Y (défaut : 600x400)
538             - filename : nom de fichier Postscript pour une sauvegarde
539             - persist  : booléen indiquant que la fenêtre affichée sera
540                          conservée lors du passage au dessin suivant
541                          Par défaut, persist = False
542             - pause    : booléen indiquant une pause après chaque tracé, et
543                          attendant un Return
544                          Par défaut, pause = True
545         """
546         #
547         # Vérification de la disponibilité du module Gnuplot
548         try:
549             import Gnuplot
550             self.__gnuplot = Gnuplot
551         except:
552             raise ImportError("The Gnuplot module is required to plot the object.")
553         #
554         # Vérification et compléments sur les paramètres d'entrée
555         if persist:
556             self.__gnuplot.GnuplotOpts.gnuplot_command = 'gnuplot -persist -geometry '+geometry
557         else:
558             self.__gnuplot.GnuplotOpts.gnuplot_command = 'gnuplot -geometry '+geometry
559         if ltitle is None:
560             ltitle = ""
561         if ( type(steps) is list ) or ( type(steps) is type(numpy.array([])) ):
562             Steps = list(steps)
563         else:
564             Steps = range(len(self.__values[0]))
565         self.__g = self.__gnuplot.Gnuplot() # persist=1
566         self.__g('set terminal '+self.__gnuplot.GnuplotOpts.default_term)
567         self.__g('set style data lines')
568         self.__g('set grid')
569         self.__g('set autoscale')
570         self.__g('set title  "'+str(title).encode('ascii','replace') +'"')
571         self.__g('set xlabel "'+str(xlabel).encode('ascii','replace')+'"')
572         self.__g('set ylabel "'+str(ylabel).encode('ascii','replace')+'"')
573         #
574         # Tracé du ou des vecteurs demandés
575         indexes = range(len(self.__values))
576         self.__g.plot( self.__gnuplot.Data( Steps, self.__values[indexes.pop(0)], title=ltitle+" (pas 0)" ) )
577         for index in indexes:
578             self.__g.replot( self.__gnuplot.Data( Steps, self.__values[index], title=ltitle+" (pas %i)"%index ) )
579         #
580         if filename != "":
581             self.__g.hardcopy(filename=filename, color=1)
582         if pause:
583             raw_input('Please press return to continue...\n')
584
585     # ---------------------------------------------------------
586     def setDataObserver(self,
587         HookFunction   = None,
588         HookParameters = None,
589         Scheduler      = None,
590         ):
591         """
592         Association à la variable d'un triplet définissant un observer
593         
594         Le Scheduler attendu est une fréquence, une simple liste d'index ou un
595         xrange des index.
596         """
597         #
598         # Vérification du Scheduler
599         # -------------------------
600         maxiter = int( 1e9 )
601         if type(Scheduler) is int:    # Considéré comme une fréquence à partir de 0
602             Schedulers = xrange( 0, maxiter, int(Scheduler) )
603         elif type(Scheduler) is xrange: # Considéré comme un itérateur
604             Schedulers = Scheduler
605         elif type(Scheduler) is list: # Considéré comme des index explicites
606             Schedulers = map( long, Scheduler )
607         else:                         # Dans tous les autres cas, activé par défaut
608             Schedulers = xrange( 0, maxiter )
609         #
610         # Stockage interne de l'observer dans la variable
611         # -----------------------------------------------
612         self.__dataobservers.append( [HookFunction, HookParameters, Schedulers] )
613
614     def removeDataObserver(self,
615         HookFunction   = None,
616         ):
617         """
618         Suppression d'un observer nommé sur la variable.
619         
620         On peut donner dans HookFunction la meme fonction que lors de la
621         définition, ou un simple string qui est le nom de la fonction.
622         
623         """
624         if hasattr(HookFunction,"func_name"):
625             name = str( HookFunction.func_name )
626         elif type(HookFunction) is str:
627             name = str( HookFunction )
628         else:
629             name = None
630         #
631         i = -1
632         index_to_remove = []
633         for [hf, hp, hs] in self.__dataobservers:
634             i = i + 1
635             if name is hf.func_name: index_to_remove.append( i )
636         index_to_remove.reverse()
637         for i in index_to_remove:
638                 self.__dataobservers.pop( i )
639
640 # ==============================================================================
641 class OneScalar(Persistence):
642     """
643     Classe définissant le stockage d'une valeur unique réelle (float) par pas
644     
645     Le type de base peut être changé par la méthode "basetype", mais il faut que
646     le nouveau type de base soit compatible avec les types par éléments de 
647     numpy. On peut même utiliser cette classe pour stocker des vecteurs/listes
648     ou des matrices comme dans les classes suivantes, mais c'est déconseillé
649     pour conserver une signification claire des noms.
650     """
651     def __init__(self, name="", unit="", basetype = float):
652         Persistence.__init__(self, name, unit, basetype)
653
654 class OneVector(Persistence):
655     """
656     Classe définissant le stockage d'une liste (list) de valeurs homogènes par
657     hypothèse par pas. Pour éviter les confusions, ne pas utiliser la classe
658     "OneVector" pour des données hétérogènes, mais bien "OneList".
659     """
660     def __init__(self, name="", unit="", basetype = list):
661         Persistence.__init__(self, name, unit, basetype)
662
663 class OneMatrix(Persistence):
664     """
665     Classe définissant le stockage d'une matrice de valeurs (numpy.matrix) par
666     pas
667     """
668     def __init__(self, name="", unit="", basetype = numpy.matrix):
669         Persistence.__init__(self, name, unit, basetype)
670
671 class OneList(Persistence):
672     """
673     Classe définissant le stockage d'une liste de valeurs potentiellement
674     hétérogènes (list) par pas. Pour éviter les confusions, ne pas utiliser la
675     classe "OneVector" pour des données hétérogènes, mais bien "OneList".
676     """
677     def __init__(self, name="", unit="", basetype = list):
678         Persistence.__init__(self, name, unit, basetype)
679
680 def NoType( value ): return value
681
682 class OneNoType(Persistence):
683     """
684     Classe définissant le stockage d'un objet sans modification (cast) de type.
685     Attention, selon le véritable type de l'objet stocké à chaque pas, les
686     opérations arithmétiques à base de numpy peuvent être invalides ou donner
687     des résultats inatendus. Cette classe n'est donc à utiliser qu'à bon escient
688     volontairement, et pas du tout par défaut.
689     """
690     def __init__(self, name="", unit="", basetype = NoType):
691         Persistence.__init__(self, name, unit, basetype)
692
693 # ==============================================================================
694 class CompositePersistence:
695     """
696     Structure de stockage permettant de rassembler plusieurs objets de
697     persistence.
698     
699     Des objets par défaut sont prévus, et des objets supplémentaires peuvent
700     être ajoutés.
701     """
702     def __init__(self, name="", defaults=True):
703         """
704         name : nom courant
705         
706         La gestion interne des données est exclusivement basée sur les variables
707         initialisées ici (qui ne sont pas accessibles depuis l'extérieur des
708         objets comme des attributs) :
709         __StoredObjects : objets de type persistence collectés dans cet objet
710         """
711         self.__name = str(name)
712         #
713         self.__StoredObjects = {}
714         #
715         # Definition des objets par defaut
716         # --------------------------------
717         if defaults:
718             self.__StoredObjects["Informations"]     = OneNoType("Informations")
719             self.__StoredObjects["Background"]       = OneVector("Background", basetype=numpy.array)
720             self.__StoredObjects["BackgroundError"]  = OneMatrix("BackgroundError")
721             self.__StoredObjects["Observation"]      = OneVector("Observation", basetype=numpy.array)
722             self.__StoredObjects["ObservationError"] = OneMatrix("ObservationError")
723             self.__StoredObjects["Analysis"]         = OneVector("Analysis", basetype=numpy.array)
724             self.__StoredObjects["AnalysisError"]    = OneMatrix("AnalysisError")
725             self.__StoredObjects["Innovation"]       = OneVector("Innovation", basetype=numpy.array)
726             self.__StoredObjects["KalmanGainK"]      = OneMatrix("KalmanGainK")
727             self.__StoredObjects["OperatorH"]        = OneMatrix("OperatorH")
728             self.__StoredObjects["RmsOMA"]           = OneScalar("RmsOMA")
729             self.__StoredObjects["RmsOMB"]           = OneScalar("RmsOMB")
730             self.__StoredObjects["RmsBMA"]           = OneScalar("RmsBMA")
731         #
732
733     def store(self, name=None, value=None, **kwargs):
734         """
735         Stockage d'une valeur "value" pour le "step" dans la variable "name".
736         """
737         if name is None: raise ValueError("Storable object name is required for storage.")
738         if name not in self.__StoredObjects.keys():
739             raise ValueError("No such name '%s' exists in storable objects."%name)
740         self.__StoredObjects[name].store( value=value, **kwargs )
741
742     def add_object(self, name=None, persistenceType=Persistence, basetype=None ):
743         """
744         Ajoute dans les objets stockables un nouvel objet défini par son nom, son
745         type de Persistence et son type de base à chaque pas.
746         """
747         if name is None: raise ValueError("Object name is required for adding an object.")
748         if name in self.__StoredObjects.keys():
749             raise ValueError("An object with the same name '%s' already exists in storable objects. Choose another one."%name)
750         if basetype is None:
751             self.__StoredObjects[name] = persistenceType( name=str(name) )
752         else:
753             self.__StoredObjects[name] = persistenceType( name=str(name), basetype=basetype )
754
755     def get_object(self, name=None ):
756         """
757         Renvoie l'objet de type Persistence qui porte le nom demandé.
758         """
759         if name is None: raise ValueError("Object name is required for retrieving an object.")
760         if name not in self.__StoredObjects.keys():
761             raise ValueError("No such name '%s' exists in stored objects."%name)
762         return self.__StoredObjects[name]
763
764     def set_object(self, name=None, objet=None ):
765         """
766         Affecte directement un 'objet' qui porte le nom 'name' demandé.
767         Attention, il n'est pas effectué de vérification sur le type, qui doit
768         comporter les méthodes habituelles de Persistence pour que cela
769         fonctionne.
770         """
771         if name is None: raise ValueError("Object name is required for setting an object.")
772         if name in self.__StoredObjects.keys():
773             raise ValueError("An object with the same name '%s' already exists in storable objects. Choose another one."%name)
774         self.__StoredObjects[name] = objet
775
776     def del_object(self, name=None ):
777         """
778         Supprime un objet de la liste des objets stockables.
779         """
780         if name is None: raise ValueError("Object name is required for retrieving an object.")
781         if name not in self.__StoredObjects.keys():
782             raise ValueError("No such name '%s' exists in stored objects."%name)
783         del self.__StoredObjects[name]
784
785     # ---------------------------------------------------------
786     # Méthodes d'accès de type dictionnaire
787     def __getitem__(self, name=None ):
788         return self.get_object( name )
789
790     def __setitem__(self, name=None, objet=None ):
791         self.set_object( name, objet )
792
793     def keys(self):
794         return self.get_stored_objects(hideVoidObjects = False)
795
796     def values(self):
797         return self.__StoredObjects.values()
798
799     def items(self):
800         return self.__StoredObjects.items()
801
802     # ---------------------------------------------------------
803     def get_stored_objects(self, hideVoidObjects = False):
804         objs = self.__StoredObjects.keys()
805         if hideVoidObjects:
806             usedObjs = []
807             for k in objs:
808                 try:
809                     if len(self.__StoredObjects[k]) > 0: usedObjs.append( k )
810                 except:
811                     pass
812             objs = usedObjs
813         objs.sort()
814         return objs
815
816     # ---------------------------------------------------------
817     def save_composite(self, filename=None, mode="pickle", compress="gzip"):
818         """
819         Enregistre l'objet dans le fichier indiqué selon le "mode" demandé,
820         et renvoi le nom du fichier
821         """
822         import os
823         if filename is None:
824             if compress == "gzip":
825                 filename = os.tempnam( os.getcwd(), 'dacp' ) + ".pkl.gz"
826             elif compress == "bzip2":
827                 filename = os.tempnam( os.getcwd(), 'dacp' ) + ".pkl.bz2"
828             else:
829                 filename = os.tempnam( os.getcwd(), 'dacp' ) + ".pkl"
830         else:
831             filename = os.path.abspath( filename )
832         #
833         import cPickle
834         if mode == "pickle":
835             if compress == "gzip":
836                 import gzip
837                 output = gzip.open( filename, 'wb')
838             elif compress == "bzip2":
839                 import bz2
840                 output = bz2.BZ2File( filename, 'wb')
841             else:
842                 output = open( filename, 'wb')
843             cPickle.dump(self, output)
844             output.close()
845         else:
846             raise ValueError("Save mode '%s' unknown. Choose another one."%mode)
847         #
848         return filename
849
850     def load_composite(self, filename=None, mode="pickle", compress="gzip"):
851         """
852         Recharge un objet composite sauvé en fichier
853         """
854         import os
855         if filename is None:
856             raise ValueError("A file name if requested to load a composite.")
857         else:
858             filename = os.path.abspath( filename )
859         #
860         import cPickle
861         if mode == "pickle":
862             if compress == "gzip":
863                 import gzip
864                 pkl_file = gzip.open( filename, 'rb')
865             elif compress == "bzip2":
866                 import bz2
867                 pkl_file = bz2.BZ2File( filename, 'rb')
868             else:
869                 pkl_file = open(filename, 'rb')
870             output = cPickle.load(pkl_file)
871             for k in output.keys():
872                 self[k] = output[k]
873         else:
874             raise ValueError("Load mode '%s' unknown. Choose another one."%mode)
875         #
876         return filename
877
878 # ==============================================================================
879 if __name__ == "__main__":
880     print '\n AUTODIAGNOSTIC \n'
881
882     OBJ = Persistence()                                                                                                
883     OBJ.store( 2)
884     OBJ.store( 3, Campagne="GR514")
885     OBJ.store( 4, Campagne="GR514")
886     OBJ.store( 5, Campagne="GR514")
887     OBJ.store( 6, Campagne="CA206", CDF="c020")
888     OBJ.store( 7, Campagne="GR514")
889     OBJ.store( 8, Campagne="GR514", CDF="c020")
890     OBJ.store( 9, Campagne="GR514", CDF="c020", BU=100.5)
891     print
892     print OBJ
893     print
894     print "Nombre d'items stockés..........................:", len(OBJ)
895     print
896     print "Mots-clé utilisés...............................:", OBJ.tagkeys()
897     print
898     print "Obtention de valeurs, clefs, items en fonction du filtrage"
899     print """  OBJ.values()................................:""", OBJ.values()
900     print """  OBJ.values(Campagne="GR514")................:""", OBJ.values(Campagne="GR514")
901     print """  OBJ.values(Campagne="c020").................:""", OBJ.values(Campagne="c020")
902     print """  OBJ.values(CDF="c020")......................:""", OBJ.values(CDF="c020")
903     print """  OBJ.values(Campagne="GR514",CDF="c020").....:""", OBJ.values(Campagne="GR514",CDF="c020")
904     print """  OBJ.values(Campagne=("GR514","CA206").......:""", OBJ.values(Campagne=("GR514","CA206"))
905     print
906     print """  OBJ.keys()..................................:""", OBJ.keys()
907     print """  OBJ.keys(Campagne="GR514")..................:""", OBJ.keys(Campagne="GR514")
908     print """  OBJ.keys(Campagne="c020")...................:""", OBJ.keys(Campagne="c020")
909     print """  OBJ.keys(CDF="c020")........................:""", OBJ.keys(CDF="c020")
910     print """  OBJ.keys(Campagne="GR514",CDF="c020").......:""", OBJ.keys(Campagne="GR514",CDF="c020")
911     print """  OBJ.keys(Campagne=("GR514","CA206").........:""", OBJ.keys(Campagne=("GR514","CA206"))
912     print
913     print """  OBJ.items().................................:""", OBJ.items()
914     print """  OBJ.items(Campagne="GR514").................:""", OBJ.items(Campagne="GR514")
915     print """  OBJ.items(Campagne="c020")..................:""", OBJ.items(Campagne="c020")
916     print """  OBJ.items(CDF="c020").......................:""", OBJ.items(CDF="c020")
917     print """  OBJ.items(Campagne="GR514",CDF="c020")......:""", OBJ.items(Campagne="GR514",CDF="c020")
918     print """  OBJ.items(Campagne=("GR514","CA206")........:""", OBJ.items(Campagne=("GR514","CA206"))
919     print
920     print "Obtention de valeurs de clefs particulières en fonction du filtrage"
921     print """  OBJ.keys("Campagne")........................:""", OBJ.keys("Campagne")
922     print """  OBJ.keys("CDF").............................:""", OBJ.keys("CDF")
923     print """  OBJ.keys("CDF",Campagne="GR514")............:""", OBJ.keys("CDF",Campagne="GR514")
924     print """  OBJ.keys("Campagne",CDF="c020").............:""", OBJ.keys("Campagne",CDF="c020")
925     print """  OBJ.keys("CDF",CDF="c020")..................:""", OBJ.keys("CDF",CDF="c020")
926     print """  OBJ.keys("BU")..............................:""", OBJ.keys("BU")
927     print """  OBJ.keys("CDF",Campagne=("GR514","CA206")...:""", OBJ.keys("CDF",Campagne=("GR514","CA206"))
928     print
929     print """  OBJ.items("Campagne").......................:""", OBJ.items("Campagne")
930     print """  OBJ.items("CDF")............................:""", OBJ.items("CDF")
931     print """  OBJ.items("CDF",Campagne="GR514")...........:""", OBJ.items("CDF",Campagne="GR514")
932     print """  OBJ.items("Campagne",CDF="c020")............:""", OBJ.items("Campagne",CDF="c020")
933     print """  OBJ.items("CDF",CDF="c020").................:""", OBJ.items("CDF",CDF="c020")
934     print """  OBJ.items("BU").............................:""", OBJ.items("BU")
935     print """  OBJ.items("CDF",Campagne=("GR514","CA206")..:""", OBJ.items("CDF",Campagne=("GR514","CA206"))
936     print
937     print "Obtention de valeurs comme dans une liste"
938     print """  OBJ[0]......................................:""", OBJ[0]
939     print """  OBJ[1]......................................:""", OBJ[1]
940     print """  OBJ[-1].....................................:""", OBJ[-1]
941     print """  OBJ[2:4]....................................:""", OBJ[2:4]
942     print """  OBJ[:]......................................:""", OBJ[:]
943     print """  len(OBJ)....................................:""", len(OBJ)
944     print """  OBJ.count(4)................................:""", OBJ.count("4")
945     print """  OBJ.index(4)................................:""", OBJ.index("4")
946     print """  OBJ.index(9)................................:""", OBJ.index("9")
947     print
948
949     print "======> Un flottant"
950     OBJET_DE_TEST = OneScalar("My float", unit="cm")
951     OBJET_DE_TEST.store( 5.)
952     OBJET_DE_TEST.store(-5.)
953     OBJET_DE_TEST.store( 1.)
954     print "Les pas de stockage :", OBJET_DE_TEST.stepserie()
955     print "Les valeurs         :", OBJET_DE_TEST[:]
956     print "La 2ème valeur      :", OBJET_DE_TEST[1]
957     print "La dernière valeur  :", OBJET_DE_TEST[-1]
958     print "Valeurs par pas :"
959     print "  La moyenne        :", OBJET_DE_TEST.means()
960     print "  L'écart-type      :", OBJET_DE_TEST.stds()
961     print "  La somme          :", OBJET_DE_TEST.sums()
962     print "  Le minimum        :", OBJET_DE_TEST.mins()
963     print "  Le maximum        :", OBJET_DE_TEST.maxs()
964     print "Valeurs globales :"
965     print "  La moyenne        :", OBJET_DE_TEST.mean()
966     print "  L'écart-type      :", OBJET_DE_TEST.std()
967     print "  La somme          :", OBJET_DE_TEST.sum()
968     print "  Le minimum        :", OBJET_DE_TEST.min()
969     print "  Le maximum        :", OBJET_DE_TEST.max()
970     print "  La somme cumulée  :", OBJET_DE_TEST.cumsum()
971     print "Taille \"shape\"      :", OBJET_DE_TEST.shape()
972     print "Taille \"len\"        :", len(OBJET_DE_TEST)
973     del OBJET_DE_TEST
974     print
975     
976     print "======> Un flottant"
977     OBJET_DE_TEST = OneScalar("My float", unit="cm")
978     OBJET_DE_TEST.store( 5., step="azerty")
979     OBJET_DE_TEST.store(-5., step="poiuyt")
980     OBJET_DE_TEST.store( 1., step="azerty")
981     OBJET_DE_TEST.store( 0., step="xxxxxx")
982     OBJET_DE_TEST.store( 5., step="poiuyt")
983     OBJET_DE_TEST.store(-5., step="azerty")
984     OBJET_DE_TEST.store( 1., step="poiuyt")
985     print "Les noms de pas     :", OBJET_DE_TEST.keys("step")
986     print "Les valeurs         :", OBJET_DE_TEST[:]
987     print "La 2ème valeur      :", OBJET_DE_TEST[1]
988     print "La dernière valeur  :", OBJET_DE_TEST[-1]
989     print "Valeurs identiques  :", OBJET_DE_TEST.values( step = "azerty" )
990     print "Valeurs identiques  :", OBJET_DE_TEST.values( step = "poiuyt" )
991     del OBJET_DE_TEST
992     print
993
994     print "======> Un entier"
995     OBJET_DE_TEST = OneScalar("My int", unit="cm", basetype=int)
996     OBJET_DE_TEST.store( 5 )
997     OBJET_DE_TEST.store(-5 )
998     OBJET_DE_TEST.store( 1.)
999     print "Les pas de stockage :", OBJET_DE_TEST.stepserie()
1000     print "Les valeurs         :", OBJET_DE_TEST[:]
1001     print "La 2ème valeur      :", OBJET_DE_TEST[1]
1002     print "La dernière valeur  :", OBJET_DE_TEST[-1]
1003     print "Valeurs par pas :"
1004     print "  La moyenne        :", OBJET_DE_TEST.means()
1005     print "  L'écart-type      :", OBJET_DE_TEST.stds()
1006     print "  La somme          :", OBJET_DE_TEST.sums()
1007     print "  Le minimum        :", OBJET_DE_TEST.mins()
1008     print "  Le maximum        :", OBJET_DE_TEST.maxs()
1009     print "Valeurs globales :"
1010     print "  La moyenne        :", OBJET_DE_TEST.mean()
1011     print "  L'écart-type      :", OBJET_DE_TEST.std()
1012     print "  La somme          :", OBJET_DE_TEST.sum()
1013     print "  Le minimum        :", OBJET_DE_TEST.min()
1014     print "  Le maximum        :", OBJET_DE_TEST.max()
1015     print "  La somme cumulée  :", OBJET_DE_TEST.cumsum()
1016     print "Taille \"shape\"      :", OBJET_DE_TEST.shape()
1017     print "Taille \"len\"        :", len(OBJET_DE_TEST)
1018     del OBJET_DE_TEST
1019     print
1020
1021     print "======> Un booléen"
1022     OBJET_DE_TEST = OneScalar("My bool", unit="", basetype=bool)
1023     OBJET_DE_TEST.store( True  )
1024     OBJET_DE_TEST.store( False )
1025     OBJET_DE_TEST.store( True  )
1026     print "Les pas de stockage :", OBJET_DE_TEST.stepserie()
1027     print "Les valeurs         :", OBJET_DE_TEST[:]
1028     print "La 2ème valeur      :", OBJET_DE_TEST[1]
1029     print "La dernière valeur  :", OBJET_DE_TEST[-1]
1030     print "Taille \"shape\"      :", OBJET_DE_TEST.shape()
1031     print "Taille \"len\"        :", len(OBJET_DE_TEST)
1032     del OBJET_DE_TEST
1033     print
1034
1035     print "======> Un vecteur de flottants"
1036     OBJET_DE_TEST = OneVector("My float vector", unit="cm")
1037     OBJET_DE_TEST.store( (5 , -5) )
1038     OBJET_DE_TEST.store( (-5, 5 ) )
1039     OBJET_DE_TEST.store( (1., 1.) )
1040     print "Les pas de stockage :", OBJET_DE_TEST.stepserie()
1041     print "Les valeurs         :", OBJET_DE_TEST[:]
1042     print "La 2ème valeur      :", OBJET_DE_TEST[1]
1043     print "La dernière valeur  :", OBJET_DE_TEST[-1]
1044     print "Valeurs par pas :"
1045     print "  La moyenne        :", OBJET_DE_TEST.means()
1046     print "  L'écart-type      :", OBJET_DE_TEST.stds()
1047     print "  La somme          :", OBJET_DE_TEST.sums()
1048     print "  Le minimum        :", OBJET_DE_TEST.mins()
1049     print "  Le maximum        :", OBJET_DE_TEST.maxs()
1050     print "Valeurs globales :"
1051     print "  La moyenne        :", OBJET_DE_TEST.mean()
1052     print "  L'écart-type      :", OBJET_DE_TEST.std()
1053     print "  La somme          :", OBJET_DE_TEST.sum()
1054     print "  Le minimum        :", OBJET_DE_TEST.min()
1055     print "  Le maximum        :", OBJET_DE_TEST.max()
1056     print "  La somme cumulée  :", OBJET_DE_TEST.cumsum()
1057     print "Taille \"shape\"      :", OBJET_DE_TEST.shape()
1058     print "Taille \"len\"        :", len(OBJET_DE_TEST)
1059     del OBJET_DE_TEST
1060     print
1061
1062     print "======> Une liste hétérogène"
1063     OBJET_DE_TEST = OneList("My list", unit="bool/cm")
1064     OBJET_DE_TEST.store( (True , -5) )
1065     OBJET_DE_TEST.store( (False,  5 ) )
1066     OBJET_DE_TEST.store( (True ,  1.) )
1067     print "Les pas de stockage :", OBJET_DE_TEST.stepserie()
1068     print "Les valeurs         :", OBJET_DE_TEST[:]
1069     print "La 2ème valeur      :", OBJET_DE_TEST[1]
1070     print "La dernière valeur  :", OBJET_DE_TEST[-1]
1071     print "Valeurs par pas : attention, on peut les calculer car True=1, False=0, mais cela n'a pas de sens"
1072     print "  La moyenne        :", OBJET_DE_TEST.means()
1073     print "  L'écart-type      :", OBJET_DE_TEST.stds()
1074     print "  La somme          :", OBJET_DE_TEST.sums()
1075     print "  Le minimum        :", OBJET_DE_TEST.mins()
1076     print "  Le maximum        :", OBJET_DE_TEST.maxs()
1077     print "Valeurs globales : attention, on peut les calculer car True=1, False=0, mais cela n'a pas de sens"
1078     print "  La moyenne        :", OBJET_DE_TEST.mean()
1079     print "  L'écart-type      :", OBJET_DE_TEST.std()
1080     print "  La somme          :", OBJET_DE_TEST.sum()
1081     print "  Le minimum        :", OBJET_DE_TEST.min()
1082     print "  Le maximum        :", OBJET_DE_TEST.max()
1083     print "  La somme cumulée  :", OBJET_DE_TEST.cumsum()
1084     print "Taille \"shape\"      :", OBJET_DE_TEST.shape()
1085     print "Taille \"len\"        :", len(OBJET_DE_TEST)
1086     del OBJET_DE_TEST
1087     print
1088
1089     print "======> Utilisation directe de la classe Persistence"
1090     OBJET_DE_TEST = Persistence("My object", unit="", basetype=int )
1091     OBJET_DE_TEST.store( 1  )
1092     OBJET_DE_TEST.store( 3 )
1093     OBJET_DE_TEST.store( 7  )
1094     print "Les pas de stockage :", OBJET_DE_TEST.stepserie()
1095     print "Les valeurs         :", OBJET_DE_TEST[:]
1096     print "La 2ème valeur      :", OBJET_DE_TEST[1]
1097     print "La dernière valeur  :", OBJET_DE_TEST[-1]
1098     print "Taille \"shape\"      :", OBJET_DE_TEST.shape()
1099     print "Taille \"len\"        :", len(OBJET_DE_TEST)
1100     del OBJET_DE_TEST
1101     print
1102
1103     print "======> Utilisation des méthodes d'accès de type dictionnaire"
1104     OBJET_DE_TEST = OneScalar("My int", unit="cm", basetype=int)
1105     for i in range(5):
1106         OBJET_DE_TEST.store( 7+i )
1107     print "Taille \"len\"        :", len(OBJET_DE_TEST)
1108     print "Les clés absentes   :", OBJET_DE_TEST.keys()
1109     print "Les valeurs         :", OBJET_DE_TEST.values()
1110     print "Les paires          :", OBJET_DE_TEST.items()
1111     OBJET_DE_TEST.pop(1)
1112     print "Les valeurs sans la 1:", OBJET_DE_TEST.values()
1113     OBJET_DE_TEST.pop(item=2)
1114     print "Les valeurs sans la 2:", OBJET_DE_TEST.values()
1115     del OBJET_DE_TEST
1116     print
1117
1118     print "======> Persistence composite"
1119     OBJET_DE_TEST = CompositePersistence("My CompositePersistence")
1120     print "Objets stockables :", OBJET_DE_TEST.get_stored_objects()
1121     print "Objets actifs     :", OBJET_DE_TEST.get_stored_objects( hideVoidObjects = True )
1122     print "--> Stockage d'une valeur de Background"
1123     OBJET_DE_TEST.store("Background",numpy.zeros(5))
1124     print "Objets actifs     :", OBJET_DE_TEST.get_stored_objects( hideVoidObjects = True )
1125     print "--> Ajout d'un objet nouveau par defaut, de type vecteur numpy par pas"
1126     OBJET_DE_TEST.add_object("ValeursVectorielles")
1127     OBJET_DE_TEST.store("ValeursVectorielles",numpy.zeros(5))
1128     print "Objets actifs     :", OBJET_DE_TEST.get_stored_objects( hideVoidObjects = True )
1129     print "--> Ajout d'un objet nouveau de type liste par pas"
1130     OBJET_DE_TEST.add_object("ValeursList", persistenceType=OneList )
1131     OBJET_DE_TEST.store("ValeursList",range(5))
1132     print "Objets actifs     :", OBJET_DE_TEST.get_stored_objects( hideVoidObjects = True )
1133     print "--> Ajout d'un objet nouveau, de type vecteur string par pas"
1134     OBJET_DE_TEST.add_object("ValeursStr", persistenceType=Persistence, basetype=str )
1135     OBJET_DE_TEST.store("ValeursStr","IGN3")
1136     OBJET_DE_TEST.store("ValeursStr","c021")
1137     print "Les valeurs       :", OBJET_DE_TEST.get_object("ValeursStr")[:]
1138     print "Acces comme dict  :", OBJET_DE_TEST["ValeursStr"].stepserie()
1139     print "Acces comme dict  :", OBJET_DE_TEST["ValeursStr"][:]
1140     print "Objets actifs     :", OBJET_DE_TEST.get_stored_objects( hideVoidObjects = True )
1141     print "--> Suppression d'un objet"
1142     OBJET_DE_TEST.del_object("ValeursVectorielles")
1143     print "Objets actifs     :", OBJET_DE_TEST.get_stored_objects( hideVoidObjects = True )
1144     print "--> Enregistrement de l'objet complet de Persistence composite"
1145     OBJET_DE_TEST.save_composite("composite.pkl", compress="None")
1146     print
1147
1148     print "======> Affichage graphique d'objets stockés"
1149     OBJET_DE_TEST = Persistence("My object", unit="", basetype=numpy.array)
1150     D = OBJET_DE_TEST
1151     vect1 = [1, 2, 1, 2, 1]
1152     vect2 = [-3, -3, 0, -3, -3]
1153     vect3 = [-1, 1, -5, 1, -1]
1154     vect4 = 100*[0.29, 0.97, 0.73, 0.01, 0.20]
1155     print "Stockage de 3 vecteurs de longueur identique"
1156     D.store(vect1)
1157     D.store(vect2)
1158     D.store(vect3)
1159     print "Affichage graphique de l'ensemble du stockage sur une même image"
1160     D.plot(
1161         title = "Tous les vecteurs",
1162         filename="vecteurs.ps",
1163         xlabel = "Axe X",
1164         ylabel = "Axe Y",
1165         pause = False )
1166     print "Stockage d'un quatrième vecteur de longueur différente"
1167     D.store(vect4)
1168     print "Affichage graphique séparé du dernier stockage"
1169     D.plots(
1170         item  = 3,
1171         title = "Vecteurs",
1172         filename = "vecteur",
1173         xlabel = "Axe X",
1174         ylabel = "Axe Y",
1175         pause = False )
1176     print "Les images ont été stockées en fichiers Postscript"
1177     print "Taille \"shape\" du dernier objet stocké",OBJET_DE_TEST.shape()
1178     print "Taille \"len\" du dernier objet stocké",len(OBJET_DE_TEST)
1179     del OBJET_DE_TEST
1180     print
1181
1182     print "======> Affichage graphique dynamique d'objets"
1183     OBJET_DE_TEST = Persistence("My object", unit="", basetype=float)
1184     D = OBJET_DE_TEST
1185     D.plots(
1186         dynamic = True,
1187         title   = "Valeur suivie",
1188         xlabel  = "Pas",
1189         ylabel  = "Valeur",
1190         pause   = False,
1191         )
1192     for i in range(1,11):
1193         D.store( i*i )
1194     print "Taille \"shape\" du dernier objet stocké",OBJET_DE_TEST.shape()
1195     print "Nombre d'objets stockés",len(OBJET_DE_TEST)
1196     del OBJET_DE_TEST
1197     print
1198
1199     print "======> Affectation simple d'observateurs dynamiques"
1200     def obs(var=None,info=None):
1201         print "  ---> Mise en oeuvre de l'observer"
1202         print "       var  =",var[-1]
1203         print "       info =",info
1204     OBJET_DE_TEST = Persistence("My object", unit="", basetype=list)
1205     D = OBJET_DE_TEST
1206     D.setDataObserver( HookFunction = obs )
1207     for i in range(5):
1208         # print
1209         print "Action de 1 observer sur la variable observée, étape :",i
1210         D.store( [i, i, i] )
1211     del OBJET_DE_TEST
1212     print
1213
1214     print "======> Affectation multiple d'observateurs dynamiques"
1215     def obs(var=None,info=None):
1216         print "  ---> Mise en oeuvre de l'observer"
1217         print "       var  =",var[-1]
1218         print "       info =",info
1219     def obs_bis(var=None,info=None):
1220         print "  ---> Mise en oeuvre de l'observer"
1221         print "       var  =",var[-1]
1222         print "       info =",info
1223     OBJET_DE_TEST = Persistence("My object", unit="", basetype=list)
1224     D = OBJET_DE_TEST
1225     D.setDataObserver(
1226         HookFunction   = obs,
1227         Scheduler      = [2, 4],
1228         HookParameters = "Premier observer",
1229         )
1230     D.setDataObserver(
1231         HookFunction   = obs,
1232         Scheduler      = xrange(1,3),
1233         HookParameters = "Second observer",
1234         )
1235     D.setDataObserver(
1236         HookFunction   = obs_bis,
1237         Scheduler      = range(1,3)+range(7,9),
1238         HookParameters = "Troisième observer",
1239         )
1240     for i in range(5):
1241         print "Action de 3 observers sur la variable observée, étape :",i
1242         D.store( [i, i, i] )
1243     D.removeDataObserver(
1244         HookFunction   = obs,
1245         )
1246     for i in range(5,10):
1247         print "Action d'un seul observer sur la variable observée, étape :",i
1248         D.store( [i, i, i] )
1249     del OBJET_DE_TEST
1250     print
1251
1252     print "======> Utilisation des tags/attributs et stockage puis récupération de l'ensemble"
1253     OBJET_DE_TEST = CompositePersistence("My CompositePersistence", defaults=False)
1254     OBJET_DE_TEST.add_object("My ecarts", basetype = numpy.array)
1255
1256     OBJET_DE_TEST.store( "My ecarts", numpy.arange(1,5),   Camp="Base",   Carte="IGN3", Niveau=1024, Palier="Premier" )
1257     OBJET_DE_TEST.store( "My ecarts", numpy.arange(1,5)+1, Camp="Base",   Carte="IGN4", Niveau= 210, Palier="Premier" )
1258     OBJET_DE_TEST.store( "My ecarts", numpy.arange(1,5)+2, Camp="Base",   Carte="IGN1", Niveau=1024 )
1259     OBJET_DE_TEST.store( "My ecarts", numpy.arange(1,5)+3, Camp="Sommet", Carte="IGN2", Niveau=4024, Palier="Second", FullMap=True )
1260
1261     print "Les pas de stockage :", OBJET_DE_TEST["My ecarts"].stepserie()
1262     print "Les valeurs         :", OBJET_DE_TEST["My ecarts"][:]
1263     print "La 2ème valeur      :", OBJET_DE_TEST["My ecarts"][1]
1264     print "La dernière valeur  :", OBJET_DE_TEST["My ecarts"][-1]
1265     print "Liste des attributs :", OBJET_DE_TEST["My ecarts"].tagserie()
1266     print "Taille \"shape\"      :", OBJET_DE_TEST["My ecarts"].shape()
1267     print "Taille \"len\"        :", len(OBJET_DE_TEST["My ecarts"])
1268     print
1269
1270     print "Pas pour tag        :", OBJET_DE_TEST["My ecarts"].stepserie( Palier="Premier" )
1271     print "Valeurs pour tag    :", OBJET_DE_TEST["My ecarts"].values( Palier="Premier" )
1272     print
1273     print "Pas pour tag        :", OBJET_DE_TEST["My ecarts"].stepserie( Carte="IGN1" )
1274     print "Pas pour tag        :", OBJET_DE_TEST["My ecarts"].stepserie( Niveau=1024 )
1275     print "Pas pour tag        :", OBJET_DE_TEST["My ecarts"].stepserie( Camp="Base" )
1276     print "Pas pour tag        :", OBJET_DE_TEST["My ecarts"].stepserie( Camp="TOTO" )
1277     print "Pas pour tag        :", OBJET_DE_TEST["My ecarts"].stepserie( Toto="Premier" )
1278     print "Pas pour tag        :", OBJET_DE_TEST["My ecarts"].stepserie( Carte="IGN1" )
1279     print
1280
1281     print "Combinaison 'ET' de plusieurs Tags"
1282     print "Attendu : [0, 1],    trouvé :",OBJET_DE_TEST["My ecarts"].stepserie( Camp="Base",   Palier="Premier" )
1283     print "Attendu : [],        trouvé :",OBJET_DE_TEST["My ecarts"].stepserie( Camp="Sommet", Palier="Premier" )
1284     print "Attendu : [3],       trouvé :",OBJET_DE_TEST["My ecarts"].stepserie( Camp="Sommet" )
1285     print "Attendu : [2],       trouvé :",OBJET_DE_TEST["My ecarts"].stepserie( Carte="IGN1",  Niveau=1024 )
1286     print
1287       
1288     print "Liste des tags pour le pas (item) 1  :",OBJET_DE_TEST["My ecarts"].tagserie(item = 1)
1289     print "Liste des tags pour le pas (item) 2  :",OBJET_DE_TEST["My ecarts"].tagserie(item = 2)
1290     print
1291     print "Liste des tags/valeurs pour le pas 1 :",OBJET_DE_TEST["My ecarts"].tagserie(item = 1, withValues=True)
1292     print "Liste des tags/valeurs pour le pas 2 :",OBJET_DE_TEST["My ecarts"].tagserie(item = 2, withValues=True)
1293     print
1294
1295     print "Liste des valeurs possibles pour 1 tag donné 'Camp'   :",OBJET_DE_TEST["My ecarts"].tagserie(outputTag="Camp")
1296     print "Liste des valeurs possibles pour 1 tag donné 'Toto'   :",OBJET_DE_TEST["My ecarts"].tagserie(outputTag="Toto")
1297     print "Liste des valeurs possibles pour 1 tag donné 'Niveau' :",OBJET_DE_TEST["My ecarts"].tagserie(outputTag="Niveau")
1298     print
1299
1300     OBJET_DE_TEST.add_object("My other ecarts", basetype = numpy.array)
1301     OBJET_DE_TEST.store( "My other ecarts", numpy.arange(-1,5),   Camp="Base",  Carte="IGN3",Niveau=1024,Palier="Premier" )
1302     OBJET_DE_TEST.store( "My other ecarts", numpy.arange(-1,5)+1, Camp="Base",  Carte="IGN4",Niveau= 210,Palier="Premier" )
1303     OBJET_DE_TEST.store( "My other ecarts", numpy.arange(-1,5)+2, Camp="Base",  Carte="IGN1",Niveau=1024 )
1304     OBJET_DE_TEST.store( "My other ecarts", numpy.arange(-1,5)+3, Camp="Sommet",Carte="IGN2",Niveau=4024,Palier="Second" )
1305
1306     print "Objets présents dans le composite :",OBJET_DE_TEST.get_stored_objects()
1307     fichier = "composite.pkl.gz"
1308     print "Sauvegarde sur \"%s\"..."%fichier
1309     OBJET_DE_TEST.save_composite( fichier )
1310     print "Effacement de l'objet en memoire"
1311     del OBJET_DE_TEST
1312     print
1313
1314     print "Relecture de l'objet sur \"%s\"..."%fichier
1315     OBJET_DE_TEST = CompositePersistence("My CompositePersistence bis", defaults=False)
1316     OBJET_DE_TEST.load_composite( fichier )
1317     print "Objets présents dans le composite :",OBJET_DE_TEST.get_stored_objects()
1318     print "Taille des objets contenus :"
1319     for name in OBJET_DE_TEST.get_stored_objects():
1320         print "  Objet \"%s\" : taille unitaire de %i"%(name,len(OBJET_DE_TEST[name][-1]))
1321
1322     print
1323     print "Les pas de stockage :", OBJET_DE_TEST["My ecarts"].stepserie()
1324     print "Les valeurs         :", OBJET_DE_TEST["My ecarts"][:]
1325     print "La 2ème valeur      :", OBJET_DE_TEST["My ecarts"][1]
1326     print "La dernière valeur  :", OBJET_DE_TEST["My ecarts"][-1]
1327     print "Liste des attributs :", OBJET_DE_TEST["My ecarts"].tagserie()
1328     print "Taille \"shape\"      :", OBJET_DE_TEST["My ecarts"].shape()
1329     print "Taille \"len\"        :", len(OBJET_DE_TEST["My ecarts"])
1330     print
1331
1332     print "Pas pour tag        :", OBJET_DE_TEST["My ecarts"].stepserie( Palier="Premier" )
1333     print "Valeurs pour tag    :", OBJET_DE_TEST["My ecarts"].values( Palier="Premier" )
1334     print
1335     print "Pas pour tag        :", OBJET_DE_TEST["My ecarts"].stepserie( Carte="IGN1" )
1336     print "Pas pour tag        :", OBJET_DE_TEST["My ecarts"].stepserie( Niveau=1024 )
1337     print "Pas pour tag        :", OBJET_DE_TEST["My ecarts"].stepserie( Camp="Base" )
1338     print "Pas pour tag        :", OBJET_DE_TEST["My ecarts"].stepserie( Camp="TOTO" )
1339     print "Pas pour tag        :", OBJET_DE_TEST["My ecarts"].stepserie( Toto="Premier" )
1340     print "Pas pour tag        :", OBJET_DE_TEST["My ecarts"].stepserie( Carte="IGN1" )
1341     print
1342     #import sys ; sys.exit()
1343     print "Attributs                 :", OBJET_DE_TEST["My ecarts"].tagserie()
1344     print "Attributs pour tag filtré :", OBJET_DE_TEST["My ecarts"].tagserie( Camp="Base" )
1345     print "Attributs pour tag filtré :", OBJET_DE_TEST["My ecarts"].tagserie( Niveau=4024 )
1346     print
1347     print "Attributs et valeurs                 :", OBJET_DE_TEST["My ecarts"].tagserie( withValues=True )
1348     print "Attributs et valeurs pour tag filtré :", OBJET_DE_TEST["My ecarts"].tagserie( withValues=True, Camp="Base" )
1349     print "Attributs et valeurs pour tag filtré :", OBJET_DE_TEST["My ecarts"].tagserie( withValues=True, Niveau=4024 )
1350     print
1351     print "Valeur d'attribut pour un tag donné 'BU'           :", OBJET_DE_TEST["My ecarts"].tagserie( outputTag = "Niveau" )
1352     print "Valeur d'attribut pour un tag donné 'BU' filtré    :", OBJET_DE_TEST["My ecarts"].tagserie( outputTag = "Niveau", Camp="Base" )
1353     print "Valeur d'attribut pour un tag donné 'BU' filtré    :", OBJET_DE_TEST["My ecarts"].tagserie( outputTag = "Niveau", Palier="Second" )
1354     print "Valeur d'attribut pour un tag donné 'Camp' filtré  :", OBJET_DE_TEST["My ecarts"].tagserie( outputTag = "Camp",   Palier="Premier" )
1355     print "Valeur d'attribut pour un tag donné 'Carte' filtré :", OBJET_DE_TEST["My ecarts"].tagserie( outputTag = "Carte",  Palier="Premier" )
1356     print "Valeur d'attribut pour un tag donné 'Carte' filtré :", OBJET_DE_TEST["My ecarts"].tagserie( outputTag = "Carte",  Palier="Premier", Niveau=4024 )
1357     print "Valeur d'attribut pour un tag donné 'Carte' filtré :", OBJET_DE_TEST["My ecarts"].tagserie( outputTag = "Carte",  Palier="Premier", Niveau=210 )
1358     print
1359
1360     print "======> Cas d'erreur"
1361     OBJET_DE_TEST = OneScalar("My float", unit="cm")
1362     OBJET_DE_TEST.store( 5., step="azerty")
1363     OBJET_DE_TEST.store(-5., step="poiuyt")
1364     OBJET_DE_TEST.store( 1., step="azerty")
1365     OBJET_DE_TEST.store( 0., step="xxxxxx")
1366     OBJET_DE_TEST.store( 5., step="poiuyt")
1367     OBJET_DE_TEST.store(-5., step="azerty")
1368     OBJET_DE_TEST.store( 1., step="poiuyt")
1369     print "Les pas de stockage :", OBJET_DE_TEST.stepserie()
1370     print "Les valeurs         :", OBJET_DE_TEST[:]
1371     print "La 2ème valeur      :", OBJET_DE_TEST[1]
1372     print "La dernière valeur  :", OBJET_DE_TEST[-1]
1373     print "Valeurs 'azerty'    :", OBJET_DE_TEST.values( step = "azerty" )
1374     print "Valeurs 'poiuyt'    :", OBJET_DE_TEST.values( step = "poiuyt" )
1375     print
1376     print "Nombre de valeurs   :", len(OBJET_DE_TEST)
1377     try:
1378         x = OBJET_DE_TEST[7]
1379         print "La 8ème valeur      :", x
1380     except IndexError, e:
1381         print "Erreur correcte     :",e
1382     try:
1383         x = OBJET_DE_TEST[7]
1384         print "La 8ème valeur      :", x
1385     except IndexError, e:
1386         print "Erreur correcte     :",e
1387     print
1388
1389     print "======> Impression d'objet Persistence"
1390     OBJET_DE_TEST = OneScalar("My float", unit="cm")
1391     OBJET_DE_TEST.store( 5., step="azerty")
1392     OBJET_DE_TEST.store(-5., step="poiuyt")
1393     OBJET_DE_TEST.store( 1., step="azerty")
1394     OBJET_DE_TEST.store( 0., step="xxxxxx")
1395     OBJET_DE_TEST.store( 5., step="poiuyt")
1396     OBJET_DE_TEST.store(-5., step="azerty")
1397     OBJET_DE_TEST.store( 1., step="poiuyt")
1398     print OBJET_DE_TEST
1399     print