1 #@ MODIF reca_interp Macro DATE 16/10/2007 AUTEUR REZETTE C.REZETTE
2 # -*- coding: iso-8859-1 -*-
3 # RESPONSABLE ASSIRE A.ASSIRE
4 # CONFIGURATION MANAGEMENT OF EDF VERSION
5 # ======================================================================
6 # COPYRIGHT (C) 1991 - 2002 EDF R&D WWW.CODE-ASTER.ORG
7 # THIS PROGRAM IS FREE SOFTWARE; YOU CAN REDISTRIBUTE IT AND/OR MODIFY
8 # IT UNDER THE TERMS OF THE GNU GENERAL PUBLIC LICENSE AS PUBLISHED BY
9 # THE FREE SOFTWARE FOUNDATION; EITHER VERSION 2 OF THE LICENSE, OR
10 # (AT YOUR OPTION) ANY LATER VERSION.
12 # THIS PROGRAM IS DISTRIBUTED IN THE HOPE THAT IT WILL BE USEFUL, BUT
13 # WITHOUT ANY WARRANTY; WITHOUT EVEN THE IMPLIED WARRANTY OF
14 # MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. SEE THE GNU
15 # GENERAL PUBLIC LICENSE FOR MORE DETAILS.
17 # YOU SHOULD HAVE RECEIVED A COPY OF THE GNU GENERAL PUBLIC LICENSE
18 # ALONG WITH THIS PROGRAM; IF NOT, WRITE TO EDF R&D CODE_ASTER,
19 # 1 AVENUE DU GENERAL DE GAULLE, 92141 CLAMART CEDEX, FRANCE.
20 # ======================================================================
22 import os, sys, pprint
24 from externe_mess import UTMESS
30 #===========================================================================================
33 # INTERPOLATION, CALCUL DE SENSIBILITE, ETC....
35 #--------------------------------------
38 def __init__ (self,result_exp,poids) :
39 self.resu_exp = result_exp
42 # ------------------------------------------------------------------------------
44 def InterpolationLineaire (self, x0, points) :
46 Interpolation Lineaire de x0 sur la fonction discrétisée yi=points(xi) i=1,..,n
48 # x0 = Une abscisse (1 colonne, 1 ligne)
49 # points = Tableau de n points (2 colonnes, n lignes)
50 # on suppose qu'il existe au moins 2 points,
51 # et que les points sont classés selon les abscisses croissantes
54 if ( x0 < points[0][0] ) or ( x0 > points[n-1][0] ) :
55 txt = "Problème lors de l'interpolation du calcul dérivé sur les données expérimentale!"
56 txt += "\nValeur à interpoler : " + str(x0)
57 txt += "\nDomaine couvert par l'experience : [" + str(points[0][0]) + ":" + str(points[n-1][0]) + "]"
58 UTMESS('F','MACR_RECAL', txt)
61 while x0 > points[i][0]:
64 y0 = (x0-points[i-1][0]) * (points[i][1]-points[i-1][1]) / (points[i][0]-points[i-1][0]) + points[i-1][1]
71 # ------------------------------------------------------------------------------
73 def DistVertAdimPointLigneBrisee (self, M, points) :
75 Distance verticale d'un point M à une ligne brisée composée de n points
77 # M = Point (2 colonnes, 1 ligne)
78 # points = Tableau de n points (2 colonnes, n lignes)
79 # on suppose qu'il existe au moins 2 points,
80 # et que les points sont classés selon les abscisses croissantes
82 if ( M[0] < points[0][0] ) or ( M[0] > points[n-1][0] ):
85 while M[0] > points[i][0]:
87 y_proj_vert = (M[0]-points[i-1][0]) * (points[i][1]-points[i-1][1]) / (points[i][0]-points[i-1][0]) + points[i-1][1]
88 d = (M[1] - y_proj_vert)
89 # Attention: la distance n'est pas normalisée
90 # Attention: problème si points[0][0] = points[1][0] = M[0]
91 # Attention: problème si M[1] = 0
95 # ------------------------------------------------------------------------------
97 def _Interpole(self, F_calc,experience,poids) : #ici on passe en argument "une" experience
99 La Fonction Interpole interpole une et une seule F_calc sur F_exp et renvoie l'erreur seulement
104 n_exp = len(experience) # nombre de points sur la courbe expérimentale num.i
105 stockage = Numeric.ones(n_exp, Numeric.Float) # matrice de stockage des erreurs en chaque point
106 for j in xrange(n_exp) :
107 d = self.DistVertAdimPointLigneBrisee(experience[j], resu_num)
109 stockage[n] = d/experience[j][1]
110 except ZeroDivisionError:
113 n = n + 1 # on totalise le nombre de points valables
114 err = Numeric.ones(n, Numeric.Float)
117 err[i] = poids*stockage[i]
121 # ------------------------------------------------------------------------------
123 def multi_interpole(self, L_F, reponses):
125 Cette fonction appelle la fonction interpole et retourne les sous-fonctionnelles J et l'erreur.
126 On interpole toutes les reponses une à une en appelant la methode interpole.
130 for i in range(len(reponses)):
131 err = self._Interpole(L_F[i],self.resu_exp[i],self.poids[i])
134 # print "L_erreur=", L_erreur
136 # On transforme L_erreur en tab num
139 for i in range(len(L_erreur)):
140 dim.append(len(L_erreur[i]))
141 dim_totale = Numeric.sum(dim)
142 L_J = self.calcul_J(L_erreur)
144 erreur = Numeric.zeros((dim_totale),Numeric.Float)
145 for n in range(len(L_erreur)):
146 for i in range(dim[n]):
147 erreur[i+a] = L_erreur[n][i]
149 del(L_erreur) #on vide la liste puisqu'on n'en a plus besoin
153 # ------------------------------------------------------------------------------
155 def multi_interpole_sensib(self, L_F, reponses):
157 Cette fonction retourne seulement l'erreur, elle est appelée dans la methode sensibilité.
158 On interpole toutes les reponses une à une en appelant la methode interpole.
162 for i in range(len(reponses)):
163 err = self._Interpole(L_F[i], self.resu_exp[i], self.poids[i])
165 # On transforme L_erreur en tab num
169 # ------------------------------------------------------------------------------
171 def calcul_J(self,L_erreur):
173 for i in range(len(L_erreur)):
175 for j in range(len(L_erreur[i])):
176 total = total + L_erreur[i][j]**2
181 # ------------------------------------------------------------------------------
183 def norme_J(self,L_J_init,L_J,unite_resu=None):
185 Cette fonction calcul une valeur normée de J
187 for i in range(len(L_J)):
189 L_J[i] = L_J[i]/L_J_init[i]
190 except ZeroDivisionError:
191 message= 'Problème de division par zéro dans la normalisation de la fonctionnelle.\n'
192 message=message+'Une des valeurs de la fonctionnelle initiale est nulle ou inférieure à la précision machine : %.2f \n'%L_J_init
194 fic=open(os.getcwd()+'/fort.'+str(unite_resu),'a')
197 UTMESS('F', "MACR_RECAL", message)
205 # ------------------------------------------------------------------------------
207 # def sensibilite(self,objet,UL,F,L_deriv_sensible,val,para,reponses,pas,unite_resu,LIST_SENSI=[],LIST_DERIV=[],INFO=1):
209 def sensibilite(self, CALCUL_ASTER, F, L_deriv_sensible, val, pas):
211 # CALCUL_ASTER est l'objet regroupant le calcul de F et des derivées, ainsi que les options
213 para = CALCUL_ASTER.para
214 reponses = CALCUL_ASTER.reponses
215 unite_resu = CALCUL_ASTER.UNITE_RESU
216 LIST_SENSI = CALCUL_ASTER.LIST_SENSI
217 LIST_DERIV = CALCUL_ASTER.LIST_DERIV
218 INFO = CALCUL_ASTER.INFO
222 # Erreur de l'interpolation de F_interp : valeur de F interpolée sur les valeurs experimentales
223 F_interp = self.multi_interpole_sensib(F, reponses) #F_interp est une liste contenant des tab num des reponses interpolés
225 # Creation de la liste des matrices de sensibilités
227 for i in range(len(reponses)):
228 L_A.append(Numeric.zeros((len(self.resu_exp[i]),len(val)),Numeric.Float) )
230 for k in range(len(val)): # pour une colone de A (dim = nb parametres)
232 # On utilise les differences finies pour calculer la sensibilité
233 # --------------------------------------------------------------
234 # Dans ce cas, un premier calcul_Aster pour val[k] a deja ete effectué, on effectue un autre calcul_Aster pour val[k]+h
236 if para[k] not in LIST_SENSI:
239 if INFO>=2: UTMESS('I','MACR_RECAL','On utilise les differences finies pour calculer la sensibilite de : %s ' % para[k])
241 fic=open(os.getcwd()+'/fort.'+str(unite_resu),'a')
242 fic.write('\nCalcul de la sensibilité par differences finies pour : '+para[k])
249 # Calcul_Aster pour la valeur perturbée
250 F_perturbe, L_deriv = CALCUL_ASTER.calcul_Aster(val)
252 # Erreur de l'interpolation de F_perturb : valeur de F (perturbée) interpolée sur les valeurs experimentales
253 F_perturbe_interp =self.multi_interpole_sensib(F_perturbe, reponses)
255 # On replace les parametres a leurs valeurs initiales
258 # Calcul de L_A (matrice sensibilité des erreurs sur F interpolée)
259 for j in range(len(reponses)):
260 for i in range(len(self.resu_exp[j])):
262 L_A[j][i,k] = -1*(F_interp[j][i] - F_perturbe_interp[j][i])/h
263 except ZeroDivisionError:
264 fic=open(os.getcwd()+'/fort.'+str(unite_resu),'a')
265 fic.write('\n Probleme de division par zéro dans le calcul de la matrice de sensiblité')
266 fic.write('\n Le parametre '+para[k]+'est nul ou plus petit que la précision machine')
268 UTMESS('F','MACR_RECAL',"Probleme de division par zéro dans le calcul de la matrice de sensiblité.\n Le parametre "+para[k]+"est nul ou plus petit que la précision machine")
272 # On utilise le calcul de SENSIBILITE
273 # --------------------------------------------------------------
274 # Dans ce cas, L_deriv_sensible a deja ete calculé pour le premier calcul pour val[k], aucun autre calcul_F n'est a lancer
276 if INFO>=2: UTMESS('I','MACR_RECAL','On utilise le calcul de SENSIBILITE pour : %s ' % para[k])
279 fic=open(os.getcwd()+'/fort.'+str(unite_resu),'a')
280 fic.write('\nCalcul de la sensibilité par la SENSIBILITE pour : '+para[k])
283 L_deriv_sensible_interp = L_deriv_sensible
285 # Calcul de L_A (matrice sensibilité des erreurs sur F interpolée)
286 for j in range(len(reponses)):
287 for i in range(len(self.resu_exp[j])):
289 # On interpole la fonction derivée aux points experimentaux
290 val_derivee_interpolee = self.InterpolationLineaire( self.resu_exp[j][i][0], L_deriv_sensible_interp[ para[k] ][:][j] )
292 # Application du poids de la reponse courante j
293 val_derivee_interpolee = val_derivee_interpolee*self.poids[j]
296 L_A[j][i,k] = -1.* ( val_derivee_interpolee ) / self.resu_exp[j][i][1]
297 except ZeroDivisionError:
298 L_A[j][i,k] = -1.* ( val_derivee_interpolee )
301 # --------------------------------------------------------------
303 # On construit la matrice de sensiblité sous forme d'un tab num
305 for i in range(len(L_A)):
306 dim.append(len(L_A[i]))
307 dim_totale = Numeric.sum(dim)
309 A = Numeric.zeros((dim_totale,len(val)),Numeric.Float)
310 for n in range(len(L_A)):
311 for k in range(len(val)):
312 for i in range(dim[n]):
313 A[i+a][k] = L_A[n][i,k]
316 del(L_A) # On ecrase tout ce qu'il y a dans L_A puisqu'on n'en a plus besoin