]> SALOME platform Git repositories - tools/eficas.git/commitdiff
Salome HOME
Modifs avec la STA8.4 V1_11b3
authorPascale Noyret <pascale.noyret@edf.fr>
Wed, 29 Nov 2006 11:25:47 +0000 (11:25 +0000)
committerPascale Noyret <pascale.noyret@edf.fr>
Wed, 29 Nov 2006 11:25:47 +0000 (11:25 +0000)
Aster/Cata/Utilitai/Graph.py
Aster/Cata/Utilitai/Table.py
Aster/Cata/Utilitai/UniteAster.py
Aster/Cata/Utilitai/Utmess.py
Aster/Cata/Utilitai/sup_gmsh.py
Aster/Cata/Utilitai/t_fonction.py

index e4fa2a283d1cf4eb6e3243e55ec14f108799a6e5..6cc8ab3db2f6bf47a5f2c41e9912061fc10def88 100644 (file)
@@ -1,4 +1,4 @@
-#@ MODIF Graph Utilitai  DATE 24/05/2005   AUTEUR MCOURTOI M.COURTOIS 
+#@ MODIF Graph Utilitai  DATE 02/05/2006   AUTEUR MCOURTOI M.COURTOIS 
 # -*- coding: iso-8859-1 -*-
 #            CONFIGURATION MANAGEMENT OF EDF VERSION
 # ======================================================================
@@ -19,6 +19,7 @@
 # ======================================================================
 
 # RESPONSABLE MCOURTOI M.COURTOIS
+__all__ = ['Graph', 'AjoutParaCourbe']
 
 import sys
 import os
@@ -104,12 +105,12 @@ class Graph:
       self.Tri       = []
       self.Titre     = ''
       self.SousTitre = ''
-      self.Min_X     =  1.e+99
-      self.Max_X     = -1.e+99
-      self.Min_Y     =  1.e+99
+      self.Min_X     = None
+      self.Max_X     = None
+      self.Min_Y     = None
+      self.Max_Y     = None
       self.MinP_X    =  1.e+99   # minimum > 0 pour les échelles LOG
       self.MinP_Y    =  1.e+99
-      self.Max_Y     = -1.e+99
       self.Legende_X = ''
       self.Legende_Y = ''
       self.Echelle_X = 'LIN'
@@ -118,31 +119,56 @@ class Graph:
       self.Grille_Y  = -1
       # attributs que l'utilisateur ne doit pas modifier
       self.NbCourbe  = len(self.Valeurs)
-      self.BBXmin    = self.Min_X
-      self.BBXmax    = self.Max_X
-      self.BBYmin    = self.Min_Y
-      self.BBYmax    = self.Max_Y
+      self.BBXmin    =  1.e+99
+      self.BBXmax    = -1.e+99
+      self.BBYmin    =  1.e+99
+      self.BBYmax    = -1.e+99
       # pour conserver les paramètres du dernier tracé
       self.LastTraceArgs = {}
       self.LastTraceFormat = ''
-      return
+
 # ------------------------------------------------------------------------------
-   def SetExtrema(self,marge=0., x0=None, x1=None, y0=None, y1=None):
-      """Remplit les limites du tracé (Min/Max_X/Y) avec les valeurs de la
+   def SetExtremaX(self,marge=0., x0=None, x1=None, force=True):
+      """Remplit les limites du tracé (Min/Max_X) avec les valeurs de la
       bounding box +/- avec une 'marge'*(Max-Min)/2.
-      x0,x1,y0,y1 permettent de modifier la bb.
+      x0,x1 permettent de modifier la bb.
       """
       if x0<>None:   self.BBXmin=min([self.BBXmin, x0])
       if x1<>None:   self.BBXmax=max([self.BBXmax, x1])
+
+      dx=max(self.BBXmax-self.BBXmin,0.01*self.BBXmax)
+      if dx == 0.:
+         dx = 1.e-6
+      if force or self.Min_X==None:
+         self.Min_X = self.BBXmin - marge*dx/2.
+      if force or self.Max_X==None:
+         self.Max_X = self.BBXmax + marge*dx/2.
+      return
+
+   def SetExtremaY(self,marge=0., y0=None, y1=None, force=True):
+      """Remplit les limites du tracé (Min/Max_Y) avec les valeurs de la
+      bounding box +/- avec une 'marge'*(Max-Min)/2.
+      y0,y1 permettent de modifier la bb.
+      """
       if y0<>None:   self.BBYmin=min([self.BBYmin, y0])
       if y1<>None:   self.BBYmax=max([self.BBYmax, y1])
 
-      dx=max(self.BBXmax-self.BBXmin,0.01*self.BBXmax)
-      self.Min_X = self.BBXmin - marge*dx/2.
-      self.Max_X = self.BBXmax + marge*dx/2.
       dy=max(self.BBYmax-self.BBYmin,0.01*self.BBYmax)
-      self.Min_Y = self.BBYmin - marge*dy/2.
-      self.Max_Y = self.BBYmax + marge*dy/2.
+      if dy == 0.:
+         dy = 1.e-6
+      if force or self.Min_Y==None:
+         self.Min_Y = self.BBYmin - marge*dy/2.
+      if force or self.Max_Y==None:
+         self.Max_Y = self.BBYmax + marge*dy/2.
+      return
+
+   def SetExtrema(self,marge=0., x0=None, x1=None, y0=None, y1=None, force=True):
+      """Remplit les limites du tracé (Min/Max_X/Y) avec les valeurs de la
+      bounding box +/- avec une 'marge'*(Max-Min)/2.
+      x0,x1,y0,y1 permettent de modifier la bb.
+      """
+      self.SetExtremaX(marge, x0, x1, force=force)
+      self.SetExtremaY(marge, y0, y1, force=force)
       return
 # ------------------------------------------------------------------------------
    def AutoBB(self,debut=-1):
@@ -269,7 +295,7 @@ class Graph:
          if opts<>{}:
             kargs['opts']=opts
       if not FORMAT in para.keys():
-         print ' <A> <Objet Graph> Format inconnu : %s' % FORMAT
+         UTMESS('A', 'Objet Graph', 'Format inconnu : %s' % FORMAT)
       else:
          kargs['fmod']=para[FORMAT]['mode']
          self.LastTraceArgs   = kargs.copy()
@@ -333,12 +359,24 @@ class TraceGraph:
       # objet Graph sous-jacent
       self.Graph=graph
       # si Min/Max incohérents
-      if graph.Min_X > graph.Max_X or graph.Min_Y > graph.Max_Y:
-         graph.SetExtrema(marge=0.05)
-      if graph.Min_X < 0. and graph.Echelle_X=='LOG':
-         graph.Min_X=graph.MinP_X
-      if graph.Min_Y < 0. and graph.Echelle_Y=='LOG':
-         graph.Min_Y=graph.MinP_Y
+      if graph.Min_X==None or graph.Max_X==None or graph.Min_X > graph.Max_X:
+         graph.SetExtremaX(marge=0.05, force=True)
+      if graph.Min_Y==None or graph.Max_Y==None or graph.Min_Y > graph.Max_Y:
+         graph.SetExtremaY(marge=0.05, force=True)
+
+      if graph.Echelle_X=='LOG':
+         graph.Grille_X=10
+         # verif si Min<0 à cause de la marge
+         if graph.Min_X < 0.:
+            if graph.BBXmin < 0.:
+               UTMESS('A', 'Graph', 'On limite la fenetre aux abscisses positives.')
+            graph.Min_X=graph.MinP_X
+      if graph.Echelle_Y=='LOG':
+         graph.Grille_Y=10
+         if graph.Min_Y < 0.:
+            if graph.BBYmin < 0.:
+               UTMESS('A', 'Graph', 'On limite la fenetre aux ordonnées positives.')
+            graph.Min_Y=graph.MinP_Y
       
       # formats de base (identiques à ceux du module Table)
       self.DicForm={
@@ -355,7 +393,7 @@ class TraceGraph:
       
       # let's go
       self.Trace()
-      return
+
 # ------------------------------------------------------------------------------
    def __del__(self):
       """Fermeture du(des) fichier(s) à la destruction"""
@@ -380,19 +418,19 @@ class TraceGraph:
 # ------------------------------------------------------------------------------
    def Entete(self):
       """Retourne l'entete"""
-      raise StandardError, "Cette méthode doit etre définie par la classe fille."
+      raise NotImplementedError, "Cette méthode doit etre définie par la classe fille."
 # ------------------------------------------------------------------------------
    def DescrCourbe(self,**args):
       """Retourne la chaine de caractères décrivant les paramètres de la courbe.
       """
-      raise StandardError, "Cette méthode doit etre définie par la classe fille."
+      raise NotImplementedError, "Cette méthode doit etre définie par la classe fille."
 # ------------------------------------------------------------------------------
    def Trace(self):
       """Méthode pour 'tracer' l'objet Graph dans un fichier.
       Met en page l'entete, la description des courbes et les valeurs selon
       le format et ferme le fichier.
       """
-      raise StandardError, "Cette méthode doit etre définie par la classe fille."
+      raise NotImplementedError, "Cette méthode doit etre définie par la classe fille."
 
 
 # ------------------------------------------------------------------------------
@@ -420,12 +458,12 @@ class TraceTableau(TraceGraph):
          max0=max(abs(t0))
          for i in range(1,g.NbCourbe):
             if g.Courbe(i)['NbPts']<>g.Courbe(0)['NbPts']:
