Ys.append( copy.copy( numpy.ravel(
Yn
) ) )
+ # ----------
#
print(" %s\n"%("-"*75,))
if self._parameters["SetDebug"]:
#
if self._parameters["StoreInternalVariables"]:
self.StoredVariables["CurrentState"].store( _X )
- self.StoredVariables["CostFunctionJb"].store( Jb )
- self.StoredVariables["CostFunctionJo"].store( Jo )
- self.StoredVariables["CostFunctionJ" ].store( J )
+ self.StoredVariables["CostFunctionJb"].store( Jb )
+ self.StoredVariables["CostFunctionJo"].store( Jo )
+ self.StoredVariables["CostFunctionJ" ].store( J )
return J
#
# Point de démarrage de l'optimisation : Xini = Xb
qBest = copy.copy( quality )
logging.debug("%s Initialisation, Insecte = %s, Qualité = %s"%(self._name, str(Best), str(qBest)))
#
+ if self._parameters["StoreInternalVariables"]:
+ self.StoredVariables["CurrentState"].store( Best )
+ self.StoredVariables["CostFunctionJb"].store( 0. )
+ self.StoredVariables["CostFunctionJo"].store( 0. )
+ self.StoredVariables["CostFunctionJ" ].store( qBest )
+ #
# Minimisation de la fonctionnelle
# --------------------------------
for n in range(self._parameters["MaximumNumberOfSteps"]):
#
# Author: Jean-Philippe Argaud, jean-philippe.argaud@edf.fr, EDF R&D
-__doc__ = """
+"""
Classe principale pour la préparation, la réalisation et la restitution de
calculs d'assimilation de données.
-
+
Ce module est destiné à être appelé par AssimilationStudy pour constituer
les objets élémentaires de l'étude.
"""
import os, sys
import numpy
import ExtendedLogging ; ExtendedLogging.ExtendedLogging() # A importer en premier
+import logging
try:
import scipy.optimize
-except:
- pass
+ logging.debug("Succeed initial import of scipy.optimize with Scipy %s", scipy.version.version)
+except ImportError:
+ logging.debug("Fail initial import of scipy.optimize")
import Persistence
from BasicObjects import Operator, Covariance
from PlatformInfo import uniq
else:
raise ValueError("Error: improperly defined background, it requires at minima either a vector, a list/tuple of vectors or a persistent object")
if toBeStored:
- self.__StoredInputs["Background"] = self.__Xb
+ self.__StoredInputs["Background"] = self.__Xb
return 0
-
+
def setBackgroundError(self,
asCovariance = None,
asEyeByScalar = None,
#
self.__StoredInputs["AlgorithmParameters"] = self.__Parameters
return 0
-
+
def getAlgorithmParameters(self, noDetails=True):
"""
Renvoie la liste des paramètres requis selon l'algorithme
#
if self.__StoredInputs.has_key("AlgorithmParameters") \
and self.__StoredInputs["AlgorithmParameters"].has_key("Bounds") \
- and (type(self.__StoredInputs["AlgorithmParameters"]["Bounds"]) is type([]) or type(self._parameters["Bounds"]) is type(())) \
+ and (type(self.__StoredInputs["AlgorithmParameters"]["Bounds"]) is type([]) or type(self.__StoredInputs["AlgorithmParameters"]["Bounds"]) is type(())) \
and (len(self.__StoredInputs["AlgorithmParameters"]["Bounds"]) != max(__Xb_shape)):
- raise ValueError("The number \"%s\" of bound pairs for the state (X) components is different of the size \"%s\" of the state itself."%(len(self.__StoredInputs["AlgorithmParameters"]["Bounds"]),max(__Xb_shape)))
+ raise ValueError("The number \"%s\" of bound pairs for the state (X) components is different of the size \"%s\" of the state itself." \
+ %(len(self.__StoredInputs["AlgorithmParameters"]["Bounds"]),max(__Xb_shape)))
#
return 1
def analyze(self):
"""
Permet de lancer le calcul d'assimilation.
-
+
Le nom de la méthode à activer est toujours "run". Les paramètres en
arguments de la méthode sont fixés. En sortie, on obtient les résultats
dans la variable de type dictionnaire "StoredVariables", qui contient en
allvariables.update( self.__StoredDiagnostics )
allvariables.update( self.__StoredInputs )
return allvariables
-
+
def get_available_variables(self):
"""
Renvoie les variables potentiellement utilisables pour l'étude,
variables.extend( self.__StoredInputs.keys() )
variables.sort()
return variables
-
+
def get_available_algorithms(self):
"""
Renvoie la liste des algorithmes potentiellement utilisables, identifiés
files.append(root)
files.sort()
return files
-
+
def get_available_diagnostics(self):
"""
Renvoie la liste des diagnostics potentiellement utilisables, identifiés
"""
Ajoute au chemin de recherche des algorithmes un répertoire dans lequel
se trouve un sous-répertoire "daAlgorithms"
-
+
Remarque : si le chemin a déjà été ajouté pour les diagnostics, il n'est
pas indispensable de le rajouter ici.
"""
"""
Ajoute au chemin de recherche des algorithmes un répertoire dans lequel
se trouve un sous-répertoire "daDiagnostics"
-
+
Remarque : si le chemin a déjà été ajouté pour les algorithmes, il n'est
pas indispensable de le rajouter ici.
"""
pas demandé dans le Scheduler, il effectue la fonction HookFunction avec
les arguments (variable persistante VariableName, paramètres HookParameters).
"""
- #
+ #
if type( self.__algorithm ) is dict:
raise ValueError("No observer can be build before choosing an algorithm.")
#
for n in VariableNames:
if not self.__algorithm.has_key( n ):
raise ValueError("An observer requires to be set on a variable named %s which does not exist."%n)
- else:
- self.__algorithm.StoredVariables[ n ].setDataObserver(
- Scheduler = Scheduler,
- HookFunction = HookFunction,
- HookParameters = HookParameters,
- )
+ else:
+ self.__algorithm.StoredVariables[ n ].setDataObserver(
+ Scheduler = Scheduler,
+ HookFunction = HookFunction,
+ HookParameters = HookParameters,
+ )
def removeDataObserver(self,
VariableName = None,
"""
Permet de retirer un observer à une ou des variable nommée.
"""
- #
+ #
if type( self.__algorithm ) is dict:
raise ValueError("No observer can be removed before choosing an algorithm.")
#
for n in VariableNames:
if not self.__algorithm.has_key( n ):
raise ValueError("An observer requires to be removed on a variable named %s which does not exist."%n)
- else:
- self.__algorithm.StoredVariables[ n ].removeDataObserver(
- HookFunction = HookFunction,
- )
+ else:
+ self.__algorithm.StoredVariables[ n ].removeDataObserver(
+ HookFunction = HookFunction,
+ )
# -----------------------------------------------------------
def setDebug(self, level=10):
appel pour changer le niveau de verbosité, avec :
NOTSET=0 < DEBUG=10 < INFO=20 < WARNING=30 < ERROR=40 < CRITICAL=50
"""
- import logging
log = logging.getLogger()
log.setLevel( level )
"""
Remet le logger au niveau par défaut
"""
- import logging
log = logging.getLogger()
log.setLevel( logging.WARNING )
def prepare_to_pickle(self):
+ """
+ Retire les variables non pickelisables
+ """
self.__algorithmFile = None
self.__diagnosticFile = None
self.__HO = {}
#
# Author: Jean-Philippe Argaud, jean-philippe.argaud@edf.fr, EDF R&D
-__doc__ = """
+"""
Définit les outils généraux élémentaires.
-
+
Ce module est destiné à etre appelée par AssimilationStudy pour constituer
les objets élémentaires de l'algorithme.
"""
lenghtOfRedundancy = -1,
):
"""
-
+ Les caractéristiques de tolérance peuvent être modifées à la création.
"""
self.__tolerBP = float(toleranceInRedundancy)
self.__lenghtOR = int(lenghtOfRedundancy)
self.__listOPCV = [] # Operator Previous Calculated Points, Results, Point Norms
# logging.debug("CM Tolerance de determination des doublons : %.2e"%self.__tolerBP)
- def wasCalculatedIn(self, xValue, info="" ):
+ def wasCalculatedIn(self, xValue ): #, info="" ):
__alc = False
__HxV = None
for i in xrange(min(len(self.__listOPCV),self.__lenghtOR)-1,-1,-1):
class Algorithm:
"""
Classe générale d'interface de type algorithme
-
+
Elle donne un cadre pour l'écriture d'une classe élémentaire d'algorithme
d'assimilation, en fournissant un container (dictionnaire) de variables
persistantes initialisées, et des méthodes d'accès à ces variables stockées.
-
+
Une classe élémentaire d'algorithme doit implémenter la méthode "run".
"""
def __init__(self, name):
disponibles de manière générique dans les algorithmes élémentaires. Ces
variables de stockage sont ensuite conservées dans un dictionnaire
interne à l'objet, mais auquel on accède par la méthode "get".
-
+
Les variables prévues sont :
- CostFunctionJ : fonction-cout globale, somme des deux parties suivantes
- CostFunctionJb : partie ébauche ou background de la fonction-cout
- GradientOfCostFunctionJb : gradient de la partie ébauche de la fonction-cout
- GradientOfCostFunctionJo : gradient de la partie observations de la fonction-cout
- CurrentState : état courant lors d'itérations
- - Analysis : l'analyse
- - Innovation : l'innovation : d = Y - H Xb
+ - Analysis : l'analyse Xa
+ - ObservedState : l'état observé H(X)
+ - Innovation : l'innovation : d = Y - H(X)
- SigmaObs2 : indicateur de correction optimale des erreurs d'observation
- SigmaBck2 : indicateur de correction optimale des erreurs d'ébauche
- MahalanobisConsistency : indicateur de consistance des covariances
self.StoredVariables["GradientOfCostFunctionJo"] = Persistence.OneVector(name = "GradientOfCostFunctionJo")
self.StoredVariables["CurrentState"] = Persistence.OneVector(name = "CurrentState")
self.StoredVariables["Analysis"] = Persistence.OneVector(name = "Analysis")
+ self.StoredVariables["ObservedState"] = Persistence.OneVector(name = "ObservedState")
self.StoredVariables["Innovation"] = Persistence.OneVector(name = "Innovation")
self.StoredVariables["SigmaObs2"] = Persistence.OneScalar(name = "SigmaObs2")
self.StoredVariables["SigmaBck2"] = Persistence.OneScalar(name = "SigmaBck2")
class Diagnostic:
"""
Classe générale d'interface de type diagnostic
-
+
Ce template s'utilise de la manière suivante : il sert de classe "patron" en
même temps que l'une des classes de persistance, comme "OneScalar" par
exemple.
-
+
Une classe élémentaire de diagnostic doit implémenter ses deux méthodes, la
méthode "_formula" pour écrire explicitement et proprement la formule pour
l'écriture mathématique du calcul du diagnostic (méthode interne non
# raise ValueError("The %s covariance matrix has to be specified either as a matrix, a vector for its diagonal or a scalar multiplying an identity matrix."%self.__name)
#
self.__validate()
-
+
def __validate(self):
if self.ismatrix() and min(self.shape) != max(self.shape):
raise ValueError("The given matrix for %s is not a square one, its shape is %s. Please check your matrix input."%(self.__name,self.shape))
L = numpy.linalg.cholesky( self.__B )
except:
raise ValueError("The %s covariance matrix is not symmetric positive-definite. Please check your matrix input."%(self.__name,))
-
+
def isscalar(self):
return self.__is_scalar
-
+
def isvector(self):
return self.__is_vector
-
+
def ismatrix(self):
return self.__is_matrix
-
+
def getI(self):
if self.ismatrix():
return Covariance(self.__name+"I", asCovariance = self.__B.I )
return Covariance(self.__name+"I", asEyeByScalar = 1. / self.__B )
else:
return None
-
+
def getT(self):
if self.ismatrix():
return Covariance(self.__name+"T", asCovariance = self.__B.T )
return Covariance(self.__name+"T", asEyeByVector = self.__B )
elif self.isscalar():
return Covariance(self.__name+"T", asEyeByScalar = self.__B )
-
+
def cholesky(self):
if self.ismatrix():
return Covariance(self.__name+"C", asCovariance = numpy.linalg.cholesky(self.__B) )
return Covariance(self.__name+"C", asEyeByVector = numpy.sqrt( self.__B ) )
elif self.isscalar():
return Covariance(self.__name+"C", asEyeByScalar = numpy.sqrt( self.__B ) )
-
+
def choleskyI(self):
if self.ismatrix():
return Covariance(self.__name+"H", asCovariance = numpy.linalg.cholesky(self.__B).I )
return Covariance(self.__name+"H", asEyeByVector = 1.0 / numpy.sqrt( self.__B ) )
elif self.isscalar():
return Covariance(self.__name+"H", asEyeByScalar = 1.0 / numpy.sqrt( self.__B ) )
-
+
def diag(self, msize=None):
if self.ismatrix():
return numpy.diag(self.__B)
raise ValueError("the size of the %s covariance matrix has to be given in case of definition as a scalar over the diagonal."%(self.__name,))
else:
return self.__B * numpy.ones(int(msize))
-
+
def asfullmatrix(self, msize=None):
if self.ismatrix():
return self.__B
raise ValueError("the size of the %s covariance matrix has to be given in case of definition as a scalar over the diagonal."%(self.__name,))
else:
return numpy.matrix( self.__B * numpy.eye(int(msize)), float )
-
+
def trace(self, msize=None):
if self.ismatrix():
return numpy.trace(self.__B)
raise ValueError("the size of the %s covariance matrix has to be given in case of definition as a scalar over the diagonal."%(self.__name,))
else:
return self.__B * int(msize)
-
+
def __repr__(self):
return repr(self.__B)
-
+
def __str__(self):
return str(self.__B)
-
+
def __add__(self, other):
if self.ismatrix():
return self.__B + numpy.asmatrix(other)
def __neg__(self):
return - self.__B
-
+
def __mul__(self, other):
if self.ismatrix() and isinstance(other,numpy.matrix):
return self.__B * other
#
# Author: Jean-Philippe Argaud, jean-philippe.argaud@edf.fr, EDF R&D
-__doc__ = """
+"""
Ce module permet de mettre en place un logging utilisable partout dans
l'application, par défaut à la console, et si nécessaire dans un fichier.
-
+
Il doit être appelé en premier dans AssimilationStudy (mais pas directement
dans les applications utilisateurs), en l'important et en instanciant un
objet :
log.setLogfile(filename="toto.log", filemode="a", level=logging.WARNING)
et on change éventuellement le niveau avec :
log.setLogfileLevel(logging.INFO)
-
+
Ensuite, n'importe où dans les applications, il suffit d'utiliser le module
"logging" (avec un petit "l") :
import logging
import logging
log = logging.getLogger(NAME) # Avec rien (recommandé) ou un nom NAME
log.setLevel(logging.DEBUG)
-
+
On rappelle les niveaux (attributs de "logging") et leur ordre :
NOTSET=0 < DEBUG=10 < INFO=20 < WARNING=30 < ERROR=40 < CRITICAL=50
"""
# Permet de changer globalement le niveau des messages disponibles.
# """
# logging.getLogger().setLevel(level)
-#
+#
def setLogfile(self, filename=LOGFILE, filemode="w", level=logging.NOTSET):
"""
Permet de disposer des messages dans un fichier EN PLUS de la console.
pris en compte que s'il est supérieur au niveau global.
"""
self.__logfile.setLevel(level)
-
+
def getLevel(self):
"""
Renvoie le niveau de logging sous forme texte