From 8b0fe9f58619f710527afbcc76d565bf697ec552 Mon Sep 17 00:00:00 2001 From: Jean-Philippe ARGAUD Date: Mon, 5 Jun 2017 21:40:28 +0200 Subject: [PATCH] Python 3 compatibility improvement (UTF-8) and data interface changes --- src/daComposant/daAlgorithms/3DVAR.py | 41 +- src/daComposant/daAlgorithms/4DVAR.py | 50 +- src/daComposant/daAlgorithms/AdjointTest.py | 37 +- src/daComposant/daAlgorithms/Blue.py | 29 +- .../DerivativeFreeOptimization.py | 24 +- src/daComposant/daAlgorithms/EnsembleBlue.py | 16 +- src/daComposant/daAlgorithms/ExtendedBlue.py | 29 +- .../daAlgorithms/ExtendedKalmanFilter.py | 10 +- src/daComposant/daAlgorithms/FunctionTest.py | 113 +- src/daComposant/daAlgorithms/GradientTest.py | 111 +- src/daComposant/daAlgorithms/KalmanFilter.py | 10 +- .../daAlgorithms/LinearLeastSquares.py | 10 +- src/daComposant/daAlgorithms/LinearityTest.py | 127 +- .../daAlgorithms/NonLinearLeastSquares.py | 30 +- src/daComposant/daAlgorithms/ObserverTest.py | 2 +- .../daAlgorithms/ParticleSwarmOptimization.py | 38 +- .../daAlgorithms/QuantileRegression.py | 24 +- src/daComposant/daAlgorithms/SamplingTest.py | 18 +- src/daComposant/daAlgorithms/TabuSearch.py | 34 +- src/daComposant/daAlgorithms/TangentTest.py | 69 +- .../daAlgorithms/UnscentedKalmanFilter.py | 10 +- src/daComposant/daAlgorithms/__init__.py | 2 +- src/daComposant/daCore/Aidsm.py | 996 ++++++++++++++++ src/daComposant/daCore/AssimilationStudy.py | 1055 +---------------- src/daComposant/daCore/BasicObjects.py | 992 +++++++++++++--- src/daComposant/daCore/ExtendedLogging.py | 36 +- src/daComposant/daCore/Persistence.py | 337 +++--- src/daComposant/daCore/PlatformInfo.py | 58 +- src/daComposant/daCore/Templates.py | 35 +- src/daComposant/daCore/__init__.py | 2 +- src/daComposant/daCore/version.py | 2 +- src/daComposant/daDiagnostics/PlotVector.py | 38 +- src/daComposant/daDiagnostics/PlotVectors.py | 46 +- src/daComposant/daDiagnostics/RMS.py | 6 +- .../daDiagnostics/ReduceVariance.py | 32 +- src/daComposant/daDiagnostics/__init__.py | 2 +- src/daComposant/daMatrices/__init__.py | 2 +- .../daNumerics/ApproximatedDerivatives.py | 74 +- src/daComposant/daNumerics/__init__.py | 2 +- src/daComposant/daNumerics/mmqr.py | 6 +- 40 files changed, 2586 insertions(+), 1969 deletions(-) create mode 100644 src/daComposant/daCore/Aidsm.py diff --git a/src/daComposant/daAlgorithms/3DVAR.py b/src/daComposant/daAlgorithms/3DVAR.py index adf9626..67a060c 100644 --- a/src/daComposant/daAlgorithms/3DVAR.py +++ b/src/daComposant/daAlgorithms/3DVAR.py @@ -1,4 +1,4 @@ -#-*-coding:iso-8859-1-*- +# -*- coding: utf-8 -*- # # Copyright (C) 2008-2017 EDF R&D # @@ -32,7 +32,7 @@ class ElementaryAlgorithm(BasicObjects.Algorithm): name = "Minimizer", default = "LBFGSB", typecast = str, - message = "Minimiseur utilisé", + message = "Minimiseur utilisé", listval = ["LBFGSB","TNC", "CG", "NCG", "BFGS"], ) self.defineRequiredParameter( @@ -46,32 +46,32 @@ class ElementaryAlgorithm(BasicObjects.Algorithm): name = "CostDecrementTolerance", default = 1.e-7, typecast = float, - message = "Diminution relative minimale du cout lors de l'arrêt", + message = "Diminution relative minimale du cout lors de l'arrêt", ) self.defineRequiredParameter( name = "ProjectedGradientTolerance", default = -1, typecast = float, - message = "Maximum des composantes du gradient projeté lors de l'arrêt", + message = "Maximum des composantes du gradient projeté lors de l'arrêt", minval = -1, ) self.defineRequiredParameter( name = "GradientNormTolerance", default = 1.e-05, typecast = float, - message = "Maximum des composantes du gradient lors de l'arrêt", + message = "Maximum des composantes du gradient lors de l'arrêt", ) self.defineRequiredParameter( name = "StoreInternalVariables", default = False, typecast = bool, - message = "Stockage des variables internes ou intermédiaires du calcul", + message = "Stockage des variables internes ou intermédiaires du calcul", ) self.defineRequiredParameter( name = "StoreSupplementaryCalculations", default = [], typecast = tuple, - message = "Liste de calculs supplémentaires à stocker et/ou effectuer", + message = "Liste de calculs supplémentaires à stocker et/ou effectuer", listval = ["APosterioriCorrelations", "APosterioriCovariance", "APosterioriStandardDeviations", "APosterioriVariances", "BMA", "OMA", "OMB", "CostFunctionJ", "CostFunctionJb", "CostFunctionJo", "CurrentState", "CurrentOptimum", "IndexOfOptimum", "Innovation", "InnovationAtCurrentState", "CostFunctionJAtCurrentOptimum", "SigmaObs2", "MahalanobisConsistency", "SimulationQuantiles", "SimulatedObservationAtBackground", "SimulatedObservationAtCurrentState", "SimulatedObservationAtOptimum", "SimulatedObservationAtCurrentOptimum"] ) self.defineRequiredParameter( @@ -85,13 +85,13 @@ class ElementaryAlgorithm(BasicObjects.Algorithm): self.defineRequiredParameter( name = "SetSeed", typecast = numpy.random.seed, - message = "Graine fixée pour le générateur aléatoire", + message = "Graine fixée pour le générateur aléatoire", ) self.defineRequiredParameter( name = "NumberOfSamplesForQuantiles", default = 100, typecast = int, - message = "Nombre d'échantillons simulés pour le calcul des quantiles", + message = "Nombre d'échantillons simulés pour le calcul des quantiles", minval = 1, ) self.defineRequiredParameter( @@ -113,15 +113,15 @@ class ElementaryAlgorithm(BasicObjects.Algorithm): if "Minimizer" in self._parameters and self._parameters["Minimizer"] == "TNC": self.setParameterValue("StoreInternalVariables",True) # - # Opérateurs + # Opérateurs # ---------- Hm = HO["Direct"].appliedTo Ha = HO["Adjoint"].appliedInXTo # - # Utilisation éventuelle d'un vecteur H(Xb) précalculé + # Utilisation éventuelle d'un vecteur H(Xb) précalculé # ---------------------------------------------------- - if HO["AppliedToX"] is not None and "HXb" in HO["AppliedToX"]: - HXb = Hm( Xb, HO["AppliedToX"]["HXb"]) + if HO["AppliedInX"] is not None and "HXb" in HO["AppliedInX"]: + HXb = Hm( Xb, HO["AppliedInX"]["HXb"]) else: HXb = Hm( Xb ) HXb = numpy.asmatrix(numpy.ravel( HXb )).T @@ -130,12 +130,12 @@ class ElementaryAlgorithm(BasicObjects.Algorithm): if max(Y.shape) != max(HXb.shape): raise ValueError("The shapes %s of observations Y and %s of observed calculation H(X) are different, they have to be identical."%(Y.shape,HXb.shape)) # - # Précalcul des inversions de B et R + # Précalcul des inversions de B et R # ---------------------------------- BI = B.getI() RI = R.getI() # - # Définition de la fonction-coût + # Définition de la fonction-coût # ------------------------------ def CostFunction(x): _X = numpy.asmatrix(numpy.ravel( x )).T @@ -185,7 +185,7 @@ class ElementaryAlgorithm(BasicObjects.Algorithm): GradJ = numpy.asmatrix( numpy.ravel( GradJb ) + numpy.ravel( GradJo ) ).T return GradJ.A1 # - # Point de démarrage de l'optimisation : Xini = Xb + # Point de démarrage de l'optimisation : Xini = Xb # ------------------------------------ Xini = numpy.ravel(Xb) # @@ -309,7 +309,7 @@ class ElementaryAlgorithm(BasicObjects.Algorithm): raise ValueError("The %s a posteriori covariance matrix A is not symmetric positive-definite. Please check your a priori covariances and your observation operator."%(self._name,)) self.StoredVariables["APosterioriCovariance"].store( A ) # - # Calculs et/ou stockages supplémentaires + # Calculs et/ou stockages supplémentaires # --------------------------------------- if "Innovation" in self._parameters["StoreSupplementaryCalculations"] or \ "SigmaObs2" in self._parameters["StoreSupplementaryCalculations"] or \ @@ -330,7 +330,6 @@ class ElementaryAlgorithm(BasicObjects.Algorithm): if "MahalanobisConsistency" in self._parameters["StoreSupplementaryCalculations"]: self.StoredVariables["MahalanobisConsistency"].store( float( 2.*MinJ/d.size ) ) if "SimulationQuantiles" in self._parameters["StoreSupplementaryCalculations"]: - Qtls = map(float, self._parameters["Quantiles"]) nech = self._parameters["NumberOfSamplesForQuantiles"] HXa = numpy.matrix(numpy.ravel( HXa )).T YfQ = None @@ -348,9 +347,9 @@ class ElementaryAlgorithm(BasicObjects.Algorithm): YfQ = numpy.hstack((YfQ,Yr)) YfQ.sort(axis=-1) YQ = None - for quantile in Qtls: - if not (0. <= quantile <= 1.): continue - indice = int(nech * quantile - 1./nech) + for quantile in self._parameters["Quantiles"]: + if not (0. <= float(quantile) <= 1.): continue + indice = int(nech * float(quantile) - 1./nech) if YQ is None: YQ = YfQ[:,indice] else: YQ = numpy.hstack((YQ,YfQ[:,indice])) self.StoredVariables["SimulationQuantiles"].store( YQ ) diff --git a/src/daComposant/daAlgorithms/4DVAR.py b/src/daComposant/daAlgorithms/4DVAR.py index 48a015d..a9f9fb1 100644 --- a/src/daComposant/daAlgorithms/4DVAR.py +++ b/src/daComposant/daAlgorithms/4DVAR.py @@ -1,4 +1,4 @@ -#-*-coding:iso-8859-1-*- +# -*- coding: utf-8 -*- # # Copyright (C) 2008-2017 EDF R&D # @@ -46,7 +46,7 @@ class ElementaryAlgorithm(BasicObjects.Algorithm): name = "Minimizer", default = "LBFGSB", typecast = str, - message = "Minimiseur utilisé", + message = "Minimiseur utilisé", listval = ["LBFGSB","TNC", "CG", "NCG", "BFGS"], ) self.defineRequiredParameter( @@ -60,32 +60,32 @@ class ElementaryAlgorithm(BasicObjects.Algorithm): name = "CostDecrementTolerance", default = 1.e-7, typecast = float, - message = "Diminution relative minimale du cout lors de l'arrêt", + message = "Diminution relative minimale du cout lors de l'arrêt", ) self.defineRequiredParameter( name = "ProjectedGradientTolerance", default = -1, typecast = float, - message = "Maximum des composantes du gradient projeté lors de l'arrêt", + message = "Maximum des composantes du gradient projeté lors de l'arrêt", minval = -1, ) self.defineRequiredParameter( name = "GradientNormTolerance", default = 1.e-05, typecast = float, - message = "Maximum des composantes du gradient lors de l'arrêt", + message = "Maximum des composantes du gradient lors de l'arrêt", ) self.defineRequiredParameter( name = "StoreInternalVariables", default = False, typecast = bool, - message = "Stockage des variables internes ou intermédiaires du calcul", + message = "Stockage des variables internes ou intermédiaires du calcul", ) self.defineRequiredParameter( name = "StoreSupplementaryCalculations", default = [], typecast = tuple, - message = "Liste de calculs supplémentaires à stocker et/ou effectuer", + message = "Liste de calculs supplémentaires à stocker et/ou effectuer", listval = ["BMA", "CurrentState", "CostFunctionJ", "CostFunctionJb", "CostFunctionJo", "IndexOfOptimum", "CurrentOptimum", "CostFunctionJAtCurrentOptimum"] ) self.defineRequiredParameter( # Pas de type @@ -100,7 +100,7 @@ class ElementaryAlgorithm(BasicObjects.Algorithm): if "Minimizer" in self._parameters and self._parameters["Minimizer"] == "TNC": self.setParameterValue("StoreInternalVariables",True) # - # Opérateurs + # Opérateurs # ---------- Hm = HO["Direct"].appliedControledFormTo # @@ -130,10 +130,10 @@ class ElementaryAlgorithm(BasicObjects.Algorithm): _CmUn = 0. return _CmUn # - # Remarque : les observations sont exploitées à partir du pas de temps - # numéro 1, et sont utilisées dans Yo comme rangées selon ces indices. - # Donc le pas 0 n'est pas utilisé puisque la première étape commence - # avec l'observation du pas 1. + # Remarque : les observations sont exploitées à partir du pas de temps + # numéro 1, et sont utilisées dans Yo comme rangées selon ces indices. + # Donc le pas 0 n'est pas utilisé puisque la première étape commence + # avec l'observation du pas 1. # # Nombre de pas identique au nombre de pas d'observations # ------------------------------------------------------- @@ -142,15 +142,15 @@ class ElementaryAlgorithm(BasicObjects.Algorithm): else: duration = 2 # - # Précalcul des inversions de B et R + # Précalcul des inversions de B et R # ---------------------------------- BI = B.getI() RI = R.getI() # - # Définition de la fonction-coût + # Définition de la fonction-coût # ------------------------------ - self.DirectCalculation = [None,] # Le pas 0 n'est pas observé - self.DirectInnovation = [None,] # Le pas 0 n'est pas observé + self.DirectCalculation = [None,] # Le pas 0 n'est pas observé + self.DirectInnovation = [None,] # Le pas 0 n'est pas observé def CostFunction(x): _X = numpy.asmatrix(numpy.ravel( x )).T if self._parameters["StoreInternalVariables"] or \ @@ -170,7 +170,7 @@ class ElementaryAlgorithm(BasicObjects.Algorithm): _Ynpu = numpy.asmatrix(numpy.ravel( Y )).T _Un = Un(step) # - # Etape d'évolution + # Etape d'évolution if self._parameters["EstimationOf"] == "State": _Xn = Mm( (_Xn, _Un) ) + CmUn(_Xn, _Un) elif self._parameters["EstimationOf"] == "Parameters": @@ -180,7 +180,7 @@ class ElementaryAlgorithm(BasicObjects.Algorithm): _Xn = numpy.max(numpy.hstack((_Xn,numpy.asmatrix(self._parameters["Bounds"])[:,0])),axis=1) _Xn = numpy.min(numpy.hstack((_Xn,numpy.asmatrix(self._parameters["Bounds"])[:,1])),axis=1) # - # Etape de différence aux observations + # Etape de différence aux observations if self._parameters["EstimationOf"] == "State": _YmHMX = _Ynpu - numpy.asmatrix(numpy.ravel( Hm( (_Xn, None) ) )).T elif self._parameters["EstimationOf"] == "Parameters": @@ -212,9 +212,9 @@ class ElementaryAlgorithm(BasicObjects.Algorithm): GradJb = BI * (_X - Xb) GradJo = 0. for step in range(duration-1,0,-1): - # Etape de récupération du dernier stockage de l'évolution + # Etape de récupération du dernier stockage de l'évolution _Xn = self.DirectCalculation.pop() - # Etape de récupération du dernier stockage de l'innovation + # Etape de récupération du dernier stockage de l'innovation _YmHMX = self.DirectInnovation.pop() # Calcul des adjoints Ha = HO["Adjoint"].asMatrix(ValueForMethodForm = _Xn) @@ -222,14 +222,14 @@ class ElementaryAlgorithm(BasicObjects.Algorithm): Ma = EM["Adjoint"].asMatrix(ValueForMethodForm = _Xn) Ma = Ma.reshape(_Xn.size,_Xn.size) # ADAO & check shape # Calcul du gradient par etat adjoint - GradJo = GradJo + Ha * RI * _YmHMX # Equivaut pour Ha lineaire à : Ha( (_Xn, RI * _YmHMX) ) - GradJo = Ma * GradJo # Equivaut pour Ma lineaire à : Ma( (_Xn, GradJo) ) + GradJo = GradJo + Ha * RI * _YmHMX # Equivaut pour Ha lineaire à : Ha( (_Xn, RI * _YmHMX) ) + GradJo = Ma * GradJo # Equivaut pour Ma lineaire à : Ma( (_Xn, GradJo) ) GradJ = numpy.asmatrix( numpy.ravel( GradJb ) - numpy.ravel( GradJo ) ).T return GradJ.A1 # - # Point de démarrage de l'optimisation : Xini = Xb + # Point de démarrage de l'optimisation : Xini = Xb # ------------------------------------ - if type(Xb) is type(numpy.matrix([])): + if isinstance(Xb, type(numpy.matrix([]))): Xini = Xb.A1.tolist() else: Xini = list(Xb) @@ -314,7 +314,7 @@ class ElementaryAlgorithm(BasicObjects.Algorithm): # self.StoredVariables["Analysis"].store( Xa.A1 ) # - # Calculs et/ou stockages supplémentaires + # Calculs et/ou stockages supplémentaires # --------------------------------------- if "BMA" in self._parameters["StoreSupplementaryCalculations"]: self.StoredVariables["BMA"].store( numpy.ravel(Xb) - numpy.ravel(Xa) ) diff --git a/src/daComposant/daAlgorithms/AdjointTest.py b/src/daComposant/daAlgorithms/AdjointTest.py index 78088e3..d49c5c3 100644 --- a/src/daComposant/daAlgorithms/AdjointTest.py +++ b/src/daComposant/daAlgorithms/AdjointTest.py @@ -1,4 +1,4 @@ -#-*-coding:iso-8859-1-*- +# -*- coding: utf-8 -*- # # Copyright (C) 2008-2017 EDF R&D # @@ -20,10 +20,12 @@ # # Author: Jean-Philippe Argaud, jean-philippe.argaud@edf.fr, EDF R&D -import logging +import sys, logging from daCore import BasicObjects, PlatformInfo import numpy mpr = PlatformInfo.PlatformInfo().MachinePrecision() +if sys.version_info.major > 2: + unicode = str # ============================================================================== class ElementaryAlgorithm(BasicObjects.Algorithm): @@ -33,14 +35,14 @@ class ElementaryAlgorithm(BasicObjects.Algorithm): name = "ResiduFormula", default = "ScalarProduct", typecast = str, - message = "Formule de résidu utilisée", + message = "Formule de résidu utilisée", listval = ["ScalarProduct"], ) self.defineRequiredParameter( name = "EpsilonMinimumExponent", default = -8, typecast = int, - message = "Exposant minimal en puissance de 10 pour le multiplicateur d'incrément", + message = "Exposant minimal en puissance de 10 pour le multiplicateur d'incrément", minval = -20, maxval = 0, ) @@ -48,18 +50,18 @@ class ElementaryAlgorithm(BasicObjects.Algorithm): name = "InitialDirection", default = [], typecast = list, - message = "Direction initiale de la dérivée directionnelle autour du point nominal", + message = "Direction initiale de la dérivée directionnelle autour du point nominal", ) self.defineRequiredParameter( name = "AmplitudeOfInitialDirection", default = 1., typecast = float, - message = "Amplitude de la direction initiale de la dérivée directionnelle autour du point nominal", + message = "Amplitude de la direction initiale de la dérivée directionnelle autour du point nominal", ) self.defineRequiredParameter( name = "SetSeed", typecast = numpy.random.seed, - message = "Graine fixée pour le générateur aléatoire", + message = "Graine fixée pour le générateur aléatoire", ) self.defineRequiredParameter( name = "ResultTitle", @@ -71,7 +73,7 @@ class ElementaryAlgorithm(BasicObjects.Algorithm): name = "StoreSupplementaryCalculations", default = [], typecast = tuple, - message = "Liste de calculs supplémentaires à stocker et/ou effectuer", + message = "Liste de calculs supplémentaires à stocker et/ou effectuer", listval = ["CurrentState", "Residu", "SimulatedObservationAtCurrentState"] ) @@ -111,13 +113,13 @@ class ElementaryAlgorithm(BasicObjects.Algorithm): # # Entete des resultats # -------------------- - __marge = 12*" " - __precision = """ + __marge = 12*u" " + __precision = u""" Remarque : les nombres inferieurs a %.0e (environ) representent un zero a la precision machine.\n"""%mpr if self._parameters["ResiduFormula"] == "ScalarProduct": - __entete = " i Alpha ||X|| ||Y|| ||dX|| R(Alpha) " - __msgdoc = """ + __entete = u" i Alpha ||X|| ||Y|| ||dX|| R(Alpha) " + __msgdoc = u""" On observe le residu qui est la difference de deux produits scalaires : R(Alpha) = | < TangentF_X(dX) , Y > - < dX , AdjointF_X(Y) > | @@ -128,12 +130,13 @@ class ElementaryAlgorithm(BasicObjects.Algorithm): """ + __precision # if len(self._parameters["ResultTitle"]) > 0: - msgs = "\n" - msgs += __marge + "====" + "="*len(self._parameters["ResultTitle"]) + "====\n" - msgs += __marge + " " + self._parameters["ResultTitle"] + "\n" - msgs += __marge + "====" + "="*len(self._parameters["ResultTitle"]) + "====\n" + __rt = unicode(self._parameters["ResultTitle"]) + msgs = u"\n" + msgs += __marge + "====" + "="*len(__rt) + "====\n" + msgs += __marge + " " + __rt + "\n" + msgs += __marge + "====" + "="*len(__rt) + "====\n" else: - msgs = "" + msgs = u"" msgs += __msgdoc # __nbtirets = len(__entete) diff --git a/src/daComposant/daAlgorithms/Blue.py b/src/daComposant/daAlgorithms/Blue.py index a382264..2d85770 100644 --- a/src/daComposant/daAlgorithms/Blue.py +++ b/src/daComposant/daAlgorithms/Blue.py @@ -1,4 +1,4 @@ -#-*-coding:iso-8859-1-*- +# -*- coding: utf-8 -*- # # Copyright (C) 2008-2017 EDF R&D # @@ -32,13 +32,13 @@ class ElementaryAlgorithm(BasicObjects.Algorithm): name = "StoreInternalVariables", default = False, typecast = bool, - message = "Stockage des variables internes ou intermédiaires du calcul", + message = "Stockage des variables internes ou intermédiaires du calcul", ) self.defineRequiredParameter( name = "StoreSupplementaryCalculations", default = [], typecast = tuple, - message = "Liste de calculs supplémentaires à stocker et/ou effectuer", + message = "Liste de calculs supplémentaires à stocker et/ou effectuer", listval = ["APosterioriCorrelations", "APosterioriCovariance", "APosterioriStandardDeviations", "APosterioriVariances", "BMA", "OMA", "OMB", "CurrentState", "CostFunctionJ", "CostFunctionJb", "CostFunctionJo", "Innovation", "SigmaBck2", "SigmaObs2", "MahalanobisConsistency", "SimulationQuantiles", "SimulatedObservationAtBackground", "SimulatedObservationAtCurrentState", "SimulatedObservationAtOptimum"] ) self.defineRequiredParameter( @@ -52,13 +52,13 @@ class ElementaryAlgorithm(BasicObjects.Algorithm): self.defineRequiredParameter( name = "SetSeed", typecast = numpy.random.seed, - message = "Graine fixée pour le générateur aléatoire", + message = "Graine fixée pour le générateur aléatoire", ) self.defineRequiredParameter( name = "NumberOfSamplesForQuantiles", default = 100, typecast = int, - message = "Nombre d'échantillons simulés pour le calcul des quantiles", + message = "Nombre d'échantillons simulés pour le calcul des quantiles", minval = 1, ) self.defineRequiredParameter( @@ -77,10 +77,10 @@ class ElementaryAlgorithm(BasicObjects.Algorithm): Ha = HO["Adjoint"].asMatrix(Xb) Ha = Ha.reshape(Xb.size,Y.size) # ADAO & check shape # - # Utilisation éventuelle d'un vecteur H(Xb) précalculé (sans cout) + # Utilisation éventuelle d'un vecteur H(Xb) précalculé (sans cout) # ---------------------------------------------------------------- - if HO["AppliedToX"] is not None and "HXb" in HO["AppliedToX"]: - HXb = HO["AppliedToX"]["HXb"] + if HO["AppliedInX"] is not None and "HXb" in HO["AppliedInX"]: + HXb = HO["AppliedInX"]["HXb"] else: HXb = Hm * Xb HXb = numpy.asmatrix(numpy.ravel( HXb )).T @@ -89,7 +89,7 @@ class ElementaryAlgorithm(BasicObjects.Algorithm): if max(Y.shape) != max(HXb.shape): raise ValueError("The shapes %s of observations Y and %s of observed calculation H(X) are different, they have to be identical."%(Y.shape,HXb.shape)) # - # Précalcul des inversions de B et R + # Précalcul des inversions de B et R # ---------------------------------- BI = B.getI() RI = R.getI() @@ -110,7 +110,7 @@ class ElementaryAlgorithm(BasicObjects.Algorithm): Xa = Xb + _u self.StoredVariables["Analysis"].store( Xa.A1 ) # - # Calcul de la fonction coût + # Calcul de la fonction coût # -------------------------- if self._parameters["StoreInternalVariables"] or \ "CostFunctionJ" in self._parameters["StoreSupplementaryCalculations"] or \ @@ -152,7 +152,7 @@ class ElementaryAlgorithm(BasicObjects.Algorithm): raise ValueError("The %s a posteriori covariance matrix A is not symmetric positive-definite. Please check your a priori covariances and your observation operator."%(self._name,)) self.StoredVariables["APosterioriCovariance"].store( A ) # - # Calculs et/ou stockages supplémentaires + # Calculs et/ou stockages supplémentaires # --------------------------------------- if self._parameters["StoreInternalVariables"] or "CurrentState" in self._parameters["StoreSupplementaryCalculations"]: self.StoredVariables["CurrentState"].store( numpy.ravel(Xa) ) @@ -172,7 +172,6 @@ class ElementaryAlgorithm(BasicObjects.Algorithm): if "MahalanobisConsistency" in self._parameters["StoreSupplementaryCalculations"]: self.StoredVariables["MahalanobisConsistency"].store( float( 2.*J/d.size ) ) if "SimulationQuantiles" in self._parameters["StoreSupplementaryCalculations"]: - Qtls = map(float, self._parameters["Quantiles"]) nech = self._parameters["NumberOfSamplesForQuantiles"] YfQ = None for i in range(nech): @@ -189,9 +188,9 @@ class ElementaryAlgorithm(BasicObjects.Algorithm): YfQ = numpy.hstack((YfQ,Yr)) YfQ.sort(axis=-1) YQ = None - for quantile in Qtls: - if not (0. <= quantile <= 1.): continue - indice = int(nech * quantile - 1./nech) + for quantile in self._parameters["Quantiles"]: + if not (0. <= float(quantile) <= 1.): continue + indice = int(nech * float(quantile) - 1./nech) if YQ is None: YQ = YfQ[:,indice] else: YQ = numpy.hstack((YQ,YfQ[:,indice])) self.StoredVariables["SimulationQuantiles"].store( YQ ) diff --git a/src/daComposant/daAlgorithms/DerivativeFreeOptimization.py b/src/daComposant/daAlgorithms/DerivativeFreeOptimization.py index e9d9a5f..eb35174 100644 --- a/src/daComposant/daAlgorithms/DerivativeFreeOptimization.py +++ b/src/daComposant/daAlgorithms/DerivativeFreeOptimization.py @@ -1,4 +1,4 @@ -#-*-coding:iso-8859-1-*- +# -*- coding: utf-8 -*- # # Copyright (C) 2008-2017 EDF R&D # @@ -32,7 +32,7 @@ class ElementaryAlgorithm(BasicObjects.Algorithm): name = "Minimizer", default = "BOBYQA", typecast = str, - message = "Minimiseur utilisé", + message = "Minimiseur utilisé", listval = ["BOBYQA", "COBYLA", "NEWUOA", "POWELL", "SIMPLEX", "SUBPLEX"], ) self.defineRequiredParameter( @@ -46,26 +46,26 @@ class ElementaryAlgorithm(BasicObjects.Algorithm): name = "MaximumNumberOfFunctionEvaluations", default = 15000, typecast = int, - message = "Nombre maximal d'évaluations de la fonction", + message = "Nombre maximal d'évaluations de la fonction", minval = -1, ) self.defineRequiredParameter( name = "StateVariationTolerance", default = 1.e-4, typecast = float, - message = "Variation relative maximale de l'état lors de l'arrêt", + message = "Variation relative maximale de l'état lors de l'arrêt", ) self.defineRequiredParameter( name = "CostDecrementTolerance", default = 1.e-7, typecast = float, - message = "Diminution relative minimale du cout lors de l'arrêt", + message = "Diminution relative minimale du cout lors de l'arrêt", ) self.defineRequiredParameter( name = "QualityCriterion", default = "AugmentedWeightedLeastSquares", typecast = str, - message = "Critère de qualité utilisé", + message = "Critère de qualité utilisé", listval = ["AugmentedWeightedLeastSquares","AWLS","DA", "WeightedLeastSquares","WLS", "LeastSquares","LS","L2", @@ -76,13 +76,13 @@ class ElementaryAlgorithm(BasicObjects.Algorithm): name = "StoreInternalVariables", default = False, typecast = bool, - message = "Stockage des variables internes ou intermédiaires du calcul", + message = "Stockage des variables internes ou intermédiaires du calcul", ) self.defineRequiredParameter( name = "StoreSupplementaryCalculations", default = [], typecast = tuple, - message = "Liste de calculs supplémentaires à stocker et/ou effectuer", + message = "Liste de calculs supplémentaires à stocker et/ou effectuer", listval = ["CurrentState", "CostFunctionJ", "CostFunctionJb", "CostFunctionJo", "CostFunctionJAtCurrentOptimum", "CurrentOptimum", "IndexOfOptimum", "InnovationAtCurrentState", "BMA", "OMA", "OMB", "SimulatedObservationAtBackground", "SimulatedObservationAtCurrentOptimum", "SimulatedObservationAtCurrentState", "SimulatedObservationAtOptimum"] ) self.defineRequiredParameter( # Pas de type @@ -96,16 +96,16 @@ class ElementaryAlgorithm(BasicObjects.Algorithm): if not PlatformInfo.has_nlopt and not self._parameters["Minimizer"] in ["COBYLA", "POWELL", "SIMPLEX"]: self._parameters["Minimizer"] = "SIMPLEX" # - # Opérateurs + # Opérateurs # ---------- Hm = HO["Direct"].appliedTo # - # Précalcul des inversions de B et R + # Précalcul des inversions de B et R # ---------------------------------- BI = B.getI() RI = R.getI() # - # Définition de la fonction-coût + # Définition de la fonction-coût # ------------------------------ def CostFunction(x, QualityMeasure="AugmentedWeightedLeastSquares"): _X = numpy.asmatrix(numpy.ravel( x )).T @@ -161,7 +161,7 @@ class ElementaryAlgorithm(BasicObjects.Algorithm): self.StoredVariables["CostFunctionJAtCurrentOptimum" ].store( self.StoredVariables["CostFunctionJ" ][IndexMin] ) return J # - # Point de démarrage de l'optimisation : Xini = Xb + # Point de démarrage de l'optimisation : Xini = Xb # ------------------------------------ Xini = numpy.ravel(Xb) if len(Xini) < 2 and self._parameters["Minimizer"] == "NEWUOA": diff --git a/src/daComposant/daAlgorithms/EnsembleBlue.py b/src/daComposant/daAlgorithms/EnsembleBlue.py index 6cc0cf2..0157578 100644 --- a/src/daComposant/daAlgorithms/EnsembleBlue.py +++ b/src/daComposant/daAlgorithms/EnsembleBlue.py @@ -1,4 +1,4 @@ -#-*-coding:iso-8859-1-*- +# -*- coding: utf-8 -*- # # Copyright (C) 2008-2017 EDF R&D # @@ -32,34 +32,34 @@ class ElementaryAlgorithm(BasicObjects.Algorithm): name = "StoreInternalVariables", default = False, typecast = bool, - message = "Stockage des variables internes ou intermédiaires du calcul", + message = "Stockage des variables internes ou intermédiaires du calcul", ) self.defineRequiredParameter( name = "StoreSupplementaryCalculations", default = [], typecast = tuple, - message = "Liste de calculs supplémentaires à stocker et/ou effectuer", + message = "Liste de calculs supplémentaires à stocker et/ou effectuer", listval = ["CurrentState", "Innovation", "SimulatedObservationAtBackground", "SimulatedObservationAtCurrentState", "SimulatedObservationAtOptimum"] ) self.defineRequiredParameter( name = "SetSeed", typecast = numpy.random.seed, - message = "Graine fixée pour le générateur aléatoire", + message = "Graine fixée pour le générateur aléatoire", ) def run(self, Xb=None, Y=None, U=None, HO=None, EM=None, CM=None, R=None, B=None, Q=None, Parameters=None): self._pre_run(Parameters) # - # Précalcul des inversions de B et R + # Précalcul des inversions de B et R # ---------------------------------- BI = B.getI() RI = R.getI() # - # Nombre d'ensemble pour l'ébauche + # Nombre d'ensemble pour l'ébauche # -------------------------------- nb_ens = Xb.stepnumber() # - # Construction de l'ensemble des observations, par génération a partir + # Construction de l'ensemble des observations, par génération a partir # de la diagonale de R # -------------------------------------------------------------------- DiagonaleR = R.diag(Y.size) @@ -69,7 +69,7 @@ class ElementaryAlgorithm(BasicObjects.Algorithm): EnsembleY[npar,:] = Y[npar] + bruit EnsembleY = numpy.matrix(EnsembleY) # - # Initialisation des opérateurs d'observation et de la matrice gain + # Initialisation des opérateurs d'observation et de la matrice gain # ----------------------------------------------------------------- Hm = HO["Tangent"].asMatrix(None) Hm = Hm.reshape(Y.size,Xb[0].size) # ADAO & check shape diff --git a/src/daComposant/daAlgorithms/ExtendedBlue.py b/src/daComposant/daAlgorithms/ExtendedBlue.py index 4752f14..893a099 100644 --- a/src/daComposant/daAlgorithms/ExtendedBlue.py +++ b/src/daComposant/daAlgorithms/ExtendedBlue.py @@ -1,4 +1,4 @@ -#-*-coding:iso-8859-1-*- +# -*- coding: utf-8 -*- # # Copyright (C) 2008-2017 EDF R&D # @@ -32,13 +32,13 @@ class ElementaryAlgorithm(BasicObjects.Algorithm): name = "StoreInternalVariables", default = False, typecast = bool, - message = "Stockage des variables internes ou intermédiaires du calcul", + message = "Stockage des variables internes ou intermédiaires du calcul", ) self.defineRequiredParameter( name = "StoreSupplementaryCalculations", default = [], typecast = tuple, - message = "Liste de calculs supplémentaires à stocker et/ou effectuer", + message = "Liste de calculs supplémentaires à stocker et/ou effectuer", listval = ["APosterioriCorrelations", "APosterioriCovariance", "APosterioriStandardDeviations", "APosterioriVariances", "BMA", "OMA", "OMB", "CurrentState", "CostFunctionJ", "CostFunctionJb", "CostFunctionJo", "Innovation", "SigmaBck2", "SigmaObs2", "MahalanobisConsistency", "SimulationQuantiles", "SimulatedObservationAtBackground", "SimulatedObservationAtCurrentState", "SimulatedObservationAtOptimum"] ) self.defineRequiredParameter( @@ -52,13 +52,13 @@ class ElementaryAlgorithm(BasicObjects.Algorithm): self.defineRequiredParameter( name = "SetSeed", typecast = numpy.random.seed, - message = "Graine fixée pour le générateur aléatoire", + message = "Graine fixée pour le générateur aléatoire", ) self.defineRequiredParameter( name = "NumberOfSamplesForQuantiles", default = 100, typecast = int, - message = "Nombre d'échantillons simulés pour le calcul des quantiles", + message = "Nombre d'échantillons simulés pour le calcul des quantiles", minval = 1, ) self.defineRequiredParameter( @@ -78,15 +78,15 @@ class ElementaryAlgorithm(BasicObjects.Algorithm): Ha = Ha.reshape(Xb.size,Y.size) # ADAO & check shape H = HO["Direct"].appliedTo # - # Utilisation éventuelle d'un vecteur H(Xb) précalculé + # Utilisation éventuelle d'un vecteur H(Xb) précalculé # ---------------------------------------------------- - if HO["AppliedToX"] is not None and "HXb" in HO["AppliedToX"]: - HXb = H( Xb, HO["AppliedToX"]["HXb"]) + if HO["AppliedInX"] is not None and "HXb" in HO["AppliedInX"]: + HXb = H( Xb, HO["AppliedInX"]["HXb"]) else: HXb = H( Xb ) HXb = numpy.asmatrix(numpy.ravel( HXb )).T # - # Précalcul des inversions de B et R + # Précalcul des inversions de B et R # ---------------------------------- BI = B.getI() RI = R.getI() @@ -111,7 +111,7 @@ class ElementaryAlgorithm(BasicObjects.Algorithm): Xa = Xb + _u self.StoredVariables["Analysis"].store( Xa.A1 ) # - # Calcul de la fonction coût + # Calcul de la fonction coût # -------------------------- if self._parameters["StoreInternalVariables"] or \ "CostFunctionJ" in self._parameters["StoreSupplementaryCalculations"] or \ @@ -151,7 +151,7 @@ class ElementaryAlgorithm(BasicObjects.Algorithm): raise ValueError("The %s a posteriori covariance matrix A is not symmetric positive-definite. Please check your a priori covariances and your observation operator."%(self._name,)) self.StoredVariables["APosterioriCovariance"].store( A ) # - # Calculs et/ou stockages supplémentaires + # Calculs et/ou stockages supplémentaires # --------------------------------------- if self._parameters["StoreInternalVariables"] or "CurrentState" in self._parameters["StoreSupplementaryCalculations"]: self.StoredVariables["CurrentState"].store( numpy.ravel(Xa) ) @@ -171,7 +171,6 @@ class ElementaryAlgorithm(BasicObjects.Algorithm): if "MahalanobisConsistency" in self._parameters["StoreSupplementaryCalculations"]: self.StoredVariables["MahalanobisConsistency"].store( float( 2.*J/d.size ) ) if "SimulationQuantiles" in self._parameters["StoreSupplementaryCalculations"]: - Qtls = map(float, self._parameters["Quantiles"]) nech = self._parameters["NumberOfSamplesForQuantiles"] HtM = HO["Tangent"].asMatrix(ValueForMethodForm = Xa) HtM = HtM.reshape(Y.size,Xa.size) # ADAO & check shape @@ -190,9 +189,9 @@ class ElementaryAlgorithm(BasicObjects.Algorithm): YfQ = numpy.hstack((YfQ,Yr)) YfQ.sort(axis=-1) YQ = None - for quantile in Qtls: - if not (0. <= quantile <= 1.): continue - indice = int(nech * quantile - 1./nech) + for quantile in self._parameters["Quantiles"]: + if not (0. <= float(quantile) <= 1.): continue + indice = int(nech * float(quantile) - 1./nech) if YQ is None: YQ = YfQ[:,indice] else: YQ = numpy.hstack((YQ,YfQ[:,indice])) self.StoredVariables["SimulationQuantiles"].store( YQ ) diff --git a/src/daComposant/daAlgorithms/ExtendedKalmanFilter.py b/src/daComposant/daAlgorithms/ExtendedKalmanFilter.py index 621cf51..db3f9ab 100644 --- a/src/daComposant/daAlgorithms/ExtendedKalmanFilter.py +++ b/src/daComposant/daAlgorithms/ExtendedKalmanFilter.py @@ -1,4 +1,4 @@ -#-*-coding:iso-8859-1-*- +# -*- coding: utf-8 -*- # # Copyright (C) 2008-2017 EDF R&D # @@ -46,13 +46,13 @@ class ElementaryAlgorithm(BasicObjects.Algorithm): name = "StoreInternalVariables", default = False, typecast = bool, - message = "Stockage des variables internes ou intermédiaires du calcul", + message = "Stockage des variables internes ou intermédiaires du calcul", ) self.defineRequiredParameter( name = "StoreSupplementaryCalculations", default = [], typecast = tuple, - message = "Liste de calculs supplémentaires à stocker et/ou effectuer", + message = "Liste de calculs supplémentaires à stocker et/ou effectuer", listval = ["APosterioriCorrelations", "APosterioriCovariance", "APosterioriStandardDeviations", "APosterioriVariances", "BMA", "CurrentState", "CostFunctionJ", "CostFunctionJb", "CostFunctionJo", "Innovation"] ) self.defineRequiredParameter( # Pas de type @@ -66,7 +66,7 @@ class ElementaryAlgorithm(BasicObjects.Algorithm): if self._parameters["EstimationOf"] == "Parameters": self._parameters["StoreInternalVariables"] = True # - # Opérateurs + # Opérateurs # ---------- if B is None: raise ValueError("Background error covariance matrix has to be properly defined!") @@ -90,7 +90,7 @@ class ElementaryAlgorithm(BasicObjects.Algorithm): else: duration = 2 # - # Précalcul des inversions de B et R + # Précalcul des inversions de B et R # ---------------------------------- if self._parameters["StoreInternalVariables"]: BI = B.getI() diff --git a/src/daComposant/daAlgorithms/FunctionTest.py b/src/daComposant/daAlgorithms/FunctionTest.py index 8b4cd5b..6e0f869 100644 --- a/src/daComposant/daAlgorithms/FunctionTest.py +++ b/src/daComposant/daAlgorithms/FunctionTest.py @@ -1,4 +1,4 @@ -#-*-coding:iso-8859-1-*- +# -*- coding: utf-8 -*- # # Copyright (C) 2008-2017 EDF R&D # @@ -20,11 +20,13 @@ # # Author: Jean-Philippe Argaud, jean-philippe.argaud@edf.fr, EDF R&D -import logging +import sys, logging from daCore import BasicObjects, PlatformInfo import numpy, copy mpr = PlatformInfo.PlatformInfo().MachinePrecision() mfp = PlatformInfo.PlatformInfo().MaximumPrecision() +if sys.version_info.major > 2: + unicode = str # ============================================================================== class ElementaryAlgorithm(BasicObjects.Algorithm): @@ -34,14 +36,14 @@ class ElementaryAlgorithm(BasicObjects.Algorithm): name = "NumberOfPrintedDigits", default = 5, typecast = int, - message = "Nombre de chiffres affichés pour les impressions de réels", + message = "Nombre de chiffres affichés pour les impressions de réels", minval = 0, ) self.defineRequiredParameter( name = "NumberOfRepetition", default = 1, typecast = int, - message = "Nombre de fois où l'exécution de la fonction est répétée", + message = "Nombre de fois où l'exécution de la fonction est répétée", minval = 1, ) self.defineRequiredParameter( @@ -54,13 +56,13 @@ class ElementaryAlgorithm(BasicObjects.Algorithm): name = "SetDebug", default = False, typecast = bool, - message = "Activation du mode debug lors de l'exécution", + message = "Activation du mode debug lors de l'exécution", ) self.defineRequiredParameter( name = "StoreSupplementaryCalculations", default = [], typecast = tuple, - message = "Liste de calculs supplémentaires à stocker et/ou effectuer", + message = "Liste de calculs supplémentaires à stocker et/ou effectuer", listval = ["CurrentState", "SimulatedObservationAtCurrentState"] ) @@ -72,24 +74,27 @@ class ElementaryAlgorithm(BasicObjects.Algorithm): Xn = copy.copy( Xb ) # # ---------- + __marge = 5*u" " _p = self._parameters["NumberOfPrintedDigits"] if len(self._parameters["ResultTitle"]) > 0: - msg = " ====" + "="*len(self._parameters["ResultTitle"]) + "====\n" - msg += " " + self._parameters["ResultTitle"] + "\n" - msg += " ====" + "="*len(self._parameters["ResultTitle"]) + "====\n" - print("%s"%msg) + __rt = unicode(self._parameters["ResultTitle"]) + msgs = u"\n" + msgs += __marge + "====" + "="*len(__rt) + "====\n" + msgs += __marge + " " + __rt + "\n" + msgs += __marge + "====" + "="*len(__rt) + "====\n" + print("%s"%msgs) # - msg = ("===> Information before launching:\n") - msg += (" -----------------------------\n") - msg += (" Characteristics of input vector X, internally converted:\n") - msg += (" Type...............: %s\n")%type( Xn ) - msg += (" Lenght of vector...: %i\n")%max(numpy.matrix( Xn ).shape) - msg += (" Minimum value......: %."+str(_p)+"e\n")%numpy.min( Xn ) - msg += (" Maximum value......: %."+str(_p)+"e\n")%numpy.max( Xn ) - msg += (" Mean of vector.....: %."+str(_p)+"e\n")%numpy.mean( Xn, dtype=mfp ) - msg += (" Standard error.....: %."+str(_p)+"e\n")%numpy.std( Xn, dtype=mfp ) - msg += (" L2 norm of vector..: %."+str(_p)+"e\n")%numpy.linalg.norm( Xn ) - print(msg) + msgs = ("===> Information before launching:\n") + msgs += (" -----------------------------\n") + msgs += (" Characteristics of input vector X, internally converted:\n") + msgs += (" Type...............: %s\n")%type( Xn ) + msgs += (" Lenght of vector...: %i\n")%max(numpy.matrix( Xn ).shape) + msgs += (" Minimum value......: %."+str(_p)+"e\n")%numpy.min( Xn ) + msgs += (" Maximum value......: %."+str(_p)+"e\n")%numpy.max( Xn ) + msgs += (" Mean of vector.....: %."+str(_p)+"e\n")%numpy.mean( Xn, dtype=mfp ) + msgs += (" Standard error.....: %."+str(_p)+"e\n")%numpy.std( Xn, dtype=mfp ) + msgs += (" L2 norm of vector..: %."+str(_p)+"e\n")%numpy.linalg.norm( Xn ) + print(msgs) # if self._parameters["SetDebug"]: CUR_LEVEL = logging.getLogger().getEffectiveLevel() @@ -114,16 +119,16 @@ class ElementaryAlgorithm(BasicObjects.Algorithm): # print("\n===> End of direct operator evaluation\n") # - msg = ("===> Information after evaluation:\n") - msg += ("\n Characteristics of simulated output vector Y=H(X), to compare to others:\n") - msg += (" Type...............: %s\n")%type( Yn ) - msg += (" Lenght of vector...: %i\n")%max(numpy.matrix( Yn ).shape) - msg += (" Minimum value......: %."+str(_p)+"e\n")%numpy.min( Yn ) - msg += (" Maximum value......: %."+str(_p)+"e\n")%numpy.max( Yn ) - msg += (" Mean of vector.....: %."+str(_p)+"e\n")%numpy.mean( Yn, dtype=mfp ) - msg += (" Standard error.....: %."+str(_p)+"e\n")%numpy.std( Yn, dtype=mfp ) - msg += (" L2 norm of vector..: %."+str(_p)+"e\n")%numpy.linalg.norm( Yn ) - print(msg) + msgs = ("===> Information after evaluation:\n") + msgs += ("\n Characteristics of simulated output vector Y=H(X), to compare to others:\n") + msgs += (" Type...............: %s\n")%type( Yn ) + msgs += (" Lenght of vector...: %i\n")%max(numpy.matrix( Yn ).shape) + msgs += (" Minimum value......: %."+str(_p)+"e\n")%numpy.min( Yn ) + msgs += (" Maximum value......: %."+str(_p)+"e\n")%numpy.max( Yn ) + msgs += (" Mean of vector.....: %."+str(_p)+"e\n")%numpy.mean( Yn, dtype=mfp ) + msgs += (" Standard error.....: %."+str(_p)+"e\n")%numpy.std( Yn, dtype=mfp ) + msgs += (" L2 norm of vector..: %."+str(_p)+"e\n")%numpy.linalg.norm( Yn ) + print(msgs) if "SimulatedObservationAtCurrentState" in self._parameters["StoreSupplementaryCalculations"]: self.StoredVariables["SimulatedObservationAtCurrentState"].store( numpy.ravel(Yn) ) # @@ -140,32 +145,32 @@ class ElementaryAlgorithm(BasicObjects.Algorithm): logging.getLogger().setLevel(CUR_LEVEL) # if self._parameters["NumberOfRepetition"] > 1: - msg = (" %s\n"%("-"*75,)) - msg += ("\n===> Statistical analysis of the outputs obtained throught repeated evaluations\n") - msg += ("\n (Remark: numbers that are (about) under %.0e represent 0 to machine precision)\n"%mpr) + msgs = (" %s\n"%("-"*75,)) + msgs += ("\n===> Statistical analysis of the outputs obtained throught repeated evaluations\n") + msgs += ("\n (Remark: numbers that are (about) under %.0e represent 0 to machine precision)\n"%mpr) Yy = numpy.array( Ys ) - msg += ("\n Characteristics of the whole set of outputs Y:\n") - msg += (" Number of evaluations.........................: %i\n")%len( Ys ) - msg += (" Minimum value of the whole set of outputs.....: %."+str(_p)+"e\n")%numpy.min( Yy ) - msg += (" Maximum value of the whole set of outputs.....: %."+str(_p)+"e\n")%numpy.max( Yy ) - msg += (" Mean of vector of the whole set of outputs....: %."+str(_p)+"e\n")%numpy.mean( Yy, dtype=mfp ) - msg += (" Standard error of the whole set of outputs....: %."+str(_p)+"e\n")%numpy.std( Yy, dtype=mfp ) + msgs += ("\n Characteristics of the whole set of outputs Y:\n") + msgs += (" Number of evaluations.........................: %i\n")%len( Ys ) + msgs += (" Minimum value of the whole set of outputs.....: %."+str(_p)+"e\n")%numpy.min( Yy ) + msgs += (" Maximum value of the whole set of outputs.....: %."+str(_p)+"e\n")%numpy.max( Yy ) + msgs += (" Mean of vector of the whole set of outputs....: %."+str(_p)+"e\n")%numpy.mean( Yy, dtype=mfp ) + msgs += (" Standard error of the whole set of outputs....: %."+str(_p)+"e\n")%numpy.std( Yy, dtype=mfp ) Ym = numpy.mean( numpy.array( Ys ), axis=0, dtype=mfp ) - msg += ("\n Characteristics of the vector Ym, mean of the outputs Y:\n") - msg += (" Size of the mean of the outputs...............: %i\n")%Ym.size - msg += (" Minimum value of the mean of the outputs......: %."+str(_p)+"e\n")%numpy.min( Ym ) - msg += (" Maximum value of the mean of the outputs......: %."+str(_p)+"e\n")%numpy.max( Ym ) - msg += (" Mean of the mean of the outputs...............: %."+str(_p)+"e\n")%numpy.mean( Ym, dtype=mfp ) - msg += (" Standard error of the mean of the outputs.....: %."+str(_p)+"e\n")%numpy.std( Ym, dtype=mfp ) + msgs += ("\n Characteristics of the vector Ym, mean of the outputs Y:\n") + msgs += (" Size of the mean of the outputs...............: %i\n")%Ym.size + msgs += (" Minimum value of the mean of the outputs......: %."+str(_p)+"e\n")%numpy.min( Ym ) + msgs += (" Maximum value of the mean of the outputs......: %."+str(_p)+"e\n")%numpy.max( Ym ) + msgs += (" Mean of the mean of the outputs...............: %."+str(_p)+"e\n")%numpy.mean( Ym, dtype=mfp ) + msgs += (" Standard error of the mean of the outputs.....: %."+str(_p)+"e\n")%numpy.std( Ym, dtype=mfp ) Ye = numpy.mean( numpy.array( Ys ) - Ym, axis=0, dtype=mfp ) - msg += "\n Characteristics of the mean of the differences between the outputs Y and their mean Ym:\n" - msg += (" Size of the mean of the differences...........: %i\n")%Ym.size - msg += (" Minimum value of the mean of the differences..: %."+str(_p)+"e\n")%numpy.min( Ye ) - msg += (" Maximum value of the mean of the differences..: %."+str(_p)+"e\n")%numpy.max( Ye ) - msg += (" Mean of the mean of the differences...........: %."+str(_p)+"e\n")%numpy.mean( Ye, dtype=mfp ) - msg += (" Standard error of the mean of the differences.: %."+str(_p)+"e\n")%numpy.std( Ye, dtype=mfp ) - msg += ("\n %s\n"%("-"*75,)) - print(msg) + msgs += "\n Characteristics of the mean of the differences between the outputs Y and their mean Ym:\n" + msgs += (" Size of the mean of the differences...........: %i\n")%Ym.size + msgs += (" Minimum value of the mean of the differences..: %."+str(_p)+"e\n")%numpy.min( Ye ) + msgs += (" Maximum value of the mean of the differences..: %."+str(_p)+"e\n")%numpy.max( Ye ) + msgs += (" Mean of the mean of the differences...........: %."+str(_p)+"e\n")%numpy.mean( Ye, dtype=mfp ) + msgs += (" Standard error of the mean of the differences.: %."+str(_p)+"e\n")%numpy.std( Ye, dtype=mfp ) + msgs += ("\n %s\n"%("-"*75,)) + print(msgs) # self._post_run(HO) return 0 diff --git a/src/daComposant/daAlgorithms/GradientTest.py b/src/daComposant/daAlgorithms/GradientTest.py index e81fd57..7be3df4 100644 --- a/src/daComposant/daAlgorithms/GradientTest.py +++ b/src/daComposant/daAlgorithms/GradientTest.py @@ -1,4 +1,4 @@ -#-*-coding:iso-8859-1-*- +# -*- coding: utf-8 -*- # # Copyright (C) 2008-2017 EDF R&D # @@ -20,10 +20,12 @@ # # Author: Jean-Philippe Argaud, jean-philippe.argaud@edf.fr, EDF R&D -import logging +import sys, logging from daCore import BasicObjects, PlatformInfo import numpy, math mpr = PlatformInfo.PlatformInfo().MachinePrecision() +if sys.version_info.major > 2: + unicode = str # ============================================================================== class ElementaryAlgorithm(BasicObjects.Algorithm): @@ -33,14 +35,14 @@ class ElementaryAlgorithm(BasicObjects.Algorithm): name = "ResiduFormula", default = "Taylor", typecast = str, - message = "Formule de résidu utilisée", + message = "Formule de résidu utilisée", listval = ["Norm", "TaylorOnNorm", "Taylor"], ) self.defineRequiredParameter( name = "EpsilonMinimumExponent", default = -8, typecast = int, - message = "Exposant minimal en puissance de 10 pour le multiplicateur d'incrément", + message = "Exposant minimal en puissance de 10 pour le multiplicateur d'incrément", minval = -20, maxval = 0, ) @@ -48,13 +50,13 @@ class ElementaryAlgorithm(BasicObjects.Algorithm): name = "InitialDirection", default = [], typecast = list, - message = "Direction initiale de la dérivée directionnelle autour du point nominal", + message = "Direction initiale de la dérivée directionnelle autour du point nominal", ) self.defineRequiredParameter( name = "AmplitudeOfInitialDirection", default = 1., typecast = float, - message = "Amplitude de la direction initiale de la dérivée directionnelle autour du point nominal", + message = "Amplitude de la direction initiale de la dérivée directionnelle autour du point nominal", ) self.defineRequiredParameter( name = "AmplitudeOfTangentPerturbation", @@ -67,19 +69,19 @@ class ElementaryAlgorithm(BasicObjects.Algorithm): self.defineRequiredParameter( name = "SetSeed", typecast = numpy.random.seed, - message = "Graine fixée pour le générateur aléatoire", + message = "Graine fixée pour le générateur aléatoire", ) self.defineRequiredParameter( name = "PlotAndSave", default = False, typecast = bool, - message = "Trace et sauve les résultats", + message = "Trace et sauve les résultats", ) self.defineRequiredParameter( name = "ResultFile", default = self._name+"_result_file", typecast = str, - message = "Nom de base (hors extension) des fichiers de sauvegarde des résultats", + message = "Nom de base (hors extension) des fichiers de sauvegarde des résultats", ) self.defineRequiredParameter( name = "ResultTitle", @@ -91,13 +93,13 @@ class ElementaryAlgorithm(BasicObjects.Algorithm): name = "ResultLabel", default = "", typecast = str, - message = "Label de la courbe tracée dans la figure", + message = "Label de la courbe tracée dans la figure", ) self.defineRequiredParameter( name = "StoreSupplementaryCalculations", default = [], typecast = tuple, - message = "Liste de calculs supplémentaires à stocker et/ou effectuer", + message = "Liste de calculs supplémentaires à stocker et/ou effectuer", listval = ["CurrentState", "Residu", "SimulatedObservationAtCurrentState"] ) @@ -141,77 +143,78 @@ class ElementaryAlgorithm(BasicObjects.Algorithm): # # Entete des resultats # -------------------- - __marge = 12*" " - __precision = """ + __marge = 12*u" " + __precision = u""" Remarque : les nombres inferieurs a %.0e (environ) representent un zero a la precision machine.\n"""%mpr if self._parameters["ResiduFormula"] == "Taylor": - __entete = " i Alpha ||X|| ||F(X)|| ||F(X+dX)|| ||dX|| ||F(X+dX)-F(X)|| ||F(X+dX)-F(X)||/||dX|| R(Alpha) log( R ) " - __msgdoc = """ - On observe le résidu issu du développement de Taylor de la fonction F, - normalisé par la valeur au point nominal : + __entete = u" i Alpha ||X|| ||F(X)|| ||F(X+dX)|| ||dX|| ||F(X+dX)-F(X)|| ||F(X+dX)-F(X)||/||dX|| R(Alpha) log( R ) " + __msgdoc = u""" + On observe le residu issu du developpement de Taylor de la fonction F, + normalise par la valeur au point nominal : || F(X+Alpha*dX) - F(X) - Alpha * GradientF_X(dX) || R(Alpha) = ---------------------------------------------------- || F(X) || - Si le résidu décroit et que la décroissance se fait en Alpha**2 selon Alpha, - cela signifie que le gradient est bien calculé jusqu'à la précision d'arrêt - de la décroissance quadratique, et que F n'est pas linéaire. + Si le residu decroit et que la decroissance se fait en Alpha**2 selon Alpha, + cela signifie que le gradient est bien calcule jusqu'a la precision d'arret + de la decroissance quadratique, et que F n'est pas lineaire. - Si le résidu décroit et que la décroissance se fait en Alpha selon Alpha, - jusqu'à un certain seuil aprés lequel le résidu est faible et constant, cela - signifie que F est linéaire et que le résidu décroit à partir de l'erreur + Si le residu decroit et que la decroissance se fait en Alpha selon Alpha, + jusqu'a un certain seuil apres lequel le residu est faible et constant, cela + signifie que F est lineaire et que le residu decroit a partir de l'erreur faite dans le calcul du terme GradientF_X. On prend dX0 = Normal(0,X) et dX = Alpha*dX0. F est le code de calcul. """ + __precision if self._parameters["ResiduFormula"] == "TaylorOnNorm": - __entete = " i Alpha ||X|| ||F(X)|| ||F(X+dX)|| ||dX|| ||F(X+dX)-F(X)|| ||F(X+dX)-F(X)||/||dX|| R(Alpha) log( R ) " - __msgdoc = """ - On observe le résidu issu du développement de Taylor de la fonction F, - rapporté au paramètre Alpha au carré : + __entete = u" i Alpha ||X|| ||F(X)|| ||F(X+dX)|| ||dX|| ||F(X+dX)-F(X)|| ||F(X+dX)-F(X)||/||dX|| R(Alpha) log( R ) " + __msgdoc = u""" + On observe le residu issu du developpement de Taylor de la fonction F, + rapporte au parametre Alpha au carre : || F(X+Alpha*dX) - F(X) - Alpha * GradientF_X(dX) || R(Alpha) = ---------------------------------------------------- Alpha**2 - C'est un résidu essentiellement similaire au critère classique de Taylor, - mais son comportement peut différer selon les propriétés numériques des - calculs de ses différents termes. + C'est un residu essentiellement similaire au critere classique de Taylor, + mais son comportement peut differer selon les proprietes numeriques des + calculs de ses differents termes. - Si le résidu est constant jusqu'à un certain seuil et croissant ensuite, - cela signifie que le gradient est bien calculé jusqu'à cette précision - d'arrêt, et que F n'est pas linéaire. + Si le residu est constant jusqu'a un certain seuil et croissant ensuite, + cela signifie que le gradient est bien calcule jusqu'a cette precision + d'arret, et que F n'est pas lineaire. - Si le résidu est systématiquement croissant en partant d'une valeur faible - par rapport à ||F(X)||, cela signifie que F est (quasi-)linéaire et que le - calcul du gradient est correct jusqu'au moment où le résidu est de l'ordre de + Si le residu est systematiquement croissant en partant d'une valeur faible + par rapport a ||F(X)||, cela signifie que F est (quasi-)lineaire et que le + calcul du gradient est correct jusqu'au moment ou le residu est de l'ordre de grandeur de ||F(X)||. On prend dX0 = Normal(0,X) et dX = Alpha*dX0. F est le code de calcul. """ + __precision if self._parameters["ResiduFormula"] == "Norm": - __entete = " i Alpha ||X|| ||F(X)|| ||F(X+dX)|| ||dX|| ||F(X+dX)-F(X)|| ||F(X+dX)-F(X)||/||dX|| R(Alpha) log( R ) " - __msgdoc = """ - On observe le résidu, qui est basé sur une approximation du gradient : + __entete = u" i Alpha ||X|| ||F(X)|| ||F(X+dX)|| ||dX|| ||F(X+dX)-F(X)|| ||F(X+dX)-F(X)||/||dX|| R(Alpha) log( R ) " + __msgdoc = u""" + On observe le residu, qui est base sur une approximation du gradient : || F(X+Alpha*dX) - F(X) || R(Alpha) = --------------------------- Alpha - qui doit rester constant jusqu'à ce que l'on atteigne la précision du calcul. + qui doit rester constant jusqu'a ce que l'on atteigne la precision du calcul. On prend dX0 = Normal(0,X) et dX = Alpha*dX0. F est le code de calcul. """ + __precision # if len(self._parameters["ResultTitle"]) > 0: - msgs = "\n" - msgs += __marge + "====" + "="*len(self._parameters["ResultTitle"]) + "====\n" - msgs += __marge + " " + self._parameters["ResultTitle"] + "\n" - msgs += __marge + "====" + "="*len(self._parameters["ResultTitle"]) + "====\n" + __rt = unicode(self._parameters["ResultTitle"]) + msgs = u"\n" + msgs += __marge + "====" + "="*len(__rt) + "====\n" + msgs += __marge + " " + __rt + "\n" + msgs += __marge + "====" + "="*len(__rt) + "====\n" else: - msgs = "" + msgs = u"" msgs += __msgdoc # __nbtirets = len(__entete) @@ -249,8 +252,8 @@ class ElementaryAlgorithm(BasicObjects.Algorithm): # Residu Norm NormedFXsAm = NormedFX/amplitude # - # if numpy.abs(NormedFX) < 1.e-20: - #  break + # if numpy.abs(NormedFX) < 1.e-20: + #  break # NormesdX.append( NormedX ) NormesFXdX.append( NormeFXdX ) @@ -289,7 +292,7 @@ class ElementaryAlgorithm(BasicObjects.Algorithm): PerturbationsCarre = [ 10**(2*i) for i in range(-len(NormesdFXGdX)+1,1) ] PerturbationsCarre.reverse() dessiner( - Perturbations, + Perturbations, Residus, titre = self._parameters["ResultTitle"], label = self._parameters["ResultLabel"], @@ -301,7 +304,7 @@ class ElementaryAlgorithm(BasicObjects.Algorithm): ) elif self._parameters["ResiduFormula"] == "Norm": dessiner( - Perturbations, + Perturbations, Residus, titre = self._parameters["ResultTitle"], label = self._parameters["ResultLabel"], @@ -314,7 +317,7 @@ class ElementaryAlgorithm(BasicObjects.Algorithm): return 0 # ============================================================================== - + def dessiner( X, Y, @@ -325,7 +328,7 @@ def dessiner( filename = "", pause = False, YRef = None, # Vecteur de reference a comparer a Y - recalYRef = True, # Decalage du point 0 de YRef à Y[0] + recalYRef = True, # Decalage du point 0 de YRef a Y[0] normdY0 = 0., # Norme de DeltaY[0] ): import Gnuplot @@ -336,8 +339,8 @@ def dessiner( __g('set grid') __g('set autoscale') __g('set title "'+titre+'"') - # __g('set range [] reverse') - # __g('set yrange [0:2]') + # __g('set range [] reverse') + # __g('set yrange [0:2]') # if logX: steps = numpy.log10( X ) @@ -370,7 +373,7 @@ def dessiner( if filename != "": __g.hardcopy( filename, color=1) if pause: - raw_input('Please press return to continue...\n') + eval(input('Please press return to continue...\n')) # ============================================================================== if __name__ == "__main__": diff --git a/src/daComposant/daAlgorithms/KalmanFilter.py b/src/daComposant/daAlgorithms/KalmanFilter.py index f8885e9..3ff5e59 100644 --- a/src/daComposant/daAlgorithms/KalmanFilter.py +++ b/src/daComposant/daAlgorithms/KalmanFilter.py @@ -1,4 +1,4 @@ -#-*-coding:iso-8859-1-*- +# -*- coding: utf-8 -*- # # Copyright (C) 2008-2017 EDF R&D # @@ -39,13 +39,13 @@ class ElementaryAlgorithm(BasicObjects.Algorithm): name = "StoreInternalVariables", default = False, typecast = bool, - message = "Stockage des variables internes ou intermédiaires du calcul", + message = "Stockage des variables internes ou intermédiaires du calcul", ) self.defineRequiredParameter( name = "StoreSupplementaryCalculations", default = [], typecast = tuple, - message = "Liste de calculs supplémentaires à stocker et/ou effectuer", + message = "Liste de calculs supplémentaires à stocker et/ou effectuer", listval = ["APosterioriCorrelations", "APosterioriCovariance", "APosterioriStandardDeviations", "APosterioriVariances", "BMA", "CurrentState", "CostFunctionJ", "CostFunctionJb", "CostFunctionJo", "Innovation"] ) @@ -55,7 +55,7 @@ class ElementaryAlgorithm(BasicObjects.Algorithm): if self._parameters["EstimationOf"] == "Parameters": self._parameters["StoreInternalVariables"] = True # - # Opérateurs + # Opérateurs # ---------- if B is None: raise ValueError("Background error covariance matrix has to be properly defined!") @@ -81,7 +81,7 @@ class ElementaryAlgorithm(BasicObjects.Algorithm): else: duration = 2 # - # Précalcul des inversions de B et R + # Précalcul des inversions de B et R # ---------------------------------- if self._parameters["StoreInternalVariables"]: BI = B.getI() diff --git a/src/daComposant/daAlgorithms/LinearLeastSquares.py b/src/daComposant/daAlgorithms/LinearLeastSquares.py index fe21b64..6fc300d 100644 --- a/src/daComposant/daAlgorithms/LinearLeastSquares.py +++ b/src/daComposant/daAlgorithms/LinearLeastSquares.py @@ -1,4 +1,4 @@ -#-*-coding:iso-8859-1-*- +# -*- coding: utf-8 -*- # # Copyright (C) 2008-2017 EDF R&D # @@ -32,13 +32,13 @@ class ElementaryAlgorithm(BasicObjects.Algorithm): name = "StoreInternalVariables", default = False, typecast = bool, - message = "Stockage des variables internes ou intermédiaires du calcul", + message = "Stockage des variables internes ou intermédiaires du calcul", ) self.defineRequiredParameter( name = "StoreSupplementaryCalculations", default = [], typecast = tuple, - message = "Liste de calculs supplémentaires à stocker et/ou effectuer", + message = "Liste de calculs supplémentaires à stocker et/ou effectuer", listval = ["OMA", "CurrentState", "CostFunctionJ", "CostFunctionJb", "CostFunctionJo", "SimulatedObservationAtCurrentState", "SimulatedObservationAtOptimum"] ) @@ -58,7 +58,7 @@ class ElementaryAlgorithm(BasicObjects.Algorithm): Xa = K * Y self.StoredVariables["Analysis"].store( Xa.A1 ) # - # Calcul de la fonction coût + # Calcul de la fonction coût # -------------------------- if self._parameters["StoreInternalVariables"] or \ "CostFunctionJ" in self._parameters["StoreSupplementaryCalculations"] or \ @@ -75,7 +75,7 @@ class ElementaryAlgorithm(BasicObjects.Algorithm): self.StoredVariables["CostFunctionJo"].store( Jo ) self.StoredVariables["CostFunctionJ" ].store( J ) # - # Calculs et/ou stockages supplémentaires + # Calculs et/ou stockages supplémentaires # --------------------------------------- if self._parameters["StoreInternalVariables"] or "CurrentState" in self._parameters["StoreSupplementaryCalculations"]: self.StoredVariables["CurrentState"].store( numpy.ravel(Xa) ) diff --git a/src/daComposant/daAlgorithms/LinearityTest.py b/src/daComposant/daAlgorithms/LinearityTest.py index d4ca039..9733aa9 100644 --- a/src/daComposant/daAlgorithms/LinearityTest.py +++ b/src/daComposant/daAlgorithms/LinearityTest.py @@ -1,4 +1,4 @@ -#-*-coding:iso-8859-1-*- +# -*- coding: utf-8 -*- # # Copyright (C) 2008-2017 EDF R&D # @@ -20,10 +20,12 @@ # # Author: Jean-Philippe Argaud, jean-philippe.argaud@edf.fr, EDF R&D -import logging +import sys, logging from daCore import BasicObjects, PlatformInfo import numpy, math mpr = PlatformInfo.PlatformInfo().MachinePrecision() +if sys.version_info.major > 2: + unicode = str # ============================================================================== class ElementaryAlgorithm(BasicObjects.Algorithm): @@ -33,14 +35,14 @@ class ElementaryAlgorithm(BasicObjects.Algorithm): name = "ResiduFormula", default = "CenteredDL", typecast = str, - message = "Formule de résidu utilisée", + message = "Formule de résidu utilisée", listval = ["CenteredDL", "Taylor", "NominalTaylor", "NominalTaylorRMS"], ) self.defineRequiredParameter( name = "EpsilonMinimumExponent", default = -8, typecast = int, - message = "Exposant minimal en puissance de 10 pour le multiplicateur d'incrément", + message = "Exposant minimal en puissance de 10 pour le multiplicateur d'incrément", minval = -20, maxval = 0, ) @@ -48,13 +50,13 @@ class ElementaryAlgorithm(BasicObjects.Algorithm): name = "InitialDirection", default = [], typecast = list, - message = "Direction initiale de la dérivée directionnelle autour du point nominal", + message = "Direction initiale de la dérivée directionnelle autour du point nominal", ) self.defineRequiredParameter( name = "AmplitudeOfInitialDirection", default = 1., typecast = float, - message = "Amplitude de la direction initiale de la dérivée directionnelle autour du point nominal", + message = "Amplitude de la direction initiale de la dérivée directionnelle autour du point nominal", ) self.defineRequiredParameter( name = "AmplitudeOfTangentPerturbation", @@ -67,7 +69,7 @@ class ElementaryAlgorithm(BasicObjects.Algorithm): self.defineRequiredParameter( name = "SetSeed", typecast = numpy.random.seed, - message = "Graine fixée pour le générateur aléatoire", + message = "Graine fixée pour le générateur aléatoire", ) self.defineRequiredParameter( name = "ResultTitle", @@ -79,7 +81,7 @@ class ElementaryAlgorithm(BasicObjects.Algorithm): name = "StoreSupplementaryCalculations", default = [], typecast = tuple, - message = "Liste de calculs supplémentaires à stocker et/ou effectuer", + message = "Liste de calculs supplémentaires à stocker et/ou effectuer", listval = ["CurrentState", "Residu", "SimulatedObservationAtCurrentState"] ) @@ -90,7 +92,7 @@ class ElementaryAlgorithm(BasicObjects.Algorithm): import math return math.sqrt( ((numpy.ravel(V2) - numpy.ravel(V1))**2).sum() / float(numpy.ravel(V1).size) ) # - # Opérateurs + # Operateurs # ---------- Hm = HO["Direct"].appliedTo if self._parameters["ResiduFormula"] in ["Taylor", "NominalTaylor", "NominalTaylorRMS"]: @@ -112,8 +114,8 @@ class ElementaryAlgorithm(BasicObjects.Algorithm): if "SimulatedObservationAtCurrentState" in self._parameters["StoreSupplementaryCalculations"]: self.StoredVariables["SimulatedObservationAtCurrentState"].store( numpy.ravel(FX) ) # - # Fabrication de la direction de l'incrément dX - # ---------------------------------------------- + # Fabrication de la direction de l'increment dX + # --------------------------------------------- if len(self._parameters["InitialDirection"]) == 0: dX0 = [] for v in Xn.A1: @@ -126,7 +128,7 @@ class ElementaryAlgorithm(BasicObjects.Algorithm): # dX0 = float(self._parameters["AmplitudeOfInitialDirection"]) * numpy.matrix( dX0 ).T # - # Calcul du gradient au point courant X pour l'incrément dX + # Calcul du gradient au point courant X pour l'increment dX # --------------------------------------------------------- if self._parameters["ResiduFormula"] in ["Taylor", "NominalTaylor", "NominalTaylorRMS"]: dX1 = float(self._parameters["AmplitudeOfTangentPerturbation"]) * dX0 @@ -136,106 +138,107 @@ class ElementaryAlgorithm(BasicObjects.Algorithm): # # Entete des resultats # -------------------- - __marge = 12*" " - __precision = """ + __marge = 12*u" " + __precision = u""" Remarque : les nombres inferieurs a %.0e (environ) representent un zero a la precision machine.\n"""%mpr if self._parameters["ResiduFormula"] == "CenteredDL": - __entete = " i Alpha ||X|| ||F(X)|| | R(Alpha) log10( R ) " - __msgdoc = """ - On observe le résidu provenant de la différence centrée des valeurs de F - au point nominal et aux points perturbés, normalisée par la valeur au + __entete = u" i Alpha ||X|| ||F(X)|| | R(Alpha) log10( R ) " + __msgdoc = u""" + On observe le residu provenant de la difference centree des valeurs de F + au point nominal et aux points perturbes, normalisee par la valeur au point nominal : || F(X+Alpha*dX) + F(X-Alpha*dX) - 2*F(X) || R(Alpha) = -------------------------------------------- || F(X) || - S'il reste constamment trés faible par rapport à 1, l'hypothèse de linéarité - de F est vérifiée. + S'il reste constamment tres faible par rapport a 1, l'hypothese de linearite + de F est verifiee. - Si le résidu varie, ou qu'il est de l'ordre de 1 ou plus, et qu'il n'est - faible qu'à partir d'un certain ordre d'incrément, l'hypothèse de linéarité - de F n'est pas vérifiée. + Si le residu varie, ou qu'il est de l'ordre de 1 ou plus, et qu'il n'est + faible qu'a partir d'un certain ordre d'increment, l'hypothese de linearite + de F n'est pas verifiee. - Si le résidu décroit et que la décroissance se fait en Alpha**2 selon Alpha, - cela signifie que le gradient est calculable jusqu'à la précision d'arrêt - de la décroissance quadratique. + Si le residu decroit et que la decroissance se fait en Alpha**2 selon Alpha, + cela signifie que le gradient est calculable jusqu'a la precision d'arret + de la decroissance quadratique. On prend dX0 = Normal(0,X) et dX = Alpha*dX0. F est le code de calcul. """ + __precision if self._parameters["ResiduFormula"] == "Taylor": - __entete = " i Alpha ||X|| ||F(X)|| | R(Alpha) log10( R ) " - __msgdoc = """ - On observe le résidu issu du développement de Taylor de la fonction F, - normalisée par la valeur au point nominal : + __entete = u" i Alpha ||X|| ||F(X)|| | R(Alpha) log10( R ) " + __msgdoc = u""" + On observe le residu issu du developpement de Taylor de la fonction F, + normalisee par la valeur au point nominal : || F(X+Alpha*dX) - F(X) - Alpha * GradientF_X(dX) || R(Alpha) = ---------------------------------------------------- || F(X) || - S'il reste constamment trés faible par rapport à 1, l'hypothèse de linéarité - de F est vérifiée. + S'il reste constamment tres faible par rapport a 1, l'hypothese de linearite + de F est verifiee. - Si le résidu varie, ou qu'il est de l'ordre de 1 ou plus, et qu'il n'est - faible qu'à partir d'un certain ordre d'incrément, l'hypothèse de linéarité - de F n'est pas vérifiée. + Si le residu varie, ou qu'il est de l'ordre de 1 ou plus, et qu'il n'est + faible qu'a partir d'un certain ordre d'increment, l'hypothese de linearite + de F n'est pas verifiee. - Si le résidu décroit et que la décroissance se fait en Alpha**2 selon Alpha, - cela signifie que le gradient est bien calculé jusqu'à la précision d'arrêt - de la décroissance quadratique. + Si le residu decroit et que la decroissance se fait en Alpha**2 selon Alpha, + cela signifie que le gradient est bien calcule jusqu'a la precision d'arret + de la decroissance quadratique. On prend dX0 = Normal(0,X) et dX = Alpha*dX0. F est le code de calcul. """ + __precision if self._parameters["ResiduFormula"] == "NominalTaylor": - __entete = " i Alpha ||X|| ||F(X)|| | R(Alpha) |R-1| en % " - __msgdoc = """ - On observe le résidu obtenu à partir de deux approximations d'ordre 1 de F(X), - normalisées par la valeur au point nominal : + __entete = u" i Alpha ||X|| ||F(X)|| | R(Alpha) |R-1| en % " + __msgdoc = u""" + On observe le residu obtenu a partir de deux approximations d'ordre 1 de F(X), + normalisees par la valeur au point nominal : R(Alpha) = max( || F(X+Alpha*dX) - Alpha * F(dX) || / || F(X) ||, || F(X-Alpha*dX) + Alpha * F(dX) || / || F(X) ||, ) - S'il reste constamment égal à 1 à moins de 2 ou 3 pourcents prés (c'est-à-dire - que |R-1| reste égal à 2 ou 3 pourcents), c'est que l'hypothèse de linéarité - de F est vérifiée. + S'il reste constamment egal a 1 a moins de 2 ou 3 pourcents pres (c'est-a-dire + que |R-1| reste egal a 2 ou 3 pourcents), c'est que l'hypothese de linearite + de F est verifiee. - S'il est égal à 1 sur une partie seulement du domaine de variation de - l'incrément Alpha, c'est sur cette partie que l'hypothèse de linéarité de F - est vérifiée. + S'il est egal a 1 sur une partie seulement du domaine de variation de + l'increment Alpha, c'est sur cette partie que l'hypothese de linearite de F + est verifiee. On prend dX0 = Normal(0,X) et dX = Alpha*dX0. F est le code de calcul. """ + __precision if self._parameters["ResiduFormula"] == "NominalTaylorRMS": - __entete = " i Alpha ||X|| ||F(X)|| | R(Alpha) |R| en % " - __msgdoc = """ - On observe le résidu obtenu à partir de deux approximations d'ordre 1 de F(X), - normalisées par la valeur au point nominal : + __entete = u" i Alpha ||X|| ||F(X)|| | R(Alpha) |R| en % " + __msgdoc = u""" + On observe le residu obtenu a partir de deux approximations d'ordre 1 de F(X), + normalisees par la valeur au point nominal : R(Alpha) = max( RMS( F(X), F(X+Alpha*dX) - Alpha * F(dX) ) / || F(X) ||, RMS( F(X), F(X-Alpha*dX) + Alpha * F(dX) ) / || F(X) ||, ) - S'il reste constamment égal à 0 à moins de 1 ou 2 pourcents prés, c'est - que l'hypothèse de linéarité de F est vérifiée. + S'il reste constamment egal a 0 a moins de 1 ou 2 pourcents pres, c'est + que l'hypothese de linearite de F est verifiee. - S'il est égal à 0 sur une partie seulement du domaine de variation de - l'incrément Alpha, c'est sur cette partie que l'hypothèse de linéarité de F - est vérifiée. + S'il est egal a 0 sur une partie seulement du domaine de variation de + l'increment Alpha, c'est sur cette partie que l'hypothese de linearite de F + est verifiee. On prend dX0 = Normal(0,X) et dX = Alpha*dX0. F est le code de calcul. """ + __precision # if len(self._parameters["ResultTitle"]) > 0: - msgs = "\n" - msgs += __marge + "====" + "="*len(self._parameters["ResultTitle"]) + "====\n" - msgs += __marge + " " + self._parameters["ResultTitle"] + "\n" - msgs += __marge + "====" + "="*len(self._parameters["ResultTitle"]) + "====\n" + __rt = unicode(self._parameters["ResultTitle"]) + msgs = u"\n" + msgs += __marge + "====" + "="*len(__rt) + "====\n" + msgs += __marge + " " + __rt + "\n" + msgs += __marge + "====" + "="*len(__rt) + "====\n" else: - msgs = "" + msgs = u"" msgs += __msgdoc # __nbtirets = len(__entete) diff --git a/src/daComposant/daAlgorithms/NonLinearLeastSquares.py b/src/daComposant/daAlgorithms/NonLinearLeastSquares.py index 83e2963..a2e4433 100644 --- a/src/daComposant/daAlgorithms/NonLinearLeastSquares.py +++ b/src/daComposant/daAlgorithms/NonLinearLeastSquares.py @@ -1,4 +1,4 @@ -#-*-coding:iso-8859-1-*- +# -*- coding: utf-8 -*- # # Copyright (C) 2008-2017 EDF R&D # @@ -32,7 +32,7 @@ class ElementaryAlgorithm(BasicObjects.Algorithm): name = "Minimizer", default = "LBFGSB", typecast = str, - message = "Minimiseur utilisé", + message = "Minimiseur utilisé", listval = ["LBFGSB","TNC", "CG", "NCG", "BFGS", "LM"], ) self.defineRequiredParameter( @@ -46,32 +46,32 @@ class ElementaryAlgorithm(BasicObjects.Algorithm): name = "CostDecrementTolerance", default = 1.e-7, typecast = float, - message = "Diminution relative minimale du cout lors de l'arrêt", + message = "Diminution relative minimale du cout lors de l'arrêt", ) self.defineRequiredParameter( name = "ProjectedGradientTolerance", default = -1, typecast = float, - message = "Maximum des composantes du gradient projeté lors de l'arrêt", + message = "Maximum des composantes du gradient projeté lors de l'arrêt", minval = -1, ) self.defineRequiredParameter( name = "GradientNormTolerance", default = 1.e-05, typecast = float, - message = "Maximum des composantes du gradient lors de l'arrêt", + message = "Maximum des composantes du gradient lors de l'arrêt", ) self.defineRequiredParameter( name = "StoreInternalVariables", default = False, typecast = bool, - message = "Stockage des variables internes ou intermédiaires du calcul", + message = "Stockage des variables internes ou intermédiaires du calcul", ) self.defineRequiredParameter( name = "StoreSupplementaryCalculations", default = [], typecast = tuple, - message = "Liste de calculs supplémentaires à stocker et/ou effectuer", + message = "Liste de calculs supplémentaires à stocker et/ou effectuer", listval = ["BMA", "OMA", "OMB", "CostFunctionJ", "CostFunctionJb", "CostFunctionJo", "CurrentState", "CurrentOptimum", "IndexOfOptimum", "Innovation", "InnovationAtCurrentState", "CostFunctionJAtCurrentOptimum", "SimulatedObservationAtBackground", "SimulatedObservationAtCurrentState", "SimulatedObservationAtOptimum", "SimulatedObservationAtCurrentOptimum"] ) self.defineRequiredParameter( # Pas de type @@ -86,15 +86,15 @@ class ElementaryAlgorithm(BasicObjects.Algorithm): if "Minimizer" in self._parameters and self._parameters["Minimizer"] == "TNC": self.setParameterValue("StoreInternalVariables",True) # - # Opérateurs + # Opérateurs # ---------- Hm = HO["Direct"].appliedTo Ha = HO["Adjoint"].appliedInXTo # - # Utilisation éventuelle d'un vecteur H(Xb) précalculé + # Utilisation éventuelle d'un vecteur H(Xb) précalculé # ---------------------------------------------------- - if HO["AppliedToX"] is not None and "HXb" in HO["AppliedToX"]: - HXb = Hm( Xb, HO["AppliedToX"]["HXb"]) + if HO["AppliedInX"] is not None and "HXb" in HO["AppliedInX"]: + HXb = Hm( Xb, HO["AppliedInX"]["HXb"]) else: HXb = Hm( Xb ) HXb = numpy.asmatrix(numpy.ravel( HXb )).T @@ -103,13 +103,13 @@ class ElementaryAlgorithm(BasicObjects.Algorithm): if max(Y.shape) != max(HXb.shape): raise ValueError("The shapes %s of observations Y and %s of observed calculation H(X) are different, they have to be identical."%(Y.shape,HXb.shape)) # - # Précalcul des inversions de B et R + # Précalcul des inversions de B et R # ---------------------------------- RI = R.getI() if self._parameters["Minimizer"] == "LM": RdemiI = R.choleskyI() # - # Définition de la fonction-coût + # Définition de la fonction-coût # ------------------------------ def CostFunction(x): _X = numpy.asmatrix(numpy.ravel( x )).T @@ -185,7 +185,7 @@ class ElementaryAlgorithm(BasicObjects.Algorithm): GradJ = numpy.asmatrix( numpy.ravel( GradJb ) + numpy.ravel( GradJo ) ).T return - RdemiI*HO["Tangent"].asMatrix( _X ) # - # Point de démarrage de l'optimisation : Xini = Xb + # Point de démarrage de l'optimisation : Xini = Xb # ------------------------------------ Xini = numpy.ravel(Xb) # @@ -291,7 +291,7 @@ class ElementaryAlgorithm(BasicObjects.Algorithm): HXa = Hm(Xa) # # - # Calculs et/ou stockages supplémentaires + # Calculs et/ou stockages supplémentaires # --------------------------------------- if "Innovation" in self._parameters["StoreSupplementaryCalculations"] or \ "OMB" in self._parameters["StoreSupplementaryCalculations"]: diff --git a/src/daComposant/daAlgorithms/ObserverTest.py b/src/daComposant/daAlgorithms/ObserverTest.py index e08fd68..89e0d5d 100644 --- a/src/daComposant/daAlgorithms/ObserverTest.py +++ b/src/daComposant/daAlgorithms/ObserverTest.py @@ -1,4 +1,4 @@ -#-*-coding:iso-8859-1-*- +# -*- coding: utf-8 -*- # # Copyright (C) 2008-2017 EDF R&D # diff --git a/src/daComposant/daAlgorithms/ParticleSwarmOptimization.py b/src/daComposant/daAlgorithms/ParticleSwarmOptimization.py index aaa289d..e288583 100644 --- a/src/daComposant/daAlgorithms/ParticleSwarmOptimization.py +++ b/src/daComposant/daAlgorithms/ParticleSwarmOptimization.py @@ -1,4 +1,4 @@ -#-*-coding:iso-8859-1-*- +# -*- coding: utf-8 -*- # # Copyright (C) 2008-2017 EDF R&D # @@ -39,13 +39,13 @@ class ElementaryAlgorithm(BasicObjects.Algorithm): name = "MaximumNumberOfFunctionEvaluations", default = 15000, typecast = int, - message = "Nombre maximal d'évaluations de la fonction", + message = "Nombre maximal d'évaluations de la fonction", minval = -1, ) self.defineRequiredParameter( name = "SetSeed", typecast = numpy.random.seed, - message = "Graine fixée pour le générateur aléatoire", + message = "Graine fixée pour le générateur aléatoire", ) self.defineRequiredParameter( name = "NumberOfInsects", @@ -58,7 +58,7 @@ class ElementaryAlgorithm(BasicObjects.Algorithm): name = "SwarmVelocity", default = 1., typecast = float, - message = "Vitesse de groupe imposée par l'essaim", + message = "Vitesse de groupe imposée par l'essaim", minval = 0., ) self.defineRequiredParameter( @@ -73,7 +73,7 @@ class ElementaryAlgorithm(BasicObjects.Algorithm): name = "QualityCriterion", default = "AugmentedWeightedLeastSquares", typecast = str, - message = "Critère de qualité utilisé", + message = "Critère de qualité utilisé", listval = ["AugmentedWeightedLeastSquares","AWLS","AugmentedPonderatedLeastSquares","APLS","DA", "WeightedLeastSquares","WLS","PonderatedLeastSquares","PLS", "LeastSquares","LS","L2", @@ -84,26 +84,26 @@ class ElementaryAlgorithm(BasicObjects.Algorithm): name = "StoreInternalVariables", default = False, typecast = bool, - message = "Stockage des variables internes ou intermédiaires du calcul", + message = "Stockage des variables internes ou intermédiaires du calcul", ) self.defineRequiredParameter( name = "StoreSupplementaryCalculations", default = [], typecast = tuple, - message = "Liste de calculs supplémentaires à stocker et/ou effectuer", + message = "Liste de calculs supplémentaires à stocker et/ou effectuer", listval = ["BMA", "OMA", "OMB", "CurrentState", "CostFunctionJ", "CostFunctionJb", "CostFunctionJo", "Innovation", "SimulatedObservationAtBackground", "SimulatedObservationAtCurrentState", "SimulatedObservationAtOptimum"] ) self.defineRequiredParameter( # Pas de type name = "BoxBounds", - message = "Liste des valeurs de bornes d'incréments de paramètres", + message = "Liste des valeurs de bornes d'incréments de paramètres", ) def run(self, Xb=None, Y=None, U=None, HO=None, EM=None, CM=None, R=None, B=None, Q=None, Parameters=None): self._pre_run(Parameters) # - if "BoxBounds" in self._parameters and (type(self._parameters["BoxBounds"]) is type([]) or type(self._parameters["BoxBounds"]) is type(())) and (len(self._parameters["BoxBounds"]) > 0): + if ("BoxBounds" in self._parameters) and isinstance(self._parameters["BoxBounds"], (list, tuple)) and (len(self._parameters["BoxBounds"]) > 0): BoxBounds = self._parameters["BoxBounds"] - logging.debug("%s Prise en compte des bornes d'incréments de paramètres effectuee"%(self._name,)) + logging.debug("%s Prise en compte des bornes d'incréments de paramètres effectuee"%(self._name,)) else: raise ValueError("Particle Swarm Optimization requires bounds on all variables to be given.") BoxBounds = numpy.array(BoxBounds) @@ -112,18 +112,18 @@ class ElementaryAlgorithm(BasicObjects.Algorithm): # Phig = float( self._parameters["GroupRecallRate"] ) Phip = 1. - Phig - logging.debug("%s Taux de rappel au meilleur insecte du groupe (entre 0 et 1) = %s et à la meilleure position précédente (son complémentaire à 1) = %s"%(self._name, str(Phig), str(Phip))) + logging.debug("%s Taux de rappel au meilleur insecte du groupe (entre 0 et 1) = %s et à la meilleure position précédente (son complémentaire à 1) = %s"%(self._name, str(Phig), str(Phip))) # - # Opérateur d'observation + # Opérateur d'observation # ----------------------- Hm = HO["Direct"].appliedTo # - # Précalcul des inversions de B et R + # Précalcul des inversions de B et R # ---------------------------------- BI = B.getI() RI = R.getI() # - # Définition de la fonction-coût + # Définition de la fonction-coût # ------------------------------ def CostFunction(x, QualityMeasure="AugmentedWeightedLeastSquares"): _X = numpy.asmatrix(numpy.ravel( x )).T @@ -154,9 +154,9 @@ class ElementaryAlgorithm(BasicObjects.Algorithm): # return J # - # Point de démarrage de l'optimisation : Xini = Xb + # Point de démarrage de l'optimisation : Xini = Xb # ------------------------------------ - if type(Xb) is type(numpy.matrix([])): + if isinstance(Xb, type(numpy.matrix([]))): Xini = Xb.A1.tolist() elif Xb is not None: Xini = list(Xb) @@ -196,7 +196,7 @@ class ElementaryAlgorithm(BasicObjects.Algorithm): if quality < qBest: Best = copy.copy( insect ) qBest = copy.copy( quality ) - logging.debug("%s Initialisation, Insecte = %s, Qualité = %s"%(self._name, str(Best), str(qBest))) + logging.debug("%s Initialisation, Insecte = %s, Qualité = %s"%(self._name, str(Best), str(qBest))) # if self._parameters["StoreInternalVariables"] or "CurrentState" in self._parameters["StoreSupplementaryCalculations"]: self.StoredVariables["CurrentState"].store( Best ) @@ -222,7 +222,7 @@ class ElementaryAlgorithm(BasicObjects.Algorithm): if quality < qBest : Best = copy.copy( insect ) qBest = copy.copy( quality ) - logging.debug("%s Etape %i, Insecte = %s, Qualité = %s"%(self._name, n, str(Best), str(qBest))) + logging.debug("%s Etape %i, Insecte = %s, Qualité = %s"%(self._name, n, str(Best), str(qBest))) # if self._parameters["StoreInternalVariables"] or "CurrentState" in self._parameters["StoreSupplementaryCalculations"]: self.StoredVariables["CurrentState"].store( Best ) @@ -252,7 +252,7 @@ class ElementaryAlgorithm(BasicObjects.Algorithm): "SimulatedObservationAtOptimum" in self._parameters["StoreSupplementaryCalculations"]: HXa = Hm(Xa) # - # Calculs et/ou stockages supplémentaires + # Calculs et/ou stockages supplémentaires # --------------------------------------- if "Innovation" in self._parameters["StoreSupplementaryCalculations"]: self.StoredVariables["Innovation"].store( numpy.ravel(d) ) diff --git a/src/daComposant/daAlgorithms/QuantileRegression.py b/src/daComposant/daAlgorithms/QuantileRegression.py index 3d95d36..b971f07 100644 --- a/src/daComposant/daAlgorithms/QuantileRegression.py +++ b/src/daComposant/daAlgorithms/QuantileRegression.py @@ -1,4 +1,4 @@ -#-*-coding:iso-8859-1-*- +# -*- coding: utf-8 -*- # # Copyright (C) 2008-2017 EDF R&D # @@ -40,7 +40,7 @@ class ElementaryAlgorithm(BasicObjects.Algorithm): name = "Minimizer", default = "MMQR", typecast = str, - message = "Minimiseur utilisé", + message = "Minimiseur utilisé", listval = ["MMQR"], ) self.defineRequiredParameter( @@ -54,19 +54,19 @@ class ElementaryAlgorithm(BasicObjects.Algorithm): name = "CostDecrementTolerance", default = 1.e-6, typecast = float, - message = "Maximum de variation de la fonction d'estimation lors de l'arrêt", + message = "Maximum de variation de la fonction d'estimation lors de l'arrêt", ) self.defineRequiredParameter( name = "StoreInternalVariables", default = False, typecast = bool, - message = "Stockage des variables internes ou intermédiaires du calcul", + message = "Stockage des variables internes ou intermédiaires du calcul", ) self.defineRequiredParameter( name = "StoreSupplementaryCalculations", default = [], typecast = tuple, - message = "Liste de calculs supplémentaires à stocker et/ou effectuer", + message = "Liste de calculs supplémentaires à stocker et/ou effectuer", listval = ["BMA", "OMA", "OMB", "CurrentState", "CostFunctionJ", "CostFunctionJb", "CostFunctionJo", "Innovation", "SimulatedObservationAtBackground", "SimulatedObservationAtCurrentState", "SimulatedObservationAtOptimum"] ) self.defineRequiredParameter( # Pas de type @@ -79,10 +79,10 @@ class ElementaryAlgorithm(BasicObjects.Algorithm): # Hm = HO["Direct"].appliedTo # - # Utilisation éventuelle d'un vecteur H(Xb) précalculé + # Utilisation éventuelle d'un vecteur H(Xb) précalculé # ---------------------------------------------------- - if HO["AppliedToX"] is not None and "HXb" in HO["AppliedToX"]: - HXb = Hm( Xb, HO["AppliedToX"]["HXb"]) + if HO["AppliedInX"] is not None and "HXb" in HO["AppliedInX"]: + HXb = Hm( Xb, HO["AppliedInX"]["HXb"]) else: HXb = Hm( Xb ) HXb = numpy.asmatrix(numpy.ravel( HXb )).T @@ -95,7 +95,7 @@ class ElementaryAlgorithm(BasicObjects.Algorithm): raise ValueError("The shapes %s of observations Y and %s of observed calculation H(X) are different, they have to be identical."%(Y.shape,HXb.shape)) d = Y - HXb # - # Définition de la fonction-coût + # Définition de la fonction-coût # ------------------------------ def CostFunction(x): _X = numpy.asmatrix(numpy.ravel( x )).T @@ -118,9 +118,9 @@ class ElementaryAlgorithm(BasicObjects.Algorithm): Hg = HO["Tangent"].asMatrix( _X ) return Hg # - # Point de démarrage de l'optimisation : Xini = Xb + # Point de démarrage de l'optimisation : Xini = Xb # ------------------------------------ - if type(Xb) is type(numpy.matrix([])): + if isinstance(Xb, type(numpy.matrix([]))): Xini = Xb.A1.tolist() else: Xini = list(Xb) @@ -154,7 +154,7 @@ class ElementaryAlgorithm(BasicObjects.Algorithm): "SimulatedObservationAtOptimum" in self._parameters["StoreSupplementaryCalculations"]: HXa = Hm(Xa) # - # Calculs et/ou stockages supplémentaires + # Calculs et/ou stockages supplémentaires # --------------------------------------- if "Innovation" in self._parameters["StoreSupplementaryCalculations"]: self.StoredVariables["Innovation"].store( numpy.ravel(d) ) diff --git a/src/daComposant/daAlgorithms/SamplingTest.py b/src/daComposant/daAlgorithms/SamplingTest.py index 77d08af..1d60f73 100644 --- a/src/daComposant/daAlgorithms/SamplingTest.py +++ b/src/daComposant/daAlgorithms/SamplingTest.py @@ -1,4 +1,4 @@ -#-*-coding:iso-8859-1-*- +# -*- coding: utf-8 -*- # # Copyright (C) 2008-2017 EDF R&D # @@ -32,31 +32,31 @@ class ElementaryAlgorithm(BasicObjects.Algorithm): name = "SampleAsnUplet", default = [], typecast = tuple, - message = "Points de calcul définis par une liste de n-uplet", + message = "Points de calcul définis par une liste de n-uplet", ) self.defineRequiredParameter( name = "SampleAsExplicitHyperCube", default = [], typecast = tuple, - message = "Points de calcul définis par un hyper-cube dont on donne la liste des échantillonages de chaque variable comme une liste", + message = "Points de calcul définis par un hyper-cube dont on donne la liste des échantillonages de chaque variable comme une liste", ) self.defineRequiredParameter( name = "SampleAsMinMaxStepHyperCube", default = [], typecast = tuple, - message = "Points de calcul définis par un hyper-cube dont on donne la liste des échantillonages de chaque variable par un triplet [min,max,step]", + message = "Points de calcul définis par un hyper-cube dont on donne la liste des échantillonages de chaque variable par un triplet [min,max,step]", ) self.defineRequiredParameter( name = "SampleAsIndependantRandomVariables", default = [], typecast = tuple, - message = "Points de calcul définis par un hyper-cube dont les points sur chaque axe proviennent de l'échantillonage indépendant de la variable selon la spécification ['distribution',[parametres],nombre]", + message = "Points de calcul définis par un hyper-cube dont les points sur chaque axe proviennent de l'échantillonage indépendant de la variable selon la spécification ['distribution',[parametres],nombre]", ) self.defineRequiredParameter( name = "QualityCriterion", default = "AugmentedWeightedLeastSquares", typecast = str, - message = "Critère de qualité utilisé", + message = "Critère de qualité utilisé", listval = ["AugmentedWeightedLeastSquares","AWLS","AugmentedPonderatedLeastSquares","APLS","DA", "WeightedLeastSquares","WLS","PonderatedLeastSquares","PLS", "LeastSquares","LS","L2", @@ -67,19 +67,19 @@ class ElementaryAlgorithm(BasicObjects.Algorithm): name = "SetDebug", default = False, typecast = bool, - message = "Activation du mode debug lors de l'exécution", + message = "Activation du mode debug lors de l'exécution", ) self.defineRequiredParameter( name = "StoreSupplementaryCalculations", default = [], typecast = tuple, - message = "Liste de calculs supplémentaires à stocker et/ou effectuer", + message = "Liste de calculs supplémentaires à stocker et/ou effectuer", listval = ["CostFunctionJ", "CostFunctionJb", "CostFunctionJo","CurrentState","InnovationAtCurrentState","SimulatedObservationAtCurrentState"] ) self.defineRequiredParameter( name = "SetSeed", typecast = numpy.random.seed, - message = "Graine fixée pour le générateur aléatoire", + message = "Graine fixée pour le générateur aléatoire", ) def run(self, Xb=None, Y=None, U=None, HO=None, EM=None, CM=None, R=None, B=None, Q=None, Parameters=None): diff --git a/src/daComposant/daAlgorithms/TabuSearch.py b/src/daComposant/daAlgorithms/TabuSearch.py index 415800d..76e42b4 100644 --- a/src/daComposant/daAlgorithms/TabuSearch.py +++ b/src/daComposant/daAlgorithms/TabuSearch.py @@ -1,4 +1,4 @@ -#-*-coding:iso-8859-1-*- +# -*- coding: utf-8 -*- # # Copyright (C) 2008-2017 EDF R&D # @@ -38,7 +38,7 @@ class ElementaryAlgorithm(BasicObjects.Algorithm): self.defineRequiredParameter( name = "SetSeed", typecast = numpy.random.seed, - message = "Graine fixée pour le générateur aléatoire", + message = "Graine fixée pour le générateur aléatoire", ) self.defineRequiredParameter( name = "LengthOfTabuList", @@ -51,21 +51,21 @@ class ElementaryAlgorithm(BasicObjects.Algorithm): name = "NumberOfElementaryPerturbations", default = 1, typecast = int, - message = "Nombre de perturbations élémentaires pour choisir une perturbation d'état", + message = "Nombre de perturbations élémentaires pour choisir une perturbation d'état", minval = 1, ) self.defineRequiredParameter( name = "NoiseDistribution", default = "Uniform", typecast = str, - message = "Distribution pour générer les perturbations d'état", + message = "Distribution pour générer les perturbations d'état", listval = ["Gaussian","Uniform"], ) self.defineRequiredParameter( name = "QualityCriterion", default = "AugmentedWeightedLeastSquares", typecast = str, - message = "Critère de qualité utilisé", + message = "Critère de qualité utilisé", listval = ["AugmentedWeightedLeastSquares","AWLS","DA", "WeightedLeastSquares","WLS", "LeastSquares","LS","L2", @@ -76,19 +76,19 @@ class ElementaryAlgorithm(BasicObjects.Algorithm): name = "NoiseHalfRange", default = [], typecast = numpy.matrix, - message = "Demi-amplitude des perturbations uniformes centrées d'état pour chaque composante de l'état", + message = "Demi-amplitude des perturbations uniformes centrées d'état pour chaque composante de l'état", ) self.defineRequiredParameter( name = "StandardDeviation", default = [], typecast = numpy.matrix, - message = "Ecart-type des perturbations gaussiennes d'état pour chaque composante de l'état", + message = "Ecart-type des perturbations gaussiennes d'état pour chaque composante de l'état", ) self.defineRequiredParameter( name = "NoiseAddingProbability", default = 1., typecast = float, - message = "Probabilité de perturbation d'une composante de l'état", + message = "Probabilité de perturbation d'une composante de l'état", minval = 0., maxval = 1., ) @@ -96,13 +96,13 @@ class ElementaryAlgorithm(BasicObjects.Algorithm): name = "StoreInternalVariables", default = False, typecast = bool, - message = "Stockage des variables internes ou intermédiaires du calcul", + message = "Stockage des variables internes ou intermédiaires du calcul", ) self.defineRequiredParameter( name = "StoreSupplementaryCalculations", default = [], typecast = tuple, - message = "Liste de calculs supplémentaires à stocker et/ou effectuer", + message = "Liste de calculs supplémentaires à stocker et/ou effectuer", listval = ["BMA", "OMA", "OMB", "CurrentState", "CostFunctionJ", "CostFunctionJb", "CostFunctionJo", "Innovation", "SimulatedObservationAtBackground", "SimulatedObservationAtCurrentState", "SimulatedObservationAtOptimum"] ) self.defineRequiredParameter( # Pas de type @@ -122,16 +122,16 @@ class ElementaryAlgorithm(BasicObjects.Algorithm): if sigma.size != Xb.size: raise ValueError("Noise generation by Gaussian distribution requires standard deviation for all variable increments. The actual standard deviation vector is:\n%s"%sigma) # - # Opérateur d'observation + # Opérateur d'observation # ----------------------- Hm = HO["Direct"].appliedTo # - # Précalcul des inversions de B et R + # Précalcul des inversions de B et R # ---------------------------------- BI = B.getI() RI = R.getI() # - # Définition de la fonction de deplacement + # Définition de la fonction de deplacement # ---------------------------------------- def Tweak( x, NoiseDistribution, NoiseAddingProbability ): _X = numpy.matrix(numpy.ravel( x )).T @@ -139,13 +139,13 @@ class ElementaryAlgorithm(BasicObjects.Algorithm): for i in range(_X.size): if NoiseAddingProbability >= numpy.random.uniform(): _increment = numpy.random.uniform(low=-nrange[i], high=nrange[i]) - # On ne traite pas encore le dépassement des bornes ici + # On ne traite pas encore le dépassement des bornes ici _X[i] += _increment elif NoiseDistribution == "Gaussian": for i in range(_X.size): if NoiseAddingProbability >= numpy.random.uniform(): _increment = numpy.random.normal(loc=0., scale=sigma[i]) - # On ne traite pas encore le dépassement des bornes ici + # On ne traite pas encore le dépassement des bornes ici _X[i] += _increment # return _X @@ -199,7 +199,7 @@ class ElementaryAlgorithm(BasicObjects.Algorithm): ) for nbt in range(self._parameters["NumberOfElementaryPerturbations"]-1): _W = Tweak( _S, self._parameters["NoiseDistribution"], self._parameters["NoiseAddingProbability"] ) - # _qualityW = CostFunction( _W, self._parameters["QualityCriterion"] ) + # _qualityW = CostFunction( _W, self._parameters["QualityCriterion"] ) _qualityW = BasicObjects.CostFunction3D( _W, _Hm = Hm, @@ -245,7 +245,7 @@ class ElementaryAlgorithm(BasicObjects.Algorithm): "SimulatedObservationAtOptimum" in self._parameters["StoreSupplementaryCalculations"]: HXa = Hm(Xa) # - # Calculs et/ou stockages supplémentaires + # Calculs et/ou stockages supplémentaires # --------------------------------------- if "Innovation" in self._parameters["StoreSupplementaryCalculations"]: self.StoredVariables["Innovation"].store( numpy.ravel(d) ) diff --git a/src/daComposant/daAlgorithms/TangentTest.py b/src/daComposant/daAlgorithms/TangentTest.py index ca81ee5..cb01499 100644 --- a/src/daComposant/daAlgorithms/TangentTest.py +++ b/src/daComposant/daAlgorithms/TangentTest.py @@ -1,4 +1,4 @@ -#-*-coding:iso-8859-1-*- +# -*- coding: utf-8 -*- # # Copyright (C) 2008-2017 EDF R&D # @@ -20,10 +20,12 @@ # # Author: Jean-Philippe Argaud, jean-philippe.argaud@edf.fr, EDF R&D -import logging +import sys, logging from daCore import BasicObjects, PlatformInfo import numpy, math mpr = PlatformInfo.PlatformInfo().MachinePrecision() +if sys.version_info.major > 2: + unicode = str # ============================================================================== class ElementaryAlgorithm(BasicObjects.Algorithm): @@ -33,14 +35,14 @@ class ElementaryAlgorithm(BasicObjects.Algorithm): name = "ResiduFormula", default = "Taylor", typecast = str, - message = "Formule de résidu utilisée", + message = "Formule de résidu utilisée", listval = ["Taylor"], ) self.defineRequiredParameter( name = "EpsilonMinimumExponent", default = -8, typecast = int, - message = "Exposant minimal en puissance de 10 pour le multiplicateur d'incrément", + message = "Exposant minimal en puissance de 10 pour le multiplicateur d'incrément", minval = -20, maxval = 0, ) @@ -48,13 +50,13 @@ class ElementaryAlgorithm(BasicObjects.Algorithm): name = "InitialDirection", default = [], typecast = list, - message = "Direction initiale de la dérivée directionnelle autour du point nominal", + message = "Direction initiale de la dérivée directionnelle autour du point nominal", ) self.defineRequiredParameter( name = "AmplitudeOfInitialDirection", default = 1., typecast = float, - message = "Amplitude de la direction initiale de la dérivée directionnelle autour du point nominal", + message = "Amplitude de la direction initiale de la dérivée directionnelle autour du point nominal", ) self.defineRequiredParameter( name = "AmplitudeOfTangentPerturbation", @@ -67,7 +69,7 @@ class ElementaryAlgorithm(BasicObjects.Algorithm): self.defineRequiredParameter( name = "SetSeed", typecast = numpy.random.seed, - message = "Graine fixée pour le générateur aléatoire", + message = "Graine fixée pour le générateur aléatoire", ) self.defineRequiredParameter( name = "ResultTitle", @@ -79,7 +81,7 @@ class ElementaryAlgorithm(BasicObjects.Algorithm): name = "StoreSupplementaryCalculations", default = [], typecast = tuple, - message = "Liste de calculs supplémentaires à stocker et/ou effectuer", + message = "Liste de calculs supplémentaires à stocker et/ou effectuer", listval = ["CurrentState", "Residu", "SimulatedObservationAtCurrentState"] ) @@ -105,8 +107,8 @@ class ElementaryAlgorithm(BasicObjects.Algorithm): if "SimulatedObservationAtCurrentState" in self._parameters["StoreSupplementaryCalculations"]: self.StoredVariables["SimulatedObservationAtCurrentState"].store( numpy.ravel(FX) ) # - # Fabrication de la direction de l'incrément dX - # ---------------------------------------------- + # Fabrication de la direction de l'increment dX + # --------------------------------------------- if len(self._parameters["InitialDirection"]) == 0: dX0 = [] for v in Xn.A1: @@ -119,8 +121,8 @@ class ElementaryAlgorithm(BasicObjects.Algorithm): # dX0 = float(self._parameters["AmplitudeOfInitialDirection"]) * numpy.matrix( dX0 ).T # - # Calcul du gradient au point courant X pour l'incrément dX - # qui est le tangent en X multiplié par dX + # Calcul du gradient au point courant X pour l'increment dX + # qui est le tangent en X multiplie par dX # --------------------------------------------------------- dX1 = float(self._parameters["AmplitudeOfTangentPerturbation"]) * dX0 GradFxdX = Ht( (Xn, dX1) ) @@ -130,41 +132,42 @@ class ElementaryAlgorithm(BasicObjects.Algorithm): # # Entete des resultats # -------------------- - __marge = 12*" " - __precision = """ + __marge = 12*u" " + __precision = u""" Remarque : les nombres inferieurs a %.0e (environ) representent un zero a la precision machine.\n"""%mpr if self._parameters["ResiduFormula"] == "Taylor": - __entete = " i Alpha ||X|| ||F(X)|| | R(Alpha) |R-1|/Alpha " - __msgdoc = """ - On observe le résidu provenant du rapport d'incréments utilisant le - linéaire tangent : + __entete = u" i Alpha ||X|| ||F(X)|| | R(Alpha) |R-1|/Alpha " + __msgdoc = u""" + On observe le residu provenant du rapport d'increments utilisant le + lineaire tangent : || F(X+Alpha*dX) - F(X) || R(Alpha) = ----------------------------- || Alpha * TangentF_X * dX || - qui doit rester stable en 1+O(Alpha) jusqu'à ce que l'on atteigne la - précision du calcul. - - Lorsque |R-1|/Alpha est inférieur ou égal à une valeur stable - lorsque Alpha varie, le tangent est valide, jusqu'à ce que l'on - atteigne la précision du calcul. - - Si |R-1|/Alpha est très faible, le code F est vraisemblablement - linéaire ou quasi-linéaire, et le tangent est valide jusqu'à ce que - l'on atteigne la précision du calcul. + qui doit rester stable en 1+O(Alpha) jusqu'a ce que l'on atteigne la + precision du calcul. + + Lorsque |R-1|/Alpha est inferieur ou egal a une valeur stable + lorsque Alpha varie, le tangent est valide, jusqu'a ce que l'on + atteigne la precision du calcul. + + Si |R-1|/Alpha est tres faible, le code F est vraisemblablement + lineaire ou quasi-lineaire, et le tangent est valide jusqu'a ce que + l'on atteigne la precision du calcul. On prend dX0 = Normal(0,X) et dX = Alpha*dX0. F est le code de calcul. """ + __precision # if len(self._parameters["ResultTitle"]) > 0: - msgs = "\n" - msgs += __marge + "====" + "="*len(self._parameters["ResultTitle"]) + "====\n" - msgs += __marge + " " + self._parameters["ResultTitle"] + "\n" - msgs += __marge + "====" + "="*len(self._parameters["ResultTitle"]) + "====\n" + __rt = unicode(self._parameters["ResultTitle"]) + msgs = u"\n" + msgs += __marge + "====" + "="*len(__rt) + "====\n" + msgs += __marge + " " + __rt + "\n" + msgs += __marge + "====" + "="*len(__rt) + "====\n" else: - msgs = "" + msgs = u"" msgs += __msgdoc # __nbtirets = len(__entete) diff --git a/src/daComposant/daAlgorithms/UnscentedKalmanFilter.py b/src/daComposant/daAlgorithms/UnscentedKalmanFilter.py index b084610..c04fd1d 100644 --- a/src/daComposant/daAlgorithms/UnscentedKalmanFilter.py +++ b/src/daComposant/daAlgorithms/UnscentedKalmanFilter.py @@ -1,4 +1,4 @@ -#-*-coding:iso-8859-1-*- +# -*- coding: utf-8 -*- # # Copyright (C) 2008-2017 EDF R&D # @@ -75,13 +75,13 @@ class ElementaryAlgorithm(BasicObjects.Algorithm): name = "StoreInternalVariables", default = False, typecast = bool, - message = "Stockage des variables internes ou intermédiaires du calcul", + message = "Stockage des variables internes ou intermédiaires du calcul", ) self.defineRequiredParameter( name = "StoreSupplementaryCalculations", default = [], typecast = tuple, - message = "Liste de calculs supplémentaires à stocker et/ou effectuer", + message = "Liste de calculs supplémentaires à stocker et/ou effectuer", listval = ["APosterioriCorrelations", "APosterioriCovariance", "APosterioriStandardDeviations", "APosterioriVariances", "BMA", "CurrentState", "CostFunctionJ", "CostFunctionJb", "CostFunctionJo", "Innovation"] ) self.defineRequiredParameter( # Pas de type @@ -118,7 +118,7 @@ class ElementaryAlgorithm(BasicObjects.Algorithm): Wc = numpy.array( Ww ) Wc[0] = Lambda / (L + Lambda) + (1. - Alpha**2 + Beta) # - # Opérateurs + # Opérateurs # ---------- if B is None: raise ValueError("Background error covariance matrix has to be properly defined!") @@ -142,7 +142,7 @@ class ElementaryAlgorithm(BasicObjects.Algorithm): else: duration = 2 # - # Précalcul des inversions de B et R + # Précalcul des inversions de B et R # ---------------------------------- if self._parameters["StoreInternalVariables"]: BI = B.getI() diff --git a/src/daComposant/daAlgorithms/__init__.py b/src/daComposant/daAlgorithms/__init__.py index 492aad4..53248cc 100644 --- a/src/daComposant/daAlgorithms/__init__.py +++ b/src/daComposant/daAlgorithms/__init__.py @@ -1,4 +1,4 @@ -#-*-coding:iso-8859-1-*- +# -*- coding: utf-8 -*- # # Copyright (C) 2008-2017 EDF R&D # diff --git a/src/daComposant/daCore/Aidsm.py b/src/daComposant/daCore/Aidsm.py new file mode 100644 index 0000000..ebdb85b --- /dev/null +++ b/src/daComposant/daCore/Aidsm.py @@ -0,0 +1,996 @@ +# -*- coding: utf-8 -*- +# +# Copyright (C) 2008-2017 EDF R&D +# +# This library is free software; you can redistribute it and/or +# modify it under the terms of the GNU Lesser General Public +# License as published by the Free Software Foundation; either +# version 2.1 of the License. +# +# This library is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +# Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public +# License along with this library; if not, write to the Free Software +# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +# +# See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com +# +# Author: Jean-Philippe Argaud, jean-philippe.argaud@edf.fr, EDF R&D + +""" + Normalized interface for ADAO scripting (generic API) +""" +__author__ = "Jean-Philippe ARGAUD" +__all__ = ["Aidsm"] + +import os, sys +from daCore import ExtendedLogging ; ExtendedLogging.ExtendedLogging() # A importer en premier +import logging +# +from daCore.BasicObjects import State, Covariance, FullOperator, Operator +from daCore.BasicObjects import AlgorithmAndParameters, DataObserver +from daCore.BasicObjects import DiagnosticAndParameters, ImportFromScript +from daCore.Templates import ObserverTemplates +from daCore import PlatformInfo + +# ============================================================================== +class Aidsm(object): + """ ADAO Internal Data Structure Model """ + def __init__(self, name = ""): + self.__name = str(name) + self.__case = _CaseLogger(self.__name) + # + self.__adaoObject = {} + self.__StoredInputs = {} + # + self.__Concepts = [ + "AlgorithmParameters", + "Background", + "CheckingPoint", + "ControlInput", + "Observation", + "Controls", + "BackgroundError", + "ObservationError", + "EvolutionError", + "ObservationOperator", + "EvolutionModel", + "ControlModel", + "Debug", + "NoDebug", + "Observer", + ] + # + for ename in self.__Concepts: + self.__adaoObject[ename] = None + for ename in ("ObservationOperator", "EvolutionModel", "ControlModel", "Observer"): + self.__adaoObject[ename] = {} + for ename in ("Diagnostic", "Observer"): + self.__adaoObject[ename] = [] + self.__StoredInputs[ename] = [] + # + # Récupère le chemin du répertoire parent et l'ajoute au path + # (Cela complète l'action de la classe PathManagement dans PlatformInfo, + # qui est activée dans Persistence) + self.__parent = os.path.abspath(os.path.join(os.path.dirname(__file__),"..")) + sys.path.insert(0, self.__parent) + sys.path = PlatformInfo.uniq( sys.path ) # Conserve en unique exemplaire chaque chemin + + def set(self, + Concept = None, # Premier argument + Algorithm = None, + AppliedInXb = None, + AvoidRC = True, + BaseType = None, + Checked = False, + Diagnostic = None, + DiagonalSparseMatrix = None, + Identifier = None, + Info = None, + Matrix = None, + ObjectFunction = None, + ObjectMatrix = None, + OneFunction = None, + Parameters = None, + ScalarSparseMatrix = None, + Scheduler = None, + Script = None, + Stored = False, + String = None, + Template = None, + ThreeFunctions = None, + Unit = None, + Variable = None, + Vector = None, + VectorSerie = None, + ): + "Interface unique de definition de variables d'entrees par argument" + self.__case.register("set",dir(),locals(),None,True) + try: + if Concept in ("Background", "CheckingPoint", "ControlInput", "Observation", "Controls"): + commande = getattr(self,"set"+Concept) + commande(Vector, VectorSerie, Script, Scheduler, Stored, Checked ) + elif Concept in ("BackgroundError", "ObservationError", "EvolutionError"): + commande = getattr(self,"set"+Concept) + commande(Matrix, ScalarSparseMatrix, DiagonalSparseMatrix, + ObjectMatrix, Script, Stored, Checked ) + elif Concept == "AlgorithmParameters": + self.setAlgorithmParameters( Algorithm, Parameters, Script ) + elif Concept == "Debug": + self.setDebug() + elif Concept == "NoDebug": + self.setNoDebug() + elif Concept == "Observer": + self.setObserver( Variable, Template, String, Script, ObjectFunction, Scheduler, Info ) + elif Concept == "Diagnostic": + self.setDiagnostic( Diagnostic, Identifier, Parameters, Script, Unit, BaseType ) + elif Concept == "ObservationOperator": + self.setObservationOperator( + Matrix, OneFunction, ThreeFunctions, AppliedInXb, + Parameters, Script, AvoidRC, Stored, Checked ) + elif Concept in ("EvolutionModel", "ControlModel"): + commande = getattr(self,"set"+Concept) + commande( + Matrix, OneFunction, ThreeFunctions, + Parameters, Script, Scheduler, AvoidRC, Stored, Checked ) + + else: + raise ValueError("the variable named '%s' is not allowed."%str(Concept)) + except Exception as e: + if isinstance(e, SyntaxError): msg = "at %s: %s"%(e.offset, e.text) + else: msg = "" + raise ValueError("during settings, the following error occurs:\n\n%s %s\n\nSee also the potential messages, which can show the origin of the above error, in the launching terminal."%(str(e),msg)) + + # ----------------------------------------------------------- + + def setBackground(self, + Vector = None, + VectorSerie = None, + Script = None, + Scheduler = None, + Stored = False, + Checked = False): + "Definition d'un concept de calcul" + Concept = "Background" + self.__case.register("set"+Concept, dir(), locals()) + self.__adaoObject[Concept] = State( + name = Concept, + asVector = Vector, + asPersistentVector = VectorSerie, + asScript = Script, + scheduledBy = Scheduler, + toBeChecked = Checked, + ) + if Stored: + self.__StoredInputs[Concept] = self.__adaoObject[Concept].getO() + return 0 + + def setCheckingPoint(self, + Vector = None, + VectorSerie = None, + Script = None, + Scheduler = None, + Stored = False, + Checked = False): + "Definition d'un concept de calcul" + Concept = "CheckingPoint" + self.__case.register("set"+Concept, dir(), locals()) + self.__adaoObject[Concept] = State( + name = Concept, + asVector = Vector, + asPersistentVector = VectorSerie, + asScript = Script, + scheduledBy = Scheduler, + toBeChecked = Checked, + ) + if Stored: + self.__StoredInputs[Concept] = self.__adaoObject[Concept].getO() + return 0 + + def setControlInput(self, + Vector = None, + VectorSerie = None, + Script = None, + Scheduler = None, + Stored = False, + Checked = False): + "Definition d'un concept de calcul" + Concept = "ControlInput" + self.__case.register("set"+Concept, dir(), locals()) + self.__adaoObject[Concept] = State( + name = Concept, + asVector = Vector, + asPersistentVector = VectorSerie, + asScript = Script, + scheduledBy = Scheduler, + toBeChecked = Checked, + ) + if Stored: + self.__StoredInputs[Concept] = self.__adaoObject[Concept].getO() + return 0 + + def setObservation(self, + Vector = None, + VectorSerie = None, + Script = None, + Scheduler = None, + Stored = False, + Checked = False): + "Definition d'un concept de calcul" + Concept = "Observation" + self.__case.register("set"+Concept, dir(), locals()) + self.__adaoObject[Concept] = State( + name = Concept, + asVector = Vector, + asPersistentVector = VectorSerie, + asScript = Script, + scheduledBy = Scheduler, + toBeChecked = Checked, + ) + if Stored: + self.__StoredInputs[Concept] = self.__adaoObject[Concept].getO() + return 0 + + def setControls(self, + Vector = (), # Valeur par defaut pour un vecteur vide + VectorSerie = None, + Script = None, + Scheduler = None, + Stored = False, + Checked = False): + "Definition d'un concept de calcul" + Concept = "Controls" + self.__case.register("set"+Concept, dir(), locals()) + self.__adaoObject[Concept] = State( + name = Concept, + asVector = Vector, + asPersistentVector = VectorSerie, + asScript = Script, + scheduledBy = Scheduler, + toBeChecked = Checked, + ) + if Stored: + self.__StoredInputs[Concept] = self.__adaoObject[Concept].getO() + return 0 + + def setBackgroundError(self, + Matrix = None, + ScalarSparseMatrix = None, + DiagonalSparseMatrix = None, + ObjectMatrix = None, + Script = None, + Stored = False, + Checked = False): + "Definition d'un concept de calcul" + Concept = "BackgroundError" + self.__case.register("set"+Concept, dir(), locals()) + self.__adaoObject[Concept] = Covariance( + name = Concept, + asCovariance = Matrix, + asEyeByScalar = ScalarSparseMatrix, + asEyeByVector = DiagonalSparseMatrix, + asCovObject = ObjectMatrix, + asScript = Script, + toBeChecked = Checked, + ) + if Stored: + self.__StoredInputs[Concept] = self.__adaoObject[Concept].getO() + return 0 + + def setObservationError(self, + Matrix = None, + ScalarSparseMatrix = None, + DiagonalSparseMatrix = None, + ObjectMatrix = None, + Script = None, + Stored = False, + Checked = False): + "Definition d'un concept de calcul" + Concept = "ObservationError" + self.__case.register("set"+Concept, dir(), locals()) + self.__adaoObject[Concept] = Covariance( + name = Concept, + asCovariance = Matrix, + asEyeByScalar = ScalarSparseMatrix, + asEyeByVector = DiagonalSparseMatrix, + asCovObject = ObjectMatrix, + asScript = Script, + toBeChecked = Checked, + ) + if Stored: + self.__StoredInputs[Concept] = self.__adaoObject[Concept].getO() + return 0 + + def setEvolutionError(self, + Matrix = None, + ScalarSparseMatrix = None, + DiagonalSparseMatrix = None, + ObjectMatrix = None, + Script = None, + Stored = False, + Checked = False): + "Definition d'un concept de calcul" + Concept = "EvolutionError" + self.__case.register("set"+Concept, dir(), locals()) + self.__adaoObject[Concept] = Covariance( + name = Concept, + asCovariance = Matrix, + asEyeByScalar = ScalarSparseMatrix, + asEyeByVector = DiagonalSparseMatrix, + asCovObject = ObjectMatrix, + asScript = Script, + toBeChecked = Checked, + ) + if Stored: + self.__StoredInputs[Concept] = self.__adaoObject[Concept].getO() + return 0 + + def setObservationOperator(self, + Matrix = None, + OneFunction = None, + ThreeFunctions = None, + AppliedInXb = None, + Parameters = None, + Script = None, + AvoidRC = True, + Stored = False, + Checked = False): + "Definition d'un concept de calcul" + Concept = "ObservationOperator" + self.__case.register("set"+Concept, dir(), locals()) + self.__adaoObject[Concept] = FullOperator( + name = Concept, + asMatrix = Matrix, + asOneFunction = OneFunction, + asThreeFunctions = ThreeFunctions, + asScript = Script, + asDict = Parameters, + appliedInX = AppliedInXb, + avoidRC = AvoidRC, + scheduledBy = None, + toBeChecked = Checked, + ) + if Stored: + self.__StoredInputs[Concept] = self.__adaoObject[Concept].getO() + return 0 + + def setEvolutionModel(self, + Matrix = None, + OneFunction = None, + ThreeFunctions = None, + Parameters = None, + Script = None, + Scheduler = None, + AvoidRC = True, + Stored = False, + Checked = False): + "Definition d'un concept de calcul" + Concept = "EvolutionModel" + self.__case.register("set"+Concept, dir(), locals()) + self.__adaoObject[Concept] = FullOperator( + name = Concept, + asMatrix = Matrix, + asOneFunction = OneFunction, + asThreeFunctions = ThreeFunctions, + asScript = Script, + asDict = Parameters, + appliedInX = None, + avoidRC = AvoidRC, + scheduledBy = Scheduler, + toBeChecked = Checked, + ) + if Stored: + self.__StoredInputs[Concept] = self.__adaoObject[Concept].getO() + return 0 + + def setControlModel(self, + Matrix = None, + OneFunction = None, + ThreeFunctions = None, + Parameters = None, + Script = None, + Scheduler = None, + AvoidRC = True, + Stored = False, + Checked = False): + "Definition d'un concept de calcul" + Concept = "ControlModel" + self.__case.register("set"+Concept, dir(), locals()) + self.__adaoObject[Concept] = FullOperator( + name = Concept, + asMatrix = Matrix, + asOneFunction = OneFunction, + asThreeFunctions = ThreeFunctions, + asScript = Script, + asDict = Parameters, + appliedInX = None, + avoidRC = AvoidRC, + scheduledBy = Scheduler, + toBeChecked = Checked, + ) + if Stored: + self.__StoredInputs[Concept] = self.__adaoObject[Concept].getO() + return 0 + + def setDebug(self, level = 10): + "NOTSET=0 < DEBUG=10 < INFO=20 < WARNING=30 < ERROR=40 < CRITICAL=50" + self.__case.register("setDebug",dir(),locals()) + log = logging.getLogger() + log.setLevel( level ) + self.__StoredInputs["Debug"] = level + self.__StoredInputs["NoDebug"] = False + return 0 + + def setNoDebug(self): + "NOTSET=0 < DEBUG=10 < INFO=20 < WARNING=30 < ERROR=40 < CRITICAL=50" + self.__case.register("setNoDebug",dir(),locals()) + log = logging.getLogger() + log.setLevel( logging.WARNING ) + self.__StoredInputs["Debug"] = logging.WARNING + self.__StoredInputs["NoDebug"] = True + return 0 + + def setAlgorithmParameters(self, + Algorithm = None, + Parameters = None, + Script = None): + "Definition d'un concept de calcul" + Concept = "AlgorithmParameters" + self.__case.register("set"+Concept, dir(), locals()) + self.__adaoObject[Concept] = AlgorithmAndParameters( + name = Concept, + asAlgorithm = Algorithm, + asDict = Parameters, + asScript = Script, + ) + return 0 + + def updateAlgorithmParameters(self, + Parameters = None, + Script = None): + "Mise a jour d'un concept de calcul" + if "AlgorithmParameters" not in self.__adaoObject: + raise ValueError("No algorithm registred, ask for one before updating parameters") + self.__adaoObject["AlgorithmParameters"].updateParameters( + asDict = Parameters, + asScript = Script, + ) + return 0 + + def setObserver(self, + Variable = None, + Template = None, + String = None, + Script = None, + ObjectFunction = None, + Scheduler = None, + Info = None): + "Definition d'un concept de calcul" + Concept = "Observer" + self.__case.register("set"+Concept, dir(), locals()) + self.__adaoObject[Concept].append( DataObserver( + name = Concept, + onVariable = Variable, + asTemplate = Template, + asString = String, + asScript = Script, + asObsObject = ObjectFunction, + withInfo = Info, + scheduledBy = Scheduler, + withAlgo = self.__adaoObject["AlgorithmParameters"] + )) + return 0 + + def removeObserver(self, + Variable = None, + ObjectFunction = None, + ): + """ + Permet de retirer un observer à une ou des variable nommée. + """ + if "AlgorithmParameters" not in self.__adaoObject: + raise ValueError("No algorithm registred, ask for one before removing observers") + # + # Vérification du nom de variable et typage + # ----------------------------------------- + if isinstance(Variable, str): + VariableNames = (Variable,) + elif isinstance(Variable, list): + VariableNames = tuple(map( str, Variable )) + else: + raise ValueError("The observer requires a name or a list of names of variables.") + # + # Association interne de l'observer à la variable + # ----------------------------------------------- + for ename in VariableNames: + if ename not in self.__adaoObject["AlgorithmParameters"]: + raise ValueError("An observer requires to be removed on a variable named %s which does not exist."%ename) + else: + return self.__adaoObject["AlgorithmParameters"].removeObserver( ename, ObjectFunction ) + + # ----------------------------------------------------------- + + def setDiagnostic(self, + Diagnostic = None, + Identifier = None, + Parameters = None, + Script = None, + Unit = None, + BaseType = None): + "Definition d'un concept de calcul" + Concept = "Diagnostic" + self.__case.register("set"+Concept, dir(), locals()) + self.__adaoObject[Concept].append( DiagnosticAndParameters( + name = Concept, + asDiagnostic = Diagnostic, + asIdentifier = Identifier, + asDict = Parameters, + asScript = Script, + asUnit = Unit, + asBaseType = BaseType, + asExistingDiags = self.__StoredInputs[Concept], + )) + self.__StoredInputs[Concept].append(str(Identifier)) + return 0 + + def get(self, Concept=None, noDetails=True ): + "Recuperation d'une sortie du calcul" + """ + Permet d'accéder aux informations stockées, diagnostics et résultats + disponibles après l'exécution du calcul. Attention, quand un diagnostic + porte le même nom qu'une variable stockée (paramètre ou résultat), + c'est la variable stockée qui est renvoyée, et le diagnostic est + inatteignable. + """ + if Concept is not None: + try: + self.__case.register("get", dir(), locals(), Concept) # Break pickle in Python 2 + except: + pass + if Concept in self.__StoredInputs: + return self.__StoredInputs[Concept] + # + elif self.__adaoObject["AlgorithmParameters"] is not None and Concept == "AlgorithmParameters": + return self.__adaoObject["AlgorithmParameters"].get() + # + elif self.__adaoObject["AlgorithmParameters"] is not None and Concept in self.__adaoObject["AlgorithmParameters"]: + return self.__adaoObject["AlgorithmParameters"].get( Concept ) + # + elif Concept == "AlgorithmRequiredParameters" and self.__adaoObject["AlgorithmParameters"] is not None: + return self.__adaoObject["AlgorithmParameters"].getAlgorithmRequiredParameters(noDetails) + # + elif Concept in self.__StoredInputs["Diagnostic"]: + indice = self.__StoredInputs["Diagnostic"].index(Concept) + return self.__adaoObject["Diagnostic"][indice].get() + # + else: + raise ValueError("The requested key \"%s\" does not exists as an input, a diagnostic or a stored variable."%Concept) + else: + allvariables = {} + allvariables.update( {"AlgorithmParameters":self.__adaoObject["AlgorithmParameters"].get()} ) + allvariables.update( self.__adaoObject["AlgorithmParameters"].get() ) + allvariables.update( self.__StoredInputs ) + allvariables.pop('Diagnostic', None) + allvariables.pop('Observer', None) + return allvariables + + # ----------------------------------------------------------- + + def get_available_variables(self): + """ + Renvoie les variables potentiellement utilisables pour l'étude, + initialement stockées comme données d'entrées ou dans les algorithmes, + identifiés par les chaînes de caractères. L'algorithme doit avoir été + préalablement choisi sinon la méthode renvoie "None". + """ + if len(list(self.__adaoObject["AlgorithmParameters"].keys())) == 0 and \ + len(list(self.__StoredInputs.keys())) == 0: + return None + else: + variables = [] + if len(list(self.__adaoObject["AlgorithmParameters"].keys())) > 0: + variables.extend(list(self.__adaoObject["AlgorithmParameters"].keys())) + if len(list(self.__StoredInputs.keys())) > 0: + variables.extend( list(self.__StoredInputs.keys()) ) + variables.remove('Diagnostic') + variables.remove('Observer') + variables.sort() + return variables + + def get_available_algorithms(self): + """ + Renvoie la liste des algorithmes potentiellement utilisables, identifiés + par les chaînes de caractères. + """ + files = [] + for directory in sys.path: + if os.path.isdir(os.path.join(directory,"daAlgorithms")): + for fname in os.listdir(os.path.join(directory,"daAlgorithms")): + root, ext = os.path.splitext(fname) + if ext == '.py' and root != '__init__': + files.append(root) + files.sort() + return files + + def get_available_diagnostics(self): + """ + Renvoie la liste des diagnostics potentiellement utilisables, identifiés + par les chaînes de caractères. + """ + files = [] + for directory in sys.path: + if os.path.isdir(os.path.join(directory,"daDiagnostics")): + for fname in os.listdir(os.path.join(directory,"daDiagnostics")): + root, ext = os.path.splitext(fname) + if ext == '.py' and root != '__init__': + files.append(root) + files.sort() + return files + + # ----------------------------------------------------------- + + def get_algorithms_main_path(self): + """ + Renvoie le chemin pour le répertoire principal contenant les algorithmes + dans un sous-répertoire "daAlgorithms" + """ + return self.__parent + + def add_algorithms_path(self, Path=None): + """ + 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. + """ + if not os.path.isdir(Path): + raise ValueError("The given "+Path+" argument must exist as a directory") + if not os.path.isdir(os.path.join(Path,"daAlgorithms")): + raise ValueError("The given \""+Path+"\" argument must contain a subdirectory named \"daAlgorithms\"") + if not os.path.isfile(os.path.join(Path,"daAlgorithms","__init__.py")): + raise ValueError("The given \""+Path+"/daAlgorithms\" path must contain a file named \"__init__.py\"") + sys.path.insert(0, os.path.abspath(Path)) + sys.path = PlatformInfo.uniq( sys.path ) # Conserve en unique exemplaire chaque chemin + return 0 + + def get_diagnostics_main_path(self): + """ + Renvoie le chemin pour le répertoire principal contenant les diagnostics + dans un sous-répertoire "daDiagnostics" + """ + return self.__parent + + def add_diagnostics_path(self, Path=None): + """ + 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. + """ + if not os.path.isdir(Path): + raise ValueError("The given "+Path+" argument must exist as a directory") + if not os.path.isdir(os.path.join(Path,"daDiagnostics")): + raise ValueError("The given \""+Path+"\" argument must contain a subdirectory named \"daDiagnostics\"") + if not os.path.isfile(os.path.join(Path,"daDiagnostics","__init__.py")): + raise ValueError("The given \""+Path+"/daDiagnostics\" path must contain a file named \"__init__.py\"") + sys.path.insert(0, os.path.abspath(Path)) + sys.path = PlatformInfo.uniq( sys.path ) # Conserve en unique exemplaire chaque chemin + return 0 + + # ----------------------------------------------------------- + + def execute(self, Executor=None, FileName=None): + "Lancement du calcul" + self.__case.register("execute",dir(),locals(),None,True) + Operator.CM.clearCache() + #~ try: + if Executor == "YACS": self.__executeYACSScheme( FileName ) + else: self.__executePythonScheme() + #~ except Exception as e: + #~ if isinstance(e, SyntaxError): msg = "at %s: %s"%(e.offset, e.text) + #~ else: msg = "" + #~ raise ValueError("during execution, the following error occurs:\n\n%s %s\n\nSee also the potential messages, which can show the origin of the above error, in the launching terminal.\n"%(str(e),msg)) + return 0 + + def __executePythonScheme(self, FileName=None): + "Lancement du calcul" + self.__case.register("executePythonScheme", dir(), locals()) + if FileName is not None: + self.dump( FileName, "TUI") + self.__adaoObject["AlgorithmParameters"].executePythonScheme( self.__adaoObject ) + return 0 + + def __executeYACSScheme(self, FileName=None): + "Lancement du calcul" + self.__case.register("executeYACSScheme", dir(), locals()) + if FileName is not None: + self.dump( FileName, "DIC") + self.__adaoObject["AlgorithmParameters"].executeYACSScheme( FileName ) + return 0 + + # ----------------------------------------------------------- + + def dump(self, FileName=None, Formater="TUI"): + "Récupération normalisée de la liste des commandes" + return self.__case.dump(FileName, Formater) + + def __dir__(self): + "Clarifie la visibilité des méthodes" + return ['set', 'get', 'execute', '__doc__', '__init__', '__module__'] + + def prepare_to_pickle(self): + "Retire les variables non pickelisables, avec recopie efficace" + if self.__adaoObject['AlgorithmParameters'] is not None: + for k in self.__adaoObject['AlgorithmParameters'].keys(): + if k == "Algorithm": continue + if k in self.__StoredInputs: + raise ValueError("the key \"%s\s to be transfered for pickling will overwrite an existing one.") + if self.__adaoObject['AlgorithmParameters'].hasObserver( k ): + self.__adaoObject['AlgorithmParameters'].removeObserver( k, "", True ) + self.__StoredInputs[k] = self.__adaoObject['AlgorithmParameters'].pop(k, None) + del self.__adaoObject # Break pickle in Python 2 + del self.__case # Break pickle in Python 2 + return 0 + +# ============================================================================== +class _CaseLogger(object): + """ + Conservation des commandes de creation d'un cas + """ + def __init__(self, __name="", __objname="case"): + self.__name = str(__name) + self.__objname = str(__objname) + self.__logSerie = [] + self.__switchoff = False + + def register(self, __command=None, __keys=None, __local=None, __pre=None, __switchoff=False): + "Enregistrement d'une commande individuelle" + if __command is not None and __keys is not None and __local is not None and not self.__switchoff: + if "self" in __keys: __keys.remove("self") + self.__logSerie.append( (str(__command), __keys, __local, __pre, __switchoff) ) + if __switchoff: + self.__switchoff = True + if not __switchoff: + self.__switchoff = False + + def dump(self, __filename=None, __format="TUI"): + """ + Récupération normalisée de la liste des commandes selon le Formater : + - TUI (API de référence) + - DIC (Transitoire, pour passer vers XML YACS) + - XML (Experimental. Structured AIDSM) + """ + if __format == "TUI": + self.__dumper = _TUIViewer(self.__name, self.__objname, self.__logSerie) + __text = self.__dumper.dump(__filename) + elif __format == "DIC": + self.__dumper = _DICViewer(self.__name, self.__objname, self.__logSerie) + __text = self.__dumper.dump(__filename) + elif __format == "XML": + self.__dumper = _XMLViewer(self.__name, self.__objname, self.__logSerie) + __text = self.__dumper.dump(__filename) + else: + raise ValueError("Dumping as \"%s\" is not available"%__format) + return __text + +# ============================================================================== +class _GenericCaseViewer(object): + """ + Etablissement des commandes de creation d'une vue + """ + def __init__(self, __name="", __objname="case", __content=None): + "Initialisation et enregistrement de l'entete" + self._name = str(__name) + self._objname = str(__objname) + self._lineSerie = [] + self._switchoff = False + self._numobservers = 2 + def _addLine(self, line=""): + "Ajoute un enregistrement individuel" + self._lineSerie.append(line) + def _finalize(self): + "Enregistrement du final" + pass + def _append(self): + "Transformation d'une commande individuelle en un enregistrement" + raise NotImplementedError() + def dump(self, __filename=None): + "Restitution de la liste des commandes de creation d'un cas" + self._finalize() + __text = "\n".join(self._lineSerie) + if __filename is not None: + __file = os.path.abspath(__filename) + fid = open(__file,"w") + fid.write(__text) + fid.close() + return __text + +class _TUIViewer(_GenericCaseViewer): + """ + Etablissement des commandes de creation d'un cas TUI + """ + def __init__(self, __name="", __objname="case", __content=None): + "Initialisation et enregistrement de l'entete" + _GenericCaseViewer.__init__(self, __name, __objname, __content) + self._addLine("#\n# Python script for ADAO TUI\n#") + self._addLine("from numpy import array, matrix") + self._addLine("import adaoBuilder") + self._addLine("%s = adaoBuilder.New('%s')"%(self._objname, self._name)) + if __content is not None: + for command in __content: + self._append(*command) + def _append(self, __command=None, __keys=None, __local=None, __pre=None, __switchoff=False): + "Transformation d'une commande individuelle en un enregistrement" + if __command is not None and __keys is not None and __local is not None: + __text = "" + if __pre is not None: + __text += "%s = "%__pre + __text += "%s.%s( "%(self._objname,str(__command)) + if "self" in __keys: __keys.remove("self") + if __command not in ("set","get") and "Concept" in __keys: __keys.remove("Concept") + for k in __keys: + __v = __local[k] + if __v is None: continue + if k == "Checked" and not __v: continue + if k == "Stored" and not __v: continue + if k == "AvoidRC" and __v: continue + if k == "noDetails": continue + __text += "%s=%s, "%(k,repr(__v)) + __text.rstrip(", ") + __text += ")" + self._addLine(__text) + +class _DICViewer(_GenericCaseViewer): + """ + Etablissement des commandes de creation d'un cas DIC + """ + def __init__(self, __name="", __objname="case", __content=None): + "Initialisation et enregistrement de l'entete" + _GenericCaseViewer.__init__(self, __name, __objname, __content) + self._addLine("# -*- coding: utf-8 -*-") + self._addLine("#\n# Input for ADAO converter to YACS\n#") + self._addLine("from numpy import array, matrix") + self._addLine("#") + self._addLine("study_config = {}") + self._addLine("study_config['StudyType'] = 'ASSIMILATION_STUDY'") + self._addLine("study_config['Name'] = '%s'"%self._name) + self._addLine("observers = {}") + self._addLine("study_config['Observers'] = observers") + self._addLine("#") + self._addLine("inputvariables_config = {}") + self._addLine("inputvariables_config['Order'] =['adao_default']") + self._addLine("inputvariables_config['adao_default'] = -1") + self._addLine("study_config['InputVariables'] = inputvariables_config") + self._addLine("#") + self._addLine("outputvariables_config = {}") + self._addLine("outputvariables_config['Order'] = ['adao_default']") + self._addLine("outputvariables_config['adao_default'] = -1") + self._addLine("study_config['OutputVariables'] = outputvariables_config") + if __content is not None: + for command in __content: + self._append(*command) + def _append(self, __command=None, __keys=None, __local=None, __pre=None, __switchoff=False): + "Transformation d'une commande individuelle en un enregistrement" + if __command == "set": __command = __local["Concept"] + else: __command = __command.replace("set", "", 1) + # + __text = None + if __command in (None, 'execute', 'executePythonScheme', 'executeYACSScheme', 'get'): + return + elif __command in ['Debug', 'setDebug']: + __text = "#\nstudy_config['Debug'] = '1'" + elif __command in ['NoDebug', 'setNoDebug']: + __text = "#\nstudy_config['Debug'] = '0'" + elif __command in ['Observer', 'setObserver']: + __obs = __local['Variable'] + self._numobservers += 1 + __text = "#\n" + __text += "observers['%s'] = {}\n"%__obs + if __local['String'] is not None: + __text += "observers['%s']['nodetype'] = '%s'\n"%(__obs, 'String') + __text += "observers['%s']['String'] = \"\"\"%s\"\"\"\n"%(__obs, __local['String']) + if __local['Script'] is not None: + __text += "observers['%s']['nodetype'] = '%s'\n"%(__obs, 'Script') + __text += "observers['%s']['Script'] = \"%s\"\n"%(__obs, __local['Script']) + if __local['Template'] is not None: + __text += "observers['%s']['nodetype'] = '%s'\n"%(__obs, 'String') + __text += "observers['%s']['String'] = \"\"\"%s\"\"\"\n"%(__obs, ObserverTemplates[__local['Template']]) + if __local['Info'] is not None: + __text += "observers['%s']['info'] = \"\"\"%s\"\"\"\n"%(__obs, __local['Info']) + else: + __text += "observers['%s']['info'] = \"\"\"%s\"\"\"\n"%(__obs, __obs) + __text += "observers['%s']['number'] = %s"%(__obs, self._numobservers) + elif __local is not None: # __keys is not None and + __text = "#\n" + __text += "%s_config = {}\n"%__command + if 'self' in __local: __local.pop('self') + __to_be_removed = [] + for __k,__v in __local.items(): + if __v is None: __to_be_removed.append(__k) + for __k in __to_be_removed: + __local.pop(__k) + for __k,__v in __local.items(): + if __k == "Concept": continue + if __k in ['ScalarSparseMatrix','DiagonalSparseMatrix','Matrix'] and 'Script' in __local: continue + if __k == 'Algorithm': + __text += "study_config['Algorithm'] = %s\n"%(repr(__v)) + elif __k == 'Script': + __k = 'Vector' + for __lk in ['ScalarSparseMatrix','DiagonalSparseMatrix','Matrix']: + if __lk in __local and __local[__lk]: __k = __lk + if __command == "AlgorithmParameters": __k = "Dict" + __text += "%s_config['Type'] = '%s'\n"%(__command,__k) + __text += "%s_config['From'] = '%s'\n"%(__command,'Script') + __text += "%s_config['Data'] = '%s'\n"%(__command,repr(__v)) + __text = __text.replace("''","'") + elif __k in ('Stored', 'Checked'): + if bool(__v): + __text += "%s_config['%s'] = '%s'\n"%(__command,__k,int(bool(__v))) + elif __k in ('AvoidRC', 'noDetails'): + if not bool(__v): + __text += "%s_config['%s'] = '%s'\n"%(__command,__k,int(bool(__v))) + else: + if __k is 'Parameters': __k = "Dict" + __text += "%s_config['Type'] = '%s'\n"%(__command,__k) + __text += "%s_config['From'] = '%s'\n"%(__command,'String') + __text += "%s_config['Data'] = \"\"\"%s\"\"\"\n"%(__command,repr(__v)) + __text += "study_config['%s'] = %s_config"%(__command,__command) + if __switchoff: + self._switchoff = True + if __text is not None: self._addLine(__text) + if not __switchoff: + self._switchoff = False + def _finalize(self): + self.__loadVariablesByScript() + self._addLine("#") + self._addLine("Analysis_config = {}") + self._addLine("Analysis_config['From'] = 'String'") + self._addLine("Analysis_config['Data'] = \"\"\"import numpy") + self._addLine("xa=numpy.ravel(ADD.get('Analysis')[-1])") + self._addLine("print 'Analysis:',xa\"\"\"") + self._addLine("study_config['UserPostAnalysis'] = Analysis_config") + def __loadVariablesByScript(self): + exec("\n".join(self._lineSerie)) + if "Algorithm" in study_config and len(study_config['Algorithm'])>0: + self.__hasAlgorithm = True + else: + self.__hasAlgorithm = False + if not self.__hasAlgorithm and \ + "AlgorithmParameters" in study_config and \ + isinstance(study_config['AlgorithmParameters'], dict) and \ + "From" in study_config['AlgorithmParameters'] and \ + "Data" in study_config['AlgorithmParameters'] and \ + study_config['AlgorithmParameters']['From'] == 'Script': + __asScript = study_config['AlgorithmParameters']['Data'] + __var = ImportFromScript(__asScript).getvalue( "Algorithm" ) + __text = "#\nstudy_config['Algorithm'] = '%s'"%(__var,) + self._addLine(__text) + if self.__hasAlgorithm and \ + "AlgorithmParameters" in study_config and \ + isinstance(study_config['AlgorithmParameters'], dict) and \ + "From" not in study_config['AlgorithmParameters'] and \ + "Data" not in study_config['AlgorithmParameters']: + __text = "#\n" + __text += "AlgorithmParameters_config['Type'] = 'Dict'\n" + __text += "AlgorithmParameters_config['From'] = 'String'\n" + __text += "AlgorithmParameters_config['Data'] = '{}'\n" + self._addLine(__text) + del study_config + +class _XMLViewer(_GenericCaseViewer): + """ + Etablissement des commandes de creation d'un cas DIC + """ + def __init__(self, __name="", __objname="case", __content=None): + "Initialisation et enregistrement de l'entete" + _GenericCaseViewer.__init__(self, __name, __objname, __content) + raise NotImplementedError() + +# ============================================================================== +if __name__ == "__main__": + print('\n AUTODIAGNOSTIC \n') diff --git a/src/daComposant/daCore/AssimilationStudy.py b/src/daComposant/daCore/AssimilationStudy.py index 82fca1b..5ad888e 100644 --- a/src/daComposant/daCore/AssimilationStudy.py +++ b/src/daComposant/daCore/AssimilationStudy.py @@ -1,4 +1,4 @@ -#-*-coding:iso-8859-1-*- +# -*- coding: utf-8 -*- # # Copyright (C) 2008-2017 EDF R&D # @@ -21,1061 +21,20 @@ # Author: Jean-Philippe Argaud, jean-philippe.argaud@edf.fr, EDF R&D """ - 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. + Normalized interface for ADAO """ __author__ = "Jean-Philippe ARGAUD" __all__ = ["AssimilationStudy"] -import os, sys -import numpy -from daCore import ExtendedLogging ; ExtendedLogging.ExtendedLogging() # A importer en premier -import logging -try: - import scipy.optimize - logging.debug("Succeed initial import of scipy.optimize with Scipy %s", scipy.version.version) -except ImportError: - logging.debug("Fail initial import of scipy.optimize") -from daCore import Persistence -from daCore.BasicObjects import Operator, Covariance -from daCore import PlatformInfo +from daCore.Aidsm import Aidsm # ============================================================================== -class AssimilationStudy: +class AssimilationStudy(Aidsm): """ - Cette classe sert d'interface pour l'utilisation de l'assimilation de - données. Elle contient les méthodes ou accesseurs nécessaires à la - construction d'un calcul d'assimilation. + Generic ADAO TUI builder """ - def __init__(self, name=""): - """ - Prévoit de conserver l'ensemble des variables nécssaires à un algorithme - élémentaire. Ces variables sont ensuite disponibles pour implémenter un - algorithme élémentaire particulier. - - - Background : vecteur Xb - - Observation : vecteur Y (potentiellement temporel) d'observations - - State : vecteur d'état dont une partie est le vecteur de contrôle. - Cette information n'est utile que si l'on veut faire des calculs sur - l'état complet, mais elle n'est pas indispensable pour l'assimilation. - - Control : vecteur X contenant toutes les variables de contrôle, i.e. - les paramètres ou l'état dont on veut estimer la valeur pour obtenir - les observations - - ObservationOperator...: opérateur d'observation H - - Les observations présentent une erreur dont la matrice de covariance est - R. L'ébauche du vecteur de contrôle présente une erreur dont la matrice - de covariance est B. - """ - self.__name = str(name) - self.__Xb = None - self.__Y = None - self.__U = None - self.__B = None - self.__R = None - self.__Q = None - self.__HO = {} - self.__EM = {} - self.__CM = {} - # - self.__X = Persistence.OneVector() - self.__Parameters = {} - self.__StoredDiagnostics = {} - self.__StoredInputs = {} - # - # Variables temporaires - self.__algorithm = {} - self.__algorithmFile = None - self.__algorithmName = None - self.__diagnosticFile = None - # - # Récupère le chemin du répertoire parent et l'ajoute au path - # (Cela complète l'action de la classe PathManagement dans PlatformInfo, - # qui est activée dans Persistence) - self.__parent = os.path.abspath(os.path.join(os.path.dirname(__file__),"..")) - sys.path.insert(0, self.__parent) - sys.path = PlatformInfo.uniq( sys.path ) # Conserve en unique exemplaire chaque chemin - - # --------------------------------------------------------- - def setBackground(self, - asVector = None, - asPersistentVector = None, - Scheduler = None, - toBeStored = False, - ): - """ - Permet de définir l'estimation a priori : - - asVector : entrée des données, comme un vecteur compatible avec le - constructeur de numpy.matrix - - asPersistentVector : entrée des données, comme un vecteur de type - persistent contruit avec la classe ad-hoc "Persistence" - - Scheduler est le contrôle temporel des données - - toBeStored : booléen indiquant si la donnée d'entrée est sauvée pour - être rendue disponible au même titre que les variables de calcul - """ - if asVector is not None: - self.__Xb = numpy.matrix( numpy.ravel(numpy.matrix(asVector)), numpy.float ).T - elif asPersistentVector is not None: - if type(asPersistentVector) in [type([]),type(()),type(numpy.array([])),type(numpy.matrix([]))]: - self.__Xb = Persistence.OneVector("Background", basetype=numpy.matrix) - for member in asPersistentVector: - self.__Xb.store( numpy.matrix( numpy.asmatrix(member).A1, numpy.float ).T ) - else: - self.__Xb = asPersistentVector - 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 - return 0 - - def setBackgroundError(self, - asCovariance = None, - asEyeByScalar = None, - asEyeByVector = None, - asCovObject = None, - toBeStored = False, - toBeChecked = False, - ): - """ - Permet de définir la covariance des erreurs d'ébauche : - - asCovariance : entrée des données, comme une matrice compatible avec - le constructeur de numpy.matrix - - asEyeByScalar : entrée des données comme un seul scalaire de variance, - multiplicatif d'une matrice de corrélation identité, aucune matrice - n'étant donc explicitement à donner - - asEyeByVector : entrée des données comme un seul vecteur de variance, - à mettre sur la diagonale d'une matrice de corrélation, aucune matrice - n'étant donc explicitement à donner - - asCovObject : entrée des données comme un objet ayant des méthodes - particulieres de type matriciel - - toBeStored : booléen indiquant si la donnée d'entrée est sauvée pour - être rendue disponible au même titre que les variables de calcul - """ - self.__B = Covariance( - name = "BackgroundError", - asCovariance = asCovariance, - asEyeByScalar = asEyeByScalar, - asEyeByVector = asEyeByVector, - asCovObject = asCovObject, - toBeChecked = toBeChecked, - ) - if toBeStored: - self.__StoredInputs["BackgroundError"] = self.__B - return 0 - - # ----------------------------------------------------------- - def setObservation(self, - asVector = None, - asPersistentVector = None, - Scheduler = None, - toBeStored = False, - ): - """ - Permet de définir les observations : - - asVector : entrée des données, comme un vecteur compatible avec le - constructeur de numpy.matrix - - asPersistentVector : entrée des données, comme un vecteur de type - persistent contruit avec la classe ad-hoc "Persistence" - - Scheduler est le contrôle temporel des données disponibles - - toBeStored : booléen indiquant si la donnée d'entrée est sauvée pour - être rendue disponible au même titre que les variables de calcul - """ - if asVector is not None: - self.__Y = numpy.matrix( numpy.ravel(numpy.matrix(asVector)), numpy.float ).T - elif asPersistentVector is not None: - if type(asPersistentVector) in [type([]),type(()),type(numpy.array([])),type(numpy.matrix([]))]: - self.__Y = Persistence.OneVector("Observation", basetype=numpy.matrix) - for member in asPersistentVector: - self.__Y.store( numpy.matrix( numpy.asmatrix(member).A1, numpy.float ).T ) - else: - self.__Y = asPersistentVector - else: - raise ValueError("Error: improperly defined observations, it requires at minima either a vector, a list/tuple of vectors or a persistent object") - if toBeStored: - self.__StoredInputs["Observation"] = self.__Y - return 0 - - def setObservationError(self, - asCovariance = None, - asEyeByScalar = None, - asEyeByVector = None, - asCovObject = None, - toBeStored = False, - toBeChecked = False, - ): - """ - Permet de définir la covariance des erreurs d'observations : - - asCovariance : entrée des données, comme une matrice compatible avec - le constructeur de numpy.matrix - - asEyeByScalar : entrée des données comme un seul scalaire de variance, - multiplicatif d'une matrice de corrélation identité, aucune matrice - n'étant donc explicitement à donner - - asEyeByVector : entrée des données comme un seul vecteur de variance, - à mettre sur la diagonale d'une matrice de corrélation, aucune matrice - n'étant donc explicitement à donner - - asCovObject : entrée des données comme un objet ayant des méthodes - particulieres de type matriciel - - toBeStored : booléen indiquant si la donnée d'entrée est sauvée pour - être rendue disponible au même titre que les variables de calcul - """ - self.__R = Covariance( - name = "ObservationError", - asCovariance = asCovariance, - asEyeByScalar = asEyeByScalar, - asEyeByVector = asEyeByVector, - asCovObject = asCovObject, - toBeChecked = toBeChecked, - ) - if toBeStored: - self.__StoredInputs["ObservationError"] = self.__R - return 0 - - def setObservationOperator(self, - asFunction = None, - asMatrix = None, - appliedToX = None, - toBeStored = False, - avoidRC = True, - ): - """ - Permet de définir un opérateur d'observation H. L'ordre de priorité des - définitions et leur sens sont les suivants : - - si asFunction["Tangent"] et asFunction["Adjoint"] ne sont pas None - alors on définit l'opérateur à l'aide de fonctions. Si la fonction - "Direct" n'est pas définie, on prend la fonction "Tangent". - Si "useApproximatedDerivatives" est vrai, on utilise une approximation - des opérateurs tangents et adjoints. On utilise par défaut des - différences finies non centrées ou centrées (si "withCenteredDF" est - vrai) avec un incrément multiplicatif "withIncrement" de 1% autour - du point courant ou sur le point fixe "withdX". - - si les fonctions ne sont pas disponibles et si asMatrix n'est pas - None, alors on définit l'opérateur "Direct" et "Tangent" à l'aide de - la matrice, et l'opérateur "Adjoint" à l'aide de la transposée. La - matrice fournie doit être sous une forme compatible avec le - constructeur de numpy.matrix. - - si l'argument "appliedToX" n'est pas None, alors on définit, pour des - X divers, l'opérateur par sa valeur appliquée à cet X particulier, - sous la forme d'un dictionnaire appliedToX[NAME] avec NAME un nom. - L'opérateur doit néanmoins déjà avoir été défini comme d'habitude. - - toBeStored : booléen indiquant si la donnée d'entrée est sauvée pour - être rendue disponible au même titre que les variables de calcul - L'argument "asFunction" peut prendre la forme complète suivante, avec - les valeurs par défaut standards : - asFunction = {"Direct":None, "Tangent":None, "Adjoint":None, - "useApproximatedDerivatives":False, - "withCenteredDF" :False, - "withIncrement" :0.01, - "withdX" :None, - "withAvoidingRedundancy" :True, - "withToleranceInRedundancy" :1.e-18, - "withLenghtOfRedundancy" :-1, - "withmpEnabled" :False, - "withmpWorkers" :None, - } - """ - if isinstance(asFunction, dict) and \ - ("useApproximatedDerivatives" in asFunction) and bool(asFunction["useApproximatedDerivatives"]) and \ - ("Direct" in asFunction) and (asFunction["Direct"] is not None): - if "withCenteredDF" not in asFunction: asFunction["withCenteredDF"] = False - if "withIncrement" not in asFunction: asFunction["withIncrement"] = 0.01 - if "withdX" not in asFunction: asFunction["withdX"] = None - if "withAvoidingRedundancy" not in asFunction: asFunction["withAvoidingRedundancy"] = True - if "withToleranceInRedundancy" not in asFunction: asFunction["withToleranceInRedundancy"] = 1.e-18 - if "withLenghtOfRedundancy" not in asFunction: asFunction["withLenghtOfRedundancy"] = -1 - if "withmpEnabled" not in asFunction: asFunction["withmpEnabled"] = False - if "withmpWorkers" not in asFunction: asFunction["withmpWorkers"] = None - from daNumerics.ApproximatedDerivatives import FDApproximation - FDA = FDApproximation( - Function = asFunction["Direct"], - centeredDF = asFunction["withCenteredDF"], - increment = asFunction["withIncrement"], - dX = asFunction["withdX"], - avoidingRedundancy = asFunction["withAvoidingRedundancy"], - toleranceInRedundancy = asFunction["withToleranceInRedundancy"], - lenghtOfRedundancy = asFunction["withLenghtOfRedundancy"], - mpEnabled = asFunction["withmpEnabled"], - mpWorkers = asFunction["withmpWorkers"], - ) - self.__HO["Direct"] = Operator( fromMethod = FDA.DirectOperator, avoidingRedundancy = avoidRC ) - self.__HO["Tangent"] = Operator( fromMethod = FDA.TangentOperator, avoidingRedundancy = avoidRC ) - self.__HO["Adjoint"] = Operator( fromMethod = FDA.AdjointOperator, avoidingRedundancy = avoidRC ) - elif isinstance(asFunction, dict) and \ - ("Tangent" in asFunction) and ("Adjoint" in asFunction) and \ - (asFunction["Tangent"] is not None) and (asFunction["Adjoint"] is not None): - if ("Direct" not in asFunction) or (asFunction["Direct"] is None): - self.__HO["Direct"] = Operator( fromMethod = asFunction["Tangent"], avoidingRedundancy = avoidRC ) - else: - self.__HO["Direct"] = Operator( fromMethod = asFunction["Direct"], avoidingRedundancy = avoidRC ) - self.__HO["Tangent"] = Operator( fromMethod = asFunction["Tangent"], avoidingRedundancy = avoidRC ) - self.__HO["Adjoint"] = Operator( fromMethod = asFunction["Adjoint"], avoidingRedundancy = avoidRC ) - elif asMatrix is not None: - matrice = numpy.matrix( asMatrix, numpy.float ) - self.__HO["Direct"] = Operator( fromMatrix = matrice, avoidingRedundancy = avoidRC ) - self.__HO["Tangent"] = Operator( fromMatrix = matrice, avoidingRedundancy = avoidRC ) - self.__HO["Adjoint"] = Operator( fromMatrix = matrice.T, avoidingRedundancy = avoidRC ) - del matrice - else: - raise ValueError("Improperly defined observation operator, it requires at minima either a matrix, a Direct for approximate derivatives or a Tangent/Adjoint pair.") - # - if appliedToX is not None: - self.__HO["AppliedToX"] = {} - if type(appliedToX) is not dict: - raise ValueError("Error: observation operator defined by \"appliedToX\" need a dictionary as argument.") - for key in list(appliedToX.keys()): - if type( appliedToX[key] ) is type( numpy.matrix([]) ): - # Pour le cas où l'on a une vraie matrice - self.__HO["AppliedToX"][key] = numpy.matrix( appliedToX[key].A1, numpy.float ).T - elif type( appliedToX[key] ) is type( numpy.array([]) ) and len(appliedToX[key].shape) > 1: - # Pour le cas où l'on a un vecteur représenté en array avec 2 dimensions - self.__HO["AppliedToX"][key] = numpy.matrix( appliedToX[key].reshape(len(appliedToX[key]),), numpy.float ).T - else: - self.__HO["AppliedToX"][key] = numpy.matrix( appliedToX[key], numpy.float ).T - else: - self.__HO["AppliedToX"] = None - # - if toBeStored: - self.__StoredInputs["ObservationOperator"] = self.__HO - return 0 - - # ----------------------------------------------------------- - def setEvolutionModel(self, - asFunction = None, - asMatrix = None, - Scheduler = None, - toBeStored = False, - avoidRC = True, - ): - """ - Permet de définir un opérateur d'évolution M. L'ordre de priorité des - définitions et leur sens sont les suivants : - - si asFunction["Tangent"] et asFunction["Adjoint"] ne sont pas None - alors on définit l'opérateur à l'aide de fonctions. Si la fonction - "Direct" n'est pas définie, on prend la fonction "Tangent". - Si "useApproximatedDerivatives" est vrai, on utilise une approximation - des opérateurs tangents et adjoints. On utilise par défaut des - différences finies non centrées ou centrées (si "withCenteredDF" est - vrai) avec un incrément multiplicatif "withIncrement" de 1% autour - du point courant ou sur le point fixe "withdX". - - si les fonctions ne sont pas disponibles et si asMatrix n'est pas - None, alors on définit l'opérateur "Direct" et "Tangent" à l'aide de - la matrice, et l'opérateur "Adjoint" à l'aide de la transposée. La - matrice fournie doit être sous une forme compatible avec le - constructeur de numpy.matrix. - - toBeStored : booléen indiquant si la donnée d'entrée est sauvée pour - être rendue disponible au même titre que les variables de calcul - L'argument "asFunction" peut prendre la forme complète suivante, avec - les valeurs par défaut standards : - asFunction = {"Direct":None, "Tangent":None, "Adjoint":None, - "useApproximatedDerivatives":False, - "withCenteredDF" :False, - "withIncrement" :0.01, - "withdX" :None, - "withAvoidingRedundancy" :True, - "withToleranceInRedundancy" :1.e-18, - "withLenghtOfRedundancy" :-1, - "withmpEnabled" :False, - "withmpWorkers" :None, - } - """ - if isinstance(asFunction, dict) and \ - ("useApproximatedDerivatives" in asFunction) and bool(asFunction["useApproximatedDerivatives"]) and \ - ("Direct" in asFunction) and (asFunction["Direct"] is not None): - if "withCenteredDF" not in asFunction: asFunction["withCenteredDF"] = False - if "withIncrement" not in asFunction: asFunction["withIncrement"] = 0.01 - if "withdX" not in asFunction: asFunction["withdX"] = None - if "withAvoidingRedundancy" not in asFunction: asFunction["withAvoidingRedundancy"] = True - if "withToleranceInRedundancy" not in asFunction: asFunction["withToleranceInRedundancy"] = 1.e-18 - if "withLenghtOfRedundancy" not in asFunction: asFunction["withLenghtOfRedundancy"] = -1 - if "withmpEnabled" not in asFunction: asFunction["withmpEnabled"] = False - if "withmpWorkers" not in asFunction: asFunction["withmpWorkers"] = None - from daNumerics.ApproximatedDerivatives import FDApproximation - FDA = FDApproximation( - Function = asFunction["Direct"], - centeredDF = asFunction["withCenteredDF"], - increment = asFunction["withIncrement"], - dX = asFunction["withdX"], - avoidingRedundancy = asFunction["withAvoidingRedundancy"], - toleranceInRedundancy = asFunction["withToleranceInRedundancy"], - lenghtOfRedundancy = asFunction["withLenghtOfRedundancy"], - mpEnabled = asFunction["withmpEnabled"], - mpWorkers = asFunction["withmpWorkers"], - ) - self.__EM["Direct"] = Operator( fromMethod = FDA.DirectOperator, avoidingRedundancy = avoidRC ) - self.__EM["Tangent"] = Operator( fromMethod = FDA.TangentOperator, avoidingRedundancy = avoidRC ) - self.__EM["Adjoint"] = Operator( fromMethod = FDA.AdjointOperator, avoidingRedundancy = avoidRC ) - elif isinstance(asFunction, dict) and \ - ("Tangent" in asFunction) and ("Adjoint" in asFunction) and \ - (asFunction["Tangent"] is not None) and (asFunction["Adjoint"] is not None): - if ("Direct" not in asFunction) or (asFunction["Direct"] is None): - self.__EM["Direct"] = Operator( fromMethod = asFunction["Tangent"], avoidingRedundancy = avoidRC ) - else: - self.__EM["Direct"] = Operator( fromMethod = asFunction["Direct"], avoidingRedundancy = avoidRC ) - self.__EM["Tangent"] = Operator( fromMethod = asFunction["Tangent"], avoidingRedundancy = avoidRC ) - self.__EM["Adjoint"] = Operator( fromMethod = asFunction["Adjoint"], avoidingRedundancy = avoidRC ) - elif asMatrix is not None: - matrice = numpy.matrix( asMatrix, numpy.float ) - self.__EM["Direct"] = Operator( fromMatrix = matrice, avoidingRedundancy = avoidRC ) - self.__EM["Tangent"] = Operator( fromMatrix = matrice, avoidingRedundancy = avoidRC ) - self.__EM["Adjoint"] = Operator( fromMatrix = matrice.T, avoidingRedundancy = avoidRC ) - del matrice - else: - raise ValueError("Improperly defined evolution model, it requires at minima either a matrix, a Direct for approximate derivatives or a Tangent/Adjoint pair.") - # - if toBeStored: - self.__StoredInputs["EvolutionModel"] = self.__EM - return 0 - - def setEvolutionError(self, - asCovariance = None, - asEyeByScalar = None, - asEyeByVector = None, - asCovObject = None, - toBeStored = False, - toBeChecked = False, - ): - """ - Permet de définir la covariance des erreurs de modèle : - - asCovariance : entrée des données, comme une matrice compatible avec - le constructeur de numpy.matrix - - asEyeByScalar : entrée des données comme un seul scalaire de variance, - multiplicatif d'une matrice de corrélation identité, aucune matrice - n'étant donc explicitement à donner - - asEyeByVector : entrée des données comme un seul vecteur de variance, - à mettre sur la diagonale d'une matrice de corrélation, aucune matrice - n'étant donc explicitement à donner - - asCovObject : entrée des données comme un objet ayant des méthodes - particulieres de type matriciel - - toBeStored : booléen indiquant si la donnée d'entrée est sauvée pour - être rendue disponible au même titre que les variables de calcul - """ - self.__Q = Covariance( - name = "EvolutionError", - asCovariance = asCovariance, - asEyeByScalar = asEyeByScalar, - asEyeByVector = asEyeByVector, - asCovObject = asCovObject, - toBeChecked = toBeChecked, - ) - if toBeStored: - self.__StoredInputs["EvolutionError"] = self.__Q - return 0 - - # ----------------------------------------------------------- - def setControlModel(self, - asFunction = None, - asMatrix = None, - Scheduler = None, - toBeStored = False, - avoidRC = True, - ): - """ - Permet de définir un opérateur de controle C. L'ordre de priorité des - définitions et leur sens sont les suivants : - - si asFunction["Tangent"] et asFunction["Adjoint"] ne sont pas None - alors on définit l'opérateur à l'aide de fonctions. Si la fonction - "Direct" n'est pas définie, on prend la fonction "Tangent". - Si "useApproximatedDerivatives" est vrai, on utilise une approximation - des opérateurs tangents et adjoints. On utilise par défaut des - différences finies non centrées ou centrées (si "withCenteredDF" est - vrai) avec un incrément multiplicatif "withIncrement" de 1% autour - du point courant ou sur le point fixe "withdX". - - si les fonctions ne sont pas disponibles et si asMatrix n'est pas - None, alors on définit l'opérateur "Direct" et "Tangent" à l'aide de - la matrice, et l'opérateur "Adjoint" à l'aide de la transposée. La - matrice fournie doit être sous une forme compatible avec le - constructeur de numpy.matrix. - - toBeStored : booléen indiquant si la donnée d'entrée est sauvée pour - être rendue disponible au même titre que les variables de calcul - L'argument "asFunction" peut prendre la forme complète suivante, avec - les valeurs par défaut standards : - asFunction = {"Direct":None, "Tangent":None, "Adjoint":None, - "useApproximatedDerivatives":False, - "withCenteredDF" :False, - "withIncrement" :0.01, - "withdX" :None, - "withAvoidingRedundancy" :True, - "withToleranceInRedundancy" :1.e-18, - "withLenghtOfRedundancy" :-1, - "withmpEnabled" :False, - "withmpWorkers" :None, - } - """ - if isinstance(asFunction, dict) and \ - ("useApproximatedDerivatives" in asFunction) and bool(asFunction["useApproximatedDerivatives"]) and \ - ("Direct" in asFunction) and (asFunction["Direct"] is not None): - if "withCenteredDF" not in asFunction: asFunction["withCenteredDF"] = False - if "withIncrement" not in asFunction: asFunction["withIncrement"] = 0.01 - if "withdX" not in asFunction: asFunction["withdX"] = None - if "withAvoidingRedundancy" not in asFunction: asFunction["withAvoidingRedundancy"] = True - if "withToleranceInRedundancy" not in asFunction: asFunction["withToleranceInRedundancy"] = 1.e-18 - if "withLenghtOfRedundancy" not in asFunction: asFunction["withLenghtOfRedundancy"] = -1 - if "withmpEnabled" not in asFunction: asFunction["withmpEnabled"] = False - if "withmpWorkers" not in asFunction: asFunction["withmpWorkers"] = None - from daNumerics.ApproximatedDerivatives import FDApproximation - FDA = FDApproximation( - Function = asFunction["Direct"], - centeredDF = asFunction["withCenteredDF"], - increment = asFunction["withIncrement"], - dX = asFunction["withdX"], - avoidingRedundancy = asFunction["withAvoidingRedundancy"], - toleranceInRedundancy = asFunction["withToleranceInRedundancy"], - lenghtOfRedundancy = asFunction["withLenghtOfRedundancy"], - mpEnabled = asFunction["withmpEnabled"], - mpWorkers = asFunction["withmpWorkers"], - ) - self.__CM["Direct"] = Operator( fromMethod = FDA.DirectOperator, avoidingRedundancy = avoidRC ) - self.__CM["Tangent"] = Operator( fromMethod = FDA.TangentOperator, avoidingRedundancy = avoidRC ) - self.__CM["Adjoint"] = Operator( fromMethod = FDA.AdjointOperator, avoidingRedundancy = avoidRC ) - elif isinstance(asFunction, dict) and \ - ("Tangent" in asFunction) and ("Adjoint" in asFunction) and \ - (asFunction["Tangent"] is not None) and (asFunction["Adjoint"] is not None): - if ("Direct" not in asFunction) or (asFunction["Direct"] is None): - self.__CM["Direct"] = Operator( fromMethod = asFunction["Tangent"], avoidingRedundancy = avoidRC ) - else: - self.__CM["Direct"] = Operator( fromMethod = asFunction["Direct"], avoidingRedundancy = avoidRC ) - self.__CM["Tangent"] = Operator( fromMethod = asFunction["Tangent"], avoidingRedundancy = avoidRC ) - self.__CM["Adjoint"] = Operator( fromMethod = asFunction["Adjoint"], avoidingRedundancy = avoidRC ) - elif asMatrix is not None: - matrice = numpy.matrix( asMatrix, numpy.float ) - self.__CM["Direct"] = Operator( fromMatrix = matrice, avoidingRedundancy = avoidRC ) - self.__CM["Tangent"] = Operator( fromMatrix = matrice, avoidingRedundancy = avoidRC ) - self.__CM["Adjoint"] = Operator( fromMatrix = matrice.T, avoidingRedundancy = avoidRC ) - del matrice - else: - raise ValueError("Improperly defined input control model, it requires at minima either a matrix, a Direct for approximate derivatives or a Tangent/Adjoint pair.") - # - if toBeStored: - self.__StoredInputs["ControlModel"] = self.__CM - return 0 - - def setControlInput(self, - asVector = None, - asPersistentVector = None, - Scheduler = None, - toBeStored = False, - ): - """ - Permet de définir le controle en entree : - - asVector : entrée des données, comme un vecteur compatible avec le - constructeur de numpy.matrix - - asPersistentVector : entrée des données, comme un vecteur de type - persistent contruit avec la classe ad-hoc "Persistence" - - Scheduler est le contrôle temporel des données disponibles - - toBeStored : booléen indiquant si la donnée d'entrée est sauvée pour - être rendue disponible au même titre que les variables de calcul - """ - if asVector is not None: - self.__U = numpy.matrix( numpy.ravel(numpy.matrix(asVector)), numpy.float ).T - elif asPersistentVector is not None: - if type(asPersistentVector) in [type([]),type(()),type(numpy.array([])),type(numpy.matrix([]))]: - self.__U = Persistence.OneVector("ControlInput", basetype=numpy.matrix) - for member in asPersistentVector: - self.__U.store( numpy.matrix( numpy.asmatrix(member).A1, numpy.float ).T ) - else: - self.__U = asPersistentVector - else: - raise ValueError("Error: improperly defined control input, it requires at minima either a vector, a list/tuple of vectors or a persistent object") - if toBeStored: - self.__StoredInputs["ControlInput"] = self.__U - return 0 - - # ----------------------------------------------------------- - def setControls (self, - asVector = None, - toBeStored = False, - ): - """ - Permet de définir la valeur initiale du vecteur X contenant toutes les - variables de contrôle, i.e. les paramètres ou l'état dont on veut - estimer la valeur pour obtenir les observations. C'est utile pour un - algorithme itératif/incrémental. - - asVector : entrée des données, comme un vecteur compatible avec le - constructeur de numpy.matrix. - - toBeStored : booléen indiquant si la donnée d'entrée est sauvée pour - être rendue disponible au même titre que les variables de calcul - """ - if asVector is not None: - self.__X.store( asVector ) - if toBeStored: - self.__StoredInputs["Controls"] = self.__X - return 0 - - # ----------------------------------------------------------- - def setAlgorithm(self, choice = None ): - """ - Permet de sélectionner l'algorithme à utiliser pour mener à bien l'étude - d'assimilation. L'argument est un champ caractère se rapportant au nom - d'un fichier contenu dans "../daAlgorithms" et réalisant l'opération - d'assimilation sur les arguments fixes. - """ - if choice is None: - raise ValueError("Error: algorithm choice has to be given") - if self.__algorithmName is not None: - raise ValueError("Error: algorithm choice has already been done as \"%s\", it can't be changed."%self.__algorithmName) - daDirectory = "daAlgorithms" - # - # Recherche explicitement le fichier complet - # ------------------------------------------ - module_path = None - for directory in sys.path: - if os.path.isfile(os.path.join(directory, daDirectory, str(choice)+'.py')): - module_path = os.path.abspath(os.path.join(directory, daDirectory)) - if module_path is None: - raise ImportError("No algorithm module named \"%s\" was found in a \"%s\" subdirectory\n The search path is %s"%(choice, daDirectory, sys.path)) - # - # Importe le fichier complet comme un module - # ------------------------------------------ - try: - sys_path_tmp = sys.path ; sys.path.insert(0,module_path) - self.__algorithmFile = __import__(str(choice), globals(), locals(), []) - self.__algorithmName = str(choice) - sys.path = sys_path_tmp ; del sys_path_tmp - except ImportError as e: - raise ImportError("The module named \"%s\" was found, but is incorrect at the import stage.\n The import error message is: %s"%(choice,e)) - # - # Instancie un objet du type élémentaire du fichier - # ------------------------------------------------- - self.__algorithm = self.__algorithmFile.ElementaryAlgorithm() - self.__StoredInputs["AlgorithmName"] = self.__algorithmName - return 0 - - def setAlgorithmParameters(self, asDico=None): - """ - Permet de définir les paramètres de l'algorithme, sous la forme d'un - dictionnaire. - """ - if asDico is not None: - self.__Parameters.update( dict( asDico ) ) - # - self.__StoredInputs["AlgorithmParameters"] = self.__Parameters - return 0 - - def getAlgorithmParameters(self, noDetails=True): - """ - Renvoie la liste des paramètres requis selon l'algorithme - """ - return self.__algorithm.getRequiredParameters(noDetails) - - # ----------------------------------------------------------- - def setDiagnostic(self, choice = None, name = "", unit = "", basetype = None, parameters = {} ): - """ - Permet de sélectionner un diagnostic a effectuer. - """ - if choice is None: - raise ValueError("Error: diagnostic choice has to be given") - daDirectory = "daDiagnostics" - # - # Recherche explicitement le fichier complet - # ------------------------------------------ - module_path = None - for directory in sys.path: - if os.path.isfile(os.path.join(directory, daDirectory, str(choice)+'.py')): - module_path = os.path.abspath(os.path.join(directory, daDirectory)) - if module_path is None: - raise ImportError("No diagnostic module named \"%s\" was found in a \"%s\" subdirectory\n The search path is %s"%(choice, daDirectory, sys.path)) - # - # Importe le fichier complet comme un module - # ------------------------------------------ - try: - sys_path_tmp = sys.path ; sys.path.insert(0,module_path) - self.__diagnosticFile = __import__(str(choice), globals(), locals(), []) - sys.path = sys_path_tmp ; del sys_path_tmp - except ImportError as e: - raise ImportError("The module named \"%s\" was found, but is incorrect at the import stage.\n The import error message is: %s"%(choice,e)) - # - # Instancie un objet du type élémentaire du fichier - # ------------------------------------------------- - if name in self.__StoredInputs: - raise ValueError("A default input with the same name \"%s\" already exists."%str(name)) - elif name in self.__StoredDiagnostics: - raise ValueError("A diagnostic with the same name \"%s\" already exists."%str(name)) - else: - self.__StoredDiagnostics[name] = self.__diagnosticFile.ElementaryDiagnostic( - name = name, - unit = unit, - basetype = basetype, - parameters = parameters ) - return 0 - - # ----------------------------------------------------------- - def shape_validate(self): - """ - Validation de la correspondance correcte des tailles des variables et - des matrices s'il y en a. - """ - if self.__Xb is None: __Xb_shape = (0,) - elif hasattr(self.__Xb,"size"): __Xb_shape = (self.__Xb.size,) - elif hasattr(self.__Xb,"shape"): - if isinstance(self.__Xb.shape, tuple): __Xb_shape = self.__Xb.shape - else: __Xb_shape = self.__Xb.shape() - else: raise TypeError("The background (Xb) has no attribute of shape: problem !") - # - if self.__Y is None: __Y_shape = (0,) - elif hasattr(self.__Y,"size"): __Y_shape = (self.__Y.size,) - elif hasattr(self.__Y,"shape"): - if isinstance(self.__Y.shape, tuple): __Y_shape = self.__Y.shape - else: __Y_shape = self.__Y.shape() - else: raise TypeError("The observation (Y) has no attribute of shape: problem !") - # - if self.__U is None: __U_shape = (0,) - elif hasattr(self.__U,"size"): __U_shape = (self.__U.size,) - elif hasattr(self.__U,"shape"): - if isinstance(self.__U.shape, tuple): __U_shape = self.__U.shape - else: __U_shape = self.__U.shape() - else: raise TypeError("The control (U) has no attribute of shape: problem !") - # - if self.__B is None: __B_shape = (0,0) - elif hasattr(self.__B,"shape"): - if isinstance(self.__B.shape, tuple): __B_shape = self.__B.shape - else: __B_shape = self.__B.shape() - else: raise TypeError("The a priori errors covariance matrix (B) has no attribute of shape: problem !") - # - if self.__R is None: __R_shape = (0,0) - elif hasattr(self.__R,"shape"): - if isinstance(self.__R.shape, tuple): __R_shape = self.__R.shape - else: __R_shape = self.__R.shape() - else: raise TypeError("The observation errors covariance matrix (R) has no attribute of shape: problem !") - # - if self.__Q is None: __Q_shape = (0,0) - elif hasattr(self.__Q,"shape"): - if isinstance(self.__Q.shape, tuple): __Q_shape = self.__Q.shape - else: __Q_shape = self.__Q.shape() - else: raise TypeError("The evolution errors covariance matrix (Q) has no attribute of shape: problem !") - # - if len(self.__HO) == 0: __HO_shape = (0,0) - elif isinstance(self.__HO, dict): __HO_shape = (0,0) - elif hasattr(self.__HO["Direct"],"shape"): - if isinstance(self.__HO["Direct"].shape, tuple): __HO_shape = self.__HO["Direct"].shape - else: __HO_shape = self.__HO["Direct"].shape() - else: raise TypeError("The observation operator (H) has no attribute of shape: problem !") - # - if len(self.__EM) == 0: __EM_shape = (0,0) - elif isinstance(self.__EM, dict): __EM_shape = (0,0) - elif hasattr(self.__EM["Direct"],"shape"): - if isinstance(self.__EM["Direct"].shape, tuple): __EM_shape = self.__EM["Direct"].shape - else: __EM_shape = self.__EM["Direct"].shape() - else: raise TypeError("The evolution model (EM) has no attribute of shape: problem !") - # - if len(self.__CM) == 0: __CM_shape = (0,0) - elif isinstance(self.__CM, dict): __CM_shape = (0,0) - elif hasattr(self.__CM["Direct"],"shape"): - if isinstance(self.__CM["Direct"].shape, tuple): __CM_shape = self.__CM["Direct"].shape - else: __CM_shape = self.__CM["Direct"].shape() - else: raise TypeError("The control model (CM) has no attribute of shape: problem !") - # - # Vérification des conditions - # --------------------------- - if not( len(__Xb_shape) == 1 or min(__Xb_shape) == 1 ): - raise ValueError("Shape characteristic of background (Xb) is incorrect: \"%s\"."%(__Xb_shape,)) - if not( len(__Y_shape) == 1 or min(__Y_shape) == 1 ): - raise ValueError("Shape characteristic of observation (Y) is incorrect: \"%s\"."%(__Y_shape,)) - # - if not( min(__B_shape) == max(__B_shape) ): - raise ValueError("Shape characteristic of a priori errors covariance matrix (B) is incorrect: \"%s\"."%(__B_shape,)) - if not( min(__R_shape) == max(__R_shape) ): - raise ValueError("Shape characteristic of observation errors covariance matrix (R) is incorrect: \"%s\"."%(__R_shape,)) - if not( min(__Q_shape) == max(__Q_shape) ): - raise ValueError("Shape characteristic of evolution errors covariance matrix (Q) is incorrect: \"%s\"."%(__Q_shape,)) - if not( min(__EM_shape) == max(__EM_shape) ): - raise ValueError("Shape characteristic of evolution operator (EM) is incorrect: \"%s\"."%(__EM_shape,)) - # - if len(self.__HO) > 0 and not(type(self.__HO) is type({})) and not( __HO_shape[1] == max(__Xb_shape) ): - raise ValueError("Shape characteristic of observation operator (H) \"%s\" and state (X) \"%s\" are incompatible."%(__HO_shape,__Xb_shape)) - if len(self.__HO) > 0 and not(type(self.__HO) is type({})) and not( __HO_shape[0] == max(__Y_shape) ): - raise ValueError("Shape characteristic of observation operator (H) \"%s\" and observation (Y) \"%s\" are incompatible."%(__HO_shape,__Y_shape)) - if len(self.__HO) > 0 and not(type(self.__HO) is type({})) and len(self.__B) > 0 and not( __HO_shape[1] == __B_shape[0] ): - raise ValueError("Shape characteristic of observation operator (H) \"%s\" and a priori errors covariance matrix (B) \"%s\" are incompatible."%(__HO_shape,__B_shape)) - if len(self.__HO) > 0 and not(type(self.__HO) is type({})) and len(self.__R) > 0 and not( __HO_shape[0] == __R_shape[1] ): - raise ValueError("Shape characteristic of observation operator (H) \"%s\" and observation errors covariance matrix (R) \"%s\" are incompatible."%(__HO_shape,__R_shape)) - # - if self.__B is not None and len(self.__B) > 0 and not( __B_shape[1] == max(__Xb_shape) ): - if self.__StoredInputs["AlgorithmName"] in ["EnsembleBlue",]: - asPersistentVector = self.__Xb.reshape((-1,min(__B_shape))) - self.__Xb = Persistence.OneVector("Background", basetype=numpy.matrix) - for member in asPersistentVector: - self.__Xb.store( numpy.matrix( numpy.ravel(member), numpy.float ).T ) - __Xb_shape = min(__B_shape) - else: - raise ValueError("Shape characteristic of a priori errors covariance matrix (B) \"%s\" and background (Xb) \"%s\" are incompatible."%(__B_shape,__Xb_shape)) - # - if self.__R is not None and len(self.__R) > 0 and not( __R_shape[1] == max(__Y_shape) ): - raise ValueError("Shape characteristic of observation errors covariance matrix (R) \"%s\" and observation (Y) \"%s\" are incompatible."%(__R_shape,__Y_shape)) - # - if self.__EM is not None and len(self.__EM) > 0 and not(type(self.__EM) is type({})) and not( __EM_shape[1] == max(__Xb_shape) ): - raise ValueError("Shape characteristic of evolution model (EM) \"%s\" and state (X) \"%s\" are incompatible."%(__EM_shape,__Xb_shape)) - # - if self.__CM is not None and len(self.__CM) > 0 and not(type(self.__CM) is type({})) and not( __CM_shape[1] == max(__U_shape) ): - raise ValueError("Shape characteristic of control model (CM) \"%s\" and control (U) \"%s\" are incompatible."%(__CM_shape,__U_shape)) - # - if ("AlgorithmParameters" in self.__StoredInputs) \ - and ("Bounds" in self.__StoredInputs["AlgorithmParameters"]) \ - and (isinstance(self.__StoredInputs["AlgorithmParameters"]["Bounds"], list) or isinstance(self.__StoredInputs["AlgorithmParameters"]["Bounds"], tuple)) \ - 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))) - # - 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 - particulier des objets de Persistence pour les analyses, OMA... - """ - Operator.CM.clearCache() - self.shape_validate() - # - self.__algorithm.run( - Xb = self.__Xb, - Y = self.__Y, - U = self.__U, - HO = self.__HO, - EM = self.__EM, - CM = self.__CM, - R = self.__R, - B = self.__B, - Q = self.__Q, - Parameters = self.__Parameters, - ) - return 0 - - # ----------------------------------------------------------- - def get(self, key=None): - """ - Renvoie les résultats disponibles après l'exécution de la méthode - d'assimilation, ou les diagnostics disponibles. Attention, quand un - diagnostic porte le même nom qu'une variable stockée, c'est la variable - stockée qui est renvoyée, et le diagnostic est inatteignable. - """ - if key is not None: - if key in self.__algorithm: - return self.__algorithm.get( key ) - elif key in self.__StoredInputs: - return self.__StoredInputs[key] - elif key in self.__StoredDiagnostics: - return self.__StoredDiagnostics[key] - else: - raise ValueError("The requested key \"%s\" does not exists as an input, a diagnostic or a stored variable."%key) - else: - allvariables = self.__algorithm.get() - allvariables.update( self.__StoredDiagnostics ) - allvariables.update( self.__StoredInputs ) - return allvariables - - def get_available_variables(self): - """ - Renvoie les variables potentiellement utilisables pour l'étude, - initialement stockées comme données d'entrées ou dans les algorithmes, - identifiés par les chaînes de caractères. L'algorithme doit avoir été - préalablement choisi sinon la méthode renvoie "None". - """ - if len(list(self.__algorithm.keys())) == 0 and len(list(self.__StoredInputs.keys())) == 0: - return None - else: - variables = [] - if len( list(self.__algorithm.keys())) > 0: - variables.extend( list(self.__algorithm.get().keys()) ) - if len( list(self.__StoredInputs.keys()) ) > 0: - variables.extend( list(self.__StoredInputs.keys()) ) - variables.sort() - return variables - - def get_available_algorithms(self): - """ - Renvoie la liste des algorithmes potentiellement utilisables, identifiés - par les chaînes de caractères. - """ - files = [] - for directory in sys.path: - if os.path.isdir(os.path.join(directory,"daAlgorithms")): - for fname in os.listdir(os.path.join(directory,"daAlgorithms")): - root, ext = os.path.splitext(fname) - if ext == '.py' and root != '__init__': - files.append(root) - files.sort() - return files - - def get_available_diagnostics(self): - """ - Renvoie la liste des diagnostics potentiellement utilisables, identifiés - par les chaînes de caractères. - """ - files = [] - for directory in sys.path: - if os.path.isdir(os.path.join(directory,"daDiagnostics")): - for fname in os.listdir(os.path.join(directory,"daDiagnostics")): - root, ext = os.path.splitext(fname) - if ext == '.py' and root != '__init__': - files.append(root) - files.sort() - return files - - # ----------------------------------------------------------- - def get_algorithms_main_path(self): - """ - Renvoie le chemin pour le répertoire principal contenant les algorithmes - dans un sous-répertoire "daAlgorithms" - """ - return self.__parent - - def add_algorithms_path(self, asPath=None): - """ - 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. - """ - if not os.path.isdir(asPath): - raise ValueError("The given "+asPath+" argument must exist as a directory") - if not os.path.isdir(os.path.join(asPath,"daAlgorithms")): - raise ValueError("The given \""+asPath+"\" argument must contain a subdirectory named \"daAlgorithms\"") - if not os.path.isfile(os.path.join(asPath,"daAlgorithms","__init__.py")): - raise ValueError("The given \""+asPath+"/daAlgorithms\" path must contain a file named \"__init__.py\"") - sys.path.insert(0, os.path.abspath(asPath)) - sys.path = PlatformInfo.uniq( sys.path ) # Conserve en unique exemplaire chaque chemin - return 1 - - def get_diagnostics_main_path(self): - """ - Renvoie le chemin pour le répertoire principal contenant les diagnostics - dans un sous-répertoire "daDiagnostics" - """ - return self.__parent - - def add_diagnostics_path(self, asPath=None): - """ - 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. - """ - if not os.path.isdir(asPath): - raise ValueError("The given "+asPath+" argument must exist as a directory") - if not os.path.isdir(os.path.join(asPath,"daDiagnostics")): - raise ValueError("The given \""+asPath+"\" argument must contain a subdirectory named \"daDiagnostics\"") - if not os.path.isfile(os.path.join(asPath,"daDiagnostics","__init__.py")): - raise ValueError("The given \""+asPath+"/daDiagnostics\" path must contain a file named \"__init__.py\"") - sys.path.insert(0, os.path.abspath(asPath)) - sys.path = PlatformInfo.uniq( sys.path ) # Conserve en unique exemplaire chaque chemin - return 1 - - # ----------------------------------------------------------- - def setDataObserver(self, - VariableName = None, - HookFunction = None, - HookParameters = None, - Scheduler = None, - ): - """ - Permet d'associer un observer à une ou des variables nommées gérées en - interne, activable selon des règles définies dans le Scheduler. A chaque - pas demandé dans le Scheduler, il effectue la fonction HookFunction avec - les arguments (variable persistante VariableName, paramètres HookParameters). - """ - # - if isinstance(self.__algorithm, dict): - raise ValueError("No observer can be build before choosing an algorithm.") - # - # Vérification du nom de variable et typage - # ----------------------------------------- - if isinstance(VariableName, str): - VariableNames = [VariableName,] - elif isinstance(VariableName, list): - VariableNames = list(map( str, VariableName )) - else: - raise ValueError("The observer requires a name or a list of names of variables.") - # - # Association interne de l'observer à la variable - # ----------------------------------------------- - for n in VariableNames: - if n not in self.__algorithm: - 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, - ) - - def removeDataObserver(self, - VariableName = None, - HookFunction = None, - ): - """ - Permet de retirer un observer à une ou des variable nommée. - """ - # - if isinstance(self.__algorithm, dict): - raise ValueError("No observer can be removed before choosing an algorithm.") - # - # Vérification du nom de variable et typage - # ----------------------------------------- - if isinstance(VariableName, str): - VariableNames = [VariableName,] - elif isinstance(VariableName, list): - VariableNames = list(map( str, VariableName )) - else: - raise ValueError("The observer requires a name or a list of names of variables.") - # - # Association interne de l'observer à la variable - # ----------------------------------------------- - for n in VariableNames: - if n not in self.__algorithm: - 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, - ) - - # ----------------------------------------------------------- - def setDebug(self, level=10): - """ - Utiliser par exemple "import logging ; level = logging.DEBUG" avant cet - appel pour changer le niveau de verbosité, avec : - NOTSET=0 < DEBUG=10 < INFO=20 < WARNING=30 < ERROR=40 < CRITICAL=50 - """ - log = logging.getLogger() - log.setLevel( level ) - - def unsetDebug(self): - """ - Remet le logger au niveau par défaut - """ - log = logging.getLogger() - log.setLevel( logging.WARNING ) - - def __dir__(self): - # return set(self.__dict__.keys() + dir(self.__class__)) - return ['get', '__doc__', '__init__', '__module__'] - - def prepare_to_pickle(self): - """ - Retire les variables non pickelisables - """ - del self.__B - del self.__CM # non pickelisable - del self.__EM # non pickelisable - del self.__HO # non pickelisable - del self.__Parameters - del self.__Q - del self.__R - del self.__U - del self.__X - del self.__Xb - del self.__Y - del self.__algorithmFile # non pickelisable - del self.__algorithmName - del self.__diagnosticFile # non pickelisable - self.__class__.__doc__ = "" + def __init__(self, name = ""): + Aidsm.__init__(self, name) # ============================================================================== if __name__ == "__main__": diff --git a/src/daComposant/daCore/BasicObjects.py b/src/daComposant/daCore/BasicObjects.py index 2d52bcb..07f1cc6 100644 --- a/src/daComposant/daCore/BasicObjects.py +++ b/src/daComposant/daCore/BasicObjects.py @@ -1,4 +1,4 @@ -#-*-coding:iso-8859-1-*- +# -*- coding: utf-8 -*- # # Copyright (C) 2008-2017 EDF R&D # @@ -21,29 +21,30 @@ # Author: Jean-Philippe Argaud, jean-philippe.argaud@edf.fr, EDF R&D """ - Définit les outils généraux élémentaires. + Définit les outils généraux élémentaires. - Ce module est destiné à être appelée par AssimilationStudy. + Ce module est destiné à être appelée par AssimilationStudy. """ __author__ = "Jean-Philippe ARGAUD" __all__ = [] -import logging, copy, os +import os, sys, logging, copy import numpy from daCore import Persistence from daCore import PlatformInfo +from daCore import Templates # ============================================================================== class CacheManager(object): """ - Classe générale de gestion d'un cache de calculs + Classe générale de gestion d'un cache de calculs """ def __init__(self, toleranceInRedundancy = 1.e-18, lenghtOfRedundancy = -1, ): """ - Les caractéristiques de tolérance peuvent être modifées à la création. + Les caractéristiques de tolérance peuvent être modifées à la création. """ self.__tolerBP = float(toleranceInRedundancy) self.__lenghtOR = int(lenghtOfRedundancy) @@ -56,27 +57,27 @@ class CacheManager(object): # logging.debug("CM Tolerance de determination des doublons : %.2e", self.__tolerBP) def wasCalculatedIn(self, xValue ): #, info="" ): - "Vérifie l'existence d'un calcul correspondant à la valeur" + "Vérifie l'existence d'un calcul correspondant à la valeur" __alc = False __HxV = None for i in range(min(len(self.__listOPCV),self.__lenghtOR)-1,-1,-1): if xValue.size != self.__listOPCV[i][0].size: - # logging.debug("CM Différence de la taille %s de X et de celle %s du point %i déjà calculé", xValue.shape,i,self.__listOPCP[i].shape) + # logging.debug("CM Différence de la taille %s de X et de celle %s du point %i déjà calculé", xValue.shape,i,self.__listOPCP[i].shape) continue if numpy.linalg.norm(numpy.ravel(xValue) - self.__listOPCV[i][0]) < self.__tolerBP * self.__listOPCV[i][2]: __alc = True __HxV = self.__listOPCV[i][1] - # logging.debug("CM Cas%s déja calculé, portant le numéro %i", info, i) + # logging.debug("CM Cas%s déja calculé, portant le numéro %i", info, i) break return __alc, __HxV def storeValueInX(self, xValue, HxValue ): - "Stocke un calcul correspondant à la valeur" + "Stocke un calcul correspondant à la valeur" if self.__lenghtOR < 0: self.__lenghtOR = 2 * xValue.size + 2 self.__initlnOR = self.__lenghtOR while len(self.__listOPCV) > self.__lenghtOR: - # logging.debug("CM Réduction de la liste des cas à %i éléments par suppression du premier", self.__lenghtOR) + # logging.debug("CM Réduction de la liste des cas à %i éléments par suppression du premier", self.__lenghtOR) self.__listOPCV.pop(0) self.__listOPCV.append( ( copy.copy(numpy.ravel(xValue)), @@ -96,7 +97,7 @@ class CacheManager(object): # ============================================================================== class Operator(object): """ - Classe générale d'interface de type opérateur + Classe générale d'interface de type opérateur simple """ NbCallsAsMatrix = 0 NbCallsAsMethod = 0 @@ -105,12 +106,12 @@ class Operator(object): # def __init__(self, fromMethod=None, fromMatrix=None, avoidingRedundancy = True): """ - On construit un objet de ce type en fournissant à l'aide de l'un des - deux mots-clé, soit une fonction python, soit une matrice. + On construit un objet de ce type en fournissant à l'aide de l'un des + deux mots-clé, soit une fonction python, soit une matrice. Arguments : - fromMethod : argument de type fonction Python - - fromMatrix : argument adapté au constructeur numpy.matrix - - avoidingRedundancy : évite ou pas les calculs redondants + - fromMatrix : argument adapté au constructeur numpy.matrix + - avoidingRedundancy : évite ou pas les calculs redondants """ self.__NbCallsAsMatrix, self.__NbCallsAsMethod, self.__NbCallsOfCached = 0, 0, 0 self.__AvoidRC = bool( avoidingRedundancy ) @@ -144,11 +145,11 @@ class Operator(object): def appliedTo(self, xValue, HValue = None): """ - Permet de restituer le résultat de l'application de l'opérateur à un - argument xValue. Cette méthode se contente d'appliquer, son argument - devant a priori être du bon type. + Permet de restituer le résultat de l'application de l'opérateur à un + argument xValue. Cette méthode se contente d'appliquer, son argument + devant a priori être du bon type. Arguments : - - xValue : argument adapté pour appliquer l'opérateur + - xValue : argument adapté pour appliquer l'opérateur """ if HValue is not None: HxValue = numpy.asmatrix( numpy.ravel( HValue ) ).T @@ -177,13 +178,13 @@ class Operator(object): def appliedControledFormTo(self, paire ): """ - Permet de restituer le résultat de l'application de l'opérateur à une - paire (xValue, uValue). Cette méthode se contente d'appliquer, son - argument devant a priori être du bon type. Si la uValue est None, - on suppose que l'opérateur ne s'applique qu'à xValue. + Permet de restituer le résultat de l'application de l'opérateur à une + paire (xValue, uValue). Cette méthode se contente d'appliquer, son + argument devant a priori être du bon type. Si la uValue est None, + on suppose que l'opérateur ne s'applique qu'à xValue. Arguments : - - xValue : argument X adapté pour appliquer l'opérateur - - uValue : argument U adapté pour appliquer l'opérateur + - xValue : argument X adapté pour appliquer l'opérateur + - uValue : argument U adapté pour appliquer l'opérateur """ assert len(paire) == 2, "Incorrect number of arguments" xValue, uValue = paire @@ -199,16 +200,16 @@ class Operator(object): def appliedInXTo(self, paire ): """ - Permet de restituer le résultat de l'application de l'opérateur à un - argument xValue, sachant que l'opérateur est valable en xNominal. - Cette méthode se contente d'appliquer, son argument devant a priori - être du bon type. Si l'opérateur est linéaire car c'est une matrice, - alors il est valable en tout point nominal et il n'est pas nécessaire + Permet de restituer le résultat de l'application de l'opérateur à un + argument xValue, sachant que l'opérateur est valable en xNominal. + Cette méthode se contente d'appliquer, son argument devant a priori + être du bon type. Si l'opérateur est linéaire car c'est une matrice, + alors il est valable en tout point nominal et il n'est pas nécessaire d'utiliser xNominal. Arguments : une liste contenant - - xNominal : argument permettant de donner le point où l'opérateur - est construit pour etre ensuite appliqué - - xValue : argument adapté pour appliquer l'opérateur + - xNominal : argument permettant de donner le point où l'opérateur + est construit pour etre ensuite appliqué + - xValue : argument adapté pour appliquer l'opérateur """ assert len(paire) == 2, "Incorrect number of arguments" xNominal, xValue = paire @@ -221,7 +222,7 @@ class Operator(object): def asMatrix(self, ValueForMethodForm = "UnknownVoidValue"): """ - Permet de renvoyer l'opérateur sous la forme d'une matrice + Permet de renvoyer l'opérateur sous la forme d'une matrice """ if self.__Matrix is not None: self.__addOneMatrixCall() @@ -234,7 +235,7 @@ class Operator(object): def shape(self): """ - Renvoie la taille sous forme numpy si l'opérateur est disponible sous + Renvoie la taille sous forme numpy si l'opérateur est disponible sous la forme d'une matrice """ if self.__Matrix is not None: @@ -244,7 +245,7 @@ class Operator(object): def nbcalls(self, which=None): """ - Renvoie les nombres d'évaluations de l'opérateur + Renvoie les nombres d'évaluations de l'opérateur """ __nbcalls = ( self.__NbCallsAsMatrix+self.__NbCallsAsMethod, @@ -274,51 +275,216 @@ class Operator(object): self.__NbCallsOfCached += 1 # Decompte local Operator.NbCallsOfCached += 1 # Decompte global +# ============================================================================== +class FullOperator(object): + """ + Classe générale d'interface de type opérateur complet + (Direct, Linéaire Tangent, Adjoint) + """ + def __init__(self, + name = "GenericFullOperator", + asMatrix = None, + asOneFunction = None, # Fonction + asThreeFunctions = None, # Dictionnaire de fonctions + asScript = None, + asDict = None, # Parameters + appliedInX = None, + avoidRC = True, + scheduledBy = None, + toBeChecked = False, + ): + "" + self.__name = str(name) + self.__check = bool(toBeChecked) + # + self.__FO = {} + # + __Parameters = {} + if (asDict is not None) and isinstance(asDict, dict): + __Parameters.update( asDict ) + if "DifferentialIncrement" in asDict: + __Parameters["withIncrement"] = asDict["DifferentialIncrement"] + if "CenteredFiniteDifference" in asDict: + __Parameters["withCenteredDF"] = asDict["CenteredFiniteDifference"] + if "EnableMultiProcessing" in asDict: + __Parameters["withmpEnabled"] = asDict["EnableMultiProcessing"] + if "NumberOfProcesses" in asDict: + __Parameters["withmpWorkers"] = asDict["NumberOfProcesses"] + # + if asScript is not None: + __Matrix, __Function = None, None + if asMatrix: + __Matrix = ImportFromScript(asScript).getvalue( self.__name ) + elif asOneFunction: + __Function = { "Direct":ImportFromScript(asScript).getvalue( "DirectOperator" ) } + __Function.update({"useApproximatedDerivatives":True}) + __Function.update(__Parameters) + elif asThreeFunctions: + __Function = { + "Direct" :ImportFromScript(asScript).getvalue( "DirectOperator" ), + "Tangent":ImportFromScript(asScript).getvalue( "TangentOperator" ), + "Adjoint":ImportFromScript(asScript).getvalue( "AdjointOperator" ), + } + __Function.update(__Parameters) + else: + __Matrix = asMatrix + if asOneFunction is not None: + if isinstance(asOneFunction, dict) and "Direct" in asOneFunction: + if asOneFunction["Direct"] is not None: + __Function = asOneFunction + else: + raise ValueError("The function has to be given in a dictionnary which have 1 key (\"Direct\")") + else: + __Function = { "Direct":asOneFunction } + __Function.update({"useApproximatedDerivatives":True}) + __Function.update(__Parameters) + elif asThreeFunctions is not None: + if isinstance(asThreeFunctions, dict) and \ + ("Tangent" in asThreeFunctions) and (asThreeFunctions["Tangent"] is not None) and \ + ("Adjoint" in asThreeFunctions) and (asThreeFunctions["Adjoint"] is not None) and \ + (("useApproximatedDerivatives" not in asThreeFunctions) or not bool(asThreeFunctions["useApproximatedDerivatives"])): + __Function = asThreeFunctions + elif isinstance(asThreeFunctions, dict) and \ + ("Direct" in asThreeFunctions) and (asThreeFunctions["Direct"] is not None): + __Function = asThreeFunctions + __Function.update({"useApproximatedDerivatives":True}) + else: + raise ValueError("The functions has to be given in a dictionnary which have either 1 key (\"Direct\") or 3 keys (\"Direct\" (optionnal), \"Tangent\" and \"Adjoint\")") + if "Direct" not in asThreeFunctions: + __Function["Direct"] = asThreeFunctions["Tangent"] + __Function.update(__Parameters) + else: + __Function = None + # + # if sys.version_info[0] < 3 and isinstance(__Function, dict): + #  for k in ("Direct", "Tangent", "Adjoint"): + #  if k in __Function and hasattr(__Function[k],"__class__"): + #  if type(__Function[k]) is type(self.__init__): + #  raise TypeError("can't use a class method (%s) as a function for the \"%s\" operator. Use a real function instead."%(type(__Function[k]),k)) + # + if appliedInX is not None and isinstance(appliedInX, dict): + __appliedInX = appliedInX + elif appliedInX is not None: + __appliedInX = {"HXb":appliedInX} + else: + __appliedInX = None + # + if scheduledBy is not None: + self.__T = scheduledBy + # + if isinstance(__Function, dict) and \ + ("useApproximatedDerivatives" in __Function) and bool(__Function["useApproximatedDerivatives"]) and \ + ("Direct" in __Function) and (__Function["Direct"] is not None): + if "withCenteredDF" not in __Function: __Function["withCenteredDF"] = False + if "withIncrement" not in __Function: __Function["withIncrement"] = 0.01 + if "withdX" not in __Function: __Function["withdX"] = None + if "withAvoidingRedundancy" not in __Function: __Function["withAvoidingRedundancy"] = True + if "withToleranceInRedundancy" not in __Function: __Function["withToleranceInRedundancy"] = 1.e-18 + if "withLenghtOfRedundancy" not in __Function: __Function["withLenghtOfRedundancy"] = -1 + if "withmpEnabled" not in __Function: __Function["withmpEnabled"] = False + if "withmpWorkers" not in __Function: __Function["withmpWorkers"] = None + from daNumerics.ApproximatedDerivatives import FDApproximation + FDA = FDApproximation( + Function = __Function["Direct"], + centeredDF = __Function["withCenteredDF"], + increment = __Function["withIncrement"], + dX = __Function["withdX"], + avoidingRedundancy = __Function["withAvoidingRedundancy"], + toleranceInRedundancy = __Function["withToleranceInRedundancy"], + lenghtOfRedundancy = __Function["withLenghtOfRedundancy"], + mpEnabled = __Function["withmpEnabled"], + mpWorkers = __Function["withmpWorkers"], + ) + self.__FO["Direct"] = Operator( fromMethod = FDA.DirectOperator, avoidingRedundancy = avoidRC ) + self.__FO["Tangent"] = Operator( fromMethod = FDA.TangentOperator, avoidingRedundancy = avoidRC ) + self.__FO["Adjoint"] = Operator( fromMethod = FDA.AdjointOperator, avoidingRedundancy = avoidRC ) + elif isinstance(__Function, dict) and \ + ("Direct" in __Function) and ("Tangent" in __Function) and ("Adjoint" in __Function) and \ + (__Function["Direct"] is not None) and (__Function["Tangent"] is not None) and (__Function["Adjoint"] is not None): + self.__FO["Direct"] = Operator( fromMethod = __Function["Direct"], avoidingRedundancy = avoidRC ) + self.__FO["Tangent"] = Operator( fromMethod = __Function["Tangent"], avoidingRedundancy = avoidRC ) + self.__FO["Adjoint"] = Operator( fromMethod = __Function["Adjoint"], avoidingRedundancy = avoidRC ) + elif asMatrix is not None: + __matrice = numpy.matrix( asMatrix, numpy.float ) + self.__FO["Direct"] = Operator( fromMatrix = __matrice, avoidingRedundancy = avoidRC ) + self.__FO["Tangent"] = Operator( fromMatrix = __matrice, avoidingRedundancy = avoidRC ) + self.__FO["Adjoint"] = Operator( fromMatrix = __matrice.T, avoidingRedundancy = avoidRC ) + del __matrice + else: + raise ValueError("Improperly defined observation operator, it requires at minima either a matrix, a Direct for approximate derivatives or a Tangent/Adjoint pair.") + # + if __appliedInX is not None: + self.__FO["AppliedInX"] = {} + if type(__appliedInX) is not dict: + raise ValueError("Error: observation operator defined by \"AppliedInX\" need a dictionary as argument.") + for key in list(__appliedInX.keys()): + if type( __appliedInX[key] ) is type( numpy.matrix([]) ): + # Pour le cas où l'on a une vraie matrice + self.__FO["AppliedInX"][key] = numpy.matrix( __appliedInX[key].A1, numpy.float ).T + elif type( __appliedInX[key] ) is type( numpy.array([]) ) and len(__appliedInX[key].shape) > 1: + # Pour le cas où l'on a un vecteur représenté en array avec 2 dimensions + self.__FO["AppliedInX"][key] = numpy.matrix( __appliedInX[key].reshape(len(__appliedInX[key]),), numpy.float ).T + else: + self.__FO["AppliedInX"][key] = numpy.matrix( __appliedInX[key], numpy.float ).T + else: + self.__FO["AppliedInX"] = None + + def getO(self): + return self.__FO + + def __repr__(self): + "x.__repr__() <==> repr(x)" + return repr(self.__V) + + def __str__(self): + "x.__str__() <==> str(x)" + return str(self.__V) + # ============================================================================== class Algorithm(object): """ - Classe générale d'interface de type algorithme + Classe générale d'interface de type algorithme - Elle donne un cadre pour l'écriture d'une classe élémentaire d'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. + 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". + Une classe élémentaire d'algorithme doit implémenter la méthode "run". """ def __init__(self, name): """ - L'initialisation présente permet de fabriquer des variables de stockage - 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". + L'initialisation présente permet de fabriquer des variables de stockage + 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 : + Les variables prévues sont : - CostFunctionJ : fonction-cout globale, somme des deux parties suivantes - - CostFunctionJb : partie ébauche ou background de la fonction-cout + - CostFunctionJb : partie ébauche ou background de la fonction-cout - CostFunctionJo : partie observations de la fonction-cout - GradientOfCostFunctionJ : gradient de la fonction-cout globale - - GradientOfCostFunctionJb : gradient de la partie ébauche 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 + - CurrentState : état courant lors d'itérations - Analysis : l'analyse Xa - - SimulatedObservationAtBackground : l'état observé H(Xb) à l'ébauche - - SimulatedObservationAtCurrentState : l'état observé H(X) à l'état courant - - SimulatedObservationAtOptimum : l'état observé H(Xa) à l'optimum + - SimulatedObservationAtBackground : l'état observé H(Xb) à l'ébauche + - SimulatedObservationAtCurrentState : l'état observé H(X) à l'état courant + - SimulatedObservationAtOptimum : l'état observé H(Xa) à l'optimum - Innovation : l'innovation : d = Y - H(X) - - InnovationAtCurrentState : l'innovation à l'état courant : dn = Y - H(Xn) + - InnovationAtCurrentState : l'innovation à l'état courant : dn = Y - H(Xn) - SigmaObs2 : indicateur de correction optimale des erreurs d'observation - - SigmaBck2 : indicateur de correction optimale des erreurs d'ébauche + - SigmaBck2 : indicateur de correction optimale des erreurs d'ébauche - MahalanobisConsistency : indicateur de consistance des covariances - OMA : Observation moins Analysis : Y - Xa - OMB : Observation moins Background : Y - Xb - AMB : Analysis moins Background : Xa - Xb - APosterioriCovariance : matrice A - APosterioriVariances : variances de la matrice A - - APosterioriStandardDeviations : écart-types de la matrice A + - APosterioriStandardDeviations : écart-types de la matrice A - APosterioriCorrelations : correlations de la matrice A - - Residu : dans le cas des algorithmes de vérification - On peut rajouter des variables à stocker dans l'initialisation de - l'algorithme élémentaire qui va hériter de cette classe + - Residu : dans le cas des algorithmes de vérification + On peut rajouter des variables à stocker dans l'initialisation de + l'algorithme élémentaire qui va hériter de cette classe """ logging.debug("%s Initialisation", str(name)) self._m = PlatformInfo.SystemUsage() @@ -361,15 +527,15 @@ class Algorithm(object): self.StoredVariables["Residu"] = Persistence.OneScalar(name = "Residu") def _pre_run(self, Parameters ): - "Pré-calcul" + "Pré-calcul" logging.debug("%s Lancement", self._name) - logging.debug("%s Taille mémoire utilisée de %.0f Mio", self._name, self._m.getUsedMemory("Mio")) + logging.debug("%s Taille mémoire utilisée de %.0f Mio", self._name, self._m.getUsedMemory("Mio")) # # Mise a jour de self._parameters avec Parameters self.__setParameters(Parameters) # # Corrections et complements - if "Bounds" in self._parameters and (type(self._parameters["Bounds"]) is type([]) or type(self._parameters["Bounds"]) is type(())) and (len(self._parameters["Bounds"]) > 0): + if ("Bounds" in self._parameters) and isinstance(self._parameters["Bounds"], (list, tuple)) and (len(self._parameters["Bounds"]) > 0): logging.debug("%s Prise en compte des bornes effectuee"%(self._name,)) else: self._parameters["Bounds"] = None @@ -405,18 +571,18 @@ class Algorithm(object): _C = numpy.dot(_EI, numpy.dot(_A, _EI)) self.StoredVariables["APosterioriCorrelations"].store( _C ) if _oH is not None: - logging.debug("%s Nombre d'évaluation(s) de l'opérateur d'observation direct/tangent/adjoint.: %i/%i/%i", self._name, _oH["Direct"].nbcalls(0),_oH["Tangent"].nbcalls(0),_oH["Adjoint"].nbcalls(0)) - logging.debug("%s Nombre d'appels au cache d'opérateur d'observation direct/tangent/adjoint..: %i/%i/%i", self._name, _oH["Direct"].nbcalls(3),_oH["Tangent"].nbcalls(3),_oH["Adjoint"].nbcalls(3)) - logging.debug("%s Taille mémoire utilisée de %.0f Mio", self._name, self._m.getUsedMemory("Mio")) - logging.debug("%s Terminé", self._name) + logging.debug("%s Nombre d'évaluation(s) de l'opérateur d'observation direct/tangent/adjoint.: %i/%i/%i", self._name, _oH["Direct"].nbcalls(0),_oH["Tangent"].nbcalls(0),_oH["Adjoint"].nbcalls(0)) + logging.debug("%s Nombre d'appels au cache d'opérateur d'observation direct/tangent/adjoint..: %i/%i/%i", self._name, _oH["Direct"].nbcalls(3),_oH["Tangent"].nbcalls(3),_oH["Adjoint"].nbcalls(3)) + logging.debug("%s Taille mémoire utilisée de %.0f Mio", self._name, self._m.getUsedMemory("Mio")) + logging.debug("%s Terminé", self._name) return 0 def get(self, key=None): """ - Renvoie l'une des variables stockées identifiée par la clé, ou le + Renvoie l'une des variables stockées identifiée par la clé, ou le dictionnaire de l'ensemble des variables disponibles en l'absence de - clé. Ce sont directement les variables sous forme objet qui sont - renvoyées, donc les méthodes d'accès à l'objet individuel sont celles + clé. Ce sont directement les variables sous forme objet qui sont + renvoyées, donc les méthodes d'accès à l'objet individuel sont celles des classes de persistance. """ if key is not None: @@ -430,19 +596,37 @@ class Algorithm(object): def keys(self): "D.keys() -> list of D's keys" - return self.StoredVariables.keys() + if hasattr(self, "StoredVariables"): + return self.StoredVariables.keys() + else: + return [] + + def pop(self, k, d): + "D.pop(k[,d]) -> v, remove specified key and return the corresponding value" + if hasattr(self, "StoredVariables"): + return self.StoredVariables.pop(k, d) + else: + try: + msg = "'%s'"%k + except: + raise TypeError("pop expected at least 1 arguments, got 0") + "If key is not found, d is returned if given, otherwise KeyError is raised" + try: + return d + except: + raise KeyError(msg) def run(self, Xb=None, Y=None, H=None, M=None, R=None, B=None, Q=None, Parameters=None): """ - Doit implémenter l'opération élémentaire de calcul d'assimilation sous - sa forme mathématique la plus naturelle possible. + Doit implémenter l'opération élémentaire de calcul d'assimilation sous + sa forme mathématique la plus naturelle possible. """ raise NotImplementedError("Mathematical assimilation calculation has not been implemented!") def defineRequiredParameter(self, name = None, default = None, typecast = None, message = None, minval = None, maxval = None, listval = None): """ - Permet de définir dans l'algorithme des paramètres requis et leurs - caractéristiques par défaut. + Permet de définir dans l'algorithme des paramètres requis et leurs + caractéristiques par défaut. """ if name is None: raise ValueError("A name is mandatory to define a required parameter.") @@ -455,23 +639,21 @@ class Algorithm(object): "listval" : listval, "message" : message, } - logging.debug("%s %s (valeur par défaut = %s)", self._name, message, self.setParameterValue(name)) + logging.debug("%s %s (valeur par défaut = %s)", self._name, message, self.setParameterValue(name)) def getRequiredParameters(self, noDetails=True): """ - Renvoie la liste des noms de paramètres requis ou directement le - dictionnaire des paramètres requis. + Renvoie la liste des noms de paramètres requis ou directement le + dictionnaire des paramètres requis. """ if noDetails: - ks = list(self.__required_parameters.keys()) - ks.sort() - return ks + return sorted(self.__required_parameters.keys()) else: return self.__required_parameters def setParameterValue(self, name=None, value=None): """ - Renvoie la valeur d'un paramètre requis de manière contrôlée + Renvoie la valeur d'un paramètre requis de manière contrôlée """ default = self.__required_parameters[name]["default"] typecast = self.__required_parameters[name]["typecast"] @@ -503,7 +685,7 @@ class Algorithm(object): def __setParameters(self, fromDico={}): """ - Permet de stocker les paramètres reçus dans le dictionnaire interne. + Permet de stocker les paramètres reçus dans le dictionnaire interne. """ self._parameters.update( fromDico ) for k in self.__required_parameters.keys(): @@ -516,17 +698,17 @@ class Algorithm(object): # ============================================================================== class Diagnostic(object): """ - Classe générale d'interface de type 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 + 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 - publique), et "calculate" pour activer la précédente tout en ayant vérifié - et préparé les données, et pour stocker les résultats à chaque pas (méthode + 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 + publique), et "calculate" pour activer la précédente tout en ayant vérifié + et préparé les données, et pour stocker les résultats à chaque pas (méthode externe d'activation). """ def __init__(self, name = "", parameters = {}): @@ -536,24 +718,120 @@ class Diagnostic(object): def _formula(self, *args): """ - Doit implémenter l'opération élémentaire de diagnostic sous sa forme - mathématique la plus naturelle possible. + Doit implémenter l'opération élémentaire de diagnostic sous sa forme + mathématique la plus naturelle possible. """ raise NotImplementedError("Diagnostic mathematical formula has not been implemented!") def calculate(self, *args): """ - Active la formule de calcul avec les arguments correctement rangés + Active la formule de calcul avec les arguments correctement rangés """ raise NotImplementedError("Diagnostic activation method has not been implemented!") # ============================================================================== -class ParameterDictionary(object): +class DiagnosticAndParameters(object): """ - Classe générale d'interface de type dictionnaire de paramètres + Classe générale d'interface d'interface de type diagnostic """ def __init__(self, - name = "GenericParamDict", + name = "GenericDiagnostic", + asDiagnostic = None, + asIdentifier = None, + asDict = None, + asScript = None, + asUnit = None, + asBaseType = None, + asExistingDiags = None, + ): + """ + """ + self.__name = str(name) + self.__D = None + self.__I = None + self.__P = {} + self.__U = "" + self.__B = None + self.__E = tuple(asExistingDiags) + self.__TheDiag = None + # + if asScript is not None: + __Diag = ImportFromScript(asScript).getvalue( "Diagnostic" ) + __Iden = ImportFromScript(asScript).getvalue( "Identifier" ) + __Dict = ImportFromScript(asScript).getvalue( self.__name, "Parameters" ) + __Unit = ImportFromScript(asScript).getvalue( "Unit" ) + __Base = ImportFromScript(asScript).getvalue( "BaseType" ) + else: + __Diag = asDiagnostic + __Iden = asIdentifier + __Dict = asDict + __Unit = asUnit + __Base = asBaseType + # + if __Diag is not None: + self.__D = str(__Diag) + if __Iden is not None: + self.__I = str(__Iden) + else: + self.__I = str(__Diag) + if __Dict is not None: + self.__P.update( dict(__Dict) ) + if __Unit is None or __Unit == "None": + self.__U = "" + if __Base is None or __Base == "None": + self.__B = None + # + self.__setDiagnostic( self.__D, self.__I, self.__U, self.__B, self.__P, self.__E ) + + def get(self): + "Renvoie l'objet" + return self.__TheDiag + + def __setDiagnostic(self, __choice = None, __name = "", __unit = "", __basetype = None, __parameters = {}, __existings = () ): + """ + Permet de sélectionner un diagnostic a effectuer + """ + if __choice is None: + raise ValueError("Error: diagnostic choice has to be given") + __daDirectory = "daDiagnostics" + # + # Recherche explicitement le fichier complet + # ------------------------------------------ + __module_path = None + for directory in sys.path: + if os.path.isfile(os.path.join(directory, __daDirectory, str(__choice)+'.py')): + __module_path = os.path.abspath(os.path.join(directory, __daDirectory)) + if __module_path is None: + raise ImportError("No diagnostic module named \"%s\" was found in a \"%s\" subdirectory\n The search path is %s"%(__choice, __daDirectory, sys.path)) + # + # Importe le fichier complet comme un module + # ------------------------------------------ + try: + __sys_path_tmp = sys.path ; sys.path.insert(0,__module_path) + self.__diagnosticFile = __import__(str(__choice), globals(), locals(), []) + sys.path = __sys_path_tmp ; del __sys_path_tmp + except ImportError as e: + raise ImportError("The module named \"%s\" was found, but is incorrect at the import stage.\n The import error message is: %s"%(__choice,e)) + # + # Instancie un objet du type élémentaire du fichier + # ------------------------------------------------- + if __name in __existings: + raise ValueError("A default input with the same name \"%s\" already exists."%str(__name)) + else: + self.__TheDiag = self.__diagnosticFile.ElementaryDiagnostic( + name = __name, + unit = __unit, + basetype = __basetype, + parameters = __parameters ) + return 0 + +# ============================================================================== +class AlgorithmAndParameters(object): + """ + Classe générale d'interface d'action pour l'algorithme et ses paramètres + """ + def __init__(self, + name = "GenericAlgorithm", asAlgorithm = None, asDict = None, asScript = None, @@ -562,69 +840,428 @@ class ParameterDictionary(object): """ self.__name = str(name) self.__A = None - self.__D = None + self.__P = {} + # + self.__algorithm = {} + self.__algorithmFile = None + self.__algorithmName = None + # + self.updateParameters( asDict, asScript ) # if asScript is not None: __Algo = ImportFromScript(asScript).getvalue( "Algorithm" ) - __Dict = ImportFromScript(asScript).getvalue( self.__name, "Parameters" ) else: __Algo = asAlgorithm - __Dict = asDict # if __Algo is not None: self.__A = str(__Algo) + self.__P.update( {"Algorithm":self.__A} ) + # + self.__setAlgorithm( self.__A ) + + def updateParameters(self, + asDict = None, + asScript = None, + ): + "Mise a jour des parametres" + if asScript is not None: + __Dict = ImportFromScript(asScript).getvalue( self.__name, "Parameters" ) + else: + __Dict = asDict + # if __Dict is not None: - self.__D = dict(__Dict) + self.__P.update( dict(__Dict) ) + + def executePythonScheme(self, asDictAO = None): + "Permet de lancer le calcul d'assimilation" + Operator.CM.clearCache() + # + if not isinstance(asDictAO, dict): + raise ValueError("The objects for algorithm calculation has to be given as a dictionnary, and is not") + if hasattr(asDictAO["Background"],"getO"): self.__Xb = asDictAO["Background"].getO() + elif hasattr(asDictAO["CheckingPoint"],"getO"): self.__Xb = asDictAO["CheckingPoint"].getO() + else: self.__Xb = None + if hasattr(asDictAO["Observation"],"getO"): self.__Y = asDictAO["Observation"].getO() + else: self.__Y = asDictAO["Observation"] + if hasattr(asDictAO["ControlInput"],"getO"): self.__U = asDictAO["ControlInput"].getO() + else: self.__U = asDictAO["ControlInput"] + if hasattr(asDictAO["ObservationOperator"],"getO"): self.__HO = asDictAO["ObservationOperator"].getO() + else: self.__HO = asDictAO["ObservationOperator"] + if hasattr(asDictAO["EvolutionModel"],"getO"): self.__EM = asDictAO["EvolutionModel"].getO() + else: self.__EM = asDictAO["EvolutionModel"] + if hasattr(asDictAO["ControlModel"],"getO"): self.__CM = asDictAO["ControlModel"].getO() + else: self.__CM = asDictAO["ControlModel"] + self.__B = asDictAO["BackgroundError"] + self.__R = asDictAO["ObservationError"] + self.__Q = asDictAO["EvolutionError"] + # + self.__shape_validate() + # + self.__algorithm.run( + Xb = self.__Xb, + Y = self.__Y, + U = self.__U, + HO = self.__HO, + EM = self.__EM, + CM = self.__CM, + R = self.__R, + B = self.__B, + Q = self.__Q, + Parameters = self.__P, + ) + return 0 + + def executeYACSScheme(self, FileName=None): + "Permet de lancer le calcul d'assimilation" + if FileName is None or not os.path.exists(FileName): + raise ValueError("a existing DIC Python file name has to be given for YACS execution.\n") + if not os.environ.has_key("ADAO_ROOT_DIR"): + raise ImportError("Unable to get ADAO_ROOT_DIR environnement variable. Please launch SALOME to add ADAO_ROOT_DIR to your environnement.\n") + # + __converterExe = os.path.join(os.environ["ADAO_ROOT_DIR"], "bin/salome", "AdaoYacsSchemaCreator.py") + __inputFile = os.path.abspath(FileName) + __outputFile = __inputFile[:__inputFile.rfind(".")] + '.xml' + # + __args = ["python", __converterExe, __inputFile, __outputFile] + import subprocess + __p = subprocess.Popen(__args) + (__stdoutdata, __stderrdata) = __p.communicate() + if not os.path.exists(__outputFile): + __msg = "An error occured during the execution of the ADAO YACS Schema\n" + __msg += "Creator applied on the input file:\n" + __msg += " %s\n"%__outputFile + __msg += "If SALOME GUI is launched by command line, see errors\n" + __msg += "details in your terminal.\n" + raise ValueError(__msg) + # + try: + import pilot + import SALOMERuntime + import loader + SALOMERuntime.RuntimeSALOME_setRuntime() + + r = pilot.getRuntime() + xmlLoader = loader.YACSLoader() + xmlLoader.registerProcCataLoader() + try: + catalogAd = r.loadCatalog("proc", __outputFile) + except: + pass + r.addCatalog(catalogAd) + + try: + p = xmlLoader.load(__outputFile) + except IOError as ex: + print("IO exception: %s"%(ex,)) + + logger = p.getLogger("parser") + if not logger.isEmpty(): + print("The imported file has errors :") + print(logger.getStr()) + + if not p.isValid(): + print("Le schéma n'est pas valide et ne peut pas être exécuté") + print(p.getErrorReport()) + + info=pilot.LinkInfo(pilot.LinkInfo.ALL_DONT_STOP) + p.checkConsistency(info) + if info.areWarningsOrErrors(): + print("Le schéma n'est pas cohérent et ne peut pas être exécuté") + print(info.getGlobalRepr()) + + e = pilot.ExecutorSwig() + e.RunW(p) + if p.getEffectiveState() != pilot.DONE: + print(p.getErrorReport()) + except: + raise ValueError("execution error of YACS scheme") + # + return 0 + + def get(self, key = None): + "Vérifie l'existence d'une clé de variable ou de paramètres" + if key in self.__algorithm: + return self.__algorithm.get( key ) + elif key in self.__P: + return self.__P[key] + else: + return self.__P + + def pop(self, k, d): + "Necessaire pour le pickling" + return self.__algorithm.pop(k, d) + + def getAlgorithmRequiredParameters(self, noDetails=True): + "Renvoie la liste des paramètres requis selon l'algorithme" + return self.__algorithm.getRequiredParameters(noDetails) + + def setObserver(self, __V, __O, __I, __S): + if self.__algorithm is None \ + or isinstance(self.__algorithm, dict) \ + or not hasattr(self.__algorithm,"StoredVariables"): + raise ValueError("No observer can be build before choosing an algorithm.") + if __V not in self.__algorithm: + raise ValueError("An observer requires to be set on a variable named %s which does not exist."%__V) + else: + self.__algorithm.StoredVariables[ __V ].setDataObserver( + Scheduler = __S, + HookFunction = __O, + HookParameters = __I, + ) + + def removeObserver(self, __V, __O, __A = False): + if self.__algorithm is None \ + or isinstance(self.__algorithm, dict) \ + or not hasattr(self.__algorithm,"StoredVariables"): + raise ValueError("No observer can be removed before choosing an algorithm.") + if __V not in self.__algorithm: + raise ValueError("An observer requires to be removed on a variable named %s which does not exist."%__V) + else: + return self.__algorithm.StoredVariables[ __V ].removeDataObserver( + HookFunction = __O, + AllObservers = __A, + ) + + def hasObserver(self, __V): + if self.__algorithm is None \ + or isinstance(self.__algorithm, dict) \ + or not hasattr(self.__algorithm,"StoredVariables"): + return False + if __V not in self.__algorithm: + return False + return self.__algorithm.StoredVariables[ __V ].hasDataObserver() + + def keys(self): + return list(self.__algorithm.keys()) + list(self.__P.keys()) + + def __contains__(self, key=None): + "D.__contains__(k) -> True if D has a key k, else False" + return key in self.__algorithm or key in self.__P def __repr__(self): "x.__repr__() <==> repr(x)" - return repr(self.__A)+"\n"+repr(self.__D) + return repr(self.__A)+", "+repr(self.__P) def __str__(self): "x.__str__() <==> str(x)" - return str(self.__A)+"\n"+str(self.__D) + return str(self.__A)+", "+str(self.__P) + + def __setAlgorithm(self, choice = None ): + """ + Permet de sélectionner l'algorithme à utiliser pour mener à bien l'étude + d'assimilation. L'argument est un champ caractère se rapportant au nom + d'un fichier contenu dans "../daAlgorithms" et réalisant l'opération + d'assimilation sur les arguments fixes. + """ + if choice is None: + raise ValueError("Error: algorithm choice has to be given") + if self.__algorithmName is not None: + raise ValueError("Error: algorithm choice has already been done as \"%s\", it can't be changed."%self.__algorithmName) + daDirectory = "daAlgorithms" + # + # Recherche explicitement le fichier complet + # ------------------------------------------ + module_path = None + for directory in sys.path: + if os.path.isfile(os.path.join(directory, daDirectory, str(choice)+'.py')): + module_path = os.path.abspath(os.path.join(directory, daDirectory)) + if module_path is None: + raise ImportError("No algorithm module named \"%s\" was found in a \"%s\" subdirectory\n The search path is %s"%(choice, daDirectory, sys.path)) + # + # Importe le fichier complet comme un module + # ------------------------------------------ + try: + sys_path_tmp = sys.path ; sys.path.insert(0,module_path) + self.__algorithmFile = __import__(str(choice), globals(), locals(), []) + self.__algorithmName = str(choice) + sys.path = sys_path_tmp ; del sys_path_tmp + except ImportError as e: + raise ImportError("The module named \"%s\" was found, but is incorrect at the import stage.\n The import error message is: %s"%(choice,e)) + # + # Instancie un objet du type élémentaire du fichier + # ------------------------------------------------- + self.__algorithm = self.__algorithmFile.ElementaryAlgorithm() + return 0 + + def __shape_validate(self): + """ + Validation de la correspondance correcte des tailles des variables et + des matrices s'il y en a. + """ + if self.__Xb is None: __Xb_shape = (0,) + elif hasattr(self.__Xb,"size"): __Xb_shape = (self.__Xb.size,) + elif hasattr(self.__Xb,"shape"): + if isinstance(self.__Xb.shape, tuple): __Xb_shape = self.__Xb.shape + else: __Xb_shape = self.__Xb.shape() + else: raise TypeError("The background (Xb) has no attribute of shape: problem !") + # + if self.__Y is None: __Y_shape = (0,) + elif hasattr(self.__Y,"size"): __Y_shape = (self.__Y.size,) + elif hasattr(self.__Y,"shape"): + if isinstance(self.__Y.shape, tuple): __Y_shape = self.__Y.shape + else: __Y_shape = self.__Y.shape() + else: raise TypeError("The observation (Y) has no attribute of shape: problem !") + # + if self.__U is None: __U_shape = (0,) + elif hasattr(self.__U,"size"): __U_shape = (self.__U.size,) + elif hasattr(self.__U,"shape"): + if isinstance(self.__U.shape, tuple): __U_shape = self.__U.shape + else: __U_shape = self.__U.shape() + else: raise TypeError("The control (U) has no attribute of shape: problem !") + # + if self.__B is None: __B_shape = (0,0) + elif hasattr(self.__B,"shape"): + if isinstance(self.__B.shape, tuple): __B_shape = self.__B.shape + else: __B_shape = self.__B.shape() + else: raise TypeError("The a priori errors covariance matrix (B) has no attribute of shape: problem !") + # + if self.__R is None: __R_shape = (0,0) + elif hasattr(self.__R,"shape"): + if isinstance(self.__R.shape, tuple): __R_shape = self.__R.shape + else: __R_shape = self.__R.shape() + else: raise TypeError("The observation errors covariance matrix (R) has no attribute of shape: problem !") + # + if self.__Q is None: __Q_shape = (0,0) + elif hasattr(self.__Q,"shape"): + if isinstance(self.__Q.shape, tuple): __Q_shape = self.__Q.shape + else: __Q_shape = self.__Q.shape() + else: raise TypeError("The evolution errors covariance matrix (Q) has no attribute of shape: problem !") + # + if len(self.__HO) == 0: __HO_shape = (0,0) + elif isinstance(self.__HO, dict): __HO_shape = (0,0) + elif hasattr(self.__HO["Direct"],"shape"): + if isinstance(self.__HO["Direct"].shape, tuple): __HO_shape = self.__HO["Direct"].shape + else: __HO_shape = self.__HO["Direct"].shape() + else: raise TypeError("The observation operator (H) has no attribute of shape: problem !") + # + if len(self.__EM) == 0: __EM_shape = (0,0) + elif isinstance(self.__EM, dict): __EM_shape = (0,0) + elif hasattr(self.__EM["Direct"],"shape"): + if isinstance(self.__EM["Direct"].shape, tuple): __EM_shape = self.__EM["Direct"].shape + else: __EM_shape = self.__EM["Direct"].shape() + else: raise TypeError("The evolution model (EM) has no attribute of shape: problem !") + # + if len(self.__CM) == 0: __CM_shape = (0,0) + elif isinstance(self.__CM, dict): __CM_shape = (0,0) + elif hasattr(self.__CM["Direct"],"shape"): + if isinstance(self.__CM["Direct"].shape, tuple): __CM_shape = self.__CM["Direct"].shape + else: __CM_shape = self.__CM["Direct"].shape() + else: raise TypeError("The control model (CM) has no attribute of shape: problem !") + # + # Vérification des conditions + # --------------------------- + if not( len(__Xb_shape) == 1 or min(__Xb_shape) == 1 ): + raise ValueError("Shape characteristic of background (Xb) is incorrect: \"%s\"."%(__Xb_shape,)) + if not( len(__Y_shape) == 1 or min(__Y_shape) == 1 ): + raise ValueError("Shape characteristic of observation (Y) is incorrect: \"%s\"."%(__Y_shape,)) + # + if not( min(__B_shape) == max(__B_shape) ): + raise ValueError("Shape characteristic of a priori errors covariance matrix (B) is incorrect: \"%s\"."%(__B_shape,)) + if not( min(__R_shape) == max(__R_shape) ): + raise ValueError("Shape characteristic of observation errors covariance matrix (R) is incorrect: \"%s\"."%(__R_shape,)) + if not( min(__Q_shape) == max(__Q_shape) ): + raise ValueError("Shape characteristic of evolution errors covariance matrix (Q) is incorrect: \"%s\"."%(__Q_shape,)) + if not( min(__EM_shape) == max(__EM_shape) ): + raise ValueError("Shape characteristic of evolution operator (EM) is incorrect: \"%s\"."%(__EM_shape,)) + # + if len(self.__HO) > 0 and not(type(self.__HO) is type({})) and not( __HO_shape[1] == max(__Xb_shape) ): + raise ValueError("Shape characteristic of observation operator (H) \"%s\" and state (X) \"%s\" are incompatible."%(__HO_shape,__Xb_shape)) + if len(self.__HO) > 0 and not(type(self.__HO) is type({})) and not( __HO_shape[0] == max(__Y_shape) ): + raise ValueError("Shape characteristic of observation operator (H) \"%s\" and observation (Y) \"%s\" are incompatible."%(__HO_shape,__Y_shape)) + if len(self.__HO) > 0 and not(type(self.__HO) is type({})) and len(self.__B) > 0 and not( __HO_shape[1] == __B_shape[0] ): + raise ValueError("Shape characteristic of observation operator (H) \"%s\" and a priori errors covariance matrix (B) \"%s\" are incompatible."%(__HO_shape,__B_shape)) + if len(self.__HO) > 0 and not(type(self.__HO) is type({})) and len(self.__R) > 0 and not( __HO_shape[0] == __R_shape[1] ): + raise ValueError("Shape characteristic of observation operator (H) \"%s\" and observation errors covariance matrix (R) \"%s\" are incompatible."%(__HO_shape,__R_shape)) + # + if self.__B is not None and len(self.__B) > 0 and not( __B_shape[1] == max(__Xb_shape) ): + if self.__algorithmName in ["EnsembleBlue",]: + asPersistentVector = self.__Xb.reshape((-1,min(__B_shape))) + self.__Xb = Persistence.OneVector("Background", basetype=numpy.matrix) + for member in asPersistentVector: + self.__Xb.store( numpy.matrix( numpy.ravel(member), numpy.float ).T ) + __Xb_shape = min(__B_shape) + else: + raise ValueError("Shape characteristic of a priori errors covariance matrix (B) \"%s\" and background (Xb) \"%s\" are incompatible."%(__B_shape,__Xb_shape)) + # + if self.__R is not None and len(self.__R) > 0 and not( __R_shape[1] == max(__Y_shape) ): + raise ValueError("Shape characteristic of observation errors covariance matrix (R) \"%s\" and observation (Y) \"%s\" are incompatible."%(__R_shape,__Y_shape)) + # + if self.__EM is not None and len(self.__EM) > 0 and not(type(self.__EM) is type({})) and not( __EM_shape[1] == max(__Xb_shape) ): + raise ValueError("Shape characteristic of evolution model (EM) \"%s\" and state (X) \"%s\" are incompatible."%(__EM_shape,__Xb_shape)) + # + if self.__CM is not None and len(self.__CM) > 0 and not(type(self.__CM) is type({})) and not( __CM_shape[1] == max(__U_shape) ): + raise ValueError("Shape characteristic of control model (CM) \"%s\" and control (U) \"%s\" are incompatible."%(__CM_shape,__U_shape)) + # + if ("Bounds" in self.__P) \ + and (isinstance(self.__P["Bounds"], list) or isinstance(self.__P["Bounds"], tuple)) \ + and (len(self.__P["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.__P["Bounds"]),max(__Xb_shape))) + # + return 1 # ============================================================================== class DataObserver(object): """ - Classe générale d'interface de type observer + Classe générale d'interface de type observer """ def __init__(self, - name = "GenericObserver", - onVariable = None, - asTemplate = None, - asString = None, - asScript = None, - withInfo = None, + name = "GenericObserver", + onVariable = None, + asTemplate = None, + asString = None, + asScript = None, + asObsObject = None, + withInfo = None, + scheduledBy = None, + withAlgo = None, ): + """ + """ self.__name = str(name) self.__V = None self.__O = None self.__I = None # if onVariable is None: - raise ValueError("setting an observer has to be done over a variable name, not over None.") - else: - self.__V = str(onVariable) - # - if withInfo is None: - self.__I = str(onVariable) + raise ValueError("setting an observer has to be done over a variable name or a list of variable names, not over None.") + elif type(onVariable) in (tuple, list): + self.__V = tuple(map( str, onVariable )) + if withInfo is None: + self.__I = self.__V + else: + self.__I = (str(withInfo),)*len(self.__V) + elif isinstance(onVariable, str): + self.__V = (onVariable,) + if withInfo is None: + self.__I = (onVariable,) + else: + self.__I = (str(withInfo),) else: - self.__I = str(withInfo) + raise ValueError("setting an observer has to be done over a variable name or a list of variable names.") # if asString is not None: __FunctionText = asString - elif (asTemplate is not None) and (asTemplate in ObserverTemplates): - __FunctionText = ObserverTemplates[asTemplate] + elif (asTemplate is not None) and (asTemplate in Templates.ObserverTemplates): + __FunctionText = Templates.ObserverTemplates[asTemplate] elif asScript is not None: __FunctionText = ImportFromScript(asScript).getstring() else: __FunctionText = "" __Function = ObserverF(__FunctionText) # - self.__O = __Function.getfunc() + if asObsObject is not None: + self.__O = asObsObject + else: + self.__O = __Function.getfunc() # - return {self.__V:(self.__O, self.__I)} + for k in range(len(self.__V)): + ename = self.__V[k] + einfo = self.__I[k] + if ename not in withAlgo: + raise ValueError("An observer is asked to be set on a variable named %s which does not exist."%ename) + else: + withAlgo.setObserver(ename, self.__O, einfo, scheduledBy) def __repr__(self): "x.__repr__() <==> repr(x)" @@ -637,26 +1274,26 @@ class DataObserver(object): # ============================================================================== class State(object): """ - Classe générale d'interface de type état + Classe générale d'interface de type état """ def __init__(self, name = "GenericVector", asVector = None, asPersistentVector = None, asScript = None, - Scheduler = None, + scheduledBy = None, toBeChecked = False, ): """ - Permet de définir un vecteur : - - asVector : entrée des données, comme un vecteur compatible avec le - constructeur de numpy.matrix, ou "True" si entrée par script. - - asPersistentVector : entrée des données, comme une série de vecteurs + Permet de définir un vecteur : + - asVector : entrée des données, comme un vecteur compatible avec le + constructeur de numpy.matrix, ou "True" si entrée par script. + - asPersistentVector : entrée des données, comme une série de vecteurs compatible avec le constructeur de numpy.matrix, ou comme un objet de - type Persistence, ou "True" si entrée par script. - - asScript : si un script valide est donné contenant une variable - nommée "name", la variable est de type "asVector" (par défaut) ou - "asPersistentVector" selon que l'une de ces variables est placée à + type Persistence, ou "True" si entrée par script. + - asScript : si un script valide est donné contenant une variable + nommée "name", la variable est de type "asVector" (par défaut) ou + "asPersistentVector" selon que l'une de ces variables est placée à "True". """ self.__name = str(name) @@ -678,12 +1315,12 @@ class State(object): # if __Vector is not None: self.__is_vector = True - self.__V = numpy.matrix( numpy.ravel(numpy.matrix(asVector)), numpy.float ).T + self.__V = numpy.matrix( numpy.asmatrix(__Vector).A1, numpy.float ).T self.shape = self.__V.shape self.size = self.__V.size elif __Series is not None: self.__is_series = True - if type(__Series) in [tuple, list, numpy.ndarray, numpy.matrix]: + if type(__Series) in (tuple, list, numpy.ndarray, numpy.matrix): self.__V = Persistence.OneVector(self.__name, basetype=numpy.matrix) for member in __Series: self.__V.store( numpy.matrix( numpy.asmatrix(member).A1, numpy.float ).T ) @@ -694,19 +1331,29 @@ class State(object): self.shape = self.__V.shape else: self.shape = self.__V.shape() + if len(self.shape) == 1: + self.shape = (self.shape[0],1) self.size = self.shape[0] * self.shape[1] else: raise ValueError("The %s object is improperly defined, it requires at minima either a vector, a list/tuple of vectors or a persistent object. Please check your vector input."%self.__name) # - if Scheduler is not None: - self.__T = Scheduler + if scheduledBy is not None: + self.__T = scheduledBy + + def getO(self, withScheduler=False): + if withScheduler: + return self.__V, self.__T + elif self.__T is None: + return self.__V + else: + return self.__V def isvector(self): - "Vérification du type interne" + "Vérification du type interne" return self.__is_vector def isseries(self): - "Vérification du type interne" + "Vérification du type interne" return self.__is_series def __repr__(self): @@ -720,7 +1367,7 @@ class State(object): # ============================================================================== class Covariance(object): """ - Classe générale d'interface de type covariance + Classe générale d'interface de type covariance """ def __init__(self, name = "GenericCovariance", @@ -732,21 +1379,21 @@ class Covariance(object): toBeChecked = False, ): """ - Permet de définir une covariance : - - asCovariance : entrée des données, comme une matrice compatible avec + Permet de définir une covariance : + - asCovariance : entrée des données, comme une matrice compatible avec le constructeur de numpy.matrix - - asEyeByScalar : entrée des données comme un seul scalaire de variance, - multiplicatif d'une matrice de corrélation identité, aucune matrice - n'étant donc explicitement à donner - - asEyeByVector : entrée des données comme un seul vecteur de variance, - à mettre sur la diagonale d'une matrice de corrélation, aucune matrice - n'étant donc explicitement à donner - - asCovObject : entrée des données comme un objet python, qui a les + - asEyeByScalar : entrée des données comme un seul scalaire de variance, + multiplicatif d'une matrice de corrélation identité, aucune matrice + n'étant donc explicitement à donner + - asEyeByVector : entrée des données comme un seul vecteur de variance, + à mettre sur la diagonale d'une matrice de corrélation, aucune matrice + n'étant donc explicitement à donner + - asCovObject : entrée des données comme un objet python, qui a les methodes obligatoires "getT", "getI", "diag", "trace", "__add__", "__sub__", "__neg__", "__mul__", "__rmul__" et facultatives "shape", "size", "cholesky", "choleskyI", "asfullmatrix", "__repr__", "__str__" - - toBeChecked : booléen indiquant si le caractère SDP de la matrice - pleine doit être vérifié + - toBeChecked : booléen indiquant si le caractère SDP de la matrice + pleine doit être vérifié """ self.__name = str(name) self.__check = bool(toBeChecked) @@ -760,13 +1407,13 @@ class Covariance(object): if asScript is not None: __Matrix, __Scalar, __Vector, __Object = None, None, None, None if asEyeByScalar: - __Scalar = _ImportFromScript(asScript).getvalue( "BackgroundError" ) + __Scalar = ImportFromScript(asScript).getvalue( self.__name ) elif asEyeByVector: - __Vector = _ImportFromScript(asScript).getvalue( "BackgroundError" ) + __Vector = ImportFromScript(asScript).getvalue( self.__name ) elif asCovObject: - __Object = _ImportFromScript(asScript).getvalue( "BackgroundError" ) + __Object = ImportFromScript(asScript).getvalue( self.__name ) else: - __Matrix = _ImportFromScript(asScript).getvalue( "BackgroundError" ) + __Matrix = ImportFromScript(asScript).getvalue( self.__name ) else: __Matrix, __Scalar, __Vector, __Object = asCovariance, asEyeByScalar, asEyeByVector, asCovObject # @@ -829,19 +1476,19 @@ class Covariance(object): raise ValueError("The %s covariance object is not symmetric positive-definite. Please check your matrix input."%(self.__name,)) def isscalar(self): - "Vérification du type interne" + "Vérification du type interne" return self.__is_scalar def isvector(self): - "Vérification du type interne" + "Vérification du type interne" return self.__is_vector def ismatrix(self): - "Vérification du type interne" + "Vérification du type interne" return self.__is_matrix def isobject(self): - "Vérification du type interne" + "Vérification du type interne" return self.__is_object def getI(self): @@ -869,7 +1516,7 @@ class Covariance(object): return Covariance(self.__name+"T", asCovObject = self.__C.getT() ) def cholesky(self): - "Décomposition de Cholesky" + "Décomposition de Cholesky" if self.ismatrix(): return Covariance(self.__name+"C", asCovariance = numpy.linalg.cholesky(self.__C) ) elif self.isvector(): @@ -880,7 +1527,7 @@ class Covariance(object): return Covariance(self.__name+"C", asCovObject = self.__C.cholesky() ) def choleskyI(self): - "Inversion de la décomposition de Cholesky" + "Inversion de la décomposition de Cholesky" if self.ismatrix(): return Covariance(self.__name+"H", asCovariance = numpy.linalg.cholesky(self.__C).I ) elif self.isvector(): @@ -932,6 +1579,9 @@ class Covariance(object): elif self.isobject(): return self.__C.trace() + def getO(self): + return self + def __repr__(self): "x.__repr__() <==> repr(x)" return repr(self.__C) @@ -1050,22 +1700,22 @@ class ImportFromScript(object): """ def __init__(self, __filename=None): "Verifie l'existence et importe le script" - __filename = __filename.rstrip(".py") - if __filename is None: + self.__filename = __filename.rstrip(".py") + if self.__filename is None: raise ValueError("The name of the file containing the variable to be imported has to be specified.") - if not os.path.isfile(str(__filename)+".py"): - raise ValueError("The file containing the variable to be imported doesn't seem to exist. The given file name is:\n \"%s\""%__filename) - self.__scriptfile = __import__(__filename, globals(), locals(), []) - self.__scriptstring = open(__filename+".py",'r').read() + if not os.path.isfile(str(self.__filename)+".py"): + raise ValueError("The file containing the variable to be imported doesn't seem to exist. The given file name is:\n \"%s\""%self.__filename) + self.__scriptfile = __import__(self.__filename, globals(), locals(), []) + self.__scriptstring = open(self.__filename+".py",'r').read() def getvalue(self, __varname=None, __synonym=None ): "Renvoie la variable demandee" if __varname is None: raise ValueError("The name of the variable to be imported has to be specified.") if not hasattr(self.__scriptfile, __varname): if __synonym is None: - raise ValueError("The imported script file doesn't contain the specified variable \"%s\"."%__varname) + raise ValueError("The imported script file \"%s\" doesn't contain the specified variable \"%s\"."%(str(self.__filename)+".py",__varname)) elif not hasattr(self.__scriptfile, __synonym): - raise ValueError("The imported script file doesn't contain the specified variable \"%s\"."%__synonym) + raise ValueError("The imported script file \"%s\" doesn't contain the specified variable \"%s\"."%(str(self.__filename)+".py",__synonym)) else: return getattr(self.__scriptfile, __synonym) else: @@ -1077,23 +1727,23 @@ class ImportFromScript(object): # ============================================================================== def CostFunction3D(_x, _Hm = None, # Pour simuler Hm(x) : HO["Direct"].appliedTo - _HmX = None, # Simulation déjà faite de Hm(x) + _HmX = None, # Simulation déjà faite de Hm(x) _arg = None, # Arguments supplementaires pour Hm, sous la forme d'un tuple _BI = None, _RI = None, _Xb = None, _Y = None, - _SIV = False, # A résorber pour la 8.0 + _SIV = False, # A résorber pour la 8.0 _SSC = [], # self._parameters["StoreSupplementaryCalculations"] _nPS = 0, # nbPreviousSteps _QM = "DA", # QualityMeasure - _SSV = {}, # Entrée et/ou sortie : self.StoredVariables - _fRt = False, # Restitue ou pas la sortie étendue + _SSV = {}, # Entrée et/ou sortie : self.StoredVariables + _fRt = False, # Restitue ou pas la sortie étendue _sSc = True, # Stocke ou pas les SSC ): """ - Fonction-coût générale utile pour les algorithmes statiques/3D : 3DVAR, BLUE - et dérivés, Kalman et dérivés, LeastSquares, SamplingTest, PSO, SA, Tabu, + Fonction-coût générale utile pour les algorithmes statiques/3D : 3DVAR, BLUE + et dérivés, Kalman et dérivés, LeastSquares, SamplingTest, PSO, SA, Tabu, DFO, QuantileRegression """ if not _sSc: diff --git a/src/daComposant/daCore/ExtendedLogging.py b/src/daComposant/daCore/ExtendedLogging.py index 8ed4948..7f0fc5d 100644 --- a/src/daComposant/daCore/ExtendedLogging.py +++ b/src/daComposant/daCore/ExtendedLogging.py @@ -1,4 +1,4 @@ -#-*-coding:iso-8859-1-*- +# -*- coding: utf-8 -*- # # Copyright (C) 2008-2017 EDF R&D # @@ -22,36 +22,36 @@ """ 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. + 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 + Il doit être appelé en premier dans AssimilationStudy (mais pas directement dans les applications utilisateurs), en l'important et en instanciant un objet : import ExtendedLogging ; ExtendedLogging.ExtendedLogging() - Par défaut, seuls les messages du niveau WARNING ou au-delà sont disponibles + Par défaut, seuls les messages du niveau WARNING ou au-delà sont disponibles (donc les simples messages d'info ne sont pas disponibles), ce que l'on peut - changer à l'instanciation avec le mot-clé "level" : + changer à l'instanciation avec le mot-clé "level" : import ExtendedLogging ; ExtendedLogging.ExtendedLogging(level=20) - On peut éventuellement demander à l'objet de sortir aussi les messages dans - un fichier (noms par défaut : AssimilationStudy.log, niveau NOTSET) : + On peut éventuellement demander à l'objet de sortir aussi les messages dans + un fichier (noms par défaut : AssimilationStudy.log, niveau NOTSET) : import ExtendedLogging ; ExtendedLogging.ExtendedLogging().setLogfile() Si on veut changer le nom du fichier ou le niveau global de message, il faut - récupérer l'instance et appliquer les méthodes : + récupérer l'instance et appliquer les méthodes : import ExtendedLogging log = ExtendedLogging.ExtendedLogging() import logging log.setLevel(logging.DEBUG) log.setLogfile(filename="toto.log", filemode="a", level=logging.WARNING) - et on change éventuellement le niveau avec : + et on change éventuellement le niveau avec : log.setLogfileLevel(logging.INFO) - Ensuite, n'importe où dans les applications, il suffit d'utiliser le module + Ensuite, n'importe où dans les applications, il suffit d'utiliser le module "logging" (avec un petit "l") : import logging - log = logging.getLogger(NAME) # Avec rien (recommandé) ou un nom NAME + log = logging.getLogger(NAME) # Avec rien (recommandé) ou un nom NAME log.critical("...") log.error("...") log.warning("...") @@ -61,10 +61,10 @@ import logging logging.info("...") - Dans une application, à n'importe quel endroit et autant de fois qu'on veut, + Dans une application, à n'importe quel endroit et autant de fois qu'on veut, on peut changer le niveau global de message en utilisant par exemple : import logging - log = logging.getLogger(NAME) # Avec rien (recommandé) ou un nom NAME + 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 : @@ -83,12 +83,12 @@ LOGFILE = os.path.join(os.path.abspath(os.curdir),"AssimilationStudy.log") # ============================================================================== class ExtendedLogging(object): """ - Logger général pour disposer conjointement de la sortie standard et de la + Logger général pour disposer conjointement de la sortie standard et de la sortie sur fichier """ def __init__(self, level=logging.WARNING): """ - Initialise un logging à la console pour TOUS les niveaux de messages. + Initialise un logging à la console pour TOUS les niveaux de messages. """ logging.basicConfig( format = '%(levelname)-8s %(message)s', @@ -123,7 +123,7 @@ class ExtendedLogging(object): Permet de disposer des messages dans un fichier EN PLUS de la console. """ if self.__logfile is not None: - # Supprime le précédent mode de stockage fichier s'il exsitait + # Supprime le précédent mode de stockage fichier s'il exsitait logging.getLogger().removeHandler(self.__logfile) self.__logfile = logging.FileHandler(filename, filemode) self.__logfile.setLevel(level) @@ -134,8 +134,8 @@ class ExtendedLogging(object): def setLogfileLevel(self, level=logging.NOTSET ): """ - Permet de changer le niveau des messages stockés en fichier. Il ne sera - pris en compte que s'il est supérieur au niveau global. + Permet de changer le niveau des messages stockés en fichier. Il ne sera + pris en compte que s'il est supérieur au niveau global. """ self.__logfile.setLevel(level) diff --git a/src/daComposant/daCore/Persistence.py b/src/daComposant/daCore/Persistence.py index d867d07..c2bbd48 100644 --- a/src/daComposant/daCore/Persistence.py +++ b/src/daComposant/daCore/Persistence.py @@ -1,4 +1,4 @@ -#-*-coding:iso-8859-1-*- +# -*- coding: utf-8 -*- # # Copyright (C) 2008-2017 EDF R&D # @@ -21,8 +21,8 @@ # Author: Jean-Philippe Argaud, jean-philippe.argaud@edf.fr, EDF R&D """ - Définit des outils de persistence et d'enregistrement de séries de valeurs - pour analyse ultérieure ou utilisation de calcul. + Définit des outils de persistence et d'enregistrement de séries de valeurs + pour analyse ultérieure ou utilisation de calcul. """ __author__ = "Jean-Philippe ARGAUD" __all__ = [] @@ -31,24 +31,32 @@ import sys, numpy, copy from daCore.PlatformInfo import PathManagement ; PathManagement() +if sys.version_info.major < 3: + range = xrange + iLong = long + import cPickle as pickle +else: + iLong = int + import pickle + # ============================================================================== class Persistence(object): """ - Classe générale de persistence définissant les accesseurs nécessaires + Classe générale de persistence définissant les accesseurs nécessaires (Template) """ def __init__(self, name="", unit="", basetype=str): """ name : nom courant - unit : unité - basetype : type de base de l'objet stocké à chaque pas + unit : unité + basetype : type de base de l'objet stocké à chaque pas - La gestion interne des données est exclusivement basée sur les variables - initialisées ici (qui ne sont pas accessibles depuis l'extérieur des + La gestion interne des données est exclusivement basée sur les variables + initialisées ici (qui ne sont pas accessibles depuis l'extérieur des objets comme des attributs) : __basetype : le type de base de chaque valeur, sous la forme d'un type permettant l'instanciation ou le casting Python - __values : les valeurs de stockage. Par défaut, c'est None + __values : les valeurs de stockage. Par défaut, c'est None """ self.__name = str(name) self.__unit = str(unit) @@ -69,7 +77,7 @@ class Persistence(object): def basetype(self, basetype=None): """ - Renvoie ou met en place le type de base des objets stockés + Renvoie ou met en place le type de base des objets stockés """ if basetype is None: return self.__basetype @@ -106,10 +114,10 @@ class Persistence(object): def shape(self): """ - Renvoie la taille sous forme numpy du dernier objet stocké. Si c'est un + Renvoie la taille sous forme numpy du dernier objet stocké. Si c'est un objet numpy, renvoie le shape. Si c'est un entier, un flottant, un complexe, renvoie 1. Si c'est une liste ou un dictionnaire, renvoie la - longueur. Par défaut, renvoie 1. + longueur. Par défaut, renvoie 1. """ if len(self.__values) > 0: if self.__basetype in [numpy.matrix, numpy.ndarray, numpy.array, numpy.ravel]: @@ -198,9 +206,8 @@ class Persistence(object): "D.tagkeys() -> list of D's tag keys" __allKeys = [] for dicotags in self.__tags: - __allKeys.extend( dicotags.keys() ) - __allKeys = list(set(__allKeys)) - __allKeys.sort() + __allKeys.extend( list(dicotags.keys()) ) + __allKeys = sorted(set(__allKeys)) return __allKeys # def valueserie(self, item=None, allSteps=True, **kwargs): @@ -220,17 +227,16 @@ class Persistence(object): else: __indexOfFilteredItems = [item,] # - # Dans le cas où la sortie donne les valeurs d'un "outputTag" + # Dans le cas où la sortie donne les valeurs d'un "outputTag" if outputTag is not None and isinstance(outputTag,str) : outputValues = [] for index in __indexOfFilteredItems: if outputTag in self.__tags[index].keys(): outputValues.append( self.__tags[index][outputTag] ) - outputValues = list(set(outputValues)) - outputValues.sort() + outputValues = sorted(set(outputValues)) return outputValues # - # Dans le cas où la sortie donne les tags satisfaisants aux conditions + # Dans le cas où la sortie donne les tags satisfaisants aux conditions else: if withValues: return [self.__tags[index] for index in __indexOfFilteredItems] @@ -238,8 +244,7 @@ class Persistence(object): allTags = {} for index in __indexOfFilteredItems: allTags.update( self.__tags[index] ) - allKeys = list(allTags.keys()) - allKeys.sort() + allKeys = sorted(allTags.keys()) return allKeys # --------------------------------------------------------- @@ -250,16 +255,22 @@ class Persistence(object): # Pour compatibilite def stepserie(self, **kwargs): - "Nombre de pas filtrés" + "Nombre de pas filtrés" __indexOfFilteredItems = self.__filteredIndexes(**kwargs) return __indexOfFilteredItems + # Pour compatibilite + def steplist(self, **kwargs): + "Nombre de pas filtrés" + __indexOfFilteredItems = self.__filteredIndexes(**kwargs) + return list(__indexOfFilteredItems) + # --------------------------------------------------------- def means(self): """ - Renvoie la série, contenant à chaque pas, la valeur moyenne des données + Renvoie la série, contenant à chaque pas, la valeur moyenne des données au pas. Il faut que le type de base soit compatible avec les types - élémentaires numpy. + élémentaires numpy. """ try: return [numpy.matrix(item).mean() for item in self.__values] @@ -268,12 +279,12 @@ class Persistence(object): def stds(self, ddof=0): """ - Renvoie la série, contenant à chaque pas, l'écart-type des données + Renvoie la série, contenant à chaque pas, l'écart-type des données au pas. Il faut que le type de base soit compatible avec les types - élémentaires numpy. + élémentaires numpy. - ddof : c'est le nombre de degrés de liberté pour le calcul de - l'écart-type, qui est dans le diviseur. Inutile avant Numpy 1.1 + ddof : c'est le nombre de degrés de liberté pour le calcul de + l'écart-type, qui est dans le diviseur. Inutile avant Numpy 1.1 """ try: if numpy.version.version >= '1.1.0': @@ -285,8 +296,8 @@ class Persistence(object): def sums(self): """ - Renvoie la série, contenant à chaque pas, la somme des données au pas. - Il faut que le type de base soit compatible avec les types élémentaires + Renvoie la série, contenant à chaque pas, la somme des données au pas. + Il faut que le type de base soit compatible avec les types élémentaires numpy. """ try: @@ -296,8 +307,8 @@ class Persistence(object): def mins(self): """ - Renvoie la série, contenant à chaque pas, le minimum des données au pas. - Il faut que le type de base soit compatible avec les types élémentaires + Renvoie la série, contenant à chaque pas, le minimum des données au pas. + Il faut que le type de base soit compatible avec les types élémentaires numpy. """ try: @@ -307,8 +318,8 @@ class Persistence(object): def maxs(self): """ - Renvoie la série, contenant à chaque pas, la maximum des données au pas. - Il faut que le type de base soit compatible avec les types élémentaires + Renvoie la série, contenant à chaque pas, la maximum des données au pas. + Il faut que le type de base soit compatible avec les types élémentaires numpy. """ try: @@ -325,16 +336,16 @@ class Persistence(object): persist = False, pause = True, ): - "Préparation des plots" + "Préparation des plots" # - # Vérification de la disponibilité du module Gnuplot + # Vérification de la disponibilité du module Gnuplot try: import Gnuplot self.__gnuplot = Gnuplot except: raise ImportError("The Gnuplot module is required to plot the object.") # - # Vérification et compléments sur les paramètres d'entrée + # Vérification et compléments sur les paramètres d'entrée if persist: self.__gnuplot.GnuplotOpts.gnuplot_command = 'gnuplot -persist -geometry '+geometry else: @@ -346,8 +357,8 @@ class Persistence(object): self.__g('set style data lines') self.__g('set grid') self.__g('set autoscale') - self.__g('set xlabel "'+str(xlabel).encode('ascii','replace')+'"') - self.__g('set ylabel "'+str(ylabel).encode('ascii','replace')+'"') + self.__g('set xlabel "'+str(xlabel)+'"') + self.__g('set ylabel "'+str(ylabel)+'"') self.__title = title self.__ltitle = ltitle self.__pause = pause @@ -367,39 +378,39 @@ class Persistence(object): pause = True, ): """ - Renvoie un affichage de la valeur à chaque pas, si elle est compatible + Renvoie un affichage de la valeur à chaque pas, si elle est compatible avec un affichage Gnuplot (donc essentiellement un vecteur). Si - l'argument "step" existe dans la liste des pas de stockage effectués, - renvoie l'affichage de la valeur stockée à ce pas "step". Si l'argument - "item" est correct, renvoie l'affichage de la valeur stockée au numéro - "item". Par défaut ou en l'absence de "step" ou "item", renvoie un + l'argument "step" existe dans la liste des pas de stockage effectués, + renvoie l'affichage de la valeur stockée à ce pas "step". Si l'argument + "item" est correct, renvoie l'affichage de la valeur stockée au numéro + "item". Par défaut ou en l'absence de "step" ou "item", renvoie un affichage successif de tous les pas. Arguments : - - step : valeur du pas à afficher - - item : index de la valeur à afficher + - step : valeur du pas à afficher + - item : index de la valeur à afficher - steps : liste unique des pas de l'axe des X, ou None si c'est - la numérotation par défaut - - title : base du titre général, qui sera automatiquement - complétée par la mention du pas + la numérotation par défaut + - title : base du titre général, qui sera automatiquement + complétée par la mention du pas - xlabel : label de l'axe des X - ylabel : label de l'axe des Y - - ltitle : titre associé au vecteur tracé - - geometry : taille en pixels de la fenêtre et position du coin haut - gauche, au format X11 : LxH+X+Y (défaut : 600x400) + - ltitle : titre associé au vecteur tracé + - geometry : taille en pixels de la fenêtre et position du coin haut + gauche, au format X11 : LxH+X+Y (défaut : 600x400) - filename : base de nom de fichier Postscript pour une sauvegarde, - qui est automatiquement complétée par le numéro du - fichier calculé par incrément simple de compteur - - dynamic : effectue un affichage des valeurs à chaque stockage - (au-delà du second). La méthode "plots" permet de - déclarer l'affichage dynamique, et c'est la méthode - "__replots" qui est utilisée pour l'effectuer - - persist : booléen indiquant que la fenêtre affichée sera - conservée lors du passage au dessin suivant - Par défaut, persist = False - - pause : booléen indiquant une pause après chaque tracé, et + qui est automatiquement complétée par le numéro du + fichier calculé par incrément simple de compteur + - dynamic : effectue un affichage des valeurs à chaque stockage + (au-delà du second). La méthode "plots" permet de + déclarer l'affichage dynamique, et c'est la méthode + "__replots" qui est utilisée pour l'effectuer + - persist : booléen indiquant que la fenêtre affichée sera + conservée lors du passage au dessin suivant + Par défaut, persist = False + - pause : booléen indiquant une pause après chaque tracé, et attendant un Return - Par défaut, pause = True + Par défaut, pause = True """ import os if not self.__dynamic: @@ -408,22 +419,22 @@ class Persistence(object): self.__dynamic = True if len(self.__values) == 0: return 0 # - # Tracé du ou des vecteurs demandés + # Tracé du ou des vecteurs demandés indexes = [] if step is not None and step < len(self.__values): indexes.append(step) elif item is not None and item < len(self.__values): indexes.append(item) else: - indexes = indexes + range(len(self.__values)) + indexes = indexes + list(range(len(self.__values))) # i = -1 for index in indexes: - self.__g('set title "'+str(title).encode('ascii','replace')+' (pas '+str(index)+')"') + self.__g('set title "'+str(title)+' (pas '+str(index)+')"') if isinstance(steps,list) or isinstance(steps,numpy.ndarray): Steps = list(steps) else: - Steps = range(len(self.__values[index])) + Steps = list(range(len(self.__values[index]))) # self.__g.plot( self.__gnuplot.Data( Steps, self.__values[index], title=ltitle ) ) # @@ -434,7 +445,7 @@ class Persistence(object): raise ValueError("Error: a file with this name \"%s\" already exists."%stepfilename) self.__g.hardcopy(filename=stepfilename, color=1) if self.__pause: - raw_input('Please press return to continue...\n') + eval(input('Please press return to continue...\n')) def __replots(self): """ @@ -442,19 +453,19 @@ class Persistence(object): """ if self.__dynamic and len(self.__values) < 2: return 0 # - self.__g('set title "'+str(self.__title).encode('ascii','replace')) - Steps = range(len(self.__values)) + self.__g('set title "'+str(self.__title)) + Steps = list(range(len(self.__values))) self.__g.plot( self.__gnuplot.Data( Steps, self.__values, title=self.__ltitle ) ) # if self.__pause: - raw_input('Please press return to continue...\n') + eval(input('Please press return to continue...\n')) # --------------------------------------------------------- def mean(self): """ Renvoie la moyenne sur toutes les valeurs sans tenir compte de la longueur des pas. Il faut que le type de base soit compatible avec - les types élémentaires numpy. + les types élémentaires numpy. """ try: if self.__basetype in [int, float]: @@ -466,12 +477,12 @@ class Persistence(object): def std(self, ddof=0): """ - Renvoie l'écart-type de toutes les valeurs sans tenir compte de la + Renvoie l'écart-type de toutes les valeurs sans tenir compte de la longueur des pas. Il faut que le type de base soit compatible avec - les types élémentaires numpy. + les types élémentaires numpy. - ddof : c'est le nombre de degrés de liberté pour le calcul de - l'écart-type, qui est dans le diviseur. Inutile avant Numpy 1.1 + ddof : c'est le nombre de degrés de liberté pour le calcul de + l'écart-type, qui est dans le diviseur. Inutile avant Numpy 1.1 """ try: if numpy.version.version >= '1.1.0': @@ -485,7 +496,7 @@ class Persistence(object): """ Renvoie la somme de toutes les valeurs sans tenir compte de la longueur des pas. Il faut que le type de base soit compatible avec - les types élémentaires numpy. + les types élémentaires numpy. """ try: return numpy.array(self.__values).sum(axis=0) @@ -496,7 +507,7 @@ class Persistence(object): """ Renvoie le minimum de toutes les valeurs sans tenir compte de la longueur des pas. Il faut que le type de base soit compatible avec - les types élémentaires numpy. + les types élémentaires numpy. """ try: return numpy.array(self.__values).min(axis=0) @@ -507,7 +518,7 @@ class Persistence(object): """ Renvoie le maximum de toutes les valeurs sans tenir compte de la longueur des pas. Il faut que le type de base soit compatible avec - les types élémentaires numpy. + les types élémentaires numpy. """ try: return numpy.array(self.__values).max(axis=0) @@ -516,9 +527,9 @@ class Persistence(object): def cumsum(self): """ - Renvoie la somme cumulée de toutes les valeurs sans tenir compte de la + Renvoie la somme cumulée de toutes les valeurs sans tenir compte de la longueur des pas. Il faut que le type de base soit compatible avec - les types élémentaires numpy. + les types élémentaires numpy. """ try: return numpy.array(self.__values).cumsum(axis=0) @@ -540,40 +551,40 @@ class Persistence(object): pause = True, ): """ - Renvoie un affichage unique pour l'ensemble des valeurs à chaque pas, si + Renvoie un affichage unique pour l'ensemble des valeurs à chaque pas, si elles sont compatibles avec un affichage Gnuplot (donc essentiellement un vecteur). Si l'argument "step" existe dans la liste des pas de - stockage effectués, renvoie l'affichage de la valeur stockée à ce pas + stockage effectués, renvoie l'affichage de la valeur stockée à ce pas "step". Si l'argument "item" est correct, renvoie l'affichage de la - valeur stockée au numéro "item". + valeur stockée au numéro "item". Arguments : - steps : liste unique des pas de l'axe des X, ou None si c'est - la numérotation par défaut - - title : base du titre général, qui sera automatiquement - complétée par la mention du pas + la numérotation par défaut + - title : base du titre général, qui sera automatiquement + complétée par la mention du pas - xlabel : label de l'axe des X - ylabel : label de l'axe des Y - - ltitle : titre associé au vecteur tracé - - geometry : taille en pixels de la fenêtre et position du coin haut - gauche, au format X11 : LxH+X+Y (défaut : 600x400) + - ltitle : titre associé au vecteur tracé + - geometry : taille en pixels de la fenêtre et position du coin haut + gauche, au format X11 : LxH+X+Y (défaut : 600x400) - filename : nom de fichier Postscript pour une sauvegarde - - persist : booléen indiquant que la fenêtre affichée sera - conservée lors du passage au dessin suivant - Par défaut, persist = False - - pause : booléen indiquant une pause après chaque tracé, et + - persist : booléen indiquant que la fenêtre affichée sera + conservée lors du passage au dessin suivant + Par défaut, persist = False + - pause : booléen indiquant une pause après chaque tracé, et attendant un Return - Par défaut, pause = True + Par défaut, pause = True """ # - # Vérification de la disponibilité du module Gnuplot + # Vérification de la disponibilité du module Gnuplot try: import Gnuplot self.__gnuplot = Gnuplot except: raise ImportError("The Gnuplot module is required to plot the object.") # - # Vérification et compléments sur les paramètres d'entrée + # Vérification et compléments sur les paramètres d'entrée if persist: self.__gnuplot.GnuplotOpts.gnuplot_command = 'gnuplot -persist -geometry '+geometry else: @@ -583,17 +594,17 @@ class Persistence(object): if isinstance(steps,list) or isinstance(steps, numpy.ndarray): Steps = list(steps) else: - Steps = range(len(self.__values[0])) + Steps = list(range(len(self.__values[0]))) self.__g = self.__gnuplot.Gnuplot() # persist=1 self.__g('set terminal '+self.__gnuplot.GnuplotOpts.default_term) self.__g('set style data lines') self.__g('set grid') self.__g('set autoscale') - self.__g('set title "'+str(title).encode('ascii','replace') +'"') - self.__g('set xlabel "'+str(xlabel).encode('ascii','replace')+'"') - self.__g('set ylabel "'+str(ylabel).encode('ascii','replace')+'"') + self.__g('set title "'+str(title) +'"') + self.__g('set xlabel "'+str(xlabel)+'"') + self.__g('set ylabel "'+str(ylabel)+'"') # - # Tracé du ou des vecteurs demandés + # Tracé du ou des vecteurs demandés indexes = list(range(len(self.__values))) self.__g.plot( self.__gnuplot.Data( Steps, self.__values[indexes.pop(0)], title=ltitle+" (pas 0)" ) ) for index in indexes: @@ -602,52 +613,45 @@ class Persistence(object): if filename != "": self.__g.hardcopy(filename=filename, color=1) if pause: - raw_input('Please press return to continue...\n') + eval(input('Please press return to continue...\n')) # --------------------------------------------------------- def setDataObserver(self, HookFunction = None, HookParameters = None, Scheduler = None): """ - Association à la variable d'un triplet définissant un observer + Association à la variable d'un triplet définissant un observer - Le Scheduler attendu est une fréquence, une simple liste d'index ou un + Le Scheduler attendu est une fréquence, une simple liste d'index ou un range des index. """ # - # Vérification du Scheduler + # Vérification du Scheduler # ------------------------- maxiter = int( 1e9 ) - if sys.version.split()[0] < '3': - if isinstance(Scheduler,int): # Considéré comme une fréquence à partir de 0 - Schedulers = xrange( 0, maxiter, int(Scheduler) ) - elif isinstance(Scheduler,xrange): # Considéré comme un itérateur - Schedulers = Scheduler - elif isinstance(Scheduler,(list,tuple)): # Considéré comme des index explicites - Schedulers = [long(i) for i in Scheduler] # map( long, Scheduler ) - else: # Dans tous les autres cas, activé par défaut - Schedulers = xrange( 0, maxiter ) - else: - if isinstance(Scheduler,int): # Considéré comme une fréquence à partir de 0 - Schedulers = range( 0, maxiter, int(Scheduler) ) - elif sys.version.split()[0] > '3' and isinstance(Scheduler,range): # Considéré comme un itérateur - Schedulers = Scheduler - elif isinstance(Scheduler,(list,tuple)): # Considéré comme des index explicites - Schedulers = [int(i) for i in Scheduler] # map( int, Scheduler ) - else: # Dans tous les autres cas, activé par défaut - Schedulers = range( 0, maxiter ) + if isinstance(Scheduler,int): # Considéré comme une fréquence à partir de 0 + Schedulers = range( 0, maxiter, int(Scheduler) ) + elif isinstance(Scheduler,range): # Considéré comme un itérateur + Schedulers = Scheduler + elif isinstance(Scheduler,(list,tuple)): # Considéré comme des index explicites + Schedulers = [iLong(i) for i in Scheduler] # map( long, Scheduler ) + else: # Dans tous les autres cas, activé par défaut + Schedulers = range( 0, maxiter ) # # Stockage interne de l'observer dans la variable # ----------------------------------------------- self.__dataobservers.append( [HookFunction, HookParameters, Schedulers] ) - def removeDataObserver(self, HookFunction = None): + def removeDataObserver(self, HookFunction = None, AllObservers = False): """ - Suppression d'un observer nommé sur la variable. + Suppression d'un observer nommé sur la variable. On peut donner dans HookFunction la meme fonction que lors de la - définition, ou un simple string qui est le nom de la fonction. + définition, ou un simple string qui est le nom de la fonction. Si + AllObservers est vrai, supprime tous les observers enregistrés. """ if hasattr(HookFunction,"func_name"): name = str( HookFunction.func_name ) + elif hasattr(HookFunction,"__name__"): + name = str( HookFunction.__name__ ) elif isinstance(HookFunction,str): name = str( HookFunction ) else: @@ -657,20 +661,24 @@ class Persistence(object): index_to_remove = [] for [hf, hp, hs] in self.__dataobservers: i = i + 1 - if name is hf.__name__: index_to_remove.append( i ) + if name is hf.__name__ or AllObservers: index_to_remove.append( i ) index_to_remove.reverse() for i in index_to_remove: self.__dataobservers.pop( i ) + return len(index_to_remove) + + def hasDataObserver(self): + return bool(len(self.__dataobservers) > 0) # ============================================================================== class OneScalar(Persistence): """ - Classe définissant le stockage d'une valeur unique réelle (float) par pas. + Classe définissant le stockage d'une valeur unique réelle (float) par pas. - Le type de base peut être changé par la méthode "basetype", mais il faut que - le nouveau type de base soit compatible avec les types par éléments de - numpy. On peut même utiliser cette classe pour stocker des vecteurs/listes - ou des matrices comme dans les classes suivantes, mais c'est déconseillé + Le type de base peut être changé par la méthode "basetype", mais il faut que + le nouveau type de base soit compatible avec les types par éléments de + numpy. On peut même utiliser cette classe pour stocker des vecteurs/listes + ou des matrices comme dans les classes suivantes, mais c'est déconseillé pour conserver une signification claire des noms. """ def __init__(self, name="", unit="", basetype = float): @@ -678,15 +686,15 @@ class OneScalar(Persistence): class OneIndex(Persistence): """ - Classe définissant le stockage d'une valeur unique entière (int) par pas. + Classe définissant le stockage d'une valeur unique entière (int) par pas. """ def __init__(self, name="", unit="", basetype = int): Persistence.__init__(self, name, unit, basetype) class OneVector(Persistence): """ - Classe de stockage d'une liste de valeurs numériques homogènes par pas. Ne - pas utiliser cette classe pour des données hétérogènes, mais "OneList". + Classe de stockage d'une liste de valeurs numériques homogènes par pas. Ne + pas utiliser cette classe pour des données hétérogènes, mais "OneList". """ def __init__(self, name="", unit="", basetype = numpy.ravel): Persistence.__init__(self, name, unit, basetype) @@ -700,8 +708,8 @@ class OneMatrix(Persistence): class OneList(Persistence): """ - Classe de stockage d'une liste de valeurs hétérogènes (list) par pas. Ne pas - utiliser cette classe pour des données numériques homogènes, mais + Classe de stockage d'une liste de valeurs hétérogènes (list) par pas. Ne pas + utiliser cette classe pour des données numériques homogènes, mais "OneVector". """ def __init__(self, name="", unit="", basetype = list): @@ -714,10 +722,10 @@ def NoType( value ): class OneNoType(Persistence): """ Classe de stockage d'un objet sans modification (cast) de type. Attention, - selon le véritable type de l'objet stocké à chaque pas, les opérations - arithmétiques à base de numpy peuvent être invalides ou donner des résultats - inattendus. Cette classe n'est donc à utiliser qu'à bon escient - volontairement, et pas du tout par défaut. + selon le véritable type de l'objet stocké à chaque pas, les opérations + arithmétiques à base de numpy peuvent être invalides ou donner des résultats + inattendus. Cette classe n'est donc à utiliser qu'à bon escient + volontairement, et pas du tout par défaut. """ def __init__(self, name="", unit="", basetype = NoType): Persistence.__init__(self, name, unit, basetype) @@ -728,17 +736,17 @@ class CompositePersistence(object): Structure de stockage permettant de rassembler plusieurs objets de persistence. - Des objets par défaut sont prévus, et des objets supplémentaires peuvent - être ajoutés. + Des objets par défaut sont prévus, et des objets supplémentaires peuvent + être ajoutés. """ def __init__(self, name="", defaults=True): """ name : nom courant - La gestion interne des données est exclusivement basée sur les variables - initialisées ici (qui ne sont pas accessibles depuis l'extérieur des + La gestion interne des données est exclusivement basée sur les variables + initialisées ici (qui ne sont pas accessibles depuis l'extérieur des objets comme des attributs) : - __StoredObjects : objets de type persistence collectés dans cet objet + __StoredObjects : objets de type persistence collectés dans cet objet """ self.__name = str(name) # @@ -773,8 +781,8 @@ class CompositePersistence(object): def add_object(self, name=None, persistenceType=Persistence, basetype=None ): """ - Ajoute dans les objets stockables un nouvel objet défini par son nom, son - type de Persistence et son type de base à chaque pas. + Ajoute dans les objets stockables un nouvel objet défini par son nom, son + type de Persistence et son type de base à chaque pas. """ if name is None: raise ValueError("Object name is required for adding an object.") if name in self.__StoredObjects.keys(): @@ -786,7 +794,7 @@ class CompositePersistence(object): def get_object(self, name=None ): """ - Renvoie l'objet de type Persistence qui porte le nom demandé. + Renvoie l'objet de type Persistence qui porte le nom demandé. """ if name is None: raise ValueError("Object name is required for retrieving an object.") if name not in self.__StoredObjects.keys(): @@ -795,9 +803,9 @@ class CompositePersistence(object): def set_object(self, name=None, objet=None ): """ - Affecte directement un 'objet' qui porte le nom 'name' demandé. - Attention, il n'est pas effectué de vérification sur le type, qui doit - comporter les méthodes habituelles de Persistence pour que cela + Affecte directement un 'objet' qui porte le nom 'name' demandé. + Attention, il n'est pas effectué de vérification sur le type, qui doit + comporter les méthodes habituelles de Persistence pour que cela fonctionne. """ if name is None: raise ValueError("Object name is required for setting an object.") @@ -815,7 +823,7 @@ class CompositePersistence(object): del self.__StoredObjects[name] # --------------------------------------------------------- - # Méthodes d'accès de type dictionnaire + # Méthodes d'accès de type dictionnaire def __getitem__(self, name=None ): "x.__getitem__(y) <==> x[y]" return self.get_object( name ) @@ -838,7 +846,7 @@ class CompositePersistence(object): # --------------------------------------------------------- def get_stored_objects(self, hideVoidObjects = False): - "Renvoie la liste des objets présents" + "Renvoie la liste des objets présents" objs = self.__StoredObjects.keys() if hideVoidObjects: usedObjs = [] @@ -848,14 +856,13 @@ class CompositePersistence(object): finally: pass objs = usedObjs - objs = list(objs) - objs.sort() + objs = sorted(objs) return objs # --------------------------------------------------------- def save_composite(self, filename=None, mode="pickle", compress="gzip"): """ - Enregistre l'objet dans le fichier indiqué selon le "mode" demandé, + Enregistre l'objet dans le fichier indiqué selon le "mode" demandé, et renvoi le nom du fichier """ import os @@ -869,10 +876,6 @@ class CompositePersistence(object): else: filename = os.path.abspath( filename ) # - if sys.version.split()[0] < '3': - import cPickle as lPickle - else: - import pickle as lPickle if mode == "pickle": if compress == "gzip": import gzip @@ -882,7 +885,7 @@ class CompositePersistence(object): output = bz2.BZ2File( filename, 'wb') else: output = open( filename, 'wb') - lPickle.dump(self, output) + pickle.dump(self, output) output.close() else: raise ValueError("Save mode '%s' unknown. Choose another one."%mode) @@ -891,7 +894,7 @@ class CompositePersistence(object): def load_composite(self, filename=None, mode="pickle", compress="gzip"): """ - Recharge un objet composite sauvé en fichier + Recharge un objet composite sauvé en fichier """ import os if filename is None: @@ -899,10 +902,6 @@ class CompositePersistence(object): else: filename = os.path.abspath( filename ) # - if sys.version.split()[0] < '3': - import cPickle as lPickle - else: - import pickle as lPickle if mode == "pickle": if compress == "gzip": import gzip @@ -912,7 +911,7 @@ class CompositePersistence(object): pkl_file = bz2.BZ2File( filename, 'rb') else: pkl_file = open(filename, 'rb') - output = lPickle.load(pkl_file) + output = pickle.load(pkl_file) for k in output.keys(): self[k] = output[k] else: diff --git a/src/daComposant/daCore/PlatformInfo.py b/src/daComposant/daCore/PlatformInfo.py index f14654e..5cb44a9 100644 --- a/src/daComposant/daCore/PlatformInfo.py +++ b/src/daComposant/daCore/PlatformInfo.py @@ -1,4 +1,4 @@ -#-*-coding:iso-8859-1-*- +# -*- coding: utf-8 -*- # # Copyright (C) 2008-2017 EDF R&D # @@ -21,19 +21,19 @@ # Author: Jean-Philippe Argaud, jean-philippe.argaud@edf.fr, EDF R&D """ - Informations sur le code et la plateforme, et mise à jour des chemins + Informations sur le code et la plateforme, et mise à jour des chemins - La classe "PlatformInfo" permet de récupérer les informations générales sur + La classe "PlatformInfo" permet de récupérer les informations générales sur le code et la plateforme sous forme de strings, ou d'afficher directement - les informations disponibles par les méthodes. L'impression directe d'un + les informations disponibles par les méthodes. L'impression directe d'un objet de cette classe affiche les informations minimales. Par exemple : print PlatformInfo() print PlatformInfo().getVersion() created = PlatformInfo().getDate() - La classe "PathManagement" permet de mettre à jour les chemins système pour - ajouter les outils numériques, matrices... On l'utilise en instanciant - simplement cette classe, sans meme récupérer d'objet : + La classe "PathManagement" permet de mettre à jour les chemins système pour + ajouter les outils numériques, matrices... On l'utilise en instanciant + simplement cette classe, sans meme récupérer d'objet : PathManagement() """ __author__ = "Jean-Philippe ARGAUD" @@ -56,12 +56,12 @@ class PlatformInfo(object): return dav.name def getVersion(self): - "Retourne le numéro de la version" + "Retourne le numéro de la version" import daCore.version as dav return dav.version def getDate(self): - "Retourne la date de création de la version" + "Retourne la date de création de la version" import daCore.version as dav return dav.date @@ -119,7 +119,7 @@ class PlatformInfo(object): return "0.0.0" def getCurrentMemorySize(self): - "Retourne la taille mémoire courante utilisée" + "Retourne la taille mémoire courante utilisée" return 1 def MaximumPrecision(self): @@ -179,7 +179,7 @@ except ImportError: # ============================================================================== def uniq(sequence): """ - Fonction pour rendre unique chaque élément d'une liste, en préservant l'ordre + Fonction pour rendre unique chaque élément d'une liste, en préservant l'ordre """ __seen = set() return [x for x in sequence if x not in __seen and not __seen.add(x)] @@ -187,10 +187,10 @@ def uniq(sequence): # ============================================================================== class PathManagement(object): """ - Mise à jour du path système pour les répertoires d'outils + Mise à jour du path système pour les répertoires d'outils """ def __init__(self): - "Déclaration des répertoires statiques" + "Déclaration des répertoires statiques" parent = os.path.abspath(os.path.join(os.path.dirname(__file__),"..")) self.__paths = {} self.__paths["daExternals"] = os.path.join(parent,"daExternals") @@ -206,18 +206,18 @@ class PathManagement(object): def getpaths(self): """ - Renvoie le dictionnaire des chemins ajoutés + Renvoie le dictionnaire des chemins ajoutés """ return self.__paths # ============================================================================== class SystemUsage(object): """ - Permet de récupérer les différentes tailles mémoires du process courant + Permet de récupérer les différentes tailles mémoires du process courant """ # - # Le module resource renvoie 0 pour les tailles mémoire. On utilise donc - # plutôt : http://code.activestate.com/recipes/286222/ et Wikipedia + # Le module resource renvoie 0 pour les tailles mémoire. On utilise donc + # plutôt : http://code.activestate.com/recipes/286222/ et Wikipedia # _proc_status = '/proc/%d/status' % os.getpid() _memo_status = '/proc/meminfo' @@ -240,7 +240,7 @@ class SystemUsage(object): pass # def _VmA(self, VmKey, unit): - "Lecture des paramètres mémoire de la machine" + "Lecture des paramètres mémoire de la machine" try: t = open(self._memo_status) v = t.read() @@ -256,26 +256,26 @@ class SystemUsage(object): return mem / self._scale[unit] # def getAvailablePhysicalMemory(self, unit="o"): - "Renvoie la mémoire physique utilisable en octets" + "Renvoie la mémoire physique utilisable en octets" return self._VmA('MemTotal:', unit) # def getAvailableSwapMemory(self, unit="o"): - "Renvoie la mémoire swap utilisable en octets" + "Renvoie la mémoire swap utilisable en octets" return self._VmA('SwapTotal:', unit) # def getAvailableMemory(self, unit="o"): - "Renvoie la mémoire totale (physique+swap) utilisable en octets" + "Renvoie la mémoire totale (physique+swap) utilisable en octets" return self._VmA('MemTotal:', unit) + self._VmA('SwapTotal:', unit) # def getUsableMemory(self, unit="o"): - """Renvoie la mémoire utilisable en octets - Rq : il n'est pas sûr que ce décompte soit juste... + """Renvoie la mémoire utilisable en octets + Rq : il n'est pas sûr que ce décompte soit juste... """ return self._VmA('MemFree:', unit) + self._VmA('SwapFree:', unit) + \ self._VmA('Cached:', unit) + self._VmA('SwapCached:', unit) # def _VmB(self, VmKey, unit): - "Lecture des paramètres mémoire du processus" + "Lecture des paramètres mémoire du processus" try: t = open(self._proc_status) v = t.read() @@ -291,23 +291,23 @@ class SystemUsage(object): return mem / self._scale[unit] # def getUsedMemory(self, unit="o"): - "Renvoie la mémoire résidente utilisée en octets" + "Renvoie la mémoire résidente utilisée en octets" return self._VmB('VmRSS:', unit) # def getVirtualMemory(self, unit="o"): - "Renvoie la mémoire totale utilisée en octets" + "Renvoie la mémoire totale utilisée en octets" return self._VmB('VmSize:', unit) # def getUsedStacksize(self, unit="o"): - "Renvoie la taille du stack utilisé en octets" + "Renvoie la taille du stack utilisé en octets" return self._VmB('VmStk:', unit) # def getMaxUsedMemory(self, unit="o"): - "Renvoie la mémoire résidente maximale mesurée" + "Renvoie la mémoire résidente maximale mesurée" return self._VmB('VmHWM:', unit) # def getMaxVirtualMemory(self, unit="o"): - "Renvoie la mémoire totale maximale mesurée" + "Renvoie la mémoire totale maximale mesurée" return self._VmB('VmPeak:', unit) # ============================================================================== diff --git a/src/daComposant/daCore/Templates.py b/src/daComposant/daCore/Templates.py index a6d1ec4..8c578ba 100644 --- a/src/daComposant/daCore/Templates.py +++ b/src/daComposant/daCore/Templates.py @@ -1,4 +1,4 @@ -#-*-coding:iso-8859-1-*- +# -*- coding: utf-8 -*- # # Copyright (C) 2008-2017 EDF R&D # @@ -21,7 +21,7 @@ # Author: Jean-Philippe Argaud, jean-philippe.argaud@edf.fr, EDF R&D """ - Modèles généraux pour les observers, le post-processing + Modèles généraux pour les observers, le post-processing """ __author__ = "Jean-Philippe ARGAUD" __all__ = ["ObserverTemplates"] @@ -31,7 +31,7 @@ import numpy # ============================================================================== class TemplateStorage(object): """ - Classe générale de stockage de type dictionnaire étendu + Classe générale de stockage de type dictionnaire étendu (Template) """ def __init__( self, language = "fr_FR" ): @@ -56,8 +56,7 @@ class TemplateStorage(object): def keys(self): "D.keys() -> list of D's keys" - __keys = list(self.__values.keys()) - __keys.sort() + __keys = sorted(self.__values.keys()) return __keys # def has_key(self, name): @@ -109,42 +108,42 @@ ObserverTemplates.store( ObserverTemplates.store( name = "ValueSeriePrinter", content = """print(str(info)+" "+str(var[:]))""", - fr_FR = "Imprime sur la sortie standard la série des valeurs de la variable", + fr_FR = "Imprime sur la sortie standard la série des valeurs de la variable", en_EN = "Print on standard output the value series of the variable", order = "next", ) ObserverTemplates.store( name = "ValueSaver", content = """import numpy, re\nv=numpy.array(var[-1], ndmin=1)\nglobal istep\ntry:\n istep += 1\nexcept:\n istep = 0\nf='/tmp/value_%s_%05i.txt'%(info,istep)\nf=re.sub('\\s','_',f)\nprint('Value saved in \"%s\"'%f)\nnumpy.savetxt(f,v)""", - fr_FR = "Enregistre la valeur courante de la variable dans un fichier du répertoire '/tmp' nommé 'value...txt' selon le nom de la variable et l'étape d'enregistrement", + fr_FR = "Enregistre la valeur courante de la variable dans un fichier du répertoire '/tmp' nommé 'value...txt' selon le nom de la variable et l'étape d'enregistrement", en_EN = "Save the current value of the variable in a file of the '/tmp' directory named 'value...txt' from the variable name and the saving step", order = "next", ) ObserverTemplates.store( name = "ValueSerieSaver", content = """import numpy, re\nv=numpy.array(var[:], ndmin=1)\nglobal istep\ntry:\n istep += 1\nexcept:\n istep = 0\nf='/tmp/value_%s_%05i.txt'%(info,istep)\nf=re.sub('\\s','_',f)\nprint('Value saved in \"%s\"'%f)\nnumpy.savetxt(f,v)""", - fr_FR = "Enregistre la série des valeurs de la variable dans un fichier du répertoire '/tmp' nommé 'value...txt' selon le nom de la variable et l'étape", + fr_FR = "Enregistre la série des valeurs de la variable dans un fichier du répertoire '/tmp' nommé 'value...txt' selon le nom de la variable et l'étape", en_EN = "Save the value series of the variable in a file of the '/tmp' directory named 'value...txt' from the variable name and the saving step", order = "next", ) ObserverTemplates.store( name = "ValuePrinterAndSaver", content = """import numpy, re\nv=numpy.array(var[-1], ndmin=1)\nprint(str(info)+" "+str(v))\nglobal istep\ntry:\n istep += 1\nexcept:\n istep = 0\nf='/tmp/value_%s_%05i.txt'%(info,istep)\nf=re.sub('\\s','_',f)\nprint('Value saved in \"%s\"'%f)\nnumpy.savetxt(f,v)""", - fr_FR = "Imprime sur la sortie standard et, en même temps enregistre dans un fichier, la valeur courante de la variable", + fr_FR = "Imprime sur la sortie standard et, en même temps enregistre dans un fichier, la valeur courante de la variable", en_EN = "Print on standard output and, in the same time save in a file, the current value of the variable", order = "next", ) ObserverTemplates.store( name = "ValueIndexPrinterAndSaver", content = """import numpy, re\nv=numpy.array(var[-1], ndmin=1)\nprint(str(info)+(" index %i:"%(len(var)-1))+" "+str(v))\nglobal istep\ntry:\n istep += 1\nexcept:\n istep = 0\nf='/tmp/value_%s_%05i.txt'%(info,istep)\nf=re.sub('\\s','_',f)\nprint('Value saved in \"%s\"'%f)\nnumpy.savetxt(f,v)""", - fr_FR = "Imprime sur la sortie standard et, en même temps enregistre dans un fichier, la valeur courante de la variable, en ajoutant son index", + fr_FR = "Imprime sur la sortie standard et, en même temps enregistre dans un fichier, la valeur courante de la variable, en ajoutant son index", en_EN = "Print on standard output and, in the same time save in a file, the current value of the variable, adding its index", order = "next", ) ObserverTemplates.store( name = "ValueSeriePrinterAndSaver", content = """import numpy, re\nv=numpy.array(var[:], ndmin=1)\nprint(str(info)+" "+str(v))\nglobal istep\ntry:\n istep += 1\nexcept:\n istep = 0\nf='/tmp/value_%s_%05i.txt'%(info,istep)\nf=re.sub('\\s','_',f)\nprint('Value saved in \"%s\"'%f)\nnumpy.savetxt(f,v)""", - fr_FR = "Imprime sur la sortie standard et, en même temps, enregistre dans un fichier la série des valeurs de la variable", + fr_FR = "Imprime sur la sortie standard et, en même temps, enregistre dans un fichier la série des valeurs de la variable", en_EN = "Print on standard output and, in the same time, save in a file the value series of the variable", order = "next", ) @@ -158,35 +157,35 @@ ObserverTemplates.store( ObserverTemplates.store( name = "ValueSerieGnuPlotter", content = """import numpy, Gnuplot\nv=numpy.array(var[:], ndmin=1)\nglobal ifig, gp\ntry:\n ifig += 1\n gp(' set style data lines')\nexcept:\n ifig = 0\n gp = Gnuplot.Gnuplot(persist=1)\n gp(' set style data lines')\ngp('set title \"%s (Figure %i)\"'%(info,ifig))\ngp.plot( Gnuplot.Data( v, with_='lines lw 2' ) )""", - fr_FR = "Affiche graphiquement avec Gnuplot la série des valeurs de la variable", + fr_FR = "Affiche graphiquement avec Gnuplot la série des valeurs de la variable", en_EN = "Graphically plot with Gnuplot the value series of the variable", order = "next", ) ObserverTemplates.store( name = "ValuePrinterAndGnuPlotter", content = """print(str(info)+" "+str(var[-1]))\nimport numpy, Gnuplot\nv=numpy.array(var[-1], ndmin=1)\nglobal ifig,gp\ntry:\n ifig += 1\n gp(' set style data lines')\nexcept:\n ifig = 0\n gp = Gnuplot.Gnuplot(persist=1)\n gp(' set style data lines')\ngp('set title \"%s (Figure %i)\"'%(info,ifig))\ngp.plot( Gnuplot.Data( v, with_='lines lw 2' ) )""", - fr_FR = "Imprime sur la sortie standard et, en même temps, affiche graphiquement avec Gnuplot la valeur courante de la variable", + fr_FR = "Imprime sur la sortie standard et, en même temps, affiche graphiquement avec Gnuplot la valeur courante de la variable", en_EN = "Print on standard output and, in the same time, graphically plot with Gnuplot the current value of the variable", order = "next", ) ObserverTemplates.store( name = "ValueSeriePrinterAndGnuPlotter", content = """print(str(info)+" "+str(var[:]))\nimport numpy, Gnuplot\nv=numpy.array(var[:], ndmin=1)\nglobal ifig,gp\ntry:\n ifig += 1\n gp(' set style data lines')\nexcept:\n ifig = 0\n gp = Gnuplot.Gnuplot(persist=1)\n gp(' set style data lines')\ngp('set title \"%s (Figure %i)\"'%(info,ifig))\ngp.plot( Gnuplot.Data( v, with_='lines lw 2' ) )""", - fr_FR = "Imprime sur la sortie standard et, en même temps, affiche graphiquement avec Gnuplot la série des valeurs de la variable", + fr_FR = "Imprime sur la sortie standard et, en même temps, affiche graphiquement avec Gnuplot la série des valeurs de la variable", en_EN = "Print on standard output and, in the same time, graphically plot with Gnuplot the value series of the variable", order = "next", ) ObserverTemplates.store( name = "ValuePrinterSaverAndGnuPlotter", content = """print(str(info)+" "+str(var[-1]))\nimport numpy, re\nv=numpy.array(var[-1], ndmin=1)\nglobal istep\ntry:\n istep += 1\nexcept:\n istep = 0\nf='/tmp/value_%s_%05i.txt'%(info,istep)\nf=re.sub('\\s','_',f)\nprint('Value saved in \"%s\"'%f)\nnumpy.savetxt(f,v)\nimport Gnuplot\nglobal ifig,gp\ntry:\n ifig += 1\n gp(' set style data lines')\nexcept:\n ifig = 0\n gp = Gnuplot.Gnuplot(persist=1)\n gp(' set style data lines')\ngp('set title \"%s (Figure %i)\"'%(info,ifig))\ngp.plot( Gnuplot.Data( v, with_='lines lw 2' ) )""", - fr_FR = "Imprime sur la sortie standard et, en même temps, enregistre dans un fichier et affiche graphiquement la valeur courante de la variable ", + fr_FR = "Imprime sur la sortie standard et, en même temps, enregistre dans un fichier et affiche graphiquement la valeur courante de la variable ", en_EN = "Print on standard output and, in the same, time save in a file and graphically plot the current value of the variable", order = "next", ) ObserverTemplates.store( name = "ValueSeriePrinterSaverAndGnuPlotter", content = """print(str(info)+" "+str(var[:]))\nimport numpy, re\nv=numpy.array(var[:], ndmin=1)\nglobal istep\ntry:\n istep += 1\nexcept:\n istep = 0\nf='/tmp/value_%s_%05i.txt'%(info,istep)\nf=re.sub('\\s','_',f)\nprint('Value saved in \"%s\"'%f)\nnumpy.savetxt(f,v)\nimport Gnuplot\nglobal ifig,gp\ntry:\n ifig += 1\n gp(' set style data lines')\nexcept:\n ifig = 0\n gp = Gnuplot.Gnuplot(persist=1)\n gp(' set style data lines')\ngp('set title \"%s (Figure %i)\"'%(info,ifig))\ngp.plot( Gnuplot.Data( v, with_='lines lw 2' ) )""", - fr_FR = "Imprime sur la sortie standard et, en même temps, enregistre dans un fichier et affiche graphiquement la série des valeurs de la variable", + fr_FR = "Imprime sur la sortie standard et, en même temps, enregistre dans un fichier et affiche graphiquement la série des valeurs de la variable", en_EN = "Print on standard output and, in the same, time save in a file and graphically plot the value series of the variable", order = "next", ) @@ -200,7 +199,7 @@ ObserverTemplates.store( ObserverTemplates.store( name = "ValueStandardError", content = """import numpy\nprint(str(info)+" "+str(numpy.nanstd(var[-1])))""", - fr_FR = "Imprime sur la sortie standard l'écart-type de la valeur courante de la variable", + fr_FR = "Imprime sur la sortie standard l'écart-type de la valeur courante de la variable", en_EN = "Print on standard output the standard error of the current value of the variable", order = "next", ) @@ -221,7 +220,7 @@ ObserverTemplates.store( ObserverTemplates.store( name = "ValueRMS", content = """import numpy\nv = numpy.matrix( numpy.ravel( var[-1] ) )\nprint(str(info)+" "+str(float( numpy.sqrt((1./v.size)*(v*v.T)) )))""", - fr_FR = "Imprime sur la sortie standard la racine de la moyenne des carrés (RMS), ou moyenne quadratique, de la valeur courante de la variable", + fr_FR = "Imprime sur la sortie standard la racine de la moyenne des carrés (RMS), ou moyenne quadratique, de la valeur courante de la variable", en_EN = "Print on standard output the root mean square (RMS), or quadratic mean, of the current value of the variable", order = "next", ) diff --git a/src/daComposant/daCore/__init__.py b/src/daComposant/daCore/__init__.py index 492aad4..53248cc 100644 --- a/src/daComposant/daCore/__init__.py +++ b/src/daComposant/daCore/__init__.py @@ -1,4 +1,4 @@ -#-*-coding:iso-8859-1-*- +# -*- coding: utf-8 -*- # # Copyright (C) 2008-2017 EDF R&D # diff --git a/src/daComposant/daCore/version.py b/src/daComposant/daCore/version.py index 2c62b87..20b8246 100644 --- a/src/daComposant/daCore/version.py +++ b/src/daComposant/daCore/version.py @@ -1,4 +1,4 @@ -#-*-coding:iso-8859-1-*- +# -*- coding: utf-8 -*- # # Copyright (C) 2008-2017 EDF R&D # diff --git a/src/daComposant/daDiagnostics/PlotVector.py b/src/daComposant/daDiagnostics/PlotVector.py index 97751e4..0bebc11 100644 --- a/src/daComposant/daDiagnostics/PlotVector.py +++ b/src/daComposant/daDiagnostics/PlotVector.py @@ -1,4 +1,4 @@ -#-*-coding:iso-8859-1-*- +# -*- coding: utf-8 -*- # # Copyright (C) 2008-2017 EDF R&D # @@ -27,7 +27,7 @@ import os.path # ============================================================================== class ElementaryDiagnostic(BasicObjects.Diagnostic): """ - Classe pour tracer simplement un vecteur à chaque pas + Classe pour tracer simplement un vecteur à chaque pas """ def __init__(self, name = "", unit = "", basetype = None, parameters = {}): BasicObjects.Diagnostic.__init__(self, name, parameters) @@ -45,7 +45,7 @@ class ElementaryDiagnostic(BasicObjects.Diagnostic): persist, pause ): """ - Trace en gnuplot le vecteur Vector, avec une légende générale, en X et + Trace en gnuplot le vecteur Vector, avec une légende générale, en X et en Y """ if persist: @@ -65,7 +65,7 @@ class ElementaryDiagnostic(BasicObjects.Diagnostic): if filename != "": self.__g.hardcopy(filename=filename, color=1) if pause: - raw_input('Please press return to continue...\n') + eval(input('Please press return to continue...\n')) # return 1 @@ -77,24 +77,24 @@ class ElementaryDiagnostic(BasicObjects.Diagnostic): pause = True ): """ Arguments : - - vector : le vecteur à tracer, en liste ou en numpy.array + - vector : le vecteur à tracer, en liste ou en numpy.array - steps : liste unique des pas de l'axe des X, ou None si c'est - la numérotation par défaut - - title : titre général du dessin + la numérotation par défaut + - title : titre général du dessin - xlabel : label de l'axe des X - ylabel : label de l'axe des Y - - ltitle : titre associé au vecteur tracé - - geometry : taille en pixels de la fenêtre et position du coin haut - gauche, au format X11 : LxH+X+Y (défaut : 600x400) - - filename : nom de fichier Postscript pour une sauvegarde à 1 pas - Attention, il faut changer le nom à l'appel pour + - ltitle : titre associé au vecteur tracé + - geometry : taille en pixels de la fenêtre et position du coin haut + gauche, au format X11 : LxH+X+Y (défaut : 600x400) + - filename : nom de fichier Postscript pour une sauvegarde à 1 pas + Attention, il faut changer le nom à l'appel pour plusieurs pas de sauvegarde - - persist : booléen indiquant que la fenêtre affichée sera - conservée lors du passage au dessin suivant - Par défaut, persist = False - - pause : booléen indiquant une pause après chaque tracé, et + - persist : booléen indiquant que la fenêtre affichée sera + conservée lors du passage au dessin suivant + Par défaut, persist = False + - pause : booléen indiquant une pause après chaque tracé, et attendant un Return - Par défaut, pause = True + Par défaut, pause = True """ if vector is None: raise ValueError("One vector must be given to plot it.") @@ -102,8 +102,8 @@ class ElementaryDiagnostic(BasicObjects.Diagnostic): if Vector.size < 1: raise ValueError("The given vector must not be empty") if steps is None: - Steps = range(len( vector )) - elif not ( type(steps) is type([]) or type(steps) is not type(numpy.array([])) ): + Steps = list(range(len( vector ))) + elif not ( isinstance(steps, type([])) or not isinstance(steps, type(numpy.array([]))) ): raise ValueError("The steps must be given as a list/tuple.") else: Steps = list(steps) diff --git a/src/daComposant/daDiagnostics/PlotVectors.py b/src/daComposant/daDiagnostics/PlotVectors.py index 24777c0..11037e7 100644 --- a/src/daComposant/daDiagnostics/PlotVectors.py +++ b/src/daComposant/daDiagnostics/PlotVectors.py @@ -1,4 +1,4 @@ -#-*-coding:iso-8859-1-*- +# -*- coding: utf-8 -*- # # Copyright (C) 2008-2017 EDF R&D # @@ -27,7 +27,7 @@ import os.path # ============================================================================== class ElementaryDiagnostic(BasicObjects.Diagnostic): """ - Classe pour tracer simplement une liste de vecteurs à chaque pas + Classe pour tracer simplement une liste de vecteurs à chaque pas """ def __init__(self, name = "", unit = "", basetype = None, parameters = {}): BasicObjects.Diagnostic.__init__(self, name, parameters) @@ -45,8 +45,8 @@ class ElementaryDiagnostic(BasicObjects.Diagnostic): persist, pause ): """ - Trace en gnuplot chaque vecteur de la liste Vector, avec une légende - générale, en X et en Y + Trace en gnuplot chaque vecteur de la liste Vector, avec une légende + générale, en X et en Y """ if persist: self.__gnuplot.GnuplotOpts.gnuplot_command = 'gnuplot -persist -geometry '+geometry @@ -67,7 +67,7 @@ class ElementaryDiagnostic(BasicObjects.Diagnostic): if filename != "": self.__g.hardcopy(filename=filename, color=1) if pause: - raw_input('Please press return to continue...\n') + eval(input('Please press return to continue...\n')) # return 1 @@ -79,30 +79,30 @@ class ElementaryDiagnostic(BasicObjects.Diagnostic): pause = True ): """ Arguments : - - vector : liste des vecteurs à tracer, chacun étant en liste ou + - vector : liste des vecteurs à tracer, chacun étant en liste ou en numpy.array - - steps : liste unique des pas, ou None si c'est la numérotation - par défaut - - title : titre général du dessin + - steps : liste unique des pas, ou None si c'est la numérotation + par défaut + - title : titre général du dessin - xlabel : label de l'axe des X - ylabel : label de l'axe des Y - - ltitle : liste des titres associés à chaque vecteur, dans le - même ordre que les vecteurs eux-mêmes - - geometry : taille en pixels de la fenêtre et position du coin haut - gauche, au format X11 : LxH+X+Y (défaut : 600x400) - - filename : nom de fichier Postscript pour une sauvegarde à 1 pas - Attention, il faut changer le nom à l'appel pour + - ltitle : liste des titres associés à chaque vecteur, dans le + même ordre que les vecteurs eux-mêmes + - geometry : taille en pixels de la fenêtre et position du coin haut + gauche, au format X11 : LxH+X+Y (défaut : 600x400) + - filename : nom de fichier Postscript pour une sauvegarde à 1 pas + Attention, il faut changer le nom à l'appel pour plusieurs pas de sauvegarde - - persist : booléen indiquant que la fenêtre affichée sera - conservée lors du passage au dessin suivant - Par défaut, persist = False - - pause : booléen indiquant une pause après chaque tracé, et + - persist : booléen indiquant que la fenêtre affichée sera + conservée lors du passage au dessin suivant + Par défaut, persist = False + - pause : booléen indiquant une pause après chaque tracé, et attendant un Return - Par défaut, pause = True + Par défaut, pause = True """ if vector is None: raise ValueError("One vector must be given to plot it.") - if type(vector) is not type([]) and type(vector) is not type(()): + if not isinstance(vector, (list, tuple)): raise ValueError("The vector(s) must be given as a list/tuple.") if ltitle is None or len(ltitle) != len(vector): ltitle = ["" for i in range(len(vector))] @@ -112,8 +112,8 @@ class ElementaryDiagnostic(BasicObjects.Diagnostic): if VectorList[-1].size < 1: raise ValueError("Each given vector must not be empty.") if steps is None: - Steps = range(len(vector[0])) - elif not ( type(steps) is type([]) or type(steps) is not type(numpy.array([])) ): + Steps = list(range(len(vector[0]))) + elif not ( isinstance(steps, type([])) or not isinstance(steps, type(numpy.array([]))) ): raise ValueError("The steps must be given as a list/tuple.") else: Steps = list(steps) diff --git a/src/daComposant/daDiagnostics/RMS.py b/src/daComposant/daDiagnostics/RMS.py index 509c15b..c36d5d7 100644 --- a/src/daComposant/daDiagnostics/RMS.py +++ b/src/daComposant/daDiagnostics/RMS.py @@ -1,4 +1,4 @@ -#-*-coding:iso-8859-1-*- +# -*- coding: utf-8 -*- # # Copyright (C) 2008-2017 EDF R&D # @@ -34,7 +34,7 @@ class ElementaryDiagnostic(BasicObjects.Diagnostic,Persistence.OneScalar): def _formula(self, V1, V2): """ - Fait un écart RMS entre deux vecteurs V1 et V2 + Fait un écart RMS entre deux vecteurs V1 et V2 """ rms = math.sqrt( ((V2 - V1)**2).sum() / float(V1.size) ) # @@ -42,7 +42,7 @@ class ElementaryDiagnostic(BasicObjects.Diagnostic,Persistence.OneScalar): def calculate(self, vector1 = None, vector2 = None, step = None): """ - Teste les arguments, active la formule de calcul et stocke le résultat + Teste les arguments, active la formule de calcul et stocke le résultat """ if vector1 is None or vector2 is None: raise ValueError("Two vectors must be given to calculate their RMS") diff --git a/src/daComposant/daDiagnostics/ReduceVariance.py b/src/daComposant/daDiagnostics/ReduceVariance.py index f8d22b3..6162f60 100644 --- a/src/daComposant/daDiagnostics/ReduceVariance.py +++ b/src/daComposant/daDiagnostics/ReduceVariance.py @@ -1,4 +1,4 @@ -#-*-coding:iso-8859-1-*- +# -*- coding: utf-8 -*- # # Copyright (C) 2008-2017 EDF R&D # @@ -33,13 +33,13 @@ class ElementaryDiagnostic(BasicObjects.Diagnostic,Persistence.OneScalar): def _formula(self, V1, V2): """ - Vérification de la reduction de variance sur les écarts entre OMB et OMA + Vérification de la reduction de variance sur les écarts entre OMB et OMA lors de l'analyse """ - varianceOMB = V1.var() - varianceOMA = V2.var() + varianceOMB = V1.var() + varianceOMA = V2.var() # - if varianceOMA > varianceOMB: + if varianceOMA > varianceOMB: reducevariance = False else : reducevariance = True @@ -48,10 +48,10 @@ class ElementaryDiagnostic(BasicObjects.Diagnostic,Persistence.OneScalar): def calculate(self, vectorOMB = None, vectorOMA = None, step = None): """ - Teste les arguments, active la formule de calcul et stocke le résultat + Teste les arguments, active la formule de calcul et stocke le résultat Arguments : - - vectorOMB : vecteur d'écart entre les observations et l'ébauche - - vectorOMA : vecteur d'écart entre les observations et l'analyse + - vectorOMB : vecteur d'écart entre les observations et l'ébauche + - vectorOMA : vecteur d'écart entre les observations et l'analyse """ if ( (vectorOMB is None) or (vectorOMA is None) ): raise ValueError("Two vectors must be given to test the reduction of the variance after analysis") @@ -78,34 +78,34 @@ if __name__ == "__main__": # ---------------------- x1 = numpy.matrix(([3. , 4., 5. ])) x2 = numpy.matrix(([1.5, 2., 2.5])) - print(" L'écart entre les observations et l'ébauche est OMB : %s"%(x1,)) + print(" L'écart entre les observations et l'ébauche est OMB : %s"%(x1,)) print(" La moyenne de OMB (i.e. le biais) est de............: %s"%(x1.mean(),)) print(" La variance de OMB est de...........................: %s"%(x1.var(),)) - print(" L'écart entre les observations et l'analyse est OMA : %s"%(x2,)) + print(" L'écart entre les observations et l'analyse est OMA : %s"%(x2,)) print(" La moyenne de OMA (i.e. le biais) est de............: %s"%(x2.mean(),)) print(" La variance de OMA est de...........................: %s"%(x2.var(),)) # D.calculate( vectorOMB = x1, vectorOMA = x2) if not D[0] : - print(" Résultat : l'analyse NE RÉDUIT PAS la variance") + print(" Résultat : l'analyse NE RÉDUIT PAS la variance") else : - print(" Résultat : l'analyse RÉDUIT la variance") + print(" Résultat : l'analyse RÉDUIT la variance") print("") # # Vecteur de type array # --------------------- x1 = numpy.array(range(11)) x2 = numpy.matrix(range(-10,12,2)) - print(" L'écart entre les observations et l'ébauche est OMB : %s"%(x1,)) + print(" L'écart entre les observations et l'ébauche est OMB : %s"%(x1,)) print(" La moyenne de OMB (i.e. le biais) est de............: %s"%(x1.mean(),)) print(" La variance de OMB est de...........................: %s"%(x1.var(),)) - print(" L'écart entre les observations et l'analyse est OMA : %s"%(x2,)) + print(" L'écart entre les observations et l'analyse est OMA : %s"%(x2,)) print(" La moyenne de OMA (i.e. le biais) est de............: %s"%(x2.mean(),)) print(" La variance de OMA est de...........................: %s"%(x2.var(),)) # D.calculate( vectorOMB = x1, vectorOMA = x2) if not D[1] : - print(" Résultat : l'analyse NE RÉDUIT PAS la variance") + print(" Résultat : l'analyse NE RÉDUIT PAS la variance") else : - print(" Résultat : l'analyse RÉDUIT la variance") + print(" Résultat : l'analyse RÉDUIT la variance") print("") diff --git a/src/daComposant/daDiagnostics/__init__.py b/src/daComposant/daDiagnostics/__init__.py index 492aad4..53248cc 100644 --- a/src/daComposant/daDiagnostics/__init__.py +++ b/src/daComposant/daDiagnostics/__init__.py @@ -1,4 +1,4 @@ -#-*-coding:iso-8859-1-*- +# -*- coding: utf-8 -*- # # Copyright (C) 2008-2017 EDF R&D # diff --git a/src/daComposant/daMatrices/__init__.py b/src/daComposant/daMatrices/__init__.py index 492aad4..53248cc 100644 --- a/src/daComposant/daMatrices/__init__.py +++ b/src/daComposant/daMatrices/__init__.py @@ -1,4 +1,4 @@ -#-*-coding:iso-8859-1-*- +# -*- coding: utf-8 -*- # # Copyright (C) 2008-2017 EDF R&D # diff --git a/src/daComposant/daNumerics/ApproximatedDerivatives.py b/src/daComposant/daNumerics/ApproximatedDerivatives.py index cd6581b..7c24495 100644 --- a/src/daComposant/daNumerics/ApproximatedDerivatives.py +++ b/src/daComposant/daNumerics/ApproximatedDerivatives.py @@ -1,4 +1,4 @@ -#-*-coding:iso-8859-1-*- +# -*- coding: utf-8 -*- # # Copyright (C) 2008-2017 EDF R&D # @@ -21,7 +21,7 @@ # Author: Jean-Philippe Argaud, jean-philippe.argaud@edf.fr, EDF R&D __doc__ = """ - Définit les versions approximées des opérateurs tangents et adjoints. + Définit les versions approximées des opérateurs tangents et adjoints. """ __author__ = "Jean-Philippe ARGAUD" @@ -45,13 +45,13 @@ def ExecuteFunction( paire ): # ============================================================================== class FDApproximation(object): """ - Cette classe sert d'interface pour définir les opérateurs approximés. A la - création d'un objet, en fournissant une fonction "Function", on obtient un - objet qui dispose de 3 méthodes "DirectOperator", "TangentOperator" et - "AdjointOperator". On contrôle l'approximation DF avec l'incrément - multiplicatif "increment" valant par défaut 1%, ou avec l'incrément fixe - "dX" qui sera multiplié par "increment" (donc en %), et on effectue de DF - centrées si le booléen "centeredDF" est vrai. + Cette classe sert d'interface pour définir les opérateurs approximés. A la + création d'un objet, en fournissant une fonction "Function", on obtient un + objet qui dispose de 3 méthodes "DirectOperator", "TangentOperator" et + "AdjointOperator". On contrôle l'approximation DF avec l'incrément + multiplicatif "increment" valant par défaut 1%, ou avec l'incrément fixe + "dX" qui sera multiplié par "increment" (donc en %), et on effectue de DF + centrées si le booléen "centeredDF" est vrai. """ def __init__(self, Function = None, @@ -98,7 +98,7 @@ class FDApproximation(object): try: mod = os.path.join(Function.__globals__['filepath'],Function.__globals__['filename']) except: - mod = os.path.abspath(Function.im_func.__globals__['__file__']) + mod = os.path.abspath(Function.__func__.__globals__['__file__']) if not os.path.isfile(mod): raise ImportError("No user defined function or method found with the name %s"%(mod,)) self.__userFunction__modl = os.path.basename(mod).replace('.pyc','').replace('.pyo','').replace('.py','') @@ -128,7 +128,7 @@ class FDApproximation(object): self.__increment = float(increment) else: self.__increment = 0.01 - if dX is None: + if dX is None: self.__dX = None else: self.__dX = numpy.asmatrix(numpy.ravel( dX )).T @@ -142,14 +142,14 @@ class FDApproximation(object): for i in range(len(l)-1,-1,-1): if numpy.linalg.norm(e - l[i]) < self.__tolerBP * n[i]: __ac, __iac = True, i - if v is not None: logging.debug("FDA Cas%s déja calculé, récupération du doublon %i"%(v,__iac)) + if v is not None: logging.debug("FDA Cas%s déja calculé, récupération du doublon %i"%(v,__iac)) break return __ac, __iac # --------------------------------------------------------- def DirectOperator(self, X ): """ - Calcul du direct à l'aide de la fonction fournie. + Calcul du direct à l'aide de la fonction fournie. """ logging.debug("FDA Calcul DirectOperator (explicite)") _X = numpy.asmatrix(numpy.ravel( X )).T @@ -160,32 +160,32 @@ class FDApproximation(object): # --------------------------------------------------------- def TangentMatrix(self, X ): """ - Calcul de l'opérateur tangent comme la Jacobienne par différences finies, - c'est-à-dire le gradient de H en X. On utilise des différences finies + Calcul de l'opérateur tangent comme la Jacobienne par différences finies, + c'est-à-dire le gradient de H en X. On utilise des différences finies directionnelles autour du point X. X est un numpy.matrix. - - Différences finies centrées (approximation d'ordre 2): - 1/ Pour chaque composante i de X, on ajoute et on enlève la perturbation - dX[i] à la composante X[i], pour composer X_plus_dXi et X_moins_dXi, et - on calcule les réponses HX_plus_dXi = H( X_plus_dXi ) et HX_moins_dXi = + + Différences finies centrées (approximation d'ordre 2): + 1/ Pour chaque composante i de X, on ajoute et on enlève la perturbation + dX[i] à la composante X[i], pour composer X_plus_dXi et X_moins_dXi, et + on calcule les réponses HX_plus_dXi = H( X_plus_dXi ) et HX_moins_dXi = H( X_moins_dXi ) - 2/ On effectue les différences (HX_plus_dXi-HX_moins_dXi) et on divise par + 2/ On effectue les différences (HX_plus_dXi-HX_moins_dXi) et on divise par le pas 2*dXi - 3/ Chaque résultat, par composante, devient une colonne de la Jacobienne - - Différences finies non centrées (approximation d'ordre 1): - 1/ Pour chaque composante i de X, on ajoute la perturbation dX[i] à la - composante X[i] pour composer X_plus_dXi, et on calcule la réponse + 3/ Chaque résultat, par composante, devient une colonne de la Jacobienne + + Différences finies non centrées (approximation d'ordre 1): + 1/ Pour chaque composante i de X, on ajoute la perturbation dX[i] à la + composante X[i] pour composer X_plus_dXi, et on calcule la réponse HX_plus_dXi = H( X_plus_dXi ) 2/ On calcule la valeur centrale HX = H(X) - 3/ On effectue les différences (HX_plus_dXi-HX) et on divise par + 3/ On effectue les différences (HX_plus_dXi-HX) et on divise par le pas dXi - 4/ Chaque résultat, par composante, devient une colonne de la Jacobienne - + 4/ Chaque résultat, par composante, devient une colonne de la Jacobienne + """ logging.debug("FDA Calcul de la Jacobienne") - logging.debug("FDA Incrément de............: %s*X"%float(self.__increment)) - logging.debug("FDA Approximation centrée...: %s"%(self.__centeredDF)) + logging.debug("FDA Incrément de............: %s*X"%float(self.__increment)) + logging.debug("FDA Approximation centrée...: %s"%(self.__centeredDF)) # if X is None or len(X)==0: raise ValueError("Nominal point X for approximate derivatives can not be None or void (X=%s)."%(str(X),)) @@ -210,10 +210,10 @@ class FDApproximation(object): __bidon, __alreadyCalculatedI = self.__doublon__(_dX, self.__listJPCI, self.__listJPIN, None) if __alreadyCalculatedP == __alreadyCalculatedI > -1: __alreadyCalculated, __i = True, __alreadyCalculatedP - logging.debug("FDA Cas J déja calculé, récupération du doublon %i"%__i) + logging.debug("FDA Cas J déja calculé, récupération du doublon %i"%__i) # if __alreadyCalculated: - logging.debug("FDA Calcul Jacobienne (par récupération du doublon %i)"%__i) + logging.debug("FDA Calcul Jacobienne (par récupération du doublon %i)"%__i) _Jacobienne = self.__listJPCR[__i] else: logging.debug("FDA Calcul Jacobienne (explicite)") @@ -322,7 +322,7 @@ class FDApproximation(object): # --------------------------------------------------------- def TangentOperator(self, paire ): """ - Calcul du tangent à l'aide de la Jacobienne. + Calcul du tangent à l'aide de la Jacobienne. """ assert len(paire) == 2, "Incorrect number of arguments" X, dX = paire @@ -334,7 +334,7 @@ class FDApproximation(object): return _Jacobienne else: # - # Calcul de la valeur linéarisée de H en X appliqué à dX + # Calcul de la valeur linéarisée de H en X appliqué à dX # ------------------------------------------------------ _dX = numpy.asmatrix(numpy.ravel( dX )).T _HtX = numpy.dot(_Jacobienne, _dX) @@ -343,7 +343,7 @@ class FDApproximation(object): # --------------------------------------------------------- def AdjointOperator(self, paire ): """ - Calcul de l'adjoint à l'aide de la Jacobienne. + Calcul de l'adjoint à l'aide de la Jacobienne. """ assert len(paire) == 2, "Incorrect number of arguments" X, Y = paire @@ -355,7 +355,7 @@ class FDApproximation(object): return _JacobienneT else: # - # Calcul de la valeur de l'adjoint en X appliqué à Y + # Calcul de la valeur de l'adjoint en X appliqué à Y # -------------------------------------------------- _Y = numpy.asmatrix(numpy.ravel( Y )).T _HaY = numpy.dot(_JacobienneT, _Y) diff --git a/src/daComposant/daNumerics/__init__.py b/src/daComposant/daNumerics/__init__.py index 492aad4..53248cc 100644 --- a/src/daComposant/daNumerics/__init__.py +++ b/src/daComposant/daNumerics/__init__.py @@ -1,4 +1,4 @@ -#-*-coding:iso-8859-1-*- +# -*- coding: utf-8 -*- # # Copyright (C) 2008-2017 EDF R&D # diff --git a/src/daComposant/daNumerics/mmqr.py b/src/daComposant/daNumerics/mmqr.py index 698398d..d3a5d5e 100644 --- a/src/daComposant/daNumerics/mmqr.py +++ b/src/daComposant/daNumerics/mmqr.py @@ -1,4 +1,4 @@ -#-*-coding:iso-8859-1-*- +# -*- coding: utf-8 -*- # # Copyright (C) 2008-2017 EDF R&D # @@ -21,7 +21,7 @@ # Author: Jean-Philippe Argaud, jean-philippe.argaud@edf.fr, EDF R&D __doc__ = """ - Implémentation informatique de l'algorithme MMQR, basée sur la publication : + Implémentation informatique de l'algorithme MMQR, basée sur la publication : David R. Hunter, Kenneth Lange, "Quantile Regression via an MM Algorithm", Journal of Computational and Graphical Statistics, 9, 1, pp.60-77, 2000. """ @@ -97,7 +97,7 @@ def mmqr( veps = 1. - 2. * quantile - residus * poids lastsurrogate = -sum(residus * veps) - (1.-2.*quantile)*sum(residus) # - # Mesure d'écart : q*Sum(residus)-sum(residus negatifs) + # Mesure d'écart : q*Sum(residus)-sum(residus negatifs) # ---------------- Ecart = quantile * sum(residus) - sum( residus[residus<0] ) # -- 2.39.2