Salome HOME
merge de la branche BR_dev_mars_06 (tag V1_10b5) dans la branche principale
[tools/eficas.git] / Aster / Cata / cataSTA8 / Macro / test_fichier_ops.py
1 #@ MODIF test_fichier_ops Macro  DATE 22/05/2006   AUTEUR MCOURTOI M.COURTOIS 
2 # -*- coding: iso-8859-1 -*-
3 #            CONFIGURATION MANAGEMENT OF EDF VERSION
4 # ======================================================================
5 # COPYRIGHT (C) 1991 - 2004  EDF R&D                  WWW.CODE-ASTER.ORG
6 # THIS PROGRAM IS FREE SOFTWARE; YOU CAN REDISTRIBUTE IT AND/OR MODIFY  
7 # IT UNDER THE TERMS OF THE GNU GENERAL PUBLIC LICENSE AS PUBLISHED BY  
8 # THE FREE SOFTWARE FOUNDATION; EITHER VERSION 2 OF THE LICENSE, OR     
9 # (AT YOUR OPTION) ANY LATER VERSION.                                                  
10 #                                                                       
11 # THIS PROGRAM IS DISTRIBUTED IN THE HOPE THAT IT WILL BE USEFUL, BUT   
12 # WITHOUT ANY WARRANTY; WITHOUT EVEN THE IMPLIED WARRANTY OF            
13 # MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. SEE THE GNU      
14 # GENERAL PUBLIC LICENSE FOR MORE DETAILS.                              
15 #                                                                       
16 # YOU SHOULD HAVE RECEIVED A COPY OF THE GNU GENERAL PUBLIC LICENSE     
17 # ALONG WITH THIS PROGRAM; IF NOT, WRITE TO EDF R&D CODE_ASTER,         
18 #    1 AVENUE DU GENERAL DE GAULLE, 92141 CLAMART CEDEX, FRANCE.        
19 # ======================================================================
20
21 import sys
22 import os.path
23 import re
24 from math import floor, log10
25 from types import StringType
26 import md5
27
28 #-------------------------------------------------------------------------------
29 def test_fichier_ops(self, FICHIER, NB_CHIFFRE, EPSILON, VALE_K, INFO, **args):
30    """
31      Macro TEST_FICHIER permettant de tester la non-regression d'un fichier
32      'a une tolerance' pres pour les nombres reels en calculant
33      le md5sum.
34    """
35    ier = 0
36    # La macro compte pour 1 dans la numerotation des commandes
37    self.set_icmd(1)
38
39    # On importe les definitions des commandes a utiliser dans la macro
40    # Le nom de la variable doit etre obligatoirement le nom de la commande
41    INFO_EXEC_ASTER = self.get_cmd('INFO_EXEC_ASTER')
42    DETRUIRE        = self.get_cmd('DETRUIRE')
43    CREA_TABLE      = self.get_cmd('CREA_TABLE')
44    TEST_TABLE      = self.get_cmd('TEST_TABLE')
45    
46    import aster
47    from Accas import _F
48    from Macro.test_fichier_ops import md5file
49    from Utilitai.Utmess import UTMESS
50
51    # vérifie la syntaxe des expressions régulières fournies
52    l_regexp = []
53    if args['EXPR_IGNORE']:
54       if type(args['EXPR_IGNORE']) is StringType:
55          lexp = [args['EXPR_IGNORE']]
56       else:
57          lexp = args['EXPR_IGNORE']
58       for exp in lexp:
59          try:
60             obj = re.compile(exp)
61          except re.error, s:
62             UTMESS('F', 'TEST_FICHIER',
63                    '<INVALID_REGEXP> %s pour %s' % (str(s), repr(exp)))
64          else:
65             l_regexp.append(exp)
66
67    is_ok = 0
68
69    # vérifier que le fichier a été fermé
70    tinfo__ = INFO_EXEC_ASTER(LISTE_INFO='ETAT_UNITE', FICHIER=FICHIER)
71    
72    if tinfo__['ETAT_UNITE', 1].find('OUVERT')>-1:
73       UTMESS('A',  'TEST_FICHIER',
74              "LE FICHIER N'A PAS ETE FERME :\n%s" % FICHIER)
75
76    # fichier correctement fermé
77    else:
78       # calcule le md5sum du fichier
79       ier, mdsum = md5file(FICHIER, NB_CHIFFRE, EPSILON, l_regexp, INFO)
80       if ier != 0:
81          if ier == 4:
82             texte_erreur = 'Fichier inexistant : '+FICHIER
83          else:
84             texte_erreur = 'Erreur dans md5file, code retour = '+str(ier)
85          texte_erreur = '<S> <TEST_FICHIER> '+texte_erreur
86          # aujourd'hui, je ne sais pas déclencher autre chose que <F>...
87          self.cr.fatal(texte_erreur)
88          return ier
89
90       # comparaison a la reference
91       if INFO > 0 :
92          aster.affiche('MESSAGE', ' %-20s : %32s\n' % ('REFERENCE', VALE_K))
93
94       if mdsum == VALE_K:
95          is_ok = 1
96
97    # produit le TEST_TABLE
98    tab1__ = CREA_TABLE(LISTE=(_F(PARA='TEST',
99                                  TYPE_K='K8',
100                                  LISTE_K='VALEUR  ',),
101                               _F(PARA='BOOLEEN',
102                                  LISTE_I=is_ok,),),)
103    if args['REFERENCE'] == 'NON_REGRESSION':
104       TEST_TABLE(TABLE=tab1__,
105                  FILTRE=_F(NOM_PARA='TEST',
106                            VALE_K='VALEUR  ',),
107                  NOM_PARA='BOOLEEN',
108                  VALE_I=1,
109                  PRECISION=1.e-3,
110                  CRITERE='ABSOLU',
111                  REFERENCE=args['REFERENCE'],
112                  VERSION=args['VERSION'],)
113    else:
114       TEST_TABLE(TABLE=tab1__,
115                  FILTRE=_F(NOM_PARA='TEST',
116                            VALE_K='VALEUR  ',),
117                  NOM_PARA='BOOLEEN',
118                  VALE_I=1,
119                  PRECISION=1.e-3,
120                  CRITERE='ABSOLU',
121                  REFERENCE=args['REFERENCE'],)
122
123    DETRUIRE(CONCEPT=_F(NOM=('tinfo__','tab1__'),),
124             ALARME='NON',INFO=1,)
125    return ier
126
127
128 #-------------------------------------------------------------------------------
129 def sign(x):
130    return int(x/abs(x))
131
132 def _round(x, n, exp):
133    v = x * 10**(-exp+n)
134    val = int(v + sign(x)*0.4999)
135    return val
136
137 def entier_ini(x, nbch, exp=None):
138    #if exp is None:
139       #exp = int(floor(log10(abs(x))))
140    val = _round(x, nbch-1, exp)
141    return val, exp-nbch+1
142
143 def entier_triple(x, nbch, exp_epsi):
144    #if abs(x) <= 10**exp_epsi:
145       #return '0'
146    y = _round(x * 10**(-exp_epsi), 0, 0) * 10**exp_epsi
147    exp = int(floor(log10(abs(y))))
148    z1, e1 = entier_ini(y,           nbch+2, exp)
149    z2, e2 = entier_ini(z1 * 10**e1, nbch+1, exp)
150    z3, e3 = entier_ini(z2 * 10**e2, nbch,   exp)
151    return '%sE%d' % (z3, e3)
152
153 #-------------------------------------------------------------------------------
154 def md5file(fich, nbch, epsi,
155             regexp_ignore=[], info=0, output=None, format_func=entier_triple):
156    """
157    Cette methode retourne le md5sum d'un fichier en arrondissant les nombres
158    reels a la valeur significative.
159    IN :
160       fich          : nom du fichier
161       nbch          : nombre de decimales significatives
162       epsi          : valeur en deca de laquelle on prend 0
163       regexp_ignore : liste d'expressions régulières permettant d'ignorer
164          certaines lignes
165       output        : pour rediriger l'interprétation du fichier (INFO=2)
166          dans le fichier de nom `output`,
167       info          : on affiche le résumé si info>0
168       format_func   : on peut préciser une autre fonction pour formatter 
169          les réels...
170    OUT :
171       code retour : 0 si ok, >0 sinon
172       md5sum
173    
174          NE PAS AJOUTER D'IMPORT QUI RENDRAIT CETTE FONCTION
175                INUTILISABLE EN DEHORS DE CODE_ASTER.
176    """   
177    if output != None:
178       try:
179          sys.stdout = open(output, 'w')
180       except IOError, msg:
181          print "Erreur d'écriture sur %s : %s" % (output, msg)
182    
183    #      1 Mo   10 Mo   100 Mo
184    # v0   2.6 s  20.4 s  196.6 s
185    # v1   2.0 s  10.3 s  94.9 s (pas de distinction entier/reel)
186    # remplacer le try/except par if re.search(...), 80% plus lent
187    # v2  10.7 s
188    if not os.path.isfile(fich):
189       return 4, ''
190    f = open(fich,'r')
191    m = md5.new()
192    exp_epsi = int(floor(log10(abs(epsi))))
193    i = 0
194    for ligne in f:
195       i = i+1
196       if info >= 2:
197          print 'LIGNE', i,
198       keep = True
199       for exp in regexp_ignore:
200          if re.search(exp, ligne):
201             keep = False
202             if info >= 2:
203                print ' >>>>>>>>>> IGNOREE <<<<<<<<<<',
204             break
205       if keep:
206          # découpe des nombres collés : 1.34E-142-1.233D+09
207          ligne = re.sub('([0-9]+)\-', '\g<1> -', ligne)
208          # conversion des DOUBLE fortran en 'E'
209          ligne = re.sub('([0-9]+)[dD]([\-\+]{0,1}[0-9]+)', '\g<1>E\g<2>', ligne)
210          r = ligne.split()
211          for x in r:
212             try:
213                xv = float(x)
214                if abs(xv)<epsi:
215                   s = '0'
216                else:
217                   #s = format_float % float(x)
218                   s = format_func(xv, nbch, exp_epsi)
219             except ValueError:
220                s = x
221             if info >= 2:
222                print (' %'+str(nbch+7)+'s') % s,
223             m.update(s)
224       if info >= 2:
225          print
226    f.close()
227    md5sum = m.hexdigest()
228    
229    affich_resu = True
230    if info >= 1:
231       while affich_resu:
232          form = ' %-20s : %32s'
233          print form % ('Fichier', fich)
234          print form % ('Nombre de lignes', str(i))
235          #print form % ('Format des reels',format_float)
236          print form % ('Nombre de chiffres', str(nbch))
237          print form % ('Epsilon', str(epsi))
238          print form % ('md5sum', md5sum)
239          if output == None:
240             affich_resu = False
241          else:
242             sys.stdout = sys.__stdout__
243             output = None
244    return 0, md5sum
245
246
247 #-------------------------------------------------------------------------------
248 if __name__ == '__main__':
249    from optparse import OptionParser, OptionGroup
250
251    p = OptionParser(usage='usage: %s a_tester [options]' % sys.argv[0])
252    p.add_option('-n', '--nbch',
253       action='store', dest='nbch', type='int', default=6,
254       help='nombre de chiffres significatifs')
255    p.add_option('-e', '--epsilon',
256       action='store', dest='epsi', type='float', default=1.e-14,
257       help='epsilon en dessous duquel on considère les nombres nuls')
258    p.add_option('--expr_ignore',
259       action='store', dest='exp', type='string',
260       help='expression régulière à ignorer')
261    p.add_option('-o', '--output',
262       action='store', dest='output', type='string', default='output.txt',
263       help='fichier de sortie')
264    opts, args = p.parse_args()
265
266    if len(args)<1:
267       p.print_usage()
268       sys.exit(1)
269    if opts.exp is None:
270       exp = []
271    else:
272       exp = [opts.exp]
273
274    print 'Lignes retenues dans %s' % opts.output
275    iret = md5file(args[0], opts.nbch, opts.epsi,
276                   regexp_ignore=exp, info=2, output=opts.output)
277