1 #@ MODIF recal Macro DATE 26/05/2010 AUTEUR ASSIRE A.ASSIRE
2 # -*- coding: iso-8859-1 -*-
3 # CONFIGURATION MANAGEMENT OF EDF VERSION
4 # ======================================================================
5 # COPYRIGHT (C) 1991 - 2002 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.
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.
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 # ======================================================================
22 #___________________________________________________________________________
24 # MODULE DE CALCUL DISTRIBUE POUR MACR_RECAL
26 # Utilisable en mode EXTERNE, voir les flags avec "python recal.py -h"
27 #___________________________________________________________________________
39 from math import log10
44 # Importation de commandes Aster
52 include_pattern = "# -->INCLUDE<--"
55 # -------------------------------------------------------------------------------
56 # -------------------------------------------------------------------------------
57 def get_absolute_path(path):
58 """Retourne le chemin absolu en suivant les liens éventuels.
60 if os.path.islink(path):
61 path = os.path.realpath(path)
62 res = os.path.normpath(os.path.abspath(path))
65 # -------------------------------------------------------------------------------
66 #if os.environ.has_key('bibpytdir'): sys.path.append( os.environ['bibpytdir'] )
68 # recupere "bibpyt" à partir de "bibpyt/Macro/recal.py"
69 sys.path.append(get_absolute_path(os.path.join(sys.argv[0], '..', '..')))
72 from Utilitai.Utmess import UTMESS
74 def UTMESS(code='I', txt='',valk='', vali='', valr=''):
75 print txt, valk, vali, valr
76 if code=='F': sys.exit()
79 # # -------------------------------------------------------------------------------
80 # def find_parameter(content, param):
82 # Return the lowest index in content where param is found and
83 # the index of the end of the command.
85 # pos, endpos = -1, -1
86 # re_start = re.compile('^ *%s *\=' % re.escape(param), re.M)
87 # mat_start = re_start.search(content)
88 # if mat_start is not None:
89 # pos = mat_start.start()
90 # endpos = search_enclosed(content, pos)
95 # -------------------------------------------------------------------------------
96 def find_parameter(content, param):
98 Supprime les parametres du fichier de commande
100 re_start = re.compile('^ *%s *\=' % re.escape(param), re.M)
102 for line in content.split('\n'):
103 mat_start = re_start.search(line)
104 if mat_start is None: l.append(line)
108 # -------------------------------------------------------------------------------
109 def Affiche_Param(para, val):
110 """Affiche les parametres
113 for p, v in zip(para, val):
114 t.append( " %s : %s" % ( p.ljust(9), v) )
118 # -------------------------------------------------------------------------------
119 def make_include_files(UNITE_INCLUDE, calcul, parametres):
120 """ Module permettant de generer les fichiers a inclure (mode INCLUSION)
123 # # Importation de commandes Aster
127 # from Accas import _F
128 # from Cata.cata import *
129 # except ImportError:
130 # raise "Le mode INCLUSION doit etre lance depuis Aster"
133 ASTER_ROOT = os.path.join(aster.repout, '..')
134 sys.path.append(os.path.join(ASTER_ROOT, 'ASTK', 'ASTK_SERV', 'lib'))
135 sys.path.append(os.path.join(ASTER_ROOT, 'lib', 'python%s.%s' % (sys.version_info[0], sys.version_info[1] ) , 'site-packages'))
138 from asrun.utils import find_command, search_enclosed
141 UTMESS('F','RECAL0_99')
144 # ----------------------------------------------------------------------------
145 # Preparation des fichiers
146 # ----------------------------------------------------------------------------
148 for reponse in [ x[0] for x in calcul ]:
149 if not reponse in liste_reponses: liste_reponses.append(reponse)
152 old = "fort.%s" % UNITE_INCLUDE
153 pre = "fort.%s.pre" % UNITE_INCLUDE
154 new = "fort.%s.new" % UNITE_INCLUDE
161 # On retire la commande DEBUT
162 pos, endpos = find_command(newtxt, "DEBUT")
163 if endpos!=-1: newtxt = newtxt[endpos+1:]
164 if newtxt[0]==';': newtxt = newtxt[1:] # Bug dans find_command si la commande se termine par un ";"
166 # On retire les parametres
167 list_params = [x[0] for x in parametres]
168 for param in list_params:
169 newtxt = find_parameter(newtxt, param)
171 # Isole la partie a inclure si elle est specifiee
172 n = newtxt.find(include_pattern)
176 pretxt = "# -*- coding: iso-8859-1 -*-\n" + pretxt
177 # Ecriture du nouveau fichier
181 newtxt = newtxt[n+len(include_pattern):]
183 # Retire la commande FIN
184 pos, endpos = find_command(newtxt, "FIN")
185 if pos!=-1: newtxt = newtxt[:pos]
187 # Ajoute un global pour ramener les courbes dans l'espace Aster
188 newtxt = "global %s\n" % ','.join(liste_reponses) + newtxt
190 # Ajoute un encodage pour eviter les erreurs dues aux accents (ssna110a par exemple)
191 newtxt = "# -*- coding: iso-8859-1 -*-\n" + newtxt
193 # Ecriture du nouveau fichier
203 # -------------------------------------------------------------------------------
204 def mes_concepts(list_concepts=[],base=None):
205 """ Fonction qui liste les concepts créés """
206 for e in base.etapes:
207 if e.nom in ('INCLUDE','MACR_RECAL',) :
208 list_concepts=list(mes_concepts(list_concepts=list_concepts,base=e))
209 elif (e.sd != None) and (e.parent.nom=='INCLUDE') :
210 nom_concept=e.sd.get_name()
211 if not(nom_concept in list_concepts):
212 list_concepts.append( nom_concept )
213 return tuple(list_concepts)
216 # -------------------------------------------------------------------------------
217 def detr_concepts(self):
218 liste_concepts=mes_concepts(base=self.parent)
219 for e in liste_concepts:
220 nom = string.strip(e)
221 DETRUIRE( OBJET =self.g_context['_F'](CHAINE = nom), INFO=2)
222 if self.jdc.g_context.has_key(nom) : del self.jdc.g_context[nom]
226 # -------------------------------------------------------------------------------
227 def get_tables(tables_calc, tmp_repe_table, prof):
228 """ Recupere les resultats Aster (Table Aster -> numpy)
230 assert (tables_calc is not None)
231 assert (tmp_repe_table is not None)
233 # Import du module lire_table
234 if os.environ.has_key('ASTER_ROOT'):
235 version = prof['version'][0]
236 bibpyt = os.path.join(os.environ['ASTER_ROOT'], version, 'bibpyt')
237 sys.path.append(bibpyt)
238 for mdl in glob.glob(os.path.join(bibpyt, '*')):
239 sys.path.append(os.path.join(os.environ['ASTER_ROOT'], version, 'bibpyt', mdl))
241 from lire_table_ops import lecture_table
243 UTMESS('F','RECAL0_23')
245 reponses = tables_calc
247 for i in range(len(reponses)):
248 _fic_table = tmp_repe_table + os.sep + "fort."+str(int(100+i))
251 f=open(_fic_table,'r')
254 except Exception, err:
256 UTMESS('F','RECAL0_24',valk=str(err))
259 table_lue = lecture_table(texte, 1, ' ')
260 list_para = table_lue.para
261 tab_lue = table_lue.values()
262 except Exception, err:
267 if ier!=0 : UTMESS('F','RECAL0_24',valk=str(err))
269 F = table2numpy(tab_lue, list_para, reponses, i)
276 # --------------------------------------------------------------------------------------------------
277 def table2numpy(tab_lue, list_para, reponses, i):
278 """ Extraction des resultats depuis la table Aster
281 nb_val = len(tab_lue[ list_para[0] ])
282 F = NP.zeros((nb_val,2))
283 for k in range(nb_val):
284 F[k][0] = tab_lue[ str(reponses[i][1]) ][k]
285 F[k][1] = tab_lue[ str(reponses[i][2]) ][k]
286 except Exception, err:
287 UTMESS('F','RECAL0_24',valk=str(err))
291 # --------------------------------------------------------------------------------------------------
292 def Ecriture_Fonctionnelle(output_file, type_fonctionnelle, fonctionnelle):
294 try: os.remove(output_file)
297 f=open(output_file, 'w')
298 if type_fonctionnelle == 'vector':
299 try: fonctionnelle = fonctionnelle.tolist()
301 fonctionnelle = str(fonctionnelle).replace('[','').replace(']','').replace('\n', ' ')
302 f.write( str(fonctionnelle) )
306 # --------------------------------------------------------------------------------------------------
307 def Ecriture_Derivees(output_file, derivees):
309 try: os.remove(output_file)
312 # on cherche a imprimer la gradient calcule a partir de Fcalc
313 if type(derivees) in [list, tuple]:
316 l = str(l).replace('[', '').replace(']', '')
320 # On cherche a imprimer la matrice des sensibilite (A ou A_nodim)
321 elif type(derivees) == NP.ndarray:
324 for c in range(len(a[0,:])):
326 l = str(l).replace('[', '').replace(']', '')
330 else: raise "Wrong type for gradient !"
333 f=open(output_file, 'w')
339 # --------------------------------------------------------------------------------------------------
340 # --------------------------------------------------------------------------------------------------
343 Classe gérant les calculs Aster (distribues ou include)
346 # ---------------------------------------------------------------------------
349 # MACR_RECAL inputs are optional here (if passed to self.run methods)
353 LANCEMENT = 'DISTRIBUTION',
357 self.parametres = parametres
359 self.experience = experience
360 #self.eval_esclave = mode_esclave
361 self.LANCEMENT = LANCEMENT
362 self.UNITE_ESCL = None
363 self.UNITE_INCLUDE = None
364 self.ASTER_ROOT = None
368 self.list_params = [x[0] for x in parametres]
369 self.list_params.sort()
371 # Valable uniquement pour le mode INCLUDE
377 # Mode dynamique desactive par defaut
378 self.SetDynamiqueMode(None, None)
381 # ---------------------------------------------------------------------------------------------------------
382 def SetDynamiqueMode(self, DYNAMIQUE, graph_mac):
383 self.DYNAMIQUE = DYNAMIQUE
384 self.graph_mac = graph_mac
387 # ---------------------------------------------------------------------------------------------------------
388 # ---------------------------------------------------------------------------------------------------------
395 # Code_Aster installation
418 # Code_Aster installation
419 self.ASTER_ROOT = ASTER_ROOT
423 self.resudir = resudir
426 if not NMAX_SIMULT: NMAX_SIMULT = 0
427 self.NMAX_SIMULT = NMAX_SIMULT
433 if parametres: self.parametres = parametres
434 if calcul: self.calcul = calcul
435 if experience: self.experience = experience
437 parametres = self.parametres
439 experience = self.experience
441 list_params = self.list_params
443 if dX: CalcGradient = True
444 else: CalcGradient = False
445 self.CalcGradient = CalcGradient
449 # Pour le moment on conserve un seul fichier
450 self.UNITE_INCLUDE = self.UNITE_ESCL
453 # ----------------------------------------------------------------------------
454 # Liste de tous les jeux de parametres (initial + differences finies)
455 # ----------------------------------------------------------------------------
458 # Dictionnaire des parametres du point courant
459 dic = dict( zip( list_params, X0 ) )
460 list_val.append( dic )
462 # Calcul du gradient (perturbations des differences finies)
464 UTMESS('I','RECAL0_16')
465 # Dictionnaires des parametres des calculs esclaves
466 for n in range(1,len(dX)+1):
469 X = [ X0[i] * (1+l[i]) for i in range(len(dX)) ]
470 dic = dict( zip( list_params, X ) )
471 list_val.append( dic )
474 # ----------------------------------------------------------------------------
475 # Aiguillage vers INCLUDE
476 # ----------------------------------------------------------------------------
477 if self.LANCEMENT == 'INCLUSION':
478 UTMESS('I','RECAL0_29', valk=self.LANCEMENT)
479 fonctionnelle, gradient = self.run_include(list_val)
482 # ----------------------------------------------------------------------------
483 # Aiguillage vers ASRUN distribue
484 # ----------------------------------------------------------------------------
485 elif self.LANCEMENT == 'DISTRIBUTION':
486 UTMESS('I','RECAL0_29', valk=self.LANCEMENT)
487 fonctionnelle, gradient = self.run_distrib(list_val)
490 # ----------------------------------------------------------------------------
491 # Erreur d'aiguillage
492 # ----------------------------------------------------------------------------
494 raise "Erreur : mode %s inconnu!" % self.LANCEMENT
498 # ----------------------------------------------------------------------------
500 # ----------------------------------------------------------------------------
501 return fonctionnelle, gradient
505 # ---------------------------------------------------------------------------------------------------------
506 # ---------------------------------------------------------------------------------------------------------
507 def run_include(self,list_val):
508 """ Module permettant de lancer N+1 calculs via un mecanisme d'include
511 # # Importation de commandes Aster
515 # from Accas import _F
516 # from Cata import cata
517 # from Cata.cata import *
518 # except ImportError:
519 # raise "Simu_point_mat doit etre lance depuis Aster"
524 from Cata import cata
525 from Cata.cata import OPER, MACRO
528 # Declaration de toutes les commandes Aster
530 for k,v in cata.__dict__.items() :
532 if isinstance(v, (OPER, MACRO)):
534 #self.jdc.current_context[k]= v
535 exec("from Cata.cata import %s" % k)
536 #self.jdc.current_context['_F']=cata.__dict__['_F']
538 raise "Le mode INCLUDE doit etre lance depuis Aster : \nErreur : " % e
541 list_params = self.list_params
543 reponses = self.calcul
545 # AA : marche pas car on peut oublier des courbes, tant pis on refait des extract en trop..
546 # liste_reponses = []
547 # for reponse in [ x[0] for x in calcul ]:
548 # if not reponse in liste_reponses: liste_reponses.append(reponse)
550 liste_reponses = [ x[0] for x in calcul ]
553 # ----------------------------------------------------------------------------
554 # Boucle sur les N+1 calculs
555 # ----------------------------------------------------------------------------
557 for i in range(len(list_val)):
561 # ----------------------------------------------------------------------------
562 # Affectation des valeurs des parametres
563 # ----------------------------------------------------------------------------
564 for nompara in list_params:
565 valpara = params[nompara]
566 exec( "%s=%s" % (nompara, valpara) ) # YOUN__ = X0[0], DSDE__ = X0[1], ...
569 # ----------------------------------------------------------------------------
570 # Affichage des parametres du calcul courant
571 # ----------------------------------------------------------------------------
572 tpara = Affiche_Param(list_params, [ params[x] for x in list_params] )
573 if i==0: UTMESS('I', 'RECAL0_67', valk=tpara)
574 else: UTMESS('I', 'RECAL0_68', valk=(tpara, list_params[i-1]) )
577 # ----------------------------------------------------------------------------
578 # Lancement du calcul (par un include)
579 # ----------------------------------------------------------------------------
580 new = "fort.%s.new" % self.UNITE_INCLUDE
584 # ----------------------------------------------------------------------------
585 # On considere que le job est OK s'il ne s'est pas plante dans le except precedent..
586 # ----------------------------------------------------------------------------
587 self.list_diag.append("OK")
590 # ----------------------------------------------------------------------------
591 # Extraction des tables
592 # ----------------------------------------------------------------------------
594 for i in range(len(liste_reponses)):
595 reponse = liste_reponses[i]
596 DETRUIRE(OBJET=_F(CHAINE='VEXTR___'), ALARME='NON', INFO=1) # Faudrait proteger ce nom ici (VEXTR___ peut etre deja utilise dans l'etude)
597 exec( "VEXTR___ = %s.EXTR_TABLE()" % reponse)
598 list_para = VEXTR___.para
599 tab_lue = VEXTR___.values()
600 F = table2numpy(tab_lue, list_para, reponses, i)
608 # Destruction des concepts Aster
609 liste_concepts = self.jdc.g_context.keys()
610 for c in liste_concepts:
611 DETRUIRE(OBJET=_F(CHAINE=c), ALARME='NON', INFO=1);
613 #detr_concepts(self.jdc) # marche pas !
617 # ----------------------------------------------------------------------------
618 # Calcul de la fonctionnelle et du gradient
619 # ----------------------------------------------------------------------------
620 if debug: print "AA4/Lcalc=", Lcalc
621 fonctionnelle, gradient = self.calc2fonc_gradient(Lcalc)
624 # ----------------------------------------------------------------------------
625 # Save all calculated responses
627 # ----------------------------------------------------------------------------
630 return fonctionnelle, gradient
637 # ---------------------------------------------------------------------------------------------------------
638 # ---------------------------------------------------------------------------------------------------------
639 def run_distrib(self, list_val):
640 """ Module permettant de lancer N+1 calculs avec le module de calculs distribues d'asrun
643 # ----------------------------------------------------------------------------
645 # ----------------------------------------------------------------------------
647 # Code_Aster installation
648 ASTER_ROOT = self.ASTER_ROOT
652 resudir = self.resudir
660 parametres = self.parametres
662 experience = self.experience
664 parametres = self.parametres
666 experience = self.experience
668 CalcGradient = self.CalcGradient
669 NMAX_SIMULT = self.NMAX_SIMULT
672 # ----------------------------------------------------------------------------
673 # Import des modules python d'ASTK
674 # ----------------------------------------------------------------------------
676 try: ASTER_ROOT = os.path.join(aster.repout, '..')
679 sys.path.append(os.path.join(ASTER_ROOT, 'ASTK', 'ASTK_SERV', 'lib'))
680 sys.path.append(os.path.join(ASTER_ROOT, 'lib', 'python%s.%s' % (sys.version_info[0], sys.version_info[1] ) , 'site-packages'))
683 from asrun.run import AsRunFactory
684 from asrun.profil import ASTER_PROFIL
685 from asrun.common_func import get_hostrc
686 from asrun.utils import get_timeout
687 from asrun.parametric import is_list_of_dict
688 from asrun.thread import Dispatcher
689 from asrun.distrib import DistribParametricTask
692 UTMESS('F','RECAL0_99')
695 assert is_list_of_dict(list_val)
696 nbval = len(list_val)
698 # ----------------------------------------------------------------------------
699 # Generation des etudes esclaves
700 # ----------------------------------------------------------------------------
703 run.options['debug_stderr'] = True # pas d'output d'executions des esclaves dans k'output maitre
706 prof = ASTER_PROFIL(filename=export)
707 tmp_param = tempfile.mkdtemp()
708 try: username = prof.param['username'][0]
709 except: username = os.environ['LOGNAME']
710 try: noeud = prof.param['noeud'][0]
711 except: noeud = platform.uname()[1]
712 tmp_param = "%s@%s:%s" % ( username, noeud, tmp_param)
713 prof.Set('R', {'type' : 'repe', 'isrep' : True, 'ul' : 0, 'compr' : False, 'path' : tmp_param })
714 if info>=2: print prof
716 # Si batch n'est pas possible, on bascule en interactif
717 if prof.param['mode'][0]=='batch' and run.get('batch')=='non':
718 UTMESS('I','RECAL0_28',valk=noeud)
719 prof.param['mode'][0] = 'interactif'
723 if not os.path.isdir(resudir):
724 try: os.mkdir(resudir)
726 if info>=1: UTMESS('A','RECAL0_82',valk=resudir)
729 # Par defaut, dans un sous-repertoire du repertoire d'execution
730 pref = 'tmp_macr_recal_'
731 # On cherche s'il y a un fichier hostfile pour placer les fichiers dans un repertoire partage
732 l_fr = getattr(prof, 'data')
735 if dico['type']=='hostfile':
736 pref = os.environ['HOME'] + os.sep + 'tmp_macr_recal_'
738 # Si batch alors on place les fichiers dans un repertoire partage
739 if prof['mode'][0]=='batch': pref = os.environ['HOME'] + os.sep + 'tmp_macr_recal_'
741 resudir = tempfile.mkdtemp(prefix=pref)
742 flashdir = os.path.join(resudir,'flash')
743 if info>=1: UTMESS('I','RECAL0_81',valk=resudir)
745 prof.WriteExportTo( os.path.join(resudir, 'master.export') )
748 hostrc = get_hostrc(run, prof)
750 # timeout before rejected a job
751 timeout = get_timeout(prof)
754 # Ajout des impressions de tables a la fin du .comm
757 for i in range(len(reponses)):
758 _ul = str(int(100+i))
761 # Pour la dynamique la table avec la matrice MAC a un traitement different
763 if ('MAC' in reponses[i][2]):
764 t.append( self.ajout_post_mac( reponses[i] ) )
766 try: os.remove( tmp_macr_recal+os.sep+"REPE_TABLE"+os.sep+"fort."+_ul )
769 t.append("\n# Recuperation de la table : " + str(reponses[i][0]) + "\n")
770 t.append("DEFI_FICHIER(UNITE=" + num_ul + ", FICHIER='" + os.path.join('.', 'REPE_OUT', 'fort.'+_ul) + "',);\n" )
771 t.append("IMPR_TABLE(TABLE="+str(reponses[i][0])+", FORMAT='ASTER', UNITE="+num_ul+", INFO=1, FORMAT_R='E30.20',);\n")
772 t.append("DEFI_FICHIER(ACTION='LIBERER', UNITE="+num_ul+",);\n")
775 # number of threads to follow execution
779 # ----------------------------------------------------------------------------
780 # Executions des etudes esclaves
781 # ----------------------------------------------------------------------------
782 # ----- Execute calcutions in parallel using a Dispatcher object
784 task = DistribParametricTask(run=run, prof=prof, # IN
786 nbmaxitem=self.NMAX_SIMULT, timeout=timeout,
787 resudir=resudir, flashdir=flashdir,
788 keywords={'POST_CALCUL': '\n'.join(t)},
790 nbnook=0, exec_result=[]) # OUT
791 # ... and dispatch task on 'list_tests'
792 etiq = 'calc_%%0%dd' % (int(log10(nbval)) + 1)
793 labels = [etiq % (i+1) for i in range(nbval)]
794 couples = zip(labels, list_val)
796 if info>=2: print couples
797 execution = Dispatcher(couples, task, numthread=numthread)
799 # ----------------------------------------------------------------------------
800 # Liste des diagnostics
801 # ----------------------------------------------------------------------------
803 for result in task.exec_result:
807 if len(result) >= 8: output_filename = os.path.join('~', 'flasheur', str(result[7]))
808 else: output_filename = ''
810 if not diag[0:2] in ['OK', '<A']:
811 if not diag in ['<F>_COPY_ERROR']:
812 UTMESS('A', 'RECAL0_70', valk=(label, output_filename))
814 # Affichage de l'output
816 f=open(output_filename, 'r')
823 UTMESS('F', 'RECAL0_71', valk=resudir)
824 self.list_diag = [ d_diag[label] for label in labels ]
826 # ----------------------------------------------------------------------------
827 # Arret si tous les jobs ne se sont pas deroules correctement
828 # ----------------------------------------------------------------------------
833 UTMESS('A', 'RECAL0_71', valk=resudir)
838 # ----------------------------------------------------------------------------
839 # Recuperation des tables calculees
840 # ----------------------------------------------------------------------------
844 tbl = get_tables(tables_calc=calcul, tmp_repe_table=os.path.join(resudir, c, 'REPE_OUT'), prof=prof)
845 Lcalc.append( tbl ) # On stocke sous la forme d'une liste de numpy
849 # ----------------------------------------------------------------------------
850 # Calcul de la fonctionnelle et du gradient
851 # ----------------------------------------------------------------------------
852 if debug: print "AA4/Lcalc=", Lcalc
853 fonctionnelle, gradient = self.calc2fonc_gradient(Lcalc)
856 # ----------------------------------------------------------------------------
857 # Clean result directories
858 # ----------------------------------------------------------------------------
859 if clean: shutil.rmtree(resudir, ignore_errors=True)
862 # ----------------------------------------------------------------------------
863 # Save all calculated responses
864 # ----------------------------------------------------------------------------
867 return fonctionnelle, gradient
870 # ---------------------------------------------------------------------------------------------------------
871 # ---------------------------------------------------------------------------
872 def calc2fonc_gradient(self, Lcalc):
873 """ Calculs de la fonctionnelle et du gradient a partir des tables calculees
876 #print "AA1/Lcalc=", Lcalc
879 CalcGradient = self.CalcGradient
881 # ----------------------------------------------------------------------------
882 # Recuperation des tables calculees
883 # ----------------------------------------------------------------------------
888 for i in range(len(Lcalc)):
894 FX.extend([ x[0] for x in array ])
895 FY.extend([ x[1] for x in array ])
896 ldims.append(len(array))
897 # Agregation des resultats
900 seq_DIMS.append(ldims)
904 # ----------------------------------------------------------------------------
906 # ----------------------------------------------------------------------------
907 # Calcul maitre (point X0)
908 idx0 = lst_iter.index(0) # index (les calculs arrivent-ils dans le desordre?)
910 fonctionnelle = FY_X0
913 # ----------------------------------------------------------------------------
914 # Procedure d'assemblage du gradient (une liste de liste)
915 # ----------------------------------------------------------------------------
918 for n in range(len(lst_iter))[1:]:
919 idx = lst_iter.index(n)
921 col = [ (y-x) for x, y in zip(FY, FY_X0) ]
923 #print 'Calcul numero: %s - Diagnostic: %s' % (n, self.list_diag[idx])
924 if info>=1: UTMESS('I', 'RECAL0_74', valk=(str(n), self.list_diag[idx]) )
926 # ----------------------------------------------------------------------------
928 # ----------------------------------------------------------------------------
930 UTMESS('I', 'RECAL0_72', valk=str(fonctionnelle))
933 UTMESS('I', 'RECAL0_73')
934 pprint.pprint(gradient)
936 return fonctionnelle, gradient
939 # ---------------------------------------------------------------------------------------------------------
940 # ---------------------------------------------------------------------------
941 def find_parameter0(self, content, param):
943 Return the lowest index in content where param is found and
944 the index of the end of the command.
946 if not self.ASTER_ROOT:
947 try: ASTER_ROOT = os.path.join(aster.repout, '..')
950 sys.path.append(os.path.join(ASTER_ROOT, 'ASTK', 'ASTK_SERV', 'lib'))
951 sys.path.append(os.path.join(ASTER_ROOT, 'lib', 'python%s.%s' % (sys.version_info[0], sys.version_info[1] ) , 'site-packages'))
954 from asrun.utils import search_enclosed
957 UTMESS('F','RECAL0_99')
960 re_start = re.compile('^ *%s *\=' % re.escape(param), re.M)
961 mat_start = re_start.search(content)
962 if mat_start is not None:
963 pos = mat_start.start()
964 endpos = search_enclosed(content, pos)
968 # ---------------------------------------------------------------------------------------------------------
969 # ---------------------------------------------------------------------------
970 def find_parameter(self, content, param):
972 Supprime les parametres du fichier de commande
974 re_start = re.compile('^ *%s *\=' % re.escape(param), re.M)
976 for line in content.split('\n'):
977 mat_start = re_start.search(line)
978 if mat_start is None: l.append(line)
982 # ---------------------------------------------------------------------------------------------------------
983 # ---------------------------------------------------------------------------
984 def ajout_post_mac(self, reponse):
986 Ajoute un bloc a la fin de l'esclave pour l'affichage des MAC pour l'appariement manuel
989 txt.append( "from Macro.reca_mac import extract_mac_array, get_modes, fenetre_mac\n" )
990 txt.append( "_mac = extract_mac_array("+str(reponse[0])+")\n" )
991 txt.append( "l_mac=[]\n" )
992 txt.append( "nb_freq=_mac.shape[1]\n" )
993 if (self.DYNAMIQUE['APPARIEMENT_MANUEL']=='OUI' and self.graph_mac):
994 txt.append( "frame =fenetre_mac(" + self.DYNAMIQUE['MODE_EXP']+"," + self.DYNAMIQUE['MODE_CALC']+",_mac)\n" )
995 txt.append( "list_exp,list_num =frame.get_list()\n" )
996 txt.append( "for i in range(nb_freq): l_mac.append(_mac[int(list_num[i])-1,int(list_exp[i])-1])\n" )
998 txt.append( "for i in range(nb_freq): l_mac.append(_mac[i,i])\n" )
999 txt.append( "DETRUIRE(CONCEPT=_F(NOM="+str(reponse[0])+"),)\n" )
1000 txt.append( str(reponse[0]) + "=CREA_TABLE(LISTE=(_F(PARA='NUME_ORDRE',LISTE_I=range(1,nb_freq+1),),_F(PARA='MAC',LISTE_R=l_mac,),),)\n" )
1001 return '\n'.join(txt)
1004 # --------------------------------------------------------------------------------------------------
1005 # --------------------------------------------------------------------------------------------------
1008 Classe gérant l'erreur par rapport aux donnees experimentales, la matrice des sensibilites
1010 # ---------------------------------------------------------------------------
1011 def __init__(self, experience, X0, calcul, poids=None, objective_type='vector', info=0, unite_resu=None):
1014 poids = NP.ones(len(experience))
1015 self.experience = experience
1017 self.calcul = calcul
1019 self.objective_type = objective_type
1021 self.unite_resu = unite_resu
1023 from Macro import reca_interp, reca_algo
1024 self.test_convergence = reca_algo.test_convergence
1025 self.calcul_gradient = reca_algo.calcul_gradient
1026 self.Simul = reca_interp.Sim_exp(self.experience, self.poids)
1027 try: self.Dim = reca_algo.Dimension(copy.copy(self.X0))
1028 except: self.Dim = reca_algo.Dimension(copy.copy(self.X0), None) # gere l'ancienne version de MACR_RECAL
1029 #self.Dim = reca_algo.Dimension(copy.copy(self.X0))
1032 self.L_J_init = None
1041 self.norme_A_ = None
1042 self.norme_A_nodim = None
1044 if info>=3: self.debug = True
1045 else: self.debug = False
1046 #if debug: self.debug = True
1050 # ---------------------------------------------------------------------------
1051 def CalcError(self, Lcalc):
1054 if self.L_init is None: self.L_init = copy.copy(self.F)
1056 self.L_J, self.erreur = self.Simul.multi_interpole(self.F, self.calcul)
1057 if self.L_J_init is None: self.L_J_init = copy.copy(self.L_J)
1059 self.J = self.Simul.norme_J( copy.copy(self.L_J_init), copy.copy(self.L_J) )
1060 if self.J_init is None: self.J_init = copy.copy(self.J)
1063 self.norme = NP.sum( [x**2 for x in self.erreur] )
1066 print "AA1/F=", self.F
1067 print "AA1/calcul=", self.calcul
1068 print "AA1/L_J=", self.L_J
1069 print "AA1/erreur=", self.erreur
1070 print "AA1/L_J_init=", self.L_J_init
1071 print "AA1/J=", self.J
1072 print "AA1/norme de l'erreur=", self.norme
1073 print "AA1/norme de J (fonctionnelle)=", str(self.J)
1076 UTMESS('I', 'RECAL0_30')
1078 if self.objective_type=='vector':
1079 if self.INFO>=1: UTMESS('I', 'RECAL0_35', valr=self.norme)
1082 if self.INFO>=1: UTMESS('I', 'RECAL0_36', valr=self.norme)
1086 # ---------------------------------------------------------------------------
1087 def CalcSensibilityMatrix(self, Lcalc, val, dX=None, pas=None):
1090 Calcul de F(X0) et de tous les F(X0+h)
1091 Formation de la matrice des sensibilites A
1092 N+1 calculs distribues
1095 if not dX and not pas: raise "Need 'dX' or 'pas' parameter."
1096 if dX and pas: raise "Need 'dX' or 'pas' parameter, not both."
1097 if pas: dX = len(val)*[pas]
1098 if len(dX) != len(val): raise "Error : 'dX' and 'val' parameters aren't compatible (lenght are not equal).\ndX = %s\nval = %s" % (str(dx), str(val))
1100 reponses = self.calcul
1101 resu_exp = self.experience
1102 len_para = len(val) # initialement len(self.para)
1105 # Erreur de l'interpolation de F_interp : valeur de F interpolée sur les valeurs experimentales
1107 F_interp = self.Simul.multi_interpole_sensib(F, reponses) #F_interp est une liste contenant des tab num des reponses interpolés
1110 # Creation de la liste des matrices de sensibilités
1112 for i in range(len(reponses)):
1113 L_A.append(NP.zeros((len(resu_exp[i]),len(val))) )
1115 for k in range(len(val)): # pour une colone de A (dim = nb parametres)
1117 F_perturbe = Lcalc[k+1]
1119 # Erreur de l'interpolation de F_perturb : valeur de F (perturbée) interpolée sur les valeurs experimentales
1120 F_perturbe_interp = self.Simul.multi_interpole_sensib(F_perturbe, reponses)
1122 # Calcul de L_A (matrice sensibilité des erreurs sur F interpolée)
1124 for j in range(len(reponses)):
1125 for i in range(len(resu_exp[j])):
1127 L_A[j][i,k] = -1*(F_interp[j][i] - F_perturbe_interp[j][i])/h
1130 fic=open(os.getcwd()+'/fort.'+str(unite_resu),'a')
1131 fic.write('\n Probleme de division par zéro dans le calcul de la matrice de sensiblité')
1132 fic.write('\n Le parametre '+para[k]+'est nul ou plus petit que la précision machine')
1134 UTMESS('F','RECAL0_45',valk=para[k])
1137 # On construit la matrice de sensiblité sous forme d'un tab num
1139 for i in range(len(L_A)):
1140 dim.append(len(L_A[i]))
1141 dim_totale = NP.sum(dim)
1143 self.A_nodim = NP.zeros((dim_totale,len(val)))
1144 for n in range(len(L_A)):
1145 for k in range(len(val)):
1146 for i in range(dim[n]):
1147 self.A_nodim[i+a][k] = L_A[n][i,k]
1153 self.A = self.Dim.adim_sensi( copy.copy(self.A_nodim) )
1155 # Si on n'est pas encore passe par CalcError...
1156 if self.erreur is None:
1157 self.erreur = self.CalcError(Lcalc)
1158 self.gradient_init = self.calcul_gradient(self.A, self.erreur) #utile pour le test de convergence, on prend les valeurs dimensionnées
1159 self.residu = self.test_convergence(self.gradient_init, self.erreur, self.A, NP.zeros(len(self.gradient_init)))
1162 print "AA1/erreur=", self.erreur
1163 print "AA1/residu=", self.residu
1164 print "AA1/A_nodim=", self.A_nodim
1165 print "AA1/A=", self.A
1168 if self.objective_type=='vector':
1169 return self.erreur, self.residu, self.A_nodim, self.A
1172 self.norme = NP.dot(self.erreur, self.erreur)**0.5
1173 self.norme_A_nodim = NP.zeros( (1,len_para))
1174 self.norme_A = NP.zeros( (1,len_para))
1175 for c in range(len(self.A[0,:])):
1178 for l in range(len(self.A[:,0])):
1179 norme_A_nodim += self.A_nodim[l,c] * self.A_nodim[l,c]
1180 norme_A += self.A[l,c] * self.A[l,c]
1181 self.norme_A_nodim[0,c] = math.sqrt( norme_A_nodim )
1182 self.norme_A[0,c] = math.sqrt( norme_A )
1184 print "AA1/norme_A_nodim=", self.norme_A_nodim
1185 print "AA1/norme_A=", self.norme_A
1186 return self.erreur, self.residu, self.norme_A_nodim, self.norme_A
1193 # ----------------------------------------------------------------------------------------------------------------------
1194 # ----------------------------------------------------------------------------------------------------------------------
1195 if __name__ == '__main__':
1197 # Execution via YACS ou en externe
1198 isFromYacs = globals().get('ASTER_ROOT', None)
1201 # ------------------------------------------------------------------------------------------------------------------
1202 # Execution depuis YACS
1203 # ------------------------------------------------------------------------------------------------------------------
1205 # Execution depuis YACS : les parametres sont deja charges en memoire
1207 # ----------------------------------------------------------------------------
1208 # Parametres courant
1209 X0 = globals().get('X0', [ 80000., 1000., 30. ])
1210 dX = globals().get('dX', [ 0.001, 0.001, 0.0001])
1211 # ----------------------------------------------------------------------------
1213 # ----------------------------------------------------------------------------
1215 os.environ['ASTER_ROOT'] = ASTER_ROOT
1222 # ----------------------------------------------------------------------------
1225 # ------------------------------------------------------------------------------------------------------------------
1226 # Execution en mode EXTERNE
1227 # ------------------------------------------------------------------------------------------------------------------
1229 # Execution en mode EXTERNE : on doit depouiller les parametres de la ligne de commande
1232 from optparse import OptionParser, OptionGroup
1234 p = OptionParser(usage='usage: %s fichier_export [options]' % sys.argv[0])
1236 # Current estimation
1237 p.add_option('--input', action='store', dest='input', type='string', help='Chaine de texte contenant les parametres')
1238 p.add_option('--input_step', action='store', dest='input_step', type='string', help='Chaine de texte contenant les pas de discretisation des differences finies')
1239 p.add_option('--input_file', action='store', dest='input_file', type='string', default='input.txt', help='Fichier contenant les parametres')
1240 p.add_option('--input_step_file', action='store', dest='input_step_file', type='string', help='Fichier contenant les pas de discretisation des differences finies')
1243 p.add_option('--output', action='store', dest='output', type='string', default='output.txt', help='fichier contenant la fonctionnelle')
1244 p.add_option('--output_grad', action='store', dest='output_grad', type='string', default='grad.txt', help='fichier contenant le gradient')
1246 # Code_Aster installation
1247 p.add_option('--aster_root', action='store', dest='aster_root', type='string', help="Chemin d'installation d'Aster")
1248 p.add_option('--as_run', action='store', dest='as_run', type='string', help="Chemin vers as_run")
1251 p.add_option('--resudir', action='store', dest='resudir', type='string', help="Chemin par defaut des executions temporaires d'Aster")
1252 p.add_option("--noclean", action="store_false", dest="clean", default=True, help="Erase temporary Code_Aster execution directory")
1253 p.add_option('--info', action='store', dest='info', type='int', default=1, help="niveau de message (0, [1], 2)")
1254 p.add_option('--sources_root', action='store', dest='SOURCES_ROOT', type='string', help="Chemin par defaut des surcharges Python")
1255 #p.add_option('--slave_computation', action='store', dest='slave_computation', type='string', default='distrib', help="Evaluation de l'esclave ([distrib], include)")
1257 # MACR_RECAL parameters
1258 p.add_option('--objective', action='store', dest='objective', type='string', default='fcalc', help="Fonctionnelle ([fcalc]/[error])")
1259 p.add_option('--objective_type', action='store', dest='objective_type', type='string', default='vector', help="type de la fonctionnelle (float/[vector])")
1260 p.add_option('--gradient_type', action='store', dest='gradient_type' , type='string', default='no', help="calcul du gradient par Aster ([no]/normal/adim)")
1263 p.add_option('--mr_parameters', action='store', dest='mr_parameters', type='string', default='N_MR_Parameters.py', help="Fichier de parametres de MACR_RECAL : parametres, calcul, experience")
1264 p.add_option('--study_parameters', action='store', dest='study_parameters', type='string', help="Fichier de parametre de l'etude : export")
1265 p.add_option('--parameters', action='store', dest='parameters', type='string', help="Fichier de parametres")
1267 options, args = p.parse_args()
1270 # Study : .export file
1271 if args: export = args[0]
1273 liste = glob.glob('*.export')
1275 if not os.path.isfile(export): raise "Export file : is missing!"
1278 # Code_Aster installation
1280 if options.aster_root: ASTER_ROOT = options.aster_root
1281 elif os.environ.has_key('ASTER_ROOT'): ASTER_ROOT = os.environ['ASTER_ROOT']
1282 if not ASTER_ROOT: raise "ASTER_ROOT is missing! Set it by --aster_root flag or environment variable ASTER_ROOT"
1283 if not os.path.isdir(ASTER_ROOT): raise "Wrong directory for ASTER_ROOT : %s" % ASTER_ROOT
1284 os.environ['ASTER_ROOT'] = ASTER_ROOT
1285 # sys.path.append(get_absolute_path(os.path.join(ASTER_ROOT, 'STA10.1', 'bibpyt' )))
1286 # from Utilitai.Utmess import UTMESS
1288 if options.as_run: as_run = options.as_run
1289 else: as_run = os.path.join(ASTER_ROOT, 'bin', 'as_run')
1293 if options.resudir: resudir = options.resudir
1294 clean = options.clean
1296 # if options.info == 0: info = False
1297 # elif options.info == 1: info = False
1298 # elif options.info == 2: info = True
1301 # Import des modules supplementaires
1302 if options.SOURCES_ROOT:
1303 if not os.path.isdir(options.SOURCES_ROOT): raise "Wrong directory for sources_root : %s" % options.SOURCES_ROOT
1305 sys.path.insert(0, options.SOURCES_ROOT)
1306 sys.path.insert(0, os.path.join(options.SOURCES_ROOT, 'sources'))
1310 if options.mr_parameters:
1312 if info>=1: print "Read MR parameters file : %s" % options.mr_parameters
1313 execfile(options.mr_parameters)
1314 except: raise "Wrong file for MR Parameters: %s" % options.mr_parameters
1315 else: raise "MR Parameters file needed ! Use --mr_parameters flag"
1316 parametres = globals().get('parametres', None)
1317 calcul = globals().get('calcul', None)
1318 experience = globals().get('experience', None)
1319 poids = globals().get('poids', None)
1321 if not parametres: raise "MR Parameters file need to define 'parametres' variable"
1322 if not calcul: raise "MR Parameters file need to define 'calcul' variable"
1323 if type(parametres) != list: raise "Wrong type for 'parametres' variable in MR parameters file : %s" % options.mr_parameters
1324 if type(calcul) != list: raise "Wrong type for 'calcul' variable in MR parameters file : %s" % options.mr_parameters
1326 if options.objective == 'error':
1327 if type(experience) != list: raise "For error objective output, the 'experience' variable must be a list of arrays"
1328 if type(poids) not in [list, tuple, NP.ndarray]: raise "The 'poids' variable must be a list or an array"
1329 if len(poids) != len(experience): raise "'experience' and 'poids' lists must have the same lenght"
1332 # MACR_RECAL parameters
1333 objective = options.objective
1334 objective_type = options.objective_type
1335 gradient_type = options.gradient_type
1338 # X0 : read from commandline flag or from file
1339 if not os.path.isfile(options.input_file): options.input_file = None
1340 if not (options.input or options.input_file): raise "Missing input parameters"
1341 if (options.input and options.input_file): raise "Error : please use only one choice for input parameters definition"
1343 if options.input_file:
1345 f = open(options.input_file, 'r')
1346 options.input = f.read()
1349 raise "Can't read input parameters file : %s" % options.input_file
1351 # Extract X0 from text
1353 txt = options.input.strip()
1354 txt = txt.replace(',', ' ')
1355 txt = txt.replace(';', ' ')
1356 X0 = [ float(x) for x in txt.split() ]
1357 if type(X0) != list: raise "Wrong string for input parameters : %s" % options.input
1359 raise "Can't decode input parameters string : %s.\n It should be a comma separated list." % options.input
1362 # dX : read from commandline flag or from file
1364 if options.gradient_type == 'no':
1365 if (options.input_step or options.input_step_file): raise "You must set 'gradient_type' to another choice than 'no' or remove input step parameters from commandline"
1367 if not (options.input_step or options.input_step_file): raise "Missing input step parameters"
1368 if (options.input_step and options.input_step_file): raise "Error : please use only one choice for input step parameters definition"
1370 if options.input_step_file:
1372 f = open(options.input_step_file, 'r')
1373 options.input_step = f.read()
1376 raise "Can't read file for discretisation step : %s" % options.input_step_file
1378 # Extract dX from text
1380 txt = options.input_step.strip()
1381 txt = txt.replace(',', ' ')
1382 txt = txt.replace(';', ' ')
1383 dX = [ float(x) for x in txt.split() ]
1384 if type(dX) != list: raise "Wrong string for discretisation step : %s" % options.input_step
1386 raise "Can't decode input parameters string : %s.\n It should be a comma separated list." % options.input_step
1391 # ------------------------------------------------------------------------------------------------------------------
1392 # Execution des calculs (N+1 calculs distribues si dX est fourni)
1393 # ------------------------------------------------------------------------------------------------------------------
1395 # Repertoire contenant les resultats des calculs Aster (None = un rep temp est cree)
1396 resudir = globals().get('resudir', None)
1398 # Affichage des parametres
1399 lpara = [x[0] for x in parametres]
1402 lpara = [x[0] for x in parametres]
1404 print "Calcul avec les parametres : \n%s" % Affiche_Param(lpara, X0)
1408 parametres = parametres,
1410 experience = experience,
1413 fonctionnelle, gradient = C.run(
1414 # Current estimation
1418 # Code_Aster installation
1419 ASTER_ROOT = ASTER_ROOT,
1430 # # MACR_RECAL inputs
1431 # parametres = parametres,
1433 # experience = experience,
1436 # ------------------------------------------------------------------------------------------------------------------
1437 # Calcul de l'erreur par rapport aux donnees experimentale
1438 # ------------------------------------------------------------------------------------------------------------------
1439 if not isFromYacs: # Execution en mode EXTERNE uniquement
1441 # Calcul de l'erreur par rapport aux donnees experimentale
1442 if objective == 'error':
1444 experience = experience,
1448 objective_type = objective_type,
1452 erreur = E.CalcError(C.Lcalc)
1453 erreur, residu, A_nodim, A = E.CalcSensibilityMatrix(C.Lcalc, X0, dX=dX, pas=None)
1455 fonctionnelle = erreur
1456 if gradient_type == 'normal': gradient = A
1457 elif gradient_type == 'adim': gradient = A_nodim
1462 # ------------------------------------------------------------------------------------------------------------------
1463 # Ecriture des resultats
1464 # ------------------------------------------------------------------------------------------------------------------
1465 if not isFromYacs: # Execution en mode EXTERNE uniquement
1468 if options.objective_type == 'float':
1469 fonctionnelle = math.sqrt( NP.sum( [x**2 for x in fonctionnelle] ) )
1470 Ecriture_Fonctionnelle(output_file=options.output, type_fonctionnelle=options.objective_type, fonctionnelle=fonctionnelle)
1473 if gradient: Ecriture_Derivees(output_file=options.output_grad, derivees=gradient)
1477 # ------------------------------------------------------------------------------------------------------------------
1479 # ------------------------------------------------------------------------------------------------------------------
1481 print "\nFonctionnelle au point X0: \n%s" % str(fonctionnelle)
1484 print "\nGradient au point X0:"
1485 pprint.pprint(gradient)