]> SALOME platform Git repositories - modules/adao.git/commitdiff
Salome HOME
Improving code quality
authorJean-Philippe ARGAUD <jean-philippe.argaud@edf.fr>
Mon, 28 Jul 2014 18:51:49 +0000 (20:51 +0200)
committerJean-Philippe ARGAUD <jean-philippe.argaud@edf.fr>
Mon, 28 Jul 2014 18:52:38 +0000 (20:52 +0200)
src/daComposant/daAlgorithms/FunctionTest.py
src/daComposant/daAlgorithms/ParticleSwarmOptimization.py
src/daComposant/daCore/AssimilationStudy.py
src/daComposant/daCore/BasicObjects.py
src/daComposant/daCore/ExtendedLogging.py

index e656b5c25a4292e98106d93a3fd38449208c0048..ee983c2bd27a7736d151f1f3779c08419f4bcd75 100644 (file)
@@ -117,6 +117,7 @@ class ElementaryAlgorithm(BasicObjects.Algorithm):
             Ys.append( copy.copy( numpy.ravel(
                 Yn
                 ) ) )
+        # ----------
         #
         print("     %s\n"%("-"*75,))
         if self._parameters["SetDebug"]:
index ba52587eb13ba1301970879f227a4db60f722419..113281e72b20822eb38d68eef0163fccd7598a74 100644 (file)
@@ -147,9 +147,9 @@ class ElementaryAlgorithm(BasicObjects.Algorithm):
             #
             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
@@ -193,6 +193,12 @@ class ElementaryAlgorithm(BasicObjects.Algorithm):
                 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"]):
index b9010d896f9e146556d5a1a41a8fabecde3762d0..d06f402ddd6bca1c0253dab4347e6ce6184fbdc8 100644 (file)
 #
 # 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.
 """
@@ -32,10 +32,12 @@ __author__ = "Jean-Philippe ARGAUD"
 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
@@ -128,9 +130,9 @@ class AssimilationStudy:
         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,
@@ -618,7 +620,7 @@ class AssimilationStudy:
         #
         self.__StoredInputs["AlgorithmParameters"] = self.__Parameters
         return 0
-    
+
     def getAlgorithmParameters(self, noDetails=True):
         """
         Renvoie la liste des paramètres requis selon l'algorithme
@@ -778,9 +780,10 @@ class AssimilationStudy:
         #
         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
 
@@ -788,7 +791,7 @@ class AssimilationStudy:
     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
@@ -833,7 +836,7 @@ class AssimilationStudy:
             allvariables.update( self.__StoredDiagnostics )
             allvariables.update( self.__StoredInputs )
             return allvariables
-    
+
     def get_available_variables(self):
         """
         Renvoie les variables potentiellement utilisables pour l'étude,
@@ -851,7 +854,7 @@ class AssimilationStudy:
                 variables.extend( self.__StoredInputs.keys() )
             variables.sort()
             return variables
-    
+
     def get_available_algorithms(self):
         """
         Renvoie la liste des algorithmes potentiellement utilisables, identifiés
@@ -866,7 +869,7 @@ class AssimilationStudy:
                         files.append(root)
         files.sort()
         return files
-        
+
     def get_available_diagnostics(self):
         """
         Renvoie la liste des diagnostics potentiellement utilisables, identifiés
@@ -894,7 +897,7 @@ class AssimilationStudy:
         """
         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.
         """
@@ -919,7 +922,7 @@ class AssimilationStudy:
         """
         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.
         """
@@ -946,7 +949,7 @@ class AssimilationStudy:
         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.")
         #
@@ -964,12 +967,12 @@ class AssimilationStudy:
         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,
@@ -978,7 +981,7 @@ class AssimilationStudy:
         """
         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.")
         #
@@ -996,10 +999,10 @@ class AssimilationStudy:
         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):
@@ -1008,7 +1011,6 @@ class AssimilationStudy:
         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 )
 
@@ -1016,11 +1018,13 @@ class AssimilationStudy:
         """
         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  = {}
index 6051264b7dc6860a5a09207267e64bfda5633662..608be799134b5c3e7ecf30dc88fcf3487e5c2c40 100644 (file)
@@ -20,9 +20,9 @@
 #
 #  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.
 """
@@ -43,7 +43,7 @@ class CacheManager:
             lenghtOfRedundancy    = -1,
             ):
         """
-        
+        Les caractéristiques de tolérance peuvent être modifées à la création.
         """
         self.__tolerBP  = float(toleranceInRedundancy)
         self.__lenghtOR = int(lenghtOfRedundancy)
@@ -53,7 +53,7 @@ class CacheManager:
         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):
@@ -238,11 +238,11 @@ class Operator:
 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):
@@ -251,7 +251,7 @@ class Algorithm:
         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
@@ -260,8 +260,9 @@ class Algorithm:
             - 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
@@ -288,6 +289,7 @@ class Algorithm:
         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")
@@ -421,11 +423,11 @@ class Algorithm:
 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
@@ -498,7 +500,7 @@ class Covariance:
             # 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))
@@ -511,16 +513,16 @@ class Covariance:
                 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 )
@@ -530,7 +532,7 @@ class Covariance:
             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 )
@@ -538,7 +540,7 @@ class Covariance:
             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) )
@@ -546,7 +548,7 @@ class Covariance:
             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 )
@@ -554,7 +556,7 @@ class Covariance:
             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)
@@ -565,7 +567,7 @@ class Covariance:
                 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
@@ -576,7 +578,7 @@ class Covariance:
                 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)
@@ -587,13 +589,13 @@ class Covariance:
                 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)
@@ -618,7 +620,7 @@ class Covariance:
 
     def __neg__(self):
         return - self.__B
-    
+
     def __mul__(self, other):
         if   self.ismatrix() and isinstance(other,numpy.matrix):
             return self.__B * other
index d1751aa332071f406333aa51815aca7d3d5cb805..3fa494fcad7cb415fdc81c40ea5e5544b4c5c576 100644 (file)
 #
 #  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 :
@@ -47,7 +47,7 @@ __doc__ = """
         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
@@ -66,7 +66,7 @@ __doc__ = """
         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
 """
@@ -110,7 +110,7 @@ class ExtendedLogging:
 #         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.
@@ -131,7 +131,7 @@ class ExtendedLogging:
         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