1 #-*-coding:iso-8859-1-*-
3 # Copyright (C) 2008-2012 EDF R&D
5 # This library is free software; you can redistribute it and/or
6 # modify it under the terms of the GNU Lesser General Public
7 # License as published by the Free Software Foundation; either
8 # version 2.1 of the License.
10 # This library is distributed in the hope that it will be useful,
11 # but WITHOUT ANY WARRANTY; without even the implied warranty of
12 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 # Lesser General Public License for more details.
15 # You should have received a copy of the GNU Lesser General Public
16 # License along with this library; if not, write to the Free Software
17 # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
19 # See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com
21 # Author: Jean-Philippe Argaud, jean-philippe.argaud@edf.fr, EDF R&D
24 Définit les outils généraux élémentaires.
26 Ce module est destiné à etre appelée par AssimilationStudy pour constituer
27 les objets élémentaires de l'algorithme.
29 __author__ = "Jean-Philippe ARGAUD"
35 # ==============================================================================
38 Classe générale d'interface de type opérateur
40 def __init__(self, fromMethod=None, fromMatrix=None):
42 On construit un objet de ce type en fournissant à l'aide de l'un des
43 deux mots-clé, soit une fonction python, soit matrice.
45 - fromMethod : argument de type fonction Python
46 - fromMatrix : argument adapté au constructeur numpy.matrix
48 if fromMethod is not None:
49 self.__Method = fromMethod
51 self.__Type = "Method"
52 elif fromMatrix is not None:
54 self.__Matrix = numpy.matrix( fromMatrix, numpy.float )
55 self.__Type = "Matrix"
64 def appliedTo(self, xValue):
66 Permet de restituer le résultat de l'application de l'opérateur à un
67 argument xValue. Cette méthode se contente d'appliquer, son argument
68 devant a priori être du bon type.
70 - xValue : argument adapté pour appliquer l'opérateur
72 if self.__Matrix is not None:
73 return self.__Matrix * xValue
75 return self.__Method( xValue )
77 def appliedInXTo(self, (xNominal, xValue) ):
79 Permet de restituer le résultat de l'application de l'opérateur à un
80 argument xValue, sachant que l'opérateur est valable en xNominal.
81 Cette méthode se contente d'appliquer, son argument devant a priori
82 être du bon type. Si l'opérateur est linéaire car c'est une matrice,
83 alors il est valable en tout point nominal et il n'est pas nécessaire
85 Arguments : une liste contenant
86 - xNominal : argument permettant de donner le point où l'opérateur
87 est construit pour etre ensuite appliqué
88 - xValue : argument adapté pour appliquer l'opérateur
90 if self.__Matrix is not None:
91 return self.__Matrix * xValue
93 return self.__Method( (xNominal, xValue) )
95 def asMatrix(self, ValueForMethodForm = "UnknownVoidValue"):
97 Permet de renvoyer l'opérateur sous la forme d'une matrice
99 if self.__Matrix is not None:
101 elif ValueForMethodForm is not "UnknownVoidValue": # Ne pas utiliser "None"
102 return self.__Method( (ValueForMethodForm, None) )
104 raise ValueError("Matrix form of the operator defined as a function/method requires to give an operating point.")
108 Renvoie la taille sous forme numpy si l'opérateur est disponible sous
109 la forme d'une matrice
111 if self.__Matrix is not None:
112 return self.__Matrix.shape
114 raise ValueError("Matrix form of the operator is not available, nor the shape")
116 # ==============================================================================
119 Classe générale d'interface de type algorithme
121 Elle donne un cadre pour l'écriture d'une classe élémentaire d'algorithme
122 d'assimilation, en fournissant un container (dictionnaire) de variables
123 persistantes initialisées, et des méthodes d'accès à ces variables stockées.
125 Une classe élémentaire d'algorithme doit implémenter la méthode "run".
127 def __init__(self, name):
129 L'initialisation présente permet de fabriquer des variables de stockage
130 disponibles de manière générique dans les algorithmes élémentaires. Ces
131 variables de stockage sont ensuite conservées dans un dictionnaire
132 interne à l'objet, mais auquel on accède par la méthode "get".
134 Les variables prévues sont :
135 - CostFunctionJ : fonction-cout globale, somme des deux parties suivantes
136 - CostFunctionJb : partie ébauche ou background de la fonction-cout
137 - CostFunctionJo : partie observations de la fonction-cout
138 - GradientOfCostFunctionJ : gradient de la fonction-cout globale
139 - GradientOfCostFunctionJb : gradient de la partie ébauche de la fonction-cout
140 - GradientOfCostFunctionJo : gradient de la partie observations de la fonction-cout
141 - CurrentState : état courant lors d'itérations
142 - Analysis : l'analyse
143 - Innovation : l'innovation : d = Y - H Xb
144 - SigmaObs2 : correction optimale des erreurs d'observation
145 - SigmaBck2 : correction optimale des erreurs d'ébauche
146 - OMA : Observation moins Analysis : Y - Xa
147 - OMB : Observation moins Background : Y - Xb
148 - AMB : Analysis moins Background : Xa - Xb
149 - APosterioriCovariance : matrice A
150 On peut rajouter des variables à stocker dans l'initialisation de
151 l'algorithme élémentaire qui va hériter de cette classe
153 logging.debug("%s Initialisation"%str(name))
154 self._name = str( name )
155 self._parameters = {}
156 self.__required_parameters = {}
157 self.StoredVariables = {}
159 self.StoredVariables["CostFunctionJ"] = Persistence.OneScalar(name = "CostFunctionJ")
160 self.StoredVariables["CostFunctionJb"] = Persistence.OneScalar(name = "CostFunctionJb")
161 self.StoredVariables["CostFunctionJo"] = Persistence.OneScalar(name = "CostFunctionJo")
162 self.StoredVariables["GradientOfCostFunctionJ"] = Persistence.OneVector(name = "GradientOfCostFunctionJ")
163 self.StoredVariables["GradientOfCostFunctionJb"] = Persistence.OneVector(name = "GradientOfCostFunctionJb")
164 self.StoredVariables["GradientOfCostFunctionJo"] = Persistence.OneVector(name = "GradientOfCostFunctionJo")
165 self.StoredVariables["CurrentState"] = Persistence.OneVector(name = "CurrentState")
166 self.StoredVariables["Analysis"] = Persistence.OneVector(name = "Analysis")
167 self.StoredVariables["Innovation"] = Persistence.OneVector(name = "Innovation")
168 self.StoredVariables["SigmaObs2"] = Persistence.OneScalar(name = "SigmaObs2")
169 self.StoredVariables["SigmaBck2"] = Persistence.OneScalar(name = "SigmaBck2")
170 self.StoredVariables["OMA"] = Persistence.OneVector(name = "OMA")
171 self.StoredVariables["OMB"] = Persistence.OneVector(name = "OMB")
172 self.StoredVariables["BMA"] = Persistence.OneVector(name = "BMA")
173 self.StoredVariables["APosterioriCovariance"] = Persistence.OneMatrix(name = "APosterioriCovariance")
175 def get(self, key=None):
177 Renvoie l'une des variables stockées identifiée par la clé, ou le
178 dictionnaire de l'ensemble des variables disponibles en l'absence de
179 clé. Ce sont directement les variables sous forme objet qui sont
180 renvoyées, donc les méthodes d'accès à l'objet individuel sont celles
181 des classes de persistance.
184 return self.StoredVariables[key]
186 return self.StoredVariables
188 def has_key(self, key=None):
190 Vérifie si l'une des variables stockées est identifiée par la clé.
192 return self.StoredVariables.has_key(key)
196 Renvoie la liste des clés de variables stockées.
198 return self.StoredVariables.keys()
200 def run(self, Xb=None, Y=None, H=None, M=None, R=None, B=None, Q=None, Parameters=None):
202 Doit implémenter l'opération élémentaire de calcul d'assimilation sous
203 sa forme mathématique la plus naturelle possible.
205 raise NotImplementedError("Mathematical assimilation calculation has not been implemented!")
207 def defineRequiredParameter(self, name = None, default = None, typecast = None, message = None, minval = None, maxval = None, listval = None):
209 Permet de définir dans l'algorithme des paramètres requis et leurs
210 caractéristiques par défaut.
213 raise ValueError("A name is mandatory to define a required parameter.")
215 self.__required_parameters[name] = {
217 "typecast" : typecast,
223 logging.debug("%s %s (valeur par défaut = %s)"%(self._name, message, self.setParameterValue(name)))
225 def getRequiredParameters(self, noDetails=True):
227 Renvoie la liste des noms de paramètres requis ou directement le
228 dictionnaire des paramètres requis.
231 ks = self.__required_parameters.keys()
235 return self.__required_parameters
237 def setParameterValue(self, name=None, value=None):
239 Renvoie la valeur d'un paramètre requis de manière contrôlée
241 default = self.__required_parameters[name]["default"]
242 typecast = self.__required_parameters[name]["typecast"]
243 minval = self.__required_parameters[name]["minval"]
244 maxval = self.__required_parameters[name]["maxval"]
245 listval = self.__required_parameters[name]["listval"]
247 if value is None and default is None:
249 elif value is None and default is not None:
250 if typecast is None: __val = default
251 else: __val = typecast( default )
253 if typecast is None: __val = value
254 else: __val = typecast( value )
256 if minval is not None and __val < minval:
257 raise ValueError("The parameter named \"%s\" of value \"%s\" can not be less than %s."%(name, __val, minval))
258 if maxval is not None and __val > maxval:
259 raise ValueError("The parameter named \"%s\" of value \"%s\" can not be greater than %s."%(name, __val, maxval))
260 if listval is not None:
261 if typecast is list or typecast is tuple or type(__val) is list or type(__val) is tuple:
264 raise ValueError("The value \"%s\" of the parameter named \"%s\" is not allowed, it has to be in the list %s."%(v, name, listval))
265 elif __val not in listval:
266 raise ValueError("The value \"%s\" of the parameter named \"%s\" is not allowed, it has to be in the list %s."%( __val, name,listval))
269 def setParameters(self, fromDico={}):
271 Permet de stocker les paramètres reçus dans le dictionnaire interne.
273 self._parameters.update( fromDico )
274 for k in self.__required_parameters.keys():
275 if k in fromDico.keys():
276 self._parameters[k] = self.setParameterValue(k,fromDico[k])
278 self._parameters[k] = self.setParameterValue(k)
279 logging.debug("%s %s : %s"%(self._name, self.__required_parameters[k]["message"], self._parameters[k]))
281 # ==============================================================================
284 Classe générale d'interface de type diagnostic
286 Ce template s'utilise de la manière suivante : il sert de classe "patron" en
287 même temps que l'une des classes de persistance, comme "OneScalar" par
290 Une classe élémentaire de diagnostic doit implémenter ses deux méthodes, la
291 méthode "_formula" pour écrire explicitement et proprement la formule pour
292 l'écriture mathématique du calcul du diagnostic (méthode interne non
293 publique), et "calculate" pour activer la précédente tout en ayant vérifié
294 et préparé les données, et pour stocker les résultats à chaque pas (méthode
295 externe d'activation).
297 def __init__(self, name = "", parameters = {}):
298 self.name = str(name)
299 self.parameters = dict( parameters )
301 def _formula(self, *args):
303 Doit implémenter l'opération élémentaire de diagnostic sous sa forme
304 mathématique la plus naturelle possible.
306 raise NotImplementedError("Diagnostic mathematical formula has not been implemented!")
308 def calculate(self, *args):
310 Active la formule de calcul avec les arguments correctement rangés
312 raise NotImplementedError("Diagnostic activation method has not been implemented!")
314 # ==============================================================================
315 if __name__ == "__main__":
316 print '\n AUTODIAGNOSTIC \n'