-               msg.append(" <A> <TraceTableau> La courbe %d n'a pas le meme " \
+               msg.append("La courbe %d n'a pas le meme " \
                      "nombre de points que la 1ère." % i)
             else:
                ti=Numeric.array(g.Courbe(i)['Abs'])
                if max(abs((ti-t0).flat)) > self.EPSILON*max0:
-                  msg.append(" <A> <TraceTableau> Courbe %d : écart entre les "\
+                  msg.append("Courbe %d : écart entre les "\
                         "abscisses supérieur à %9.2E" % (i+1,self.EPSILON))
                   msg.append("     Utilisez IMPR_FONCTION pour interpoler " \
                         "les valeurs sur la première liste d'abscisses.")
@@ -462,7 +500,7 @@ class TraceTableau(TraceGraph):
          Tab.Impr(FICHIER=self.NomFich[0], FORMAT='TABLEAU')
          # erreurs ?
          if msg:
-            print '\n'.join(msg)
+            UTMESS('A', 'Graph.TraceTableau', '\n'.join(msg))
       return
 
 # ------------------------------------------------------------------------------
@@ -796,23 +834,29 @@ class TraceXmgrace(TraceGraph):
       Met en page l'entete, la description des courbes et les valeurs selon
       le format et ferme le fichier.
       """
-      g=self.Graph
-      if self.PILOTE=='INTERACTIF':
-         self.NomFich[0]='Trace_'+time.strftime('%y%m%d%H%M%S',time.localtime())+'.dat'
-         self.Fich[0]=open(self.NomFich[0],'w')
+      g = self.Graph
+      if self.PILOTE == 'INTERACTIF':
+         self.NomFich[0] = 'Trace_%s.dat' % time.strftime('%y%m%d%H%M%S',time.localtime())
+         self.Fich[0] = open(self.NomFich[0],'w')
       # initialise le graph
       self._FermFich()
       nbsets, x0, x1, y0, y1 = IniGrace(self.NomFich[0])
       NumSetIni = nbsets+1
-      g.SetExtrema(0.05, x0, x1, y0, y1)
+      g.SetExtrema(0.05, x0, x1, y0, y1, force=False)
       # si Min/Max incohérents
-      if g.Min_X < 0. and g.Echelle_X=='LOG':
-         g.Min_X=g.MinP_X
-      if g.Min_Y < 0. and g.Echelle_Y=='LOG':
-         g.Min_Y=g.MinP_Y
+      if g.Echelle_X=='LOG':
+         g.Grille_X=10
+         if g.Min_X < 0.:
+            if g.BBXmin < 0.:
+               UTMESS('A', 'TraceXmgrace', 'On limite la fenetre aux abscisses positives.')
+            g.Min_X=g.MinP_X
+      if g.Echelle_Y=='LOG':
+         g.Grille_Y=10
+         if g.Min_Y < 0.:
+            if g.BBYmin < 0.:
+               UTMESS('A', 'TraceXmgrace', 'On limite la fenetre aux ordonnées positives.')
+            g.Min_Y=g.MinP_Y
       
-      self._OuvrFich()
-      fich=self.Fich[0]
       if g.NbCourbe < 1:
          self._FermFich()
          return
@@ -826,9 +870,13 @@ class TraceXmgrace(TraceGraph):
             g.Grille_X=int(round(g.Grille_X))
          if deltaY>4:
             g.Grille_Y=int(round(g.Grille_Y))
+         if g.Grille_X == 0.:
+            g.Grille_X = 1.e-6
+         if g.Grille_Y == 0.:
+            g.Grille_Y = 1.e-6
       # entete
-      fich.write('\n'.join(self.Entete()))
-      fich.write('\n')
+      content = self.Entete()
+      content.append('')
       # valeurs
       it=-1
       for i in range(g.NbCourbe):
@@ -836,62 +884,66 @@ class TraceXmgrace(TraceGraph):
          for k in range(dCi['NbCol']-1):
             it=it+1
             dCi['NumSet'] = NumSetIni + it
-            fich.write('\n'.join(self.DescrCourbe(**dCi)))
-            fich.write('\n')
+            content.extend(self.DescrCourbe(**dCi))
+            content.append('')
       # partie données (.dat)
-      lig=[]
       it=-1
       for i in range(g.NbCourbe):
          dCi=g.Courbe(i)
          for k in range(dCi['NbCol']-1):
             it=it+1
-            lig.append('@target g0.s%d' % (NumSetIni + it))
-            lig.append('@type xy')
+            content.append('@target g0.s%d' % (NumSetIni + it))
+            content.append('@type xy')
             listX, listY = Tri(g.Tri, lx=dCi['Abs'], ly=dCi['Ord'][k])
             for j in range(dCi['NbPts']):
-               svX=self.DicForm['formR'] % listX[j]
-               svY=self.DicForm['formR'] % listY[j]
-               lig.append(self.DicForm['formR'] % listX[j] + \
+               svX = self.DicForm['formR'] % listX[j]
+               svY = self.DicForm['formR'] % listY[j]
+               content.append(self.DicForm['formR'] % listX[j] + \
                   ' ' + self.DicForm['formR'] % listY[j])
-            lig.append('&')
-      fich.write('\n'.join(lig))
-      fich.write('\n')
-      self._FermFich()
+            content.append('&')
+      content.append('')
       
       # Production du fichier postscript, jpeg ou lancement interactif
       pilo=self.PILOTE
-      if self.PILOTE<>'':
+      if pilo == '':
+         self._OuvrFich()
+         self.Fich[0].write('\n'.join(content))
+         self._FermFich()
+      else:
          xmgr=os.path.join(aster.repout(),'xmgrace')
-         nfhard=self.NomFich[0]+'.hardcopy'
+         nfwrk = self.NomFich[0]+'.wrk'
+         open(nfwrk, 'w').write('\n'.join(content))
+         nfhard = self.NomFich[0]+'.hardcopy'
          # nom exact du pilote
-         if pilo=='POSTSCRIPT':
-            pilo='PostScript'
-         elif pilo=='INTERACTIF':
-            pilo='X11'
+         if pilo == 'POSTSCRIPT':
+            pilo = 'PostScript'
+         elif pilo == 'INTERACTIF':
+            pilo = 'X11'
          # ligne de commande
-         if pilo=='X11':
-            lcmde=xmgr+' '+self.NomFich[0]
+         if pilo == 'X11':
+            lcmde = '%s %s' % (xmgr, nfwrk)
             if not os.environ.has_key('DISPLAY') or os.environ['DISPLAY']=='':
                os.environ['DISPLAY']=':0.0'
                UTMESS('A','TraceXmgrace','Variable DISPLAY non définie')
             UTMESS('I','TraceXmgrace','on fixe le DISPLAY à %s' % os.environ['DISPLAY'])
          else:
             if os.path.exists(os.path.join(aster.repout(),'gracebat')):
-               xmgr=os.path.join(aster.repout(),'gracebat')
-            lcmde=xmgr+' -hdevice '+pilo+' -hardcopy -printfile '+nfhard+' '+self.NomFich[0]
+               xmgr = os.path.join(aster.repout(),'gracebat')
+            lcmde = '%s -hdevice %s -hardcopy -printfile %s %s' % (xmgr, pilo, nfhard, nfwrk)
          # appel xmgrace
          UTMESS('I','TraceXmgrace','Lancement de : '+lcmde)
          if not os.path.exists(xmgr):
             UTMESS('S','TraceXmgrace','Fichier inexistant : '+xmgr)
-         iret=os.system(lcmde)
-         if iret==0 or os.path.exists(nfhard):
-            if pilo not in ['','X11']:
-               os.remove(self.NomFich[0])             # necessaire sous windows
-               os.rename(nfhard,self.NomFich[0])
+         iret = os.system(lcmde)
+         if iret == 0 or os.path.exists(nfhard):
+            if pilo not in ('', 'X11'):
+               new = open(nfhard, 'r').read()
+               open(self.NomFich[0], 'a').write(new)
          else:
-            UTMESS('A','TraceXmgrace',"Erreur lors de l'utilisation du filtre "+pilo+"\nLe fichier retourné est le fichier '.agr'")
+            UTMESS('A','TraceXmgrace', "Erreur lors de l'utilisation du filtre %s" \
+                  "\nLe fichier retourné est le fichier '.agr'" % pilo)
       # menage
-      if self.PILOTE=='INTERACTIF':
+      if self.PILOTE == 'INTERACTIF':
          os.remove(self.NomFich[0])
       return
 
@@ -1142,10 +1194,14 @@ def IniGrace(fich):
             fnew.write(line)
       fpre.close()
       fnew.close()
-      print """
+      try:
+         UTMESS('I', 'Graph.IniGrace', """
    <I> Informations sur le fichier '%s' :
       Nombre de courbes    : %3d
       Bornes des abscisses : [ %13.6G , %13.6G ]
       Bornes des ordonnées : [ %13.6G , %13.6G ]
-""" % (fich, ns, x0, x1, y0, y1)
+""" % (fich, ns, x0, x1, y0, y1))
+      except TypeError:
+         # pas un format xmgrace
+         pass
    return ns, x0, x1, y0, y1
index b923acf37f64b393c116b4a1b88037e718b08547..9ad24144d8dc35f47ffae7540985a034500d82e7 100644 (file)
@@ -1,4 +1,4 @@
-#@ MODIF Table Utilitai  DATE 17/05/2005   AUTEUR DURAND C.DURAND 
+#@ MODIF Table Utilitai  DATE 06/11/2006   AUTEUR MCOURTOI M.COURTOIS 
 # -*- coding: iso-8859-1 -*-
 #            CONFIGURATION MANAGEMENT OF EDF VERSION
 # ======================================================================
 # ======================================================================
 
 # RESPONSABLE MCOURTOI M.COURTOIS
+__all__ = ['Table', 'merge']
 
 import sys
-import string
 import re
+from copy  import copy
 
-from types import *
-EnumTypes=(ListType, TupleType)
-NumberTypes=(IntType, LongType, FloatType, ComplexType)
+from types import ListType, TupleType, IntType, LongType, FloatType, ComplexType, \
+                  DictType, StringType, StringTypes, UnicodeType, NoneType
+EnumTypes = (ListType, TupleType)
+NumberTypes = (IntType, LongType, FloatType, ComplexType)
+
+import transpose
 
 # try/except pour utiliser hors aster
 try:
    from Utilitai.Utmess import UTMESS
 except ImportError:
    def UTMESS(code,sprg,texte):
-      fmt='\n <%s> <%s> %s\n\n'
-      print fmt % (code,sprg,texte)
+      fmt = '\n <%s> <%s> %s\n\n'
+      if code == 'F':
+         raise StandardError, fmt % (code,sprg,texte)
+      else:
+         print fmt % (code,sprg,texte)
 
 if not sys.modules.has_key('Graph'):
    try:
@@ -43,15 +50,18 @@ if not sys.modules.has_key('Graph'):
       import Graph
 
 # formats de base (identiques à ceux du module Graph)
-DicForm={
+DicForm = {
    'csep'  : ' ',       # séparateur
    'ccom'  : '#',       # commentaire
    'cdeb'  : '',        # début de ligne
    'cfin'  : '\n',      # fin de ligne
+   'sepch' : ';',       # séparateur entre deux lignes d'une cellule
    'formK' : '%-8s',    # chaines
    'formR' : '%12.5E',  # réels
    'formI' : '%8d'      # entiers
 }
+# type par défaut des chaines de caractères
+Kdef = 'K24'
 
 # ------------------------------------------------------------------------------
 # ------------------------------------------------------------------------------
@@ -61,13 +71,26 @@ class TableBase(object):
    (c'est surtout utile pour vérifier que l'extraction et les filtres sur les
    colonnes sont corrects).
    """
+   def __init__(self):
+      """Constructeur.
+      """
+      self.rows=None
+      self.para=None
+      self.type=None
+      self.titr=None
+   
    def __repr__(self):
       return self.ReprTable()
-   def Croise(self,**kargs):
-      raise StandardError, 'Must be defined in a derived class'
+   def Croise(self, **kargs):
+      raise NotImplementedError, 'Must be defined in a derived class'
+
+   def __len__(self):
+      """Retourne le nombre de ligne dans la Table/Colonne.
+      """
+      return len(self.rows)
 
 # ------------------------------------------------------------------------------
-   def Impr(self,FICHIER=None,FORMAT='TABLEAU',dform=None,**opts):
+   def Impr(self, FICHIER=None, FORMAT='TABLEAU', dform=None, **opts):
       """Impresssion de la Table selon le format spécifié.
          FICHIER : nom du(des) fichier(s). Si None, on dirige vers stdout
          dform : dictionnaire de formats d'impression (format des réels,
@@ -87,7 +110,7 @@ class TableBase(object):
          'dform'     : DicForm.copy(),
          'mode'      : para[FORMAT]['mode'],
       }
-      if dform<>None and type(dform)==DictType:
+      if dform != None and type(dform) == DictType:
          kargs['dform'].update(dform)
       # ajout des options
       kargs.update(opts)
@@ -98,36 +121,36 @@ class TableBase(object):
 
       else:
          if not type(kargs['PAGINATION']) in EnumTypes:
-            ppag=[kargs['PAGINATION'],]
+            ppag = [kargs['PAGINATION'],]
          else:
-            ppag=list(kargs['PAGINATION'])
+            ppag = list(kargs['PAGINATION'])
          del kargs['PAGINATION']
-         npag=len(ppag)
+         npag = len(ppag)
          # paramètres hors ceux de la pagination
-         lkeep=[p for p in self.para if ppag.count(p)==0]
+         lkeep = [p for p in self.para if ppag.count(p)==0]
          # création des listes des valeurs distinctes
-         lvd=[]
+         lvd = []
          for p in ppag:
-            lvp=getattr(self,p).values()
-            lvn=[]
+            lvp = getattr(self,p).values()
+            lvn = []
             for it in lvp:
-               if it<>None and lvn.count(it)==0:
+               if it != None and lvn.count(it) == 0:
                   lvn.append(it)
             lvn.sort()
             lvd.append(lvn)
          # création des n-uplets
-         s = '[['+','.join(['x'+str(i) for i in range(npag)])+'] '
-         s+= ' '.join(['for x'+str(i)+' in lvd['+str(i)+']' for i in range(npag)])+']'
+         s  = '[['+','.join(['x'+str(i) for i in range(npag)])+'] '
+         s += ' '.join(['for x'+str(i)+' in lvd['+str(i)+']' for i in range(npag)])+']'
          try:
-            lnup=eval(s)
+            lnup = eval(s)
          except SyntaxError, s:
             UTMESS('F','Table','Erreur lors de la construction des n-uplets')
          # pour chaque n-uplet, on imprime la sous-table
          for nup in lnup:
-            tab=self
+            tab = self
             for i in range(npag):
                tab = tab & (getattr(tab,ppag[i]) == nup[i])
-               sl=''
+               sl = ''
                if tab.titr: sl='\n'
                tab.titr += sl+ppag[i]+': '+str(nup[i])
             tab[lkeep].Impr(**kargs)
@@ -147,7 +170,8 @@ class TableBase(object):
       if kargs.get('FICHIER')<>None:
          f.close()
 
-   def ReprTable(self,FORMAT='TABLEAU',dform=DicForm,**ignore):
+# ------------------------------------------------------------------------------
+   def ReprTable(self,FORMAT='TABLEAU',dform=None,**ignore):
       """Représentation d'une Table ou d'une Colonne sous forme d'un tableau.
       """
       rows=self.rows
@@ -156,6 +180,8 @@ class TableBase(object):
       if not type(para) in EnumTypes:
          para=[self.para,]
          typ =[self.type,]
+      if dform==None:
+         dform = DicForm.copy()
       # est-ce que l'attribut .type est renseigné ?
       typdef=typ<>[None]*len(typ)
       txt=[]
@@ -172,9 +198,9 @@ class TableBase(object):
       if typdef:
          stype=dform['csep'].join([''] + \
           [FMT(dform,'formK',typ[i],lmax[i]) % typ[i] for i in range(len(para))])
-      txt.append('')
-      txt.append('-'*80)
-      txt.append('')
+      txt.append(dform['ccom'])
+      txt.append(dform['ccom']+'-'*80)
+      txt.append(dform['ccom'])
       ASTER=(FORMAT=='ASTER')
       if ASTER:
          txt.append('#DEBUT_TABLE')
@@ -182,7 +208,7 @@ class TableBase(object):
          if ASTER:
             txt.extend(['#TITRE '+lig for lig in self.titr.split('\n')])
          else:
-            txt.append(self.titr)
+            txt.extend([dform['ccom']+lig for lig in self.titr.split('\n')])
       txt.append(dform['csep'].join(lspa))
       if ASTER and typdef:
          txt.append(stype)
@@ -196,7 +222,7 @@ class TableBase(object):
             if type(rep) is FloatType:
                lig.append(FMT(dform,'formR',t,lmax[i]) % rep)
                empty=False
-            elif type(rep) is IntType:
+            elif type(rep) in (IntType, LongType):
                lig.append(FMT(dform,'formI',t,lmax[i]) % rep)
                empty=False
             else:
@@ -210,9 +236,14 @@ class TableBase(object):
                   s='\\'+s
                lig.append(s)
          if not empty:
-            txt.append(dform['csep'].join(lig))
+            lig2 = [dform['sepch'].join(ch.splitlines()) for ch in lig]
+            txt.append(dform['csep'].join(lig2))
       if ASTER:
          txt.append('#FIN_TABLE')
+      # ajout du debut de ligne
+      if dform['cdeb']<>'':
+         txt=[dform['cdeb']+t for t in txt]
+
       return dform['cfin'].join(txt)
 # ------------------------------------------------------------------------------
    def ImprTabCroise(self,**kargs):
@@ -223,19 +254,23 @@ class TableBase(object):
       kargs['FORMAT']='TABLEAU'
       tabc.Impr(**kargs)
 # ------------------------------------------------------------------------------
-   def ImprGraph(self,**kargs):
+   def ImprGraph(self, **kargs):
       """Impression au format XMGRACE : via le module Graph
       """
       args=kargs.copy()
-      if len(self.para)<>2:
-         UTMESS('A','Table','La table doit avoir exactement deux paramètres.')
+      if len(self.para) != 2:
+         UTMESS('A','Table','La table doit avoir exactement deux paramètres '\
+                'pour une impression au format XMGRACE.')
          return
-      lx, ly = [[v for v in getattr(self,p).values() if v<>None] for p in self.para]
+      # suppression des lignes contenant une cellule vide
+      tnv = getattr(self, self.para[0]).NON_VIDE() \
+          & getattr(self, self.para[1]).NON_VIDE()
       # objet Graph
       graph=Graph.Graph()
       dicC={
-         'Val' : [lx, ly],
-         'Lab' : self.para,
+         'Val' : [getattr(tnv, tnv.para[0]).values(),
+                  getattr(tnv, tnv.para[1]).values()],
+         'Lab' : tnv.para,
       }
       if args['LEGENDE']==None: del args['LEGENDE']
       Graph.AjoutParaCourbe(dicC, args)
@@ -285,6 +320,7 @@ class Table(TableBase):
    t.a retourne un objet intermédiaire de la classe Colonne qui mémorise
    le nom de la colonne demandée (a, ici).
    """
+# ------------------------------------------------------------------------------
    def __init__(self, rows=[], para=[], typ=[], titr=''):
       """Constructeur de la Table :
          rows : liste des lignes (dict)
@@ -292,22 +328,124 @@ class Table(TableBase):
          type : liste des types des paramètres
          titr : titre de la table
       """
-      self.rows=[r for r in rows if r.values()<>[None]*len(r.values())]
-      self.para=list(para)
-      if len(typ)==len(self.para):
-         self.type=list(typ)
+      self.rows = [r for r in rows if r.values() != [None]*len(r.values())]
+      self.para = list(para)
+      for i in self.para :
+          if self.para.count(i) != 1 :
+             UTMESS('F','Table','Parametre en double: %s' %i)
+      if len(typ) == len(self.para):
+         self.type = list(typ)
       else:
-         self.type=[None]*len(self.para)
-      self.titr=titr
+         self.type = [None]*len(self.para)
+      self.titr = titr
+   
+# ------------------------------------------------------------------------------
+   def copy(self):
+      """Retourne une copie de la table.
+      """
+      rows = []
+      for r in self.rows:
+         rows.append(copy(r))
+      return Table(rows, self.para[:], self.type[:], self.titr)
 
+# ------------------------------------------------------------------------------
    def append(self, obj):
-      """Ajoute une ligne (type dict) à la Table"""
+      """Ajoute une ligne (type dict) qui peut éventuellement définir un
+      nouveau paramètre."""
+      para=obj.keys()
+      for p in para:
+         if not p in self.para:
+            self.para.append(p)
+            self.type.append(_typaster(obj[p]))
+         else:
+            ip=self.para.index(p)
+            self.type[ip]=_typaster(obj[p], self.type[ip])
       self.rows.append(obj)
 
+# ------------------------------------------------------------------------------
+   def SansColonneVide(self):
+      """Retourne une copie de la table dans laquelle on a supprimé les colonnes
+      vides (les lignes vides sont automatiquement supprimées).
+      """
+      tab = self.copy()
+      lp = tab.para[:]
+      for para in lp:
+         if len(tab[para]) == 0:
+            bid = lp.pop(0)
+      return tab[lp]
+
+# ------------------------------------------------------------------------------
+   def __setitem__(self, k_para, k_value):
+      """Ajoute une colonne k_para dont les valeurs sont dans k_value"""
+      if len(k_value)==0:
+         return
+      if k_para in self.para :
+         UTMESS('F','Table','(setitem) Le parametre %s existe déjà.' % k_para)
+      self.para.append(k_para)
+      self.type.append(_typaster(k_value[0]))
+      i=0
+      for row in self:
+         if i<len(k_value):
+            row[k_para]=k_value[i]
+            self.type[-1]=_typaster(k_value[i], self.type[-1])
+         else:
+            row[k_para]=None
+         i+=1
+      for j in range(i,len(k_value)): 
+         self.append({k_para:k_value[j]})
+
+# ------------------------------------------------------------------------------
+   def fromfunction(self, nom_para, funct, l_para=None, const=None):
+      """Ajoute une colonne `nom_para` en évaluant la fonction `funct` sur
+      la valeur des paramètres `l_para` (qui doivent exister dans la table).
+      Si `l_para` n'est pas fourni, on prend `funct`.nompar (FORMULE Aster).
+      On peut passer un dictionnaire de constantes dans `const`. Quand on
+      utilise une FORMULE Aster, les constantes sont prises dans le contexte
+      global.
+      """
+      # vérif préalables
+      if not hasattr(funct, '__call__'):
+         UTMESS('F', 'Table', "(fromfunction) '%s' n'a pas d'attribut '__call__'." \
+            % funct.__name__)
+      if nom_para in self.para :
+         UTMESS('F','Table','Le parametre %s existe déjà.' % nom_para)
+      if l_para == None:
+         if not hasattr(funct, 'nompar'):
+            UTMESS('F', 'Table', "(fromfunction) '%s' n'a pas d'attribut 'nompar'." \
+               % funct.__name__)
+         l_para = funct.nompar
+      if not type(l_para) in EnumTypes:
+         l_para = [l_para]
+      not_found = ', '.join([p for p in l_para if not p in self.para])
+      if not_found != '':
+         UTMESS('F','Table','Parametre(s) absent(s) de la table : %s' % not_found)
+      if const == None:
+         const = {}
+      if type(const) is not DictType:
+         UTMESS('F', 'Table', "L'argument 'const' doit etre de type 'dict'.")
+      # liste des valeurs des paramètres
+      tabpar = []
+      for para in l_para:
+         vals = getattr(self, para).values()
+         tabpar.append(vals)
+      tabpar = transpose.transpose(tabpar)
+      # évaluation de la fonction sur ces paramètres
+      vectval = []
+      for lpar in tabpar:
+         # si un paramètre est absent, on ne peut pas évaluer la formule
+         if None in lpar:
+            vectval.append(None)
+         else:
+            vectval.append(funct(*lpar, **const))
+      # ajout de la colonne
+      self[nom_para] = vectval
+
+# ------------------------------------------------------------------------------
    def __iter__(self):
       """Itère sur les lignes de la Table"""
       return iter(self.rows)
 
+# ------------------------------------------------------------------------------
    def __getattr__(self, column):
       """Construit un objet intermediaire (couple table, colonne)"""
       typ=None
@@ -317,39 +455,29 @@ class Table(TableBase):
          typ=self.type[self.para.index(column)]
       return Colonne(self, column, typ)
 
+# ------------------------------------------------------------------------------
    def sort(self, CLES=None, ORDRE='CROISSANT'):
       """Tri de la table.
          CLES  : liste des clés de tri
-         ORDRE : CROISSANT ou DECROISSANT (de longueur 1 ou len(keys))
+         ORDRE : CROISSANT ou DECROISSANT
       """
       # par défaut, on prend tous les paramètres
-      if CLES==None:
-         CLES=self.para[:]
+      if CLES == None:
+         CLES = self.para[:]
+      # vérification des arguments
       if not type(CLES) in EnumTypes:
-         CLES=[CLES,]
+         CLES = [CLES]
       else:
-         CLES=list(CLES)
-      self.rows=sort_table(self.rows, self.para, CLES, (ORDRE=='DECROISSANT'))
-#       if not type(order) in EnumTypes:
-#          order=[order,]
-#       print 'TRI clés=%s, order=%s' % (keys,order)
-#       # on ne garde que le premier si les longueurs sont différentes
-#       if len(order)<>len(keys):
-#          order=[order[0],]
-#       else:
-#          # si toutes les valeurs sont identiques, on peut ne garder que la 1ère
-#          d={}
-#          for o in order: d[o]=None
-#          if len(order)<>len(keys) or len(d.keys())==1:
-#             order=[order[0],]
-#       if len(order)==1:
-#          self.rows=sort_table(self.rows, self.para, keys, (order[0]=='DECROISSANT'))
-#       else:
-#          # de la dernière clé à la première
-#          for k,o in [(keys[i],order[i]) for i in range(len(keys)-1,-1,-1)]:
-#             print 'TRI : clé=%s, order=%s' % (k,o)
-#             self.rows=sort_table(self.rows, self.para, [k], (o=='DECROISSANT'))
+         CLES = list(CLES)
+      not_found = ', '.join([p for p in CLES if not p in self.para])
+      if not_found != '':
+         UTMESS('F', 'Table', 'Parametre(s) absent(s) de la table : %s' % not_found)
+      if not ORDRE in ('CROISSANT', 'DECROISSANT'):
+         UTMESS('F', 'Table', 'Valeur incorrecte pour ORDRE : %s' % ORDRE)
+      # tri
+      self.rows = sort_table(self.rows, self.para, CLES, (ORDRE=='DECROISSANT'))
 
+# ------------------------------------------------------------------------------
    def __delitem__(self, args):
       """Supprime les colonnes correspondantes aux éléments de args """
       if not type(args) in EnumTypes:
@@ -360,16 +488,17 @@ class Table(TableBase):
       for item in args:
          del new_type[new_para.index(item)]
          new_para.remove(item)
-         for line in new_rows : del line[item] 
+         for line in new_rows:
+            del line[item] 
       return Table(new_rows, new_para, new_type, self.titr)
 
+# ------------------------------------------------------------------------------
    def __getitem__(self, args):
       """Extrait la sous table composée des colonnes dont les paramètres sont dans args """
       if not type(args) in EnumTypes:
          args=[args,]
       else:
          args=list(args)
-      #print '<getitem> args=',args
       new_rows=[]
       new_para=args
       new_type=[]
@@ -384,6 +513,7 @@ class Table(TableBase):
          new_rows.append(new_line)
       return Table(new_rows, new_para, new_type, self.titr)
 
+# ------------------------------------------------------------------------------
    def __and__(self, other):
       """Intersection de deux tables (opérateur &)"""
       if other.para<>self.para:
@@ -393,6 +523,7 @@ class Table(TableBase):
          tmp = [ r for r in self if r in other.rows ]
          return Table(tmp, self.para, self.type, self.titr)
 
+# ------------------------------------------------------------------------------
    def __or__(self, other):
       """Union de deux tables (opérateur |)"""
       if other.para<>self.para:
@@ -403,6 +534,7 @@ class Table(TableBase):
          tmp.extend([ r for r in other if r not in self ])
          return Table(tmp, self.para, self.type[:], self.titr)
 
+# ------------------------------------------------------------------------------
    def values(self):
       """Renvoie la table sous la forme d'un dictionnaire de listes dont les
       clés sont les paramètres.
@@ -412,25 +544,67 @@ class Table(TableBase):
          dico[column]=Colonne(self, column).values()
       return dico
 
+# ------------------------------------------------------------------------------
+   def dict_CREA_TABLE(self):
+      """Renvoie le dictionnaire des mots-clés à fournir à la commande CREA_TABLE
+      pour produire une table_sdaster.
+      """
+      dico={ 'TITRE' : ['%-80s' % lig for lig in self.titr.split('\n')],
+             'LISTE' : [], }
+      # remplissage de chaque occurence (pour chaque paramètre) du mot-clé facteur LISTE
+      for i in range(len(self.para)):
+         # nom du paramètre et type si K*
+         d={ 'PARA' : self.para[i], }
+         typ=self.type[i]
+         if typ==None:
+            UTMESS('F', 'Table', 'Type du paramètre %s non défini.' %\
+                   self.para[i])
+         elif typ[0]=='K':
+            mc='LISTE_K'
+            if not typ in ('K8', 'K16', 'K24'):
+               UTMESS('A','Table','Type du paramètre %s forcé à %s' % (self.para[i],Kdef))
+               typ=Kdef
+            d['TYPE_K']=typ
+         elif typ=='I':
+            mc='LISTE_I'
+         elif typ=='R':
+            mc='LISTE_R'
+         # valeurs sans trou / avec trou
+         vals=getattr(self, self.para[i]).values()
+         if vals.count(None)==0:
+            d[mc]=vals
+         else:
+            d['NUME_LIGN'] = [j+1 for j in range(len(vals)) if vals[j]<>None]
+            d[mc]          = [v   for v in vals             if v      <>None]
+         if len(d[mc])==0:
+            UTMESS('I','Table','Colonne %s vide' % self.para[i])
+         else:
+            dico['LISTE'].append(d)
+      if len(dico['LISTE'])==0:
+         UTMESS('F','Table','La table est vide')
+      return dico
+
+# ------------------------------------------------------------------------------
    def Array(self,Para,Champ):
       """Renvoie sous forme de NumArray le résultat d'une extraction dans une table
       méthode utile à macr_recal
       """
       import Numeric
       __Rep = self[Para,Champ].values()
-      F=Numeric.zeros((len(__Rep[Para]),2),Numeric.Float)
+      F = Numeric.zeros((len(__Rep[Para]),2), Numeric.Float)
       for i in range(len(__Rep[Para])):
-       F[i][0] = __Rep[Para][i]
-       F[i][1] = __Rep[Champ][i]
+         F[i][0] = __Rep[Para][i]
+         F[i][1] = __Rep[Champ][i]
       del(__Rep)
       return F
 
+# ------------------------------------------------------------------------------
    def Croise(self):
       """Retourne un tableau croisé P3(P1,P2) à partir d'une table ayant
       trois paramètres (P1, P2, P3).
       """
       if len(self.para)<>3:
-         UTMESS('A','Table','La table doit avoir exactement trois paramètres.')
+         UTMESS('A', 'Table', 'La table doit avoir exactement trois paramètres.')
          return Table()
       py, px, pz = self.para
       ly, lx, lz = [getattr(self,p).values() for p in self.para]
@@ -459,6 +633,20 @@ class Table(TableBase):
       new_titr+=pz + ' FONCTION DE ' + px + ' ET ' + py
       return Table(new_rows, new_para, new_type, new_titr)
 
+# ------------------------------------------------------------------------------
+   def Renomme(self, pold, pnew):
+      """Renomme le paramètre `pold` en `pnew`.
+      """
+      if not pold in self.para:
+         raise KeyError, 'Paramètre %s inexistant dans cette table' % pold
+      elif self.para.count(pnew)>0:
+         raise KeyError, 'Le paramètre %s existe déjà dans la table' % pnew
+      else:
+         self.para[self.para.index(pold)] = pnew
+         for lig in self:
+            lig[pnew] = lig[pold]
+            del lig[pold]
+
 # ------------------------------------------------------------------------------
 # ------------------------------------------------------------------------------
 # ------------------------------------------------------------------------------
@@ -469,13 +657,14 @@ class Colonne(TableBase):
    Alors on peut écrire la requete simple :
      soustable=t.a<10
    Ainsi que des requetes plus complexes :
-     soustable=t.a<10 & t.b <4
+     soustable=t.a<10 and t.b <4
    ou
-     soustable=t.a<10 | t.b <4
+     soustable=t.a<10 or t.b <4
    Les "alias" EQ, NE, LE, LT, GE, GT permettent à la macro IMPR_TABLE
    d'utiliser directement le mot-clé utilisateur CRIT_COMP défini dans le
    catalogue : getattr(Table,CRIT_COMP).
    """
+# ------------------------------------------------------------------------------
    def __init__(self, table, column, typ=None):
       """Constructeur (objet Table associé, paramètre de la colonne, type du
       paramètre).
@@ -486,6 +675,7 @@ class Colonne(TableBase):
       self.type=typ
       self.titr=''
 
+# ------------------------------------------------------------------------------
    def _extract(self, fun):
       """Construit une table avec les lignes de self.Table 
          dont l'élément de nom self.para satisfait le critère fun,
@@ -493,18 +683,23 @@ class Colonne(TableBase):
       """
       return Table([row for row in self.Table if fun(row.get(self.para))], self.Table.para, self.Table.type, self.Table.titr)
 
+# ------------------------------------------------------------------------------
    def __le__(self, VALE):
       return self._extract(lambda v: v<>None and v<=VALE)
 
+# ------------------------------------------------------------------------------
    def __lt__(self, VALE):
       return self._extract(lambda v: v<>None and v<VALE)
 
+# ------------------------------------------------------------------------------
    def __ge__(self, VALE):
       return self._extract(lambda v: v<>None and v>=VALE)
 
+# ------------------------------------------------------------------------------
    def __gt__(self, VALE):
       return self._extract(lambda v: v<>None and v>VALE)
 
+# ------------------------------------------------------------------------------
    def __eq__(self, VALE, CRITERE='RELATIF', PRECISION=0.):
       if type(VALE) in EnumTypes :
          return self._extract(lambda v: v in VALE)
@@ -522,6 +717,16 @@ class Colonne(TableBase):
             vmax=(1.+PRECISION)*VALE
          return self._extract(lambda v: v<>None and vmin<v<vmax)
 
+# ------------------------------------------------------------------------------
+   def REGEXP(self, regexp):
+      """Retient les lignes dont le paramètre satisfait l'expression
+      régulière `regexp`.
+      """
+      if not type(regexp) in StringTypes:
+         return self._extract(lambda v : False)
+      return self._extract(lambda v : v != None and re.search(regexp, v) != None)
+
+# ------------------------------------------------------------------------------
    def __ne__(self, VALE, CRITERE='RELATIF', PRECISION=0.):
       if type(VALE) in EnumTypes :
          return self._extract(lambda v: v not in VALE)
@@ -539,27 +744,32 @@ class Colonne(TableBase):
             vmax=(1.+PRECISION)*VALE
          return self._extract(lambda v: v<>None and (v<vmin or vmax<v))
 
+# ------------------------------------------------------------------------------
    def MAXI(self):
       # important pour les performances de récupérer le max une fois pour toutes
       maxi=max(self)
       return self._extract(lambda v: v==maxi)
 
+# ------------------------------------------------------------------------------
    def MINI(self):
       # important pour les performances de récupérer le min une fois pour toutes
       mini=min(self)
       return self._extract(lambda v: v==mini)
 
+# ------------------------------------------------------------------------------
    def ABS_MAXI(self):
       # important pour les performances de récupérer le max une fois pour toutes
       abs_maxi=max([abs(v) for v in self.values() if type(v) in NumberTypes])
       return self._extract(lambda v: v==abs_maxi or v==-abs_maxi)
 
+# ------------------------------------------------------------------------------
    def ABS_MINI(self):
       # important pour les performances de récupérer le min une fois pour toutes
       abs_mini=min([abs(v) for v in self.values() if type(v) in NumberTypes])
       # tester le type de v est trop long donc pas de abs(v)
       return self._extract(lambda v: v==abs_mini or v==-abs_mini)
 
+# ------------------------------------------------------------------------------
    def __iter__(self):
       """Itère sur les éléments de la colonne"""
       for row in self.Table:
@@ -567,14 +777,21 @@ class Colonne(TableBase):
          yield row.get(self.para)
          #yield row[self.para]
 
+# ------------------------------------------------------------------------------
    def __getitem__(self, i):
       """Retourne la ième valeur d'une colonne"""
       return self.values()[i]
 
+# ------------------------------------------------------------------------------
    def values(self):
       """Renvoie la liste des valeurs"""
-      return [r[self.para] for r in self.Table]
+      return [r.get(self.para,None) for r in self.Table]
+
+   def not_none_values(self):
+      """Renvoie la liste des valeurs non 'None'"""
+      return [val for val in self.values() if val != None]
 
+# ------------------------------------------------------------------------------
    # équivalences avec les opérateurs dans Aster
    LE=__le__
    LT=__lt__
@@ -582,13 +799,15 @@ class Colonne(TableBase):
    GT=__gt__
    EQ=__eq__
    NE=__ne__
-   def VIDE(self)    : return self.__eq__(None)
-   def NON_VIDE(self): return self.__ne__(None)
+   def VIDE(self):
+      return self.__eq__(None)
+   def NON_VIDE(self):
+      return self.__ne__(None)
 
 # ------------------------------------------------------------------------------
 # ------------------------------------------------------------------------------
 # ------------------------------------------------------------------------------
-def sort_table(rows,l_para,w_para,reverse=False):
+def sort_table(rows, l_para, w_para, reverse=False):
    """Sort list of dict.
       rows     : list of dict
       l_para   : list of the keys of dict
@@ -596,17 +815,23 @@ def sort_table(rows,l_para,w_para,reverse=False):
    """
    c_para=[i for i in l_para if i not in w_para]
    new_rows=rows
+   # rename sort keys by "__" + number + para
+   # ("__" to avoid conflict with existing parameters)
    for i in w_para :
       new_key= '__'+str(w_para.index(i))+i
       for row in new_rows :
          row[new_key]=row[i]
          del row[i]
+   # rename others parameters by "___" + para
+   # ("___" to be after sort keys)
    for i in c_para :
       new_key= '___'+i
       for row in new_rows :
          row[new_key]=row[i]
          del row[i]
+   # sort
    new_rows.sort()
+   # reversed sort
    if reverse:
       new_rows.reverse()
    for i in w_para :
@@ -635,7 +860,6 @@ def FMT(dform, nform, typAster=None, larg=0, val=''):
       if nform=='formK':
          # convertit %12.5E en %-12s
          fmt=re.sub('([0-9]+)[\.0-9]*[diueEfFgG]+','-\g<1>s',dform['form'+typAster])
-         #print nform, typAster, fmt
       else:
          fmt=dform[nform]
    else:
@@ -647,76 +871,96 @@ def FMT(dform, nform, typAster=None, larg=0, val=''):
    return fmt
 
 # ------------------------------------------------------------------------------
+def merge(tab1, tab2, labels=[]):
+   """Assemble les deux tables tb1 et tb2 selon une liste de labels communs.
+      Si labels est vide:
+       - les lignes de tb2 sont ajoutés à celles de tb1,
+      sinon :
+       - si on trouve les valeurs de tb2 sur les labels dans tb1 (et une seule fois),
+         on surcharge tb1 avec les lignes de tb2 ;
+       - sinon on ajoute la ligne de tb2 à la fin de tb1.
+   """
+   tb1 = tab1.copy()
+   tb2 = tab2.copy()
+   if type(labels) not in EnumTypes:
+      labels=(labels,)
+   for key in labels :
+       if key not in tb1.para : UTMESS('F','Table','Erreur, label non présent %s' % key)
+       if key not in tb2.para : UTMESS('F','Table','Erreur, label non présent %s' % key)
+   # ensemble des paramètres et des types
+   n_para=tb1.para[:]
+   n_type=tb1.type[:]
+   for i in tb2.para:
+      if i not in tb1.para:
+         n_para.append(i)
+         n_type.append(tb2.type[tb2.para.index(i)])
+   # restriction des lignes aux labels communs (peu cher en cpu)
+   rows1 = tb1.rows
+   dlab1 = {}
+   for i1 in range(len(rows1)):
+      tu1 = tuple(map(rows1[i1].__getitem__, labels))
+      if dlab1.get(tu1, '') == '':
+         dlab1[tu1] = i1
+      else:
+         dlab1[tu1] = None
+   # restriction des lignes aux labels communs (peu cher en cpu)
+   rows2 = tb2.rows
+   dlab2 = {}
+   for i2 in range(len(rows2)):
+      tu2 = tuple(map(rows2[i2].__getitem__, labels))
+      if dlab2.get(tu2, '') == '':
+         dlab2[tu2] = i2
+      else:
+         dlab2[tu2] = None
+   # creation de dic1 : dictionnaire de correspondance entre les 
+   # lignes a merger dans les deux tableaux
+   dic1 = {}
+   for cle in dlab1.keys():
+      if dlab1[cle] == None or cle == ():
+         bid = dlab1.pop(cle)
+   for cle in dlab2.keys():
+      if dlab2[cle] == None or cle == ():
+         bid = dlab2.pop(cle)
+   for cle in dlab2.keys():
+      if dlab1.has_key(cle):
+         dic1[dlab2[cle]] = dlab1[cle]
+   # insertion des valeurs de tb2 dans tb1 quand les labels sont communs
+   # (et uniques dans chaque table) OU ajout de la ligne de tb2 dans tb1
+   i2 = -1
+   for r2 in rows2:
+      i2 += 1
+      try:
+         rows1[dic1[i2]].update(r2)
+      except KeyError:
+         rows1.append(r2)
+   # concaténation des titres + info sur le merge
+   tit = '\n'.join([tb1.titr, tb2.titr, 'MERGE avec labels=%s' % repr(labels)])
+   return Table(rows1, n_para, n_type, tit)
+
 # ------------------------------------------------------------------------------
-# ------------------------------------------------------------------------------
-if __name__ == "__main__":
-   listdic = [
-   {'NOEUD': 'N1' ,'NUME_ORDRE': 1 ,'INST': 0.5, 'DX': -0.00233, 'COOR_Y': 0.53033,},
-   {'NOEUD': 'N1' ,'NUME_ORDRE': 2 ,'INST': 1.0, 'DX': -0.00467, 'COOR_Y': 0.53033,},
-   {'NOEUD': 'N1' ,'NUME_ORDRE': 3 ,'INST': 1.5, 'DX': -0.00701, 'COOR_Y': 0.53033,},
-   {'NOEUD': 'N1' ,'NUME_ORDRE': 4 ,'INST': 2.0, 'DX': -0.00934, 'COOR_Y': 0.53033,},
-   {'NOEUD': 'N1' ,'NUME_ORDRE': 5 ,'INST': 2.5, 'DX': -0.01168, 'COOR_Y': 0.53033,},
-   {'NOEUD': 'N2' ,'NUME_ORDRE': 11,'INST': 5.5, 'DX': -0.00233, 'COOR_Y': 0.53033,},
-   {'NOEUD': 'N2' ,'NUME_ORDRE': 12,'INST': 6.0, 'DX': -0.00467, 'COOR_Y': 0.53033,},
-   {'NOEUD': 'N2' ,'NUME_ORDRE': 13,'INST': 6.5, 'DX': -0.00701, 'COOR_Y': 0.53033,},
-   {'NOEUD': 'N2' ,'NUME_ORDRE': 14,'INST': 7.0, 'DX': -0.00934, 'COOR_Y': 0.53033,},
-   {'NOEUD': 'N2' ,'NUME_ORDRE': 15,'INST': 7.5, 'DX': -0.01168, 'COOR_Y': 0.53033,},
-   ]
-   import random
-   random.shuffle(listdic)
-   listpara=['NOEUD','NUME_ORDRE','INST','COOR_Y','DX']
-   listtype=['K8','I','R','R','R']
-   t=Table(listdic,listpara,listtype)
-   
-   tb=t[('NOEUD','DX')]
-   print tb.para
-   print tb.type
-   
-   print
-   print "------Table initiale----"
-   print t
-   print
-   print "--------- CRIT --------"
-   print t.NUME_ORDRE <=5
-   print
-   print "------- CRIT & CRIT -----"
-   print (t.NUME_ORDRE < 10) & (t.INST >=1.5)
-   print
-   print "----- EQ maxi / min(col), max(col) ------"
-   print t.DX == max(t.DX)
-   print min(t.DX)
-   print max(t.DX)
-   print "------ getitem sur 2 paramètres ------"
-   print t.NUME_ORDRE
-   print t.DX
-   print t['DX','NUME_ORDRE']
-   print "------ sort sur INST ------"
-   t.sort('INST')
-   print t
-
-   print "------- TABLEAU_CROISE ------"
-   tabc=t['NOEUD','INST','DX'] 
-   tabc.Impr(FORMAT='TABLEAU_CROISE')
-
-   N=5
-   ldic=[]
-   for i in range(N):
-      ldic.append({'IND':float(i), 'VAL' : random.random()*i})
-   para=['IND','VAL']
-   t3=Table(ldic, para, titr='Table aléatoire')
-   col=t3.VAL.ABS_MAXI()
-   col=t3.VAL.MINI()
-   
-   t3.sort('VAL','IND')
-   
-   tg=tabc['INST','DX'].DX.NON_VIDE()
-   #tg.Impr(FORMAT='XMGRACE')
-   
-   g=Graph.Graph()
-   g.Titre="Tracé d'une fonction au format TABLEAU"
-   g.AjoutCourbe(Val=[tg.INST.values(), tg.DX.values()], Lab=['INST','DX'])
-   g.Trace(FORMAT='TABLEAU')
-   
-#   t.Impr(PAGINATION='NOEUD')
-   t.Impr(PAGINATION=('NOEUD','INST'))
-   
+def _typaster(obj, prev=None, strict=False):
+   """Retourne le type Aster ('R', 'I', Kdef) correspondant à l'objet obj.
+   Si prev est fourni, on vérifie que obj est du type prev.
+   Si strict=False, on autorise que obj ne soit pas du type prev s'ils sont
+   tous les deux numériques ; dans ce cas, on retourne le "type enveloppe" 'R'.
+   """
+   dtyp={
+      IntType    : 'I',
+      FloatType  : 'R',
+      StringType : Kdef, UnicodeType : Kdef,
+      NoneType   : 'I',
+   }
+   if type(obj) in dtyp.keys():
+      typobj=dtyp[type(obj)]
+      if prev in [None, typobj]:
+         return typobj
+      elif strict:   # prev<>None et typobj<>prev et strict
+         raise TypeError, "La valeur %s n'est pas de type %s" % (repr(obj),repr(prev))
+      elif prev in ('I','R') and typobj in ('I','R'):
+         return 'R'
+      else:
+         raise TypeError, "La valeur %s n'est pas compatible avec le type %s" \
+               % (repr(obj),repr(prev))
+   else:
+      raise TypeError, 'Une table ne peut contenir que des entiers, réels ' \
+                       'ou chaines de caractères.'
index 141b324915bbbca14f8259d30c3890acf3595b11..54e2adc42041622975166c8b5d8cbc12ad629f14 100644 (file)
@@ -1,4 +1,4 @@
-#@ MODIF UniteAster Utilitai  DATE 11/05/2005   AUTEUR MCOURTOI M.COURTOIS 
+#@ MODIF UniteAster Utilitai  DATE 29/08/2006   AUTEUR MCOURTOI M.COURTOIS 
 # -*- coding: iso-8859-1 -*-
 #            CONFIGURATION MANAGEMENT OF EDF VERSION
 # ======================================================================
@@ -84,16 +84,17 @@ class UniteAster:
          print __tab.EXTR_TABLE()
          raise aster.FatalError,"<F> <UniteAster._setinfo> %s" % message
       self.infos[unit]['nom'] = nomfich
-      DETRUIRE(CONCEPT=_F(NOM=__tab))
+      #print 'DEBUG infos[unit] = ', self.infos[unit]
+      DETRUIRE(CONCEPT=_F(NOM=__tab),INFO=1)
 
 #-------------------------------------------------------------------------------
-   def Libre(self, nom=None):
-      """Réserve et retourne une unité libre en y associant, s'il est fourni,
-      le fichier 'nom'.
+   def Libre(self, nom=None, action='RESERVER'):
+      """Réserve/associe et retourne une unité libre en y associant, s'il est
+      fourni, le fichier 'nom'.
       """
       __tab=INFO_EXEC_ASTER(LISTE_INFO=('UNITE_LIBRE'))
       unit = __tab['UNITE_LIBRE',1]
-      DETRUIRE(CONCEPT=_F(NOM=__tab))
+      DETRUIRE(CONCEPT=_F(NOM=__tab),INFO=1)
       if nom==None:
          nom='fort.'+str(unit)
 
@@ -103,7 +104,7 @@ class UniteAster:
             self.infos[unit]['nom']
          raise aster.FatalError,"<F> <UniteAster.Libre> %s" % message
 
-      DEFI_FICHIER(ACTION='RESERVER', UNITE=unit , FICHIER=nom.strip())
+      DEFI_FICHIER(ACTION=action, UNITE=unit , FICHIER=nom.strip())
       self.infos[unit] = {}
       self.infos[unit]['nom']       = nom.strip()
       self.infos[unit]['etat']      = 'R'
@@ -129,8 +130,9 @@ class UniteAster:
       """Retourne l'état de l'unité si 'etat' n'est pas fourni
       et/ou change son état :
          kargs['etat']  : nouvel état,
+         kargs['nom']   : nom du fichier,
          kargs['TYPE']  : type du fichier à ouvrir ASCII/BINARY/LIBRE,
-         kargs['ACCES'] : type d'accès NEW/APPEND/OLD.
+         kargs['ACCES'] : type d'accès NEW/APPEND/OLD (APPEND uniquement en ASCII).
       """
       # ul peut etre un entier Aster
       try:
@@ -156,17 +158,26 @@ class UniteAster:
             DEFI_FICHIER(ACTION='LIBERER',  UNITE=unit)
          DEFI_FICHIER(ACTION  = 'RESERVER', 
                       UNITE   = unit,
-                      FICHIER = self.infos[unit]['nom'])
+                      FICHIER = kargs.get('nom', self.infos[unit]['nom']))
+         self._setinfo(unit)
       elif new == 'F':
          DEFI_FICHIER(ACTION='LIBERER', UNITE=unit)
       elif new == 'O':
          if self.infos[unit]['etat'] == 'R':
             DEFI_FICHIER(ACTION='LIBERER', UNITE=unit)
+         # valeurs par défaut
+         typ   = kargs.get('TYPE', 'ASCII')
+         if typ == 'ASCII':
+            acces = 'APPEND'
+         else:
+            acces = 'OLD'
+         acces = kargs.get('ACCES', acces)
          DEFI_FICHIER(ACTION  ='ASSOCIER',
                       UNITE   = unit,
-                      FICHIER = self.infos[unit]['nom'],
-                      TYPE    = kargs.get('TYPE', 'ASCII'),
-                      ACCES   = kargs.get('ACCES', 'APPEND'),)
+                      FICHIER = kargs.get('nom', self.infos[unit]['nom']),
+                      TYPE    = typ,
+                      ACCES   = acces,)
+         self._setinfo(unit)
       self.infos[unit]['etat'] = new
       return self.infos[unit]['etat']
 
index 1659f9ef381187e51f8e690fabe99c33a09216a6..118101684f167fad644b06a82fecef76a9e1345c 100644 (file)
@@ -1,4 +1,4 @@
-#@ MODIF Utmess Utilitai  DATE 30/11/2004   AUTEUR MCOURTOI M.COURTOIS 
+#@ MODIF Utmess Utilitai  DATE 17/10/2005   AUTEUR MCOURTOI M.COURTOIS 
 # -*- coding: iso-8859-1 -*-
 #            CONFIGURATION MANAGEMENT OF EDF VERSION
 # ======================================================================
@@ -23,42 +23,27 @@ import aster
 
 def UTMESS(code, sprg, texte):
    """Utilitaire analogue à la routine fortran UTMESS.
-      code  : 'A', 'E', 'S', 'F'
+      code  : 'A', 'E', 'S', 'F', 'I'
       sprg  : nom du module, classe ou fonction python où l'on se trouve
       texte : contenu du message
    """
    fmt='\n <%s> <%s> %s\n\n'
-   UL={
-      'MESSAGE' : 6,
-      'RESULTAT' : 8,
-      #'ERREUR' : 9,
-   }
-   # On importe la définition des commandes à utiliser dans la macro
-#    if jdc:
-#       DEFI_FICHIER     = jdc.get_cmd('DEFI_FICHIER')
-#    else:
-#       # on se limite au print !
-#       UL={ 'MESSAGE' : 6, }
-   try:
-      from Cata.cata import DEFI_FICHIER
-   except ImportError:
-      # on se limite au print !
-      UL={ 'MESSAGE' : 6, }
-
-   reason=fmt % (code, sprg, texte)
+   sanscode='\n <%s> %s\n\n'
+   UL=[
+      'MESSAGE',
+      'RESULTAT',
+      #'ERREUR',
+   ]
+#
+   # Comme l'UTMESS fortran, on supprime le code si on ne fait pas l'abort
+   if aster.onFatalError()=='EXCEPTION':
+      reason=sanscode % (sprg, texte)
+   else:
+      reason=fmt % (code, sprg, texte)
    
-   for nom,ul in UL.items():
-      if ul<>6:
-         DEFI_FICHIER(ACTION='LIBERER', UNITE=ul, )
-         f=open('fort.'+str(ul),'a')
-      else:
-         f=sys.stdout
+   for nom in UL:
       # écriture du message
-      f.write(reason)
-
-      if ul<>6:
-         f.close()
-         DEFI_FICHIER(ACTION='ASSOCIER', UNITE=ul, TYPE='ASCII', ACCES='APPEND')
+      aster.affiche(nom,reason)
 
    if code=='S':
       raise aster.error, reason
index a173ab11cbe31c58563e3bc9fbb682431f05352d..94e323cef0c187374b4d5d1c3f85680b45fcda6f 100644 (file)
@@ -1,4 +1,4 @@
-#@ MODIF sup_gmsh Utilitai  DATE 10/05/2005   AUTEUR GJBHHEL E.LORENTZ 
+#@ MODIF sup_gmsh Utilitai  DATE 08/11/2005   AUTEUR ASSIRE A.ASSIRE 
 # -*- coding: iso-8859-1 -*-
 #            CONFIGURATION MANAGEMENT OF EDF VERSION
 # ======================================================================
@@ -1320,8 +1320,9 @@ class Mesh :
   def Create(self, file = 'fort.19') :
 
     self.Save()
-#    os.system('gmsh -3 fort.geo')
     os.system(self.gmsh + ' -3 fort.geo')
+    try: os.remove(file)
+    except: pass
     os.rename('fort.msh',file)
 
 
index 0ead839cdf68d008cf9c6f94969cc69003b8e888..ed6042b1ea5ca805e05103b05327a303a2dcd787 100644 (file)
@@ -1,4 +1,4 @@
-#@ MODIF t_fonction Utilitai  DATE 31/05/2005   AUTEUR DURAND C.DURAND 
+#@ MODIF t_fonction Utilitai  DATE 25/09/2006   AUTEUR MCOURTOI M.COURTOIS 
 # -*- coding: iso-8859-1 -*-
 #            CONFIGURATION MANAGEMENT OF EDF VERSION
 # ======================================================================
 from Numeric import *
 import copy
 import types
+from sets import Set
+
+class FonctionError(Exception):
+   pass
 
 def interp(typ_i,val,x1,x2,y1,y2) :
+  """Interpolation linéaire/logarithmique entre un couple de valeurs
+  """
   if typ_i==['LIN','LIN']: return y1+(y2-y1)*(val-x1)/(x2-x1)
   if typ_i==['LIN','LOG']: return exp(log(y1)+(val-x1)*(log(y2)-log(y1))/(x2-x1))
   if typ_i==['LOG','LOG']: return exp(log(y1)+(log(val)-log(x1))*(log(y2)-log(y1))/(log(x2)-log(x1)))
@@ -29,38 +35,41 @@ def interp(typ_i,val,x1,x2,y1,y2) :
   if typ_i[0]=='NON'     : 
                            if   val==x1 : return y1
                            elif val==x2 : return y2
-                           else         : raise StandardError, 'fonction : interpolation NON'
+                           else         : raise FonctionError, 'fonction : interpolation NON'
 def is_ordo(liste) :
-  listb=dict([(i,0) for i in liste]).keys()
+  listb=list(Set(liste))
   listb.sort()
   return liste==listb
 
 class t_fonction :
-  ### Classe pour fonctions réelles, équivalent au type aster = fonction_sdaster
+  """Classe pour fonctions réelles, équivalent au type aster = fonction_sdaster
+  """
   def __init__(self,vale_x,vale_y,para) :
-    # création d'un objet fonction
-    # vale_x et vale_y sont des listes de réels de meme longueur
-    # para est un dictionnaire contenant les entrées PROL_DROITE, PROL_GAUCHE et INTERPOL (cf sd ASTER)
+    """Création d'un objet fonction
+    - vale_x et vale_y sont des listes de réels de meme longueur
+    - para est un dictionnaire contenant les entrées PROL_DROITE, PROL_GAUCHE et INTERPOL (cf sd ASTER)
+    """
     pk=para.keys()
     pk.sort()
     if pk!=['INTERPOL','NOM_PARA','NOM_RESU','PROL_DROITE','PROL_GAUCHE'] :
-         raise StandardError, 'fonction : parametres incorrects'
+         raise FonctionError, 'fonction : parametres incorrects'
     if para['INTERPOL'] not in [['NON','NON'],['LIN','LIN'],['LIN','LOG'],['LOG','LOG'],['LOG','LIN'],] :
-         raise StandardError, 'fonction : parametre INTERPOL incorrect'
+         raise FonctionError, 'fonction : parametre INTERPOL incorrect'
     if para['PROL_DROITE'] not in ['EXCLU','CONSTANT','LINEAIRE'] :
-         raise StandardError, 'fonction : parametre PROL_DROITE incorrect'
+         raise FonctionError, 'fonction : parametre PROL_DROITE incorrect'
     if para['PROL_GAUCHE'] not in ['EXCLU','CONSTANT','LINEAIRE'] :
-         raise StandardError, 'fonction : parametre PROL_GAUCHE incorrect'
+         raise FonctionError, 'fonction : parametre PROL_GAUCHE incorrect'
     self.vale_x    = array(vale_x)
     self.vale_y    = array(vale_y)
     self.para      = para
     if len(self.vale_x)!=len(self.vale_y) :
-         raise StandardError, 'fonction : longueur abscisse <> longueur ordonnées'
+         raise FonctionError, 'fonction : longueur abscisse <> longueur ordonnées'
     if not is_ordo(self.vale_x) :
-         raise StandardError, 'fonction : abscisses non strictement croissantes'
+         raise FonctionError, 'fonction : abscisses non strictement croissantes'
 
   def __add__(self,other) :
-    # addition avec une autre fonction ou un nombre, par surcharge de l'opérateur +
+    """addition avec une autre fonction ou un nombre, par surcharge de l'opérateur +
+    """
     if   isinstance(other,t_fonction):
       para=copy.copy(self.para)
       vale_x,para['PROL_GAUCHE'],para['PROL_DROITE']=self.homo_support(other)
@@ -71,10 +80,11 @@ class t_fonction :
     elif type(other) in [types.FloatType,types.IntType,types.ComplexType] :
       if   isinstance(self,t_fonction_c): return t_fonction_c(self.vale_x,self.vale_y+other,self.para)
       else                              : return t_fonction(self.vale_x,self.vale_y+other,self.para)
-    else:  raise StandardError, 'fonctions : erreur de type dans __add__'
+    else:  raise FonctionError, 'fonctions : erreur de type dans __add__'
 
   def __mul__(self,other) :
-    # multiplication avec une autre fonction ou un nombre, par surcharge de l'opérateur *
+    """multiplication avec une autre fonction ou un nombre, par surcharge de l'opérateur *
+    """
     if   isinstance(other,t_fonction):
       para=copy.copy(self.para)
       vale_x,para['PROL_GAUCHE'],para['PROL_DROITE']=self.homo_support(other)
@@ -86,34 +96,37 @@ class t_fonction :
       return t_fonction(self.vale_x,self.vale_y*other,self.para)
     elif type(other) ==types.ComplexType :
       return t_fonction_c(self.vale_x,self.vale_y*other,self.para)
-    else:  raise StandardError, 'fonctions : erreur de type dans __mul__'
+    else:  raise FonctionError, 'fonctions : erreur de type dans __mul__'
 
   def __repr__(self) :
-    # affichage de la fonction en double colonne
+    """affichage de la fonction en double colonne
+    """
     texte=[]
     for i in range(len(self.vale_x)) :
       texte.append('%f %f' % (self.vale_x[i],self.vale_y[i]))
     return '\n'.join(texte)
 
   def __getitem__(self,other) :
-    # composition de deux fonction F[G]=FoG=F(G(x))
+    """composition de deux fonction F[G]=FoG=F(G(x))
+    """
     para=copy.copy(self.para)
     if other.para['NOM_RESU']!=self.para['NOM_PARA'] :
-       raise StandardError,'''composition de fonctions : NOM_RESU1 et NOM_PARA2 incohérents '''
+       raise FonctionError,'''composition de fonctions : NOM_RESU1 et NOM_PARA2 incohérents '''
     para['NOM_PARA']==other.para['NOM_PARA']
     return t_fonction(other.vale_x,map(self,other.vale_y),para)
 
   def __call__(self,val,tol=1.e-6):
-    # méthode pour évaluer f(x)
-    # tolérance, par défaut 1.e-6 en relatif sur la longueur de l'intervalle
-    # adjacent, pour capter les erreurs d'arrondi en cas de prolongement exclu
+    """méthode pour évaluer f(x)
+    - tolérance, par défaut 1.e-6 en relatif sur la longueur de l'intervalle
+    - adjacent, pour capter les erreurs d'arrondi en cas de prolongement exclu
+    """
     i=searchsorted(self.vale_x,val)
     n=len(self.vale_x)
     if i==0 :
       if self.para['PROL_GAUCHE']=='EXCLU'    :
          eps_g=(val-self.vale_x[0] )/(self.vale_x[1] -self.vale_x[0])
          if abs(eps_g)<=tol  : return self.vale_y[0]
-         else                : raise StandardError, 'fonction évaluée hors du domaine de définition'
+         else                : raise FonctionError, 'fonction évaluée hors du domaine de définition'
       else  : 
          if self.para['PROL_GAUCHE']=='CONSTANT' : return self.vale_y[0]
          if self.para['PROL_GAUCHE']=='LINEAIRE' : return interp(self.para['INTERPOL'],val,self.vale_x[0],
@@ -124,7 +137,7 @@ class t_fonction :
       if self.para['PROL_DROITE']=='EXCLU'    :
          eps_d=(val-self.vale_x[-1])/(self.vale_x[-1]-self.vale_x[-2])
          if abs(eps_d)<=tol  : return self.vale_y[-1]
-         else                : raise StandardError, 'fonction évaluée hors du domaine de définition'
+         else                : raise FonctionError, 'fonction évaluée hors du domaine de définition'
       else  : 
          if self.para['PROL_DROITE']=='CONSTANT' : return self.vale_y[-1]
          if self.para['PROL_DROITE']=='LINEAIRE' : return interp(self.para['INTERPOL'],val,self.vale_x[-1],
@@ -138,11 +151,12 @@ class t_fonction :
                                               self.vale_y[i])
 
   def homo_support(self,other) :
-    # renvoie le support d'abscisses homogénéisé entre self et other
-    # i.e. si prolongement exclu, on retient plus grand min ou plus petit max, selon
-    # si prolongement autorisé, on conserve les abscisses d'une fonction, extrapolantes
-    # sur l'autre.
-    # Pour les points intermédiaires : union et tri des valeurs des vale_x réunis.
+    """Renvoie le support d'abscisses homogénéisé entre self et other
+    i.e. si prolongement exclu, on retient plus grand min ou plus petit max, selon
+    si prolongement autorisé, on conserve les abscisses d'une fonction, extrapolantes
+    sur l'autre.
+    Pour les points intermédiaires : union et tri des valeurs des vale_x réunis.
+    """
     if other.vale_x[0]>self.vale_x[0]:
        if other.para['PROL_GAUCHE']!='EXCLU' : f_g=self
        else                                  : f_g=other
@@ -165,18 +179,19 @@ class t_fonction :
     return vale_x,prol_gauche,prol_droite
 
   def cut(self,rinf,rsup,prec,crit='RELATIF') :
-    # renvoie la fonction self dont on a 'coupé' les extrémités en x=rinf et x=rsup
-    # pour la recherche de rinf et rsup dans la liste d'abscisses :
-    #      prec=precision crit='absolu' ou 'relatif'
+    """Renvoie la fonction self dont on a 'coupé' les extrémités en x=rinf et x=rsup
+    pour la recherche de rinf et rsup dans la liste d'abscisses :
+       prec=precision crit='absolu' ou 'relatif'
+    """
     para=copy.copy(self.para)
     para['PROL_GAUCHE']='EXCLU'
     para['PROL_DROITE']='EXCLU'
     if   crit=='ABSOLU' : rinf_tab=greater(abs(self.vale_x-rinf),prec)
     elif crit=='RELATIF': rinf_tab=greater(abs(self.vale_x-rinf),prec*rinf)
-    else : raise StandardError, 'fonction : cut : critère absolu ou relatif'
+    else : raise FonctionError, 'fonction : cut : critère absolu ou relatif'
     if   crit=='ABSOLU' : rsup_tab=greater(abs(self.vale_x-rsup),prec)
     elif crit=='RELATIF': rsup_tab=greater(abs(self.vale_x-rsup),prec*rsup)
-    else : raise StandardError, 'fonction : cut : critère absolu ou relatif'
+    else : raise FonctionError, 'fonction : cut : critère absolu ou relatif'
     if alltrue(rinf_tab) : i=searchsorted(self.vale_x,rinf)
     else                 : i=rinf_tab.tolist().index(0)+1
     if alltrue(rsup_tab) : j=searchsorted(self.vale_x,rsup)
@@ -186,9 +201,10 @@ class t_fonction :
     return t_fonction(vale_x,vale_y,para)
 
   def cat(self,other,surcharge) :
-    # renvoie une fonction concaténée avec une autre, avec règles de surcharge
+    """renvoie une fonction concaténée avec une autre, avec règles de surcharge
+    """
     para=copy.copy(self.para)
-    if self.para['INTERPOL']!=other.para['INTERPOL'] : raise StandardError, 'concaténation de fonctions à interpolations différentes'
+    if self.para['INTERPOL']!=other.para['INTERPOL'] : raise FonctionError, 'concaténation de fonctions à interpolations différentes'
     if min(self.vale_x)<min(other.vale_x) :
             f1=self
             f2=other
@@ -211,12 +227,14 @@ class t_fonction :
     return t_fonction(vale_x,vale_y,para)
 
   def tabul(self) :
-    # mise en forme de la fonction selon un vecteur unique (x1,y1,x2,y2,...)
+    """mise en forme de la fonction selon un vecteur unique (x1,y1,x2,y2,...)
+    """
     __tab=array([self.vale_x,self.vale_y])
     return ravel(transpose(__tab)).tolist()
 
   def extreme(self) :
-    # renvoie un dictionnaire des valeurs d'ordonnées min et max
+    """renvoie un dictionnaire des valeurs d'ordonnées min et max
+    """
     val_min=min(self.vale_y)
     val_max=max(self.vale_y)
     vm={}
@@ -231,7 +249,8 @@ class t_fonction :
     return vm
 
   def trapeze(self,coef) :
-    # renvoie la primitive de la fonction, calculée avec la constante d'intégration 'coef'
+    """renvoie la primitive de la fonction, calculée avec la constante d'intégration 'coef'
+    """
     trapz     = zeros(len(self.vale_y),Float)
     trapz[0]  = coef
     trapz[1:] = (self.vale_y[1:]+self.vale_y[:-1])/2*(self.vale_x[1:]-self.vale_x[:-1])
@@ -244,7 +263,8 @@ class t_fonction :
     return t_fonction(self.vale_x,prim_y,para)
 
   def simpson(self,coef) :
-    # renvoie la primitive de la fonction, calculée avec la constante d'intégration 'coef'
+    """renvoie la primitive de la fonction, calculée avec la constante d'intégration 'coef'
+    """
     para=copy.copy(self.para)
     para['PROL_GAUCHE']='EXCLU'
     para['PROL_DROITE']='EXCLU'
@@ -277,7 +297,8 @@ class t_fonction :
     return t_fonction(self.vale_x,prim_y,para)
 
   def derive(self) :
-    # renvoie la dérivée de la fonction
+    """renvoie la dérivée de la fonction
+    """
     pas=self.vale_x[1:]-self.vale_x[:-1]
     pentes=(self.vale_y[1:]-self.vale_y[:-1])/(self.vale_x[1:]-self.vale_x[:-1])
     derive=(pentes[1:]*pas[1:]+pentes[:-1]*pas[:-1])/(pas[1:]+pas[:-1])
@@ -290,8 +311,9 @@ class t_fonction :
     return t_fonction(self.vale_x,derv_y,para)
 
   def inverse(self) :
-    # renvoie l'inverse de la fonction
-    # on intervertit vale_x et vale_y, on swape interpolation
+    """renvoie l'inverse de la fonction
+    on intervertit vale_x et vale_y, on swape interpolation
+    """
     para=copy.copy(self.para)
     para['NOM_RESU']='TOUTRESU'
     para['NOM_PARA']=self.para['NOM_PARA']
@@ -306,23 +328,26 @@ class t_fonction :
     return t_fonction(vale_x,vale_y,para)
 
   def abs(self) :
-    # renvoie la mm fonction avec valeur absolue des ordonnées
+    """renvoie la mm fonction avec valeur absolue des ordonnées
+    """
     para=copy.copy(self.para)
     if para['PROL_GAUCHE']=='LINEAIRE' : para['PROL_GAUCHE']='EXCLU'
     if para['PROL_DROITE']=='LINEAIRE' : para['PROL_DROITE']='EXCLU'
     return t_fonction(self.vale_x,absolute(self.vale_y),para)
 
   def evalfonc(self,liste_val) :
-    # renvoie la mm fonction interpolée aux points définis par la liste 'liste_val'
-    return t_fonction(liste_val,map(self,liste_val),self.para)
+    """renvoie la mm fonction interpolée aux points définis par la liste 'liste_val'
+    """
+    return self.__class__(liste_val,map(self,liste_val),self.para)
 
   def sup(self,other) :
-   # renvoie l'enveloppe supérieure de self et other
+    """renvoie l'enveloppe supérieure de self et other
+    """
     para=copy.copy(self.para)
-#   commentaire : pour les prolongements et l'interpolation, c'est self
-#   qui prime sur other
+    # commentaire : pour les prolongements et l'interpolation, c'est self
+    # qui prime sur other
     vale_x=self.vale_x.tolist()+other.vale_x.tolist()
-#   on ote les abscisses doublons
+    # on ote les abscisses doublons
     vale_x=dict([(i,0) for i in vale_x]).keys()
     vale_x.sort()
     vale_x=array(vale_x)
@@ -332,12 +357,13 @@ class t_fonction :
     return t_fonction(vale_x,vale_y,para)
 
   def inf(self,other) :
-   # renvoie l'enveloppe inférieure de self et other
+    """renvoie l'enveloppe inférieure de self et other
+    """
     para=copy.copy(self.para)
-#   commentaire : pour les prolongements et l'interpolation, c'est self
-#   qui prime sur other
+    # commentaire : pour les prolongements et l'interpolation, c'est self
+    # qui prime sur other
     vale_x=self.vale_x.tolist()+other.vale_x.tolist()
-#   on ote les abscisses doublons
+    # on ote les abscisses doublons
     vale_x=dict([(i,0) for i in vale_x]).keys()
     vale_x.sort()
     vale_x=array(vale_x)
@@ -347,8 +373,9 @@ class t_fonction :
     return t_fonction(vale_x,vale_y,para)
 
   def suppr_tend(self) :
-   # pour les corrections d'accélérogrammes
-   # suppression de la tendance moyenne d'une fonction
+    """pour les corrections d'accélérogrammes
+    suppression de la tendance moyenne d'une fonction
+    """
     para=copy.copy(self.para)
     xy=sum(self.vale_x*self.vale_y)
     x0=sum(self.vale_x)
@@ -360,23 +387,25 @@ class t_fonction :
     return t_fonction(self.vale_x,self.vale_y-a1*self.vale_x-a0,self.para)
 
   def normel2(self) :
-   # norme de la fonction
+    """norme de la fonction
+    """
     __ex=self*self
     __ex=__ex.trapeze(0.)
     return sqrt(__ex.vale_y[-1])
 
   def fft(self,methode) :
-   # renvoie la transformée de Fourier rapide FFT
+    """renvoie la transformée de Fourier rapide FFT
+    """
     import FFT
     para=copy.copy(self.para)
     para['NOM_PARA']='FREQ'
     if self.para['NOM_PARA']!='INST' :
-       raise StandardError, 'fonction réelle : FFT : NOM_PARA=INST pour une transformée directe'
+       raise FonctionError, 'fonction réelle : FFT : NOM_PARA=INST pour une transformée directe'
     pas = self.vale_x[1]-self.vale_x[0]
     for i in range(1,len(self.vale_x)) :
         ecart = abs(((self.vale_x[i]-self.vale_x[i-1])-pas)/pas)
         if ecart>1.e-2 :
-           raise StandardError, 'fonction réelle : FFT : la fonction doit etre à pas constant'
+           raise FonctionError, 'fonction réelle : FFT : la fonction doit etre à pas constant'
     n=int(log(len(self.vale_x))/log(2))
     if   methode=='TRONCATURE' :
        vale_y=self.vale_y[:2**n]
@@ -391,31 +420,35 @@ class t_fonction :
     return t_fonction_c(vale_x,vale_y,para)
 
 class t_fonction_c(t_fonction) :
-  ### Classe pour fonctions complexes, équivalent au type aster = fonction_c
+  """Classe pour fonctions complexes, équivalent au type aster = fonction_c
+  """
   def tabul(self) :
-    # mise en forme de la fonction selon un vecteur unique (x1,yr1,yi1,x2,yr2,yr2,...)
+    """mise en forme de la fonction selon un vecteur unique (x1,yr1,yi1,x2,yr2,yr2,...)
+    """
     __tab=array([self.vale_x,self.vale_y.real,self.vale_y.imag])
     return ravel(transpose(__tab)).tolist()
 
   def __repr__(self) :
-    # affichage de la fonction en double colonne
+    """affichage de la fonction en double colonne
+    """
     texte=[]
     for i in range(len(self.vale_x)) :
       texte.append('%f %f + %f .j' % (self.vale_x[i],self.vale_y[i].real,self.vale_y[i].imag))
     return '\n'.join(texte)
 
   def fft(self,methode,syme) :
-   # renvoie la transformée de Fourier rapide FFT (sens inverse)
+    """renvoie la transformée de Fourier rapide FFT (sens inverse)
+    """
     import FFT
     para=copy.copy(self.para)
     para['NOM_PARA']='INST'
     if self.para['NOM_PARA']!='FREQ' :
-       raise StandardError, 'fonction complexe : FFT : NOM_PARA=FREQ pour une transformée directe'
+       raise FonctionError, 'fonction complexe : FFT : NOM_PARA=FREQ pour une transformée directe'
     pas = self.vale_x[1]-self.vale_x[0]
     for i in range(1,len(self.vale_x)) :
         ecart = abs(((self.vale_x[i]-self.vale_x[i-1])-pas)/pas)
         if ecart>1.e-3 :
-           raise StandardError, 'fonction complexe : FFT : la fonction doit etre à pas constant'
+           raise FonctionError, 'fonction complexe : FFT : la fonction doit etre à pas constant'
     n=int(log(len(self.vale_x))/log(2))
     if   syme=='OUI' and len(self.vale_x)==2**n :
        vale_fonc=self.vale_y
@@ -439,7 +472,7 @@ class t_fonction_c(t_fonction) :
        vale_fonc=vale_fonc+vale_fon1
        vale_fonc=array(vale_fonc)
     if   syme=='OUI' and len(self.vale_x)!=2**n :
-       raise StandardError, 'fonction complexe : FFT : syme=OUI et nombre de points<>2**n'
+       raise FonctionError, 'fonction complexe : FFT : syme=OUI et nombre de points<>2**n'
     part1=vale_fonc[:len(vale_fonc)/2+1]
     part2=vale_fonc[1:len(vale_fonc)/2]
     part2=conjugate(part2)
@@ -456,42 +489,45 @@ class t_fonction_c(t_fonction) :
 
 
 class t_nappe :
-  ### Classe pour nappes, équivalent au type aster = nappe_sdaster
+  """Classe pour nappes, équivalent au type aster = nappe_sdaster
+  """
   def __init__(self,vale_para,l_fonc,para) :
-    # création d'un objet nappe
-    # vale_para est la liste de valeur des parametres (mot clé PARA dans DEFI_NAPPE)
-    # para est un dictionnaire contenant les entrées PROL_DROITE, PROL_GAUCHE et INTERPOL (cf sd ASTER)
-    # l_fonc est la liste des fonctions, de cardinal égal à celui de vale_para
+    """Création d'un objet nappe
+    - vale_para est la liste de valeur des parametres (mot clé PARA dans DEFI_NAPPE)
+    - para est un dictionnaire contenant les entrées PROL_DROITE, PROL_GAUCHE et INTERPOL (cf sd ASTER)
+    - l_fonc est la liste des fonctions, de cardinal égal à celui de vale_para
+    """
     pk=para.keys()
     pk.sort()
     if pk!=['INTERPOL','NOM_PARA','NOM_PARA_FONC','NOM_RESU','PROL_DROITE','PROL_GAUCHE'] :
-         raise StandardError, 'nappe : parametres incorrects'
+         raise FonctionError, 'nappe : parametres incorrects'
     if para['INTERPOL'] not in [['NON','NON'],['LIN','LIN'],
                                 ['LIN','LOG'],['LOG','LOG'],['LOG','LIN'],] :
-         raise StandardError, 'nappe : parametre INTERPOL incorrect'
+         raise FonctionError, 'nappe : parametre INTERPOL incorrect'
     if para['PROL_DROITE'] not in ['EXCLU','CONSTANT','LINEAIRE'] :
-         raise StandardError, 'nappe : parametre PROL_DROITE incorrect'
+         raise FonctionError, 'nappe : parametre PROL_DROITE incorrect'
     if para['PROL_GAUCHE'] not in ['EXCLU','CONSTANT','LINEAIRE'] :
-         raise StandardError, 'nappe : parametre PROL_GAUCHE incorrect'
+         raise FonctionError, 'nappe : parametre PROL_GAUCHE incorrect'
     self.vale_para    = array(vale_para)
     if type(l_fonc) not in (types.ListType,types.TupleType) :
-         raise StandardError, 'nappe : la liste de fonctions fournie n est pas une liste'
+         raise FonctionError, 'nappe : la liste de fonctions fournie n est pas une liste'
     if len(l_fonc)!=len(vale_para) :
-         raise StandardError, 'nappe : nombre de fonctions différent du nombre de valeurs du paramètre'
+         raise FonctionError, 'nappe : nombre de fonctions différent du nombre de valeurs du paramètre'
     for f in l_fonc :
       if not isinstance(f,t_fonction) and not isinstance(f,t_fonction_c) :
-         raise StandardError, 'nappe : les fonctions fournies ne sont pas du bon type'
+         raise FonctionError, 'nappe : les fonctions fournies ne sont pas du bon type'
     self.l_fonc       = l_fonc
     self.para         = para
 
   def __call__(self,val1,val2):
-    # méthode pour évaluer nappe(val1,val2)
+    """méthode pour évaluer nappe(val1,val2)
+    """
     i=searchsorted(self.vale_para,val1)
     n=len(self.vale_para)
     if i==0 :
       if val1==self.vale_para[0]  : return self.l_fonc[0](val2)
       if val1 <self.vale_para[0]  : 
-         if self.para['PROL_GAUCHE']=='EXCLU'    : raise StandardError, 'nappe évaluée hors du domaine de définition'
+         if self.para['PROL_GAUCHE']=='EXCLU'    : raise FonctionError, 'nappe évaluée hors du domaine de définition'
          if self.para['PROL_GAUCHE']=='CONSTANT' : return self.l_fonc[0](val2)
          if self.para['PROL_GAUCHE']=='LINEAIRE' : return interp(self.para['INTERPOL'],val1,
                                                                  self.vale_para[0],
@@ -501,7 +537,7 @@ class t_nappe :
     elif i==n :
       if val1==self.vale_para[-1] : return self.l_fonc[-1](val2)
       if val1 >self.vale_para[-1]  : 
-         if self.para['PROL_DROITE']=='EXCLU'    : raise StandardError, 'nappe évaluée hors du domaine de définition'
+         if self.para['PROL_DROITE']=='EXCLU'    : raise FonctionError, 'nappe évaluée hors du domaine de définition'
          if self.para['PROL_DROITE']=='CONSTANT' : return self.l_fonc[-1](val2)
          if self.para['PROL_DROITE']=='LINEAIRE' : return interp(self.para['INTERPOL'],val1,
                                                                  self.vale_para[-1],
@@ -514,30 +550,43 @@ class t_nappe :
                                                self.l_fonc[i-1](val2),
                                                self.l_fonc[i](val2))
 
+  def evalfonc(self, liste_val) :
+    """Renvoie la mm nappe dont les fonctions sont interpolées aux points définis
+    par la liste 'liste_val'.
+    """
+    l_fonc = []
+    for f in self.l_fonc:
+      f2 = f.evalfonc(liste_val)
+      l_fonc.append(f2)
+    return t_nappe(self.vale_para, l_fonc, self.para)
+
   def __add__(self,other) :
-    # addition avec une autre nappe ou un nombre, par surcharge de l'opérateur +
+    """addition avec une autre nappe ou un nombre, par surcharge de l'opérateur +
+    """
     l_fonc=[]
     if   isinstance(other,t_nappe):
-      if self.vale_para!=other.vale_para : raise StandardError, 'nappes à valeurs de paramètres différentes'
+      if self.vale_para!=other.vale_para : raise FonctionError, 'nappes à valeurs de paramètres différentes'
       for i in range(len(self.l_fonc)) : l_fonc.append(self.l_fonc[i]+other.l_fonc[i])
     elif type(other) in [types.FloatType,types.IntType] :
       for i in range(len(self.l_fonc)) : l_fonc.append(self.l_fonc[i]+other)
-    else:  raise StandardError, 't_nappe : erreur de type dans __add__'
+    else:  raise FonctionError, 't_nappe : erreur de type dans __add__'
     return t_nappe(self.vale_para,l_fonc,self.para)
 
   def __mul__(self,other) :
-    # multiplication avec une autre fonction ou un nombre, par surcharge de l'opérateur *
+    """multiplication avec une autre fonction ou un nombre, par surcharge de l'opérateur *
+    """
     l_fonc=[]
     if   isinstance(other,t_nappe):
-      if self.vale_para!=other.vale_para : raise StandardError, 'nappes à valeurs de paramètres différentes'
+      if self.vale_para!=other.vale_para : raise FonctionError, 'nappes à valeurs de paramètres différentes'
       for i in range(len(self.l_fonc)) : l_fonc.append(self.l_fonc[i]*other.l_fonc[i])
     elif type(other) in [types.FloatType,types.IntType] :
       for i in range(len(self.l_fonc)) : l_fonc.append(self.l_fonc[i]*other)
-    else:  raise StandardError, 't_nappe : erreur de type dans __mul__'
+    else:  raise FonctionError, 't_nappe : erreur de type dans __mul__'
     return t_nappe(self.vale_para,l_fonc,self.para)
 
   def __repr__(self) :
-    # affichage de la nappe en double colonne
+    """affichage de la nappe en double colonne
+    """
     texte=[]
     for i in range(len(self.vale_para)) :
       texte.append('paramètre : %f' % self.vale_para[i])
@@ -545,10 +594,11 @@ class t_nappe :
     return '\n'.join(texte)
 
   def homo_support(self,other) :
-    # renvoie la nappe self avec un support union de celui de self et de other
-    # le support est la discrétisation vale_para et les discrétisations des fonctions
+    """Renvoie la nappe self avec un support union de celui de self et de other
+    le support est la discrétisation vale_para et les discrétisations des fonctions
+    """
     if self==other : return self
-    if self.para!=other.para : raise StandardError, 'combinaison de nappes à caractéristiques interpolation et prolongement différentes'
+    if self.para!=other.para : raise FonctionError, 'combinaison de nappes à caractéristiques interpolation et prolongement différentes'
     vale_para=self.vale_para.tolist()+other.vale_para.tolist()
     vale_para=dict([(i,0) for i in vale_para]).keys()
     vale_para.sort()
@@ -565,11 +615,12 @@ class t_nappe :
                                                l_fonc.append(t_fonction(new_vale_x,new_vale_y,new_para))
                                       if isinstance(other_fonc,t_fonction_c) :
                                                l_fonc.append(t_fonction_c(new_vale_x,new_vale_y,new_para))
-        else : raise StandardError, 'combinaison de nappes : incohérence'
+        else : raise FonctionError, 'combinaison de nappes : incohérence'
     return t_nappe(vale_para,l_fonc,self.para)
 
   def extreme(self) :
-    # renvoie un dictionnaire des valeurs d'ordonnées min et max
+    """renvoie un dictionnaire des valeurs d'ordonnées min et max
+    """
     val_min=min([min(fonc.vale_y) for fonc in self.l_fonc])
     val_max=max([max(fonc.vale_y) for fonc in self.l_fonc])
     vm={'min':[],'max':[]}