From fc1d599444a5176cf114996d176991843c0bdfba Mon Sep 17 00:00:00 2001 From: Jean-Philippe ARGAUD Date: Mon, 13 Sep 2021 08:10:39 +0200 Subject: [PATCH] Documentation and performance improvements --- doc/en/advanced.rst | 16 +++--- doc/en/snippets/PopulationSize.rst | 4 +- doc/fr/advanced.rst | 61 ++++++++++++++--------- doc/fr/snippets/PopulationSize.rst | 4 +- src/daComposant/daCore/NumericObjects.py | 63 ++++++++++++------------ 5 files changed, 83 insertions(+), 65 deletions(-) diff --git a/doc/en/advanced.rst b/doc/en/advanced.rst index 5c67019..42ed950 100644 --- a/doc/en/advanced.rst +++ b/doc/en/advanced.rst @@ -296,10 +296,10 @@ Using the ADAO EFICAS graphical interface as an ADAO TUI command ---------------------------------------------------------------- To make it easier to quickly edit an ADAO command file with ADAO EFICAS (JDC, -or pair of files ".comm/.py", that are together in a directory), you can launch -the graphical user interface from the Python interpreter. To do this, in a -Python interpreter obtained from the "SALOME shell", the following commands are -used:: +or pair of files ".comm/.py", that are together in a user study directory), you +can launch the graphical user interface from the Python interpreter. To do +this, in a Python interpreter obtained from the "SALOME shell", the following +commands are used:: from adao import adaoBuilder adaoBuilder.Gui() @@ -307,10 +307,10 @@ used:: If necessary, explicit messages can be used to identify the required environment variables that are missing. However, this command should not be run in the SALOME Python console (because in this case it is enough to activate the -module...) but it can be done in a "SALOME shell" session obtained from the -"Tools/Extensions" menu of SALOME. As a reminder, the easiest way to get a -Python interpreter included in a "SALOME shell" session is to run the following -command in a terminal:: +module since we already are in the graphical environment...) but it can be done +in a "SALOME shell" session obtained from the "Tools/Extensions" menu of +SALOME. As a reminder, the easiest way to get a Python interpreter included in +a "SALOME shell" session is to run the following command in a terminal:: $SALOMEDIR/salome shell -- python diff --git a/doc/en/snippets/PopulationSize.rst b/doc/en/snippets/PopulationSize.rst index 916e263..c83d26d 100644 --- a/doc/en/snippets/PopulationSize.rst +++ b/doc/en/snippets/PopulationSize.rst @@ -5,8 +5,8 @@ PopulationSize population at each generation. This size is slightly adjusted to take into account the number of state variables to be optimized. The default value is 100, and it is recommended to choose a population between 1 and about ten - times the number of state variables, the size being smaller as the number of - variables increases. + times the number of state variables, the size being proportionally smaller as + the number of variables increases. Example: ``{"PopulationSize":100}`` diff --git a/doc/fr/advanced.rst b/doc/fr/advanced.rst index 5181643..cd30130 100644 --- a/doc/fr/advanced.rst +++ b/doc/fr/advanced.rst @@ -66,7 +66,8 @@ L'exemple le plus simple consiste uniquement à lancer l'exécution d'un schéma YACS donné, qui a préalablement été généré par l'utilisateur en interface graphique. Dans ce cas, en ayant pris soin de remplacer les textes contenus entre les symboles ``<...>``, il suffit d'enregistrer le script de commandes -Shell suivant:: +Shell suivant : +:: #!/bin/bash USERDIR="" @@ -80,7 +81,8 @@ Il faut ensuite le rendre exécutable pour l'exécuter. Un exemple un peu plus complet consiste à lancer l'exécution d'un schéma YACS indiqué par l'utilisateur, en ayant préalablement vérifié sa disponibilité. Pour cela, en remplaçant le texte ````, il suffit d'enregistrer le script de commandes Shell suivant:: +SALOME>``, il suffit d'enregistrer le script de commandes Shell suivant : +:: #!/bin/bash if (test $# != 1) @@ -106,7 +108,8 @@ commandes ADAO (JDC, ou paire de fichiers ".comm/.py") en un schéma YACS associ (fichier ".xml"). A la fin du script, on choisit aussi de supprimer le fichier de ```` car c'est un fichier généré. Pour cela, en ayant bien pris soin de remplacer le texte ````, il suffit d'enregistrer le script de commandes Shell suivant:: +SALOME>``, il suffit d'enregistrer le script de commandes Shell suivant : +:: #!/bin/bash if (test $# != 1) @@ -146,7 +149,8 @@ informations) à travers un exemple simple. Comme décrit dans la documentation, un schéma XML peut être chargé en python. On donne ici une séquence complète de commandes pour tester la validité du schéma avant de l'exécuter, ajoutant des lignes supplémentaires initiales pour charger de manière explicite le catalogue -de types pour éviter d'obscures difficultés:: +de types pour éviter d'obscures difficultés : +:: #-*- coding: utf-8 -*- import pilot @@ -204,7 +208,8 @@ d'utiliser les calculs ADAO dans l'environnement **R** (voir [R]_ pour plus de détails). Ce dernier est disponible dans SALOME en lançant l'interpréteur R dans le shell "``salome shell``". Il faut de plus disposer, en R, du package "*rPython*", qui peut si nécessaire être installé par l'utilisateur à l'aide de -la commande R suivante:: +la commande R suivante : +:: #-*- coding: utf-8 -*- # @@ -220,7 +225,8 @@ Les calculs ADAO définis en interface textuelle (API/TUI, voir la utilisant des données et des informations depuis R. La démarche est illustrée sur :ref:`subsection_tui_example`, proposé dans la description de l'interface API/TUI. Dans l'interpréteur R, on peut exécuter les commandes suivantes, -directement issues de l'exemple simple:: +directement issues de l'exemple simple : +:: #-*- coding: utf-8 -*- # @@ -241,7 +247,8 @@ directement issues de l'exemple simple:: case.execute() ") -dont le résultat est:: +dont le résultat est : +:: Analysis [ 0.25000264 0.79999797 0.94999939] @@ -255,7 +262,8 @@ ADAO. On se reportera à la documentation [GilBellosta15]_ pour la mise en oeuvre. On peut transformer l'exemple ci-dessus pour utiliser des données provenant de R pour alimenter les trois variables d'ébauche, d'observation et d'opérateur d'observation. On récupère à la fin l'état optimal dans une variable -R aussi. Les autres lignes sont identiques. L'exemple devient ainsi:: +R aussi. Les autres lignes sont identiques. L'exemple devient ainsi : +:: #-*- coding: utf-8 -*- # @@ -312,20 +320,23 @@ Utiliser l'interface graphique EFICAS d'ADAO comme une commande TUI d'ADAO Pour faciliter l'édition rapide avec EFICAS d'ADAO d'un fichier de commandes ADAO (JDC, ou paire de fichiers ".comm/.py", qui se trouvent ensemble dans un -répertoire), on peut lancer l'interface graphique depuis l'interpréteur Python. -Pour cela, dans un interpréteur Python obtenu depuis le "SALOME shell", on -utilise les commandes suivantes:: +répertoire d'étude de l'utilisateur), on peut lancer l'interface graphique +directement depuis l'interpréteur Python. Pour cela, dans un interpréteur +Python obtenu depuis le "SALOME shell", on utilise les commandes suivantes : +:: from adao import adaoBuilder adaoBuilder.Gui() -si nécessaire, des messages explicites permettent d'identifier les variables +Si nécessaire, des messages explicites permettent d'identifier les variables d'environnement requises qui seraient absentes. Cette commande ne doit néanmoins pas être lancée dans la console Python de SALOME (car dans ce cas il -suffit d'activer le module...), mais elle peut l'être dans une session "SALOME -shell" obtenue depuis le menu "Outils/Extensions" de SALOME. Pour mémoire, le -moyen le plus simple d'obtenir un interpréteur Python inclu dans une session -"SALOME shell" est de lancer la commande suivante dans un terminal:: +suffit d'activer le module puisque l'on est déjà dans l'interface +graphique...), mais elle peut l'être dans une session "SALOME shell" obtenue +depuis le menu "Outils/Extensions" de SALOME. Pour mémoire, le moyen le plus +simple d'obtenir un interpréteur Python inclu dans une session "SALOME shell" +est de lancer la commande suivante dans un terminal : +:: $SALOMEDIR/salome shell -- python @@ -429,7 +440,8 @@ Les différents niveaux de logging sont : "*DEBUG*", "*INFO*", "*WARNING*", "*ERROR*", "*CRITICAL*". Toutes les informations associées à un niveau sont affichées à tous les niveaux au-dessus de celui-ci (inclut). La méthode la plus facile consiste à changer le niveau de surveillance en utilisant les lignes -Python suivantes:: +Python suivantes : +:: import logging logging.getLogger().setLevel(logging.DEBUG) @@ -568,19 +580,22 @@ Pour faciliter les futures évolutions, il est fortement recommandé de veiller ce que vos fichiers scripts utilisateurs utilisent une syntaxe compatible avec Python 2 et avec Python 3. En particulier, on recommande d'utiliser la syntaxe fonctionnelle pour les "*print*" et non pas la syntaxe "*commande*", comme par -exemple:: +exemple : +:: # Python 2 & 3 x, unit = 1., "cm" print( "x = %s %s"%(str(x),str(unit)) ) -ou:: +ou : +:: # Python 2 & 3 x, unit = 1., "cm" print( "x = {0} {1}".format(str(x),str(unit)) ) -plutôt que:: +plutôt que : +:: # Python 2 uniquement x, unit = 1., "cm" @@ -610,13 +625,15 @@ le nouveau module SALOME/ADAO, et à l'enregistrer avec un nouveau nom. Il y a une incompatibilité introduite dans les fichiers de script de post-processing ou d'observers. L'ancienne syntaxe pour interroger un objet résultat, comme celui d'analyse "*Analysis*" (fourni dans un script à travers le -mot-clé "*UserPostAnalysis*"), était par exemple:: +mot-clé "*UserPostAnalysis*"), était par exemple : +:: Analysis = ADD.get("Analysis").valueserie(-1) Analysis = ADD.get("Analysis").valueserie() La nouvelle syntaxe est entièrement compatible avec celle (classique) pour les -objets de type liste ou tuple:: +objets de type liste ou tuple : +:: Analysis = ADD.get("Analysis")[-1] Analysis = ADD.get("Analysis")[:] diff --git a/doc/fr/snippets/PopulationSize.rst b/doc/fr/snippets/PopulationSize.rst index 071f863..b11990a 100644 --- a/doc/fr/snippets/PopulationSize.rst +++ b/doc/fr/snippets/PopulationSize.rst @@ -5,8 +5,8 @@ PopulationSize population à chaque génération. Cette taille est légèrement ajustée pour tenir compte du nombre de variables d'état à optimiser. La valeur par défaut est 100. Il est conseillé de choisir une population comprise entre 1 et une - dizaine de fois le nombre de variables d'états, la taille étant d'autant plus - petite que le nombre de variables augmente. + dizaine de fois le nombre de variables d'états, la taille étant + proportionnellement d'autant plus petite que le nombre de variables augmente. Exemple : ``{"PopulationSize":100}`` diff --git a/src/daComposant/daCore/NumericObjects.py b/src/daComposant/daCore/NumericObjects.py index 39f96e7..abbe9a5 100644 --- a/src/daComposant/daCore/NumericObjects.py +++ b/src/daComposant/daCore/NumericObjects.py @@ -37,7 +37,7 @@ mfp = PlatformInfo().MaximumPrecision() def ExecuteFunction( triplet ): assert len(triplet) == 3, "Incorrect number of arguments" X, xArgs, funcrepr = triplet - __X = numpy.asmatrix(numpy.ravel( X )).T + __X = numpy.ravel( X ).reshape((-1,1)) __sys_path_tmp = sys.path ; sys.path.insert(0,funcrepr["__userFunction__path"]) __module = __import__(funcrepr["__userFunction__modl"], globals(), locals(), []) __fonction = getattr(__module,funcrepr["__userFunction__name"]) @@ -149,7 +149,7 @@ class FDApproximation(object): if dX is None: self.__dX = None else: - self.__dX = numpy.asmatrix(numpy.ravel( dX )).T + self.__dX = numpy.ravel( dX ) logging.debug("FDA Reduction des doublons de calcul : %s"%self.__avoidRC) if self.__avoidRC: logging.debug("FDA Tolerance de determination des doublons : %.2e"%self.__tolerBP) @@ -176,8 +176,7 @@ class FDApproximation(object): if self.__mfEnabled: _HX = self.__userFunction( X, argsAsSerie = True ) else: - _X = numpy.asmatrix(numpy.ravel( X )).T - _HX = numpy.ravel(self.__userFunction( _X )) + _HX = numpy.ravel(self.__userFunction( numpy.ravel(X) )) # return _HX @@ -214,12 +213,14 @@ class FDApproximation(object): if X is None or len(X)==0: raise ValueError("Nominal point X for approximate derivatives can not be None or void (given X: %s)."%(str(X),)) # - _X = numpy.asmatrix(numpy.ravel( X )).T + _X = numpy.ravel( X ) # if self.__dX is None: _dX = self.__increment * _X else: - _dX = numpy.asmatrix(numpy.ravel( self.__dX )).T + _dX = numpy.ravel( self.__dX ) + assert len(_X) == len(_dX), "Inconsistent dX increment length with respect to the X one" + assert _X.size == _dX.size, "Inconsistent dX increment size with respect to the X one" # if (_dX == 0.).any(): moyenne = _dX.mean() @@ -234,7 +235,7 @@ 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éjà calculé, récupération du doublon %i"%__i) # if __alreadyCalculated: logging.debug("FDA Calcul Jacobienne (par récupération du doublon %i)"%__i) @@ -252,9 +253,9 @@ class FDApproximation(object): _jobs = [] for i in range( len(_dX) ): _dXi = _dX[i] - _X_plus_dXi = numpy.array( _X.A1, dtype=float ) + _X_plus_dXi = numpy.array( _X, dtype=float ) _X_plus_dXi[i] = _X[i] + _dXi - _X_moins_dXi = numpy.array( _X.A1, dtype=float ) + _X_moins_dXi = numpy.array( _X, dtype=float ) _X_moins_dXi[i] = _X[i] - _dXi # _jobs.append( (_X_plus_dXi, self.__extraArgs, funcrepr) ) @@ -274,9 +275,9 @@ class FDApproximation(object): _xserie = [] for i in range( len(_dX) ): _dXi = _dX[i] - _X_plus_dXi = numpy.array( _X.A1, dtype=float ) + _X_plus_dXi = numpy.array( _X, dtype=float ) _X_plus_dXi[i] = _X[i] + _dXi - _X_moins_dXi = numpy.array( _X.A1, dtype=float ) + _X_moins_dXi = numpy.array( _X, dtype=float ) _X_moins_dXi[i] = _X[i] - _dXi # _xserie.append( _X_plus_dXi ) @@ -292,9 +293,9 @@ class FDApproximation(object): _Jacobienne = [] for i in range( _dX.size ): _dXi = _dX[i] - _X_plus_dXi = numpy.array( _X.A1, dtype=float ) + _X_plus_dXi = numpy.array( _X, dtype=float ) _X_plus_dXi[i] = _X[i] + _dXi - _X_moins_dXi = numpy.array( _X.A1, dtype=float ) + _X_moins_dXi = numpy.array( _X, dtype=float ) _X_moins_dXi[i] = _X[i] - _dXi # _HX_plus_dXi = self.DirectOperator( _X_plus_dXi ) @@ -311,9 +312,9 @@ class FDApproximation(object): "__userFunction__name" : self.__userFunction__name, } _jobs = [] - _jobs.append( (_X.A1, self.__extraArgs, funcrepr) ) + _jobs.append( (_X, self.__extraArgs, funcrepr) ) for i in range( len(_dX) ): - _X_plus_dXi = numpy.array( _X.A1, dtype=float ) + _X_plus_dXi = numpy.array( _X, dtype=float ) _X_plus_dXi[i] = _X[i] + _dX[i] # _jobs.append( (_X_plus_dXi, self.__extraArgs, funcrepr) ) @@ -332,9 +333,9 @@ class FDApproximation(object): # elif self.__mfEnabled: _xserie = [] - _xserie.append( _X.A1 ) + _xserie.append( _X ) for i in range( len(_dX) ): - _X_plus_dXi = numpy.array( _X.A1, dtype=float ) + _X_plus_dXi = numpy.array( _X, dtype=float ) _X_plus_dXi[i] = _X[i] + _dX[i] # _xserie.append( _X_plus_dXi ) @@ -352,7 +353,7 @@ class FDApproximation(object): _HX = self.DirectOperator( _X ) for i in range( _dX.size ): _dXi = _dX[i] - _X_plus_dXi = numpy.array( _X.A1, dtype=float ) + _X_plus_dXi = numpy.array( _X, dtype=float ) _X_plus_dXi[i] = _X[i] + _dXi # _HX_plus_dXi = self.DirectOperator( _X_plus_dXi ) @@ -360,7 +361,7 @@ class FDApproximation(object): _Jacobienne.append( numpy.ravel(( _HX_plus_dXi - _HX ) / _dXi) ) # # - _Jacobienne = numpy.asmatrix( numpy.vstack( _Jacobienne ) ).T + _Jacobienne = numpy.transpose( numpy.vstack( _Jacobienne ) ) if self.__avoidRC: if self.__lenghtRJ < 0: self.__lenghtRJ = 2 * _X.size while len(self.__listJPCP) > self.__lenghtRJ: @@ -406,10 +407,10 @@ class FDApproximation(object): # # Calcul de la valeur linéarisée de H en X appliqué à dX # ------------------------------------------------------ - _dX = numpy.asmatrix(numpy.ravel( dX )).T + _dX = numpy.ravel( dX ) _HtX = numpy.dot(_Jacobienne, _dX) - if self.__mfEnabled: return [_HtX.A1,] - else: return _HtX.A1 + if self.__mfEnabled: return [_HtX,] + else: return _HtX # --------------------------------------------------------- def AdjointOperator(self, paire, **extraArgs ): @@ -438,10 +439,10 @@ class FDApproximation(object): # # Calcul de la valeur de l'adjoint en X appliqué à Y # -------------------------------------------------- - _Y = numpy.asmatrix(numpy.ravel( Y )).T + _Y = numpy.ravel( Y ) _HaY = numpy.dot(_JacobienneT, _Y) - if self.__mfEnabled: return [_HaY.A1,] - else: return _HaY.A1 + if self.__mfEnabled: return [_HaY,] + else: return _HaY # ============================================================================== def EnsembleOfCenteredPerturbations( _bgcenter, _bgcovariance, _nbmembers ): @@ -850,7 +851,7 @@ def cekf(selfA, Xb, Y, U, HO, EM, CM, R, B, Q): if Cm is not None and Un is not None: # Attention : si Cm est aussi dans M, doublon ! Cm = Cm.reshape(__n,Un.size) # ADAO & check shape Xn_predicted = Xn_predicted + Cm * Un - Pn_predicted = Q + Mt * Pn * Ma + Pn_predicted = Q + Mt * (Pn * Ma) elif selfA._parameters["EstimationOf"] == "Parameters": # Observation of forecast # --- > Par principe, M = Id, Q = 0 Xn_predicted = Xn @@ -1543,7 +1544,7 @@ def exkf(selfA, Xb, Y, U, HO, EM, CM, R, B, Q): if Cm is not None and Un is not None: # Attention : si Cm est aussi dans M, doublon ! Cm = Cm.reshape(__n,Un.size) # ADAO & check shape Xn_predicted = Xn_predicted + Cm * Un - Pn_predicted = Q + Mt * Pn * Ma + Pn_predicted = Q + Mt * (Pn * Ma) elif selfA._parameters["EstimationOf"] == "Parameters": # Observation of forecast # --- > Par principe, M = Id, Q = 0 Xn_predicted = Xn @@ -3400,8 +3401,8 @@ def std4dvar(selfA, Xb, Y, U, HO, EM, CM, R, B, Q): Ma = EM["Adjoint"].asMatrix(ValueForMethodForm = _Xn) Ma = Ma.reshape(_Xn.size,_Xn.size) # ADAO & check shape # Calcul du gradient par état adjoint - GradJo = GradJo + Ha * RI * _YmHMX # Équivaut pour Ha linéaire à : Ha( (_Xn, RI * _YmHMX) ) - GradJo = Ma * GradJo # Équivaut pour Ma linéaire à : Ma( (_Xn, GradJo) ) + GradJo = GradJo + Ha * (RI * _YmHMX) # Équivaut pour Ha linéaire à : Ha( (_Xn, RI * _YmHMX) ) + GradJo = Ma * GradJo # Équivaut pour Ma linéaire à : Ma( (_Xn, GradJo) ) GradJ = numpy.ravel( GradJb ) - numpy.ravel( GradJo ) return GradJ # @@ -3485,7 +3486,7 @@ def std4dvar(selfA, Xb, Y, U, HO, EM, CM, R, B, Q): # # Obtention de l'analyse # ---------------------- - Xa = numpy.asmatrix(numpy.ravel( Minimum )).T + Xa = Minimum # selfA.StoredVariables["Analysis"].store( Xa ) # @@ -3578,7 +3579,7 @@ def stdkf(selfA, Xb, Y, U, HO, EM, CM, R, B, Q): if Cm is not None and Un is not None: # Attention : si Cm est aussi dans M, doublon ! Cm = Cm.reshape(__n,Un.size) # ADAO & check shape Xn_predicted = Xn_predicted + Cm * Un - Pn_predicted = Q + Mt * Pn * Ma + Pn_predicted = Q + Mt * (Pn * Ma) elif selfA._parameters["EstimationOf"] == "Parameters": # Observation of forecast # --- > Par principe, M = Id, Q = 0 Xn_predicted = Xn -- 2.39.2