1 #@ MODIF t_fonction Utilitai DATE 25/09/2006 AUTEUR MCOURTOI M.COURTOIS
2 # -*- coding: iso-8859-1 -*-
3 # CONFIGURATION MANAGEMENT OF EDF VERSION
4 # ======================================================================
5 # COPYRIGHT (C) 1991 - 2005 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 # ======================================================================
25 class FonctionError(Exception):
28 def interp(typ_i,val,x1,x2,y1,y2) :
29 """Interpolation linéaire/logarithmique entre un couple de valeurs
31 if typ_i==['LIN','LIN']: return y1+(y2-y1)*(val-x1)/(x2-x1)
32 if typ_i==['LIN','LOG']: return exp(log(y1)+(val-x1)*(log(y2)-log(y1))/(x2-x1))
33 if typ_i==['LOG','LOG']: return exp(log(y1)+(log(val)-log(x1))*(log(y2)-log(y1))/(log(x2)-log(x1)))
34 if typ_i==['LOG','LIN']: return y1+(log(val)-log(x1))*(y2-y1)/(log(x2)-log(x1))
36 if val==x1 : return y1
37 elif val==x2 : return y2
38 else : raise FonctionError, 'fonction : interpolation NON'
40 listb=list(Set(liste))
45 """Classe pour fonctions réelles, équivalent au type aster = fonction_sdaster
47 def __init__(self,vale_x,vale_y,para) :
48 """Création d'un objet fonction
49 - vale_x et vale_y sont des listes de réels de meme longueur
50 - para est un dictionnaire contenant les entrées PROL_DROITE, PROL_GAUCHE et INTERPOL (cf sd ASTER)
54 if pk!=['INTERPOL','NOM_PARA','NOM_RESU','PROL_DROITE','PROL_GAUCHE'] :
55 raise FonctionError, 'fonction : parametres incorrects'
56 if para['INTERPOL'] not in [['NON','NON'],['LIN','LIN'],['LIN','LOG'],['LOG','LOG'],['LOG','LIN'],] :
57 raise FonctionError, 'fonction : parametre INTERPOL incorrect'
58 if para['PROL_DROITE'] not in ['EXCLU','CONSTANT','LINEAIRE'] :
59 raise FonctionError, 'fonction : parametre PROL_DROITE incorrect'
60 if para['PROL_GAUCHE'] not in ['EXCLU','CONSTANT','LINEAIRE'] :
61 raise FonctionError, 'fonction : parametre PROL_GAUCHE incorrect'
62 self.vale_x = array(vale_x)
63 self.vale_y = array(vale_y)
65 if len(self.vale_x)!=len(self.vale_y) :
66 raise FonctionError, 'fonction : longueur abscisse <> longueur ordonnées'
67 if not is_ordo(self.vale_x) :
68 raise FonctionError, 'fonction : abscisses non strictement croissantes'
70 def __add__(self,other) :
71 """addition avec une autre fonction ou un nombre, par surcharge de l'opérateur +
73 if isinstance(other,t_fonction):
74 para=copy.copy(self.para)
75 vale_x,para['PROL_GAUCHE'],para['PROL_DROITE']=self.homo_support(other)
76 fff=self.evalfonc(vale_x)
77 ggg=other.evalfonc(vale_x)
78 if isinstance(self,t_fonction_c): return t_fonction_c(vale_x,fff.vale_y+ggg.vale_y,para)
79 else : return t_fonction(vale_x,fff.vale_y+ggg.vale_y,para)
80 elif type(other) in [types.FloatType,types.IntType,types.ComplexType] :
81 if isinstance(self,t_fonction_c): return t_fonction_c(self.vale_x,self.vale_y+other,self.para)
82 else : return t_fonction(self.vale_x,self.vale_y+other,self.para)
83 else: raise FonctionError, 'fonctions : erreur de type dans __add__'
85 def __mul__(self,other) :
86 """multiplication avec une autre fonction ou un nombre, par surcharge de l'opérateur *
88 if isinstance(other,t_fonction):
89 para=copy.copy(self.para)
90 vale_x,para['PROL_GAUCHE'],para['PROL_DROITE']=self.homo_support(other)
91 fff=self.evalfonc(vale_x)
92 ggg=other.evalfonc(vale_x)
93 if isinstance(self,t_fonction_c): return t_fonction_c(vale_x,fff.vale_y*ggg.vale_y,para)
94 else : return t_fonction(vale_x,fff.vale_y*ggg.vale_y,para)
95 elif type(other) in [types.FloatType,types.IntType] :
96 return t_fonction(self.vale_x,self.vale_y*other,self.para)
97 elif type(other) ==types.ComplexType :
98 return t_fonction_c(self.vale_x,self.vale_y*other,self.para)
99 else: raise FonctionError, 'fonctions : erreur de type dans __mul__'
102 """affichage de la fonction en double colonne
105 for i in range(len(self.vale_x)) :
106 texte.append('%f %f' % (self.vale_x[i],self.vale_y[i]))
107 return '\n'.join(texte)
109 def __getitem__(self,other) :
110 """composition de deux fonction F[G]=FoG=F(G(x))
112 para=copy.copy(self.para)
113 if other.para['NOM_RESU']!=self.para['NOM_PARA'] :
114 raise FonctionError,'''composition de fonctions : NOM_RESU1 et NOM_PARA2 incohérents '''
115 para['NOM_PARA']==other.para['NOM_PARA']
116 return t_fonction(other.vale_x,map(self,other.vale_y),para)
118 def __call__(self,val,tol=1.e-6):
119 """méthode pour évaluer f(x)
120 - tolérance, par défaut 1.e-6 en relatif sur la longueur de l'intervalle
121 - adjacent, pour capter les erreurs d'arrondi en cas de prolongement exclu
123 i=searchsorted(self.vale_x,val)
126 if self.para['PROL_GAUCHE']=='EXCLU' :
127 eps_g=(val-self.vale_x[0] )/(self.vale_x[1] -self.vale_x[0])
128 if abs(eps_g)<=tol : return self.vale_y[0]
129 else : raise FonctionError, 'fonction évaluée hors du domaine de définition'
131 if self.para['PROL_GAUCHE']=='CONSTANT' : return self.vale_y[0]
132 if self.para['PROL_GAUCHE']=='LINEAIRE' : return interp(self.para['INTERPOL'],val,self.vale_x[0],
137 if self.para['PROL_DROITE']=='EXCLU' :
138 eps_d=(val-self.vale_x[-1])/(self.vale_x[-1]-self.vale_x[-2])
139 if abs(eps_d)<=tol : return self.vale_y[-1]
140 else : raise FonctionError, 'fonction évaluée hors du domaine de définition'
142 if self.para['PROL_DROITE']=='CONSTANT' : return self.vale_y[-1]
143 if self.para['PROL_DROITE']=='LINEAIRE' : return interp(self.para['INTERPOL'],val,self.vale_x[-1],
148 return interp(self.para['INTERPOL'],val,self.vale_x[i-1],
153 def homo_support(self,other) :
154 """Renvoie le support d'abscisses homogénéisé entre self et other
155 i.e. si prolongement exclu, on retient plus grand min ou plus petit max, selon
156 si prolongement autorisé, on conserve les abscisses d'une fonction, extrapolantes
158 Pour les points intermédiaires : union et tri des valeurs des vale_x réunis.
160 if other.vale_x[0]>self.vale_x[0]:
161 if other.para['PROL_GAUCHE']!='EXCLU' : f_g=self
164 if self.para['PROL_GAUCHE'] !='EXCLU' : f_g=other
166 val_min =f_g.vale_x[0]
167 prol_gauche=f_g.para['PROL_GAUCHE']
168 if self.vale_x[0]>other.vale_x[0]:
169 if other.para['PROL_DROITE']!='EXCLU' : f_d=self
172 if self.para['PROL_DROITE'] !='EXCLU' : f_d=other
174 val_max =f_d.vale_x[-1]
175 prol_droite=f_d.para['PROL_DROITE']
176 vale_x=concatenate((self.vale_x,other.vale_x))
177 vale_x=clip(vale_x,val_min,val_max)
178 vale_x=sort(dict([(i,0) for i in vale_x]).keys())
179 return vale_x,prol_gauche,prol_droite
181 def cut(self,rinf,rsup,prec,crit='RELATIF') :
182 """Renvoie la fonction self dont on a 'coupé' les extrémités en x=rinf et x=rsup
183 pour la recherche de rinf et rsup dans la liste d'abscisses :
184 prec=precision crit='absolu' ou 'relatif'
186 para=copy.copy(self.para)
187 para['PROL_GAUCHE']='EXCLU'
188 para['PROL_DROITE']='EXCLU'
189 if crit=='ABSOLU' : rinf_tab=greater(abs(self.vale_x-rinf),prec)
190 elif crit=='RELATIF': rinf_tab=greater(abs(self.vale_x-rinf),prec*rinf)
191 else : raise FonctionError, 'fonction : cut : critère absolu ou relatif'
192 if crit=='ABSOLU' : rsup_tab=greater(abs(self.vale_x-rsup),prec)
193 elif crit=='RELATIF': rsup_tab=greater(abs(self.vale_x-rsup),prec*rsup)
194 else : raise FonctionError, 'fonction : cut : critère absolu ou relatif'
195 if alltrue(rinf_tab) : i=searchsorted(self.vale_x,rinf)
196 else : i=rinf_tab.tolist().index(0)+1
197 if alltrue(rsup_tab) : j=searchsorted(self.vale_x,rsup)
198 else : j=rsup_tab.tolist().index(0)
199 vale_x=array([rinf,]+self.vale_x.tolist()[i:j]+[rsup,])
200 vale_y=array([self(rinf),]+self.vale_y.tolist()[i:j]+[self(rsup),])
201 return t_fonction(vale_x,vale_y,para)
203 def cat(self,other,surcharge) :
204 """renvoie une fonction concaténée avec une autre, avec règles de surcharge
206 para=copy.copy(self.para)
207 if self.para['INTERPOL']!=other.para['INTERPOL'] : raise FonctionError, 'concaténation de fonctions à interpolations différentes'
208 if min(self.vale_x)<min(other.vale_x) :
214 para['PROL_GAUCHE']=f1.para['PROL_GAUCHE']
215 if surcharge=='GAUCHE' :
216 i=searchsorted(f2.vale_x,f1.vale_x[-1])
217 if i!=len(f2.vale_x) : para['PROL_DROITE']=f2.para['PROL_DROITE']
218 else : para['PROL_DROITE']=f1.para['PROL_DROITE']
219 vale_x=array(f1.vale_x.tolist()+f2.vale_x[i:].tolist())
220 vale_y=array(f1.vale_y.tolist()+f2.vale_y[i:].tolist())
221 elif surcharge=='DROITE' :
222 i=searchsorted(f1.vale_x,f2.vale_x[0])
223 if i!=len(f1.vale_x) : para['PROL_DROITE']=f2.para['PROL_DROITE']
224 else : para['PROL_DROITE']=f1.para['PROL_DROITE']
225 vale_x=array(f1.vale_x[:i].tolist()+f2.vale_x.tolist())
226 vale_y=array(f1.vale_y[:i].tolist()+f2.vale_y.tolist())
227 return t_fonction(vale_x,vale_y,para)
230 """mise en forme de la fonction selon un vecteur unique (x1,y1,x2,y2,...)
232 __tab=array([self.vale_x,self.vale_y])
233 return ravel(transpose(__tab)).tolist()
236 """renvoie un dictionnaire des valeurs d'ordonnées min et max
238 val_min=min(self.vale_y)
239 val_max=max(self.vale_y)
241 vm['min']=[[self.vale_y[i],self.vale_x[i]] for i in range(len(self.vale_x))\
242 if self.vale_y[i]==val_min]
243 vm['max']=[[self.vale_y[i],self.vale_x[i]] for i in range(len(self.vale_x))\
244 if self.vale_y[i]==val_max]
247 for item in vm['min'] : item.reverse()
248 for item in vm['max'] : item.reverse()
251 def trapeze(self,coef) :
252 """renvoie la primitive de la fonction, calculée avec la constante d'intégration 'coef'
254 trapz = zeros(len(self.vale_y),Float)
256 trapz[1:] = (self.vale_y[1:]+self.vale_y[:-1])/2*(self.vale_x[1:]-self.vale_x[:-1])
258 para=copy.copy(self.para)
259 para['PROL_GAUCHE']='EXCLU'
260 para['PROL_DROITE']='EXCLU'
261 if para['NOM_RESU'][:4]=='VITE' : para['NOM_RESU']='DEPL'
262 elif para['NOM_RESU'][:4]=='ACCE' : para['NOM_RESU']='VITE'
263 return t_fonction(self.vale_x,prim_y,para)
265 def simpson(self,coef) :
266 """renvoie la primitive de la fonction, calculée avec la constante d'intégration 'coef'
268 para=copy.copy(self.para)
269 para['PROL_GAUCHE']='EXCLU'
270 para['PROL_DROITE']='EXCLU'
271 if para['NOM_RESU'][:4]=='VITE' : para['NOM_RESU']='DEPL'
272 elif para['NOM_RESU'][:4]=='ACCE' : para['NOM_RESU']='VITE'
275 h2 = self.vale_x[1] - self.vale_x[0]
276 tabl = [coef,coef +(fb+fm)*h2/2.]
277 prim_y = copy.copy(tabl)
281 for i in range(2,len(self.vale_x)) :
283 h2 = self.vale_x[i] - self.vale_x[i-1]
289 if h1==0. or h2==0. or abs( deltah / h1 ) <= eps :
292 epsi = deltah / (h1*h2)
293 ct = (1.-epsi*h2,2.+epsi*deltah,1.+epsi*h1)
294 tabl[iperm] = tabl[iperm] + (bma/6.)*(ct[0]*fa+ct[1]*fm+ct[2]*fb)
295 prim_y.append(tabl[iperm])
297 return t_fonction(self.vale_x,prim_y,para)
300 """renvoie la dérivée de la fonction
302 pas=self.vale_x[1:]-self.vale_x[:-1]
303 pentes=(self.vale_y[1:]-self.vale_y[:-1])/(self.vale_x[1:]-self.vale_x[:-1])
304 derive=(pentes[1:]*pas[1:]+pentes[:-1]*pas[:-1])/(pas[1:]+pas[:-1])
305 derv_y=[pentes[0]]+derive.tolist()+[pentes[-1]]
306 para=copy.copy(self.para)
307 para['PROL_GAUCHE']='EXCLU'
308 para['PROL_DROITE']='EXCLU'
309 if para['NOM_RESU'][:4]=='DEPL' : para['NOM_RESU']='VITE'
310 elif para['NOM_RESU'][:4]=='VITE' : para['NOM_RESU']='ACCE'
311 return t_fonction(self.vale_x,derv_y,para)
314 """renvoie l'inverse de la fonction
315 on intervertit vale_x et vale_y, on swape interpolation
317 para=copy.copy(self.para)
318 para['NOM_RESU']='TOUTRESU'
319 para['NOM_PARA']=self.para['NOM_PARA']
320 para['INTERPOL'].reverse()
321 if para['PROL_GAUCHE']=='CONSTANT' : para['PROL_GAUCHE']='EXCLU'
322 if para['PROL_DROITE']=='CONSTANT' : para['PROL_DROITE']='EXCLU'
325 if not is_ordo(vale_x) :
328 return t_fonction(vale_x,vale_y,para)
331 """renvoie la mm fonction avec valeur absolue des ordonnées
333 para=copy.copy(self.para)
334 if para['PROL_GAUCHE']=='LINEAIRE' : para['PROL_GAUCHE']='EXCLU'
335 if para['PROL_DROITE']=='LINEAIRE' : para['PROL_DROITE']='EXCLU'
336 return t_fonction(self.vale_x,absolute(self.vale_y),para)
338 def evalfonc(self,liste_val) :
339 """renvoie la mm fonction interpolée aux points définis par la liste 'liste_val'
341 return self.__class__(liste_val,map(self,liste_val),self.para)
343 def sup(self,other) :
344 """renvoie l'enveloppe supérieure de self et other
346 para=copy.copy(self.para)
347 # commentaire : pour les prolongements et l'interpolation, c'est self
348 # qui prime sur other
349 vale_x=self.vale_x.tolist()+other.vale_x.tolist()
350 # on ote les abscisses doublons
351 vale_x=dict([(i,0) for i in vale_x]).keys()
354 vale_y1=map(self, vale_x)
355 vale_y2=map(other,vale_x)
356 vale_y=map(max,vale_y1,vale_y2)
357 return t_fonction(vale_x,vale_y,para)
359 def inf(self,other) :
360 """renvoie l'enveloppe inférieure de self et other
362 para=copy.copy(self.para)
363 # commentaire : pour les prolongements et l'interpolation, c'est self
364 # qui prime sur other
365 vale_x=self.vale_x.tolist()+other.vale_x.tolist()
366 # on ote les abscisses doublons
367 vale_x=dict([(i,0) for i in vale_x]).keys()
370 vale_y1=map(self, vale_x)
371 vale_y2=map(other,vale_x)
372 vale_y=map(min,vale_y1,vale_y2)
373 return t_fonction(vale_x,vale_y,para)
375 def suppr_tend(self) :
376 """pour les corrections d'accélérogrammes
377 suppression de la tendance moyenne d'une fonction
379 para=copy.copy(self.para)
380 xy=sum(self.vale_x*self.vale_y)
383 xx=sum(self.vale_x*self.vale_x)
385 a1 = ( n*xy - x0*y0) / (n*xx - x0*x0)
386 a0 = (xx*x0 - x0*xy) / (n*xx - x0*x0)
387 return t_fonction(self.vale_x,self.vale_y-a1*self.vale_x-a0,self.para)
390 """norme de la fonction
393 __ex=__ex.trapeze(0.)
394 return sqrt(__ex.vale_y[-1])
396 def fft(self,methode) :
397 """renvoie la transformée de Fourier rapide FFT
400 para=copy.copy(self.para)
401 para['NOM_PARA']='FREQ'
402 if self.para['NOM_PARA']!='INST' :
403 raise FonctionError, 'fonction réelle : FFT : NOM_PARA=INST pour une transformée directe'
404 pas = self.vale_x[1]-self.vale_x[0]
405 for i in range(1,len(self.vale_x)) :
406 ecart = abs(((self.vale_x[i]-self.vale_x[i-1])-pas)/pas)
408 raise FonctionError, 'fonction réelle : FFT : la fonction doit etre à pas constant'
409 n=int(log(len(self.vale_x))/log(2))
410 if methode=='TRONCATURE' :
411 vale_y=self.vale_y[:2**n]
412 elif methode=='PROL_ZERO' :
413 vale_y=self.vale_y.tolist()
414 vale_y=vale_y+[0.]*(2**(n+1)-len(self.vale_x))
417 pasfreq =1./(pas*(len(vect)-1))
418 vale_x =[pasfreq*i for i in range(len(vect))]
420 return t_fonction_c(vale_x,vale_y,para)
422 class t_fonction_c(t_fonction) :
423 """Classe pour fonctions complexes, équivalent au type aster = fonction_c
426 """mise en forme de la fonction selon un vecteur unique (x1,yr1,yi1,x2,yr2,yr2,...)
428 __tab=array([self.vale_x,self.vale_y.real,self.vale_y.imag])
429 return ravel(transpose(__tab)).tolist()
432 """affichage de la fonction en double colonne
435 for i in range(len(self.vale_x)) :
436 texte.append('%f %f + %f .j' % (self.vale_x[i],self.vale_y[i].real,self.vale_y[i].imag))
437 return '\n'.join(texte)
439 def fft(self,methode,syme) :
440 """renvoie la transformée de Fourier rapide FFT (sens inverse)
443 para=copy.copy(self.para)
444 para['NOM_PARA']='INST'
445 if self.para['NOM_PARA']!='FREQ' :
446 raise FonctionError, 'fonction complexe : FFT : NOM_PARA=FREQ pour une transformée directe'
447 pas = self.vale_x[1]-self.vale_x[0]
448 for i in range(1,len(self.vale_x)) :
449 ecart = abs(((self.vale_x[i]-self.vale_x[i-1])-pas)/pas)
451 raise FonctionError, 'fonction complexe : FFT : la fonction doit etre à pas constant'
452 n=int(log(len(self.vale_x))/log(2))
453 if syme=='OUI' and len(self.vale_x)==2**n :
454 vale_fonc=self.vale_y
455 elif syme=='NON' and len(self.vale_x)==2**n :
456 vale_fonc=self.vale_y.tolist()
457 vale_fon1=vale_fonc[:]
459 vale_fonc=vale_fonc+vale_fon1
460 vale_fonc=array(vale_fonc)
461 elif syme=='NON' and len(self.vale_x)!=2**n and methode=='PROL_ZERO' :
462 vale_fonc=self.vale_y.tolist()+[complex(0.)]*(2**(n+1)-len(self.vale_x))
463 vale_fon1=vale_fonc[:]
465 vale_fonc=vale_fonc+vale_fon1
466 vale_fonc=array(vale_fonc)
467 elif syme=='NON' and len(self.vale_x)!=2**n and methode=='TRONCATURE' :
468 vale_fonc=self.vale_y[:2**n]
469 vale_fonc=vale_fonc.tolist()
470 vale_fon1=vale_fonc[:]
472 vale_fonc=vale_fonc+vale_fon1
473 vale_fonc=array(vale_fonc)
474 if syme=='OUI' and len(self.vale_x)!=2**n :
475 raise FonctionError, 'fonction complexe : FFT : syme=OUI et nombre de points<>2**n'
476 part1=vale_fonc[:len(vale_fonc)/2+1]
477 part2=vale_fonc[1:len(vale_fonc)/2]
478 part2=conjugate(part2)
481 vale_fonc=array(part1.tolist()+part2)
482 vect=FFT.inverse_fft(vale_fonc)
484 pasfreq =1./(pas*(len(vect)-1))
485 vale_x =[pasfreq*i for i in range(len(vect))]
486 pas2 =(1./self.vale_x[-1])*((len(self.vale_x))/float(len(vect)))
488 return t_fonction(vale_x,vale_y,para)
492 """Classe pour nappes, équivalent au type aster = nappe_sdaster
494 def __init__(self,vale_para,l_fonc,para) :
495 """Création d'un objet nappe
496 - vale_para est la liste de valeur des parametres (mot clé PARA dans DEFI_NAPPE)
497 - para est un dictionnaire contenant les entrées PROL_DROITE, PROL_GAUCHE et INTERPOL (cf sd ASTER)
498 - l_fonc est la liste des fonctions, de cardinal égal à celui de vale_para
502 if pk!=['INTERPOL','NOM_PARA','NOM_PARA_FONC','NOM_RESU','PROL_DROITE','PROL_GAUCHE'] :
503 raise FonctionError, 'nappe : parametres incorrects'
504 if para['INTERPOL'] not in [['NON','NON'],['LIN','LIN'],
505 ['LIN','LOG'],['LOG','LOG'],['LOG','LIN'],] :
506 raise FonctionError, 'nappe : parametre INTERPOL incorrect'
507 if para['PROL_DROITE'] not in ['EXCLU','CONSTANT','LINEAIRE'] :
508 raise FonctionError, 'nappe : parametre PROL_DROITE incorrect'
509 if para['PROL_GAUCHE'] not in ['EXCLU','CONSTANT','LINEAIRE'] :
510 raise FonctionError, 'nappe : parametre PROL_GAUCHE incorrect'
511 self.vale_para = array(vale_para)
512 if type(l_fonc) not in (types.ListType,types.TupleType) :
513 raise FonctionError, 'nappe : la liste de fonctions fournie n est pas une liste'
514 if len(l_fonc)!=len(vale_para) :
515 raise FonctionError, 'nappe : nombre de fonctions différent du nombre de valeurs du paramètre'
517 if not isinstance(f,t_fonction) and not isinstance(f,t_fonction_c) :
518 raise FonctionError, 'nappe : les fonctions fournies ne sont pas du bon type'
522 def __call__(self,val1,val2):
523 """méthode pour évaluer nappe(val1,val2)
525 i=searchsorted(self.vale_para,val1)
526 n=len(self.vale_para)
528 if val1==self.vale_para[0] : return self.l_fonc[0](val2)
529 if val1 <self.vale_para[0] :
530 if self.para['PROL_GAUCHE']=='EXCLU' : raise FonctionError, 'nappe évaluée hors du domaine de définition'
531 if self.para['PROL_GAUCHE']=='CONSTANT' : return self.l_fonc[0](val2)
532 if self.para['PROL_GAUCHE']=='LINEAIRE' : return interp(self.para['INTERPOL'],val1,
535 self.l_fonc[0](val2),
536 self.l_fonc[1](val2))
538 if val1==self.vale_para[-1] : return self.l_fonc[-1](val2)
539 if val1 >self.vale_para[-1] :
540 if self.para['PROL_DROITE']=='EXCLU' : raise FonctionError, 'nappe évaluée hors du domaine de définition'
541 if self.para['PROL_DROITE']=='CONSTANT' : return self.l_fonc[-1](val2)
542 if self.para['PROL_DROITE']=='LINEAIRE' : return interp(self.para['INTERPOL'],val1,
545 self.l_fonc[-1](val2),
546 self.l_fonc[-2](val2))
548 return interp(self.para['INTERPOL'],val1,self.vale_para[i-1],
550 self.l_fonc[i-1](val2),
551 self.l_fonc[i](val2))
553 def evalfonc(self, liste_val) :
554 """Renvoie la mm nappe dont les fonctions sont interpolées aux points définis
555 par la liste 'liste_val'.
558 for f in self.l_fonc:
559 f2 = f.evalfonc(liste_val)
561 return t_nappe(self.vale_para, l_fonc, self.para)
563 def __add__(self,other) :
564 """addition avec une autre nappe ou un nombre, par surcharge de l'opérateur +
567 if isinstance(other,t_nappe):
568 if self.vale_para!=other.vale_para : raise FonctionError, 'nappes à valeurs de paramètres différentes'
569 for i in range(len(self.l_fonc)) : l_fonc.append(self.l_fonc[i]+other.l_fonc[i])
570 elif type(other) in [types.FloatType,types.IntType] :
571 for i in range(len(self.l_fonc)) : l_fonc.append(self.l_fonc[i]+other)
572 else: raise FonctionError, 't_nappe : erreur de type dans __add__'
573 return t_nappe(self.vale_para,l_fonc,self.para)
575 def __mul__(self,other) :
576 """multiplication avec une autre fonction ou un nombre, par surcharge de l'opérateur *
579 if isinstance(other,t_nappe):
580 if self.vale_para!=other.vale_para : raise FonctionError, 'nappes à valeurs de paramètres différentes'
581 for i in range(len(self.l_fonc)) : l_fonc.append(self.l_fonc[i]*other.l_fonc[i])
582 elif type(other) in [types.FloatType,types.IntType] :
583 for i in range(len(self.l_fonc)) : l_fonc.append(self.l_fonc[i]*other)
584 else: raise FonctionError, 't_nappe : erreur de type dans __mul__'
585 return t_nappe(self.vale_para,l_fonc,self.para)
588 """affichage de la nappe en double colonne
591 for i in range(len(self.vale_para)) :
592 texte.append('paramètre : %f' % self.vale_para[i])
593 texte.append(repr(self.l_fonc[i]))
594 return '\n'.join(texte)
596 def homo_support(self,other) :
597 """Renvoie la nappe self avec un support union de celui de self et de other
598 le support est la discrétisation vale_para et les discrétisations des fonctions
600 if self==other : return self
601 if self.para!=other.para : raise FonctionError, 'combinaison de nappes à caractéristiques interpolation et prolongement différentes'
602 vale_para=self.vale_para.tolist()+other.vale_para.tolist()
603 vale_para=dict([(i,0) for i in vale_para]).keys()
605 vale_para=array(vale_para)
607 for val in vale_para :
608 if val in self.vale_para : l_fonc.append(self.l_fonc[searchsorted(self.vale_para,val)])
609 elif val in other.vale_para :
610 other_fonc=other.l_fonc[searchsorted(other.vale_para,val)]
611 new_vale_x=other_fonc.vale_x
612 new_para =other_fonc.para
613 new_vale_y=[self(x) for x in new_vale_x]
614 if isinstance(other_fonc,t_fonction) :
615 l_fonc.append(t_fonction(new_vale_x,new_vale_y,new_para))
616 if isinstance(other_fonc,t_fonction_c) :
617 l_fonc.append(t_fonction_c(new_vale_x,new_vale_y,new_para))
618 else : raise FonctionError, 'combinaison de nappes : incohérence'
619 return t_nappe(vale_para,l_fonc,self.para)
622 """renvoie un dictionnaire des valeurs d'ordonnées min et max
624 val_min=min([min(fonc.vale_y) for fonc in self.l_fonc])
625 val_max=max([max(fonc.vale_y) for fonc in self.l_fonc])
626 vm={'min':[],'max':[]}
627 for i in range(len(self.vale_para)) :
628 for j in range(len(self.l_fonc[i].vale_y)) :
629 y = self.l_fonc[i].vale_y[j]
630 if y==val_min : vm['min'].append([y,self.l_fonc[i].vale_x[j],self.vale_para[i]])
631 if y==val_max : vm['max'].append([y,self.l_fonc[i].vale_x[j],self.vale_para[i]])
634 for item in vm['min'] : item.reverse()
635 for item in vm['max'] : item.reverse()