2 Copyright (C) 2008-2015 EDF R&D
4 This file is part of SALOME ADAO module.
6 This library is free software; you can redistribute it and/or
7 modify it under the terms of the GNU Lesser General Public
8 License as published by the Free Software Foundation; either
9 version 2.1 of the License, or (at your option) any later version.
11 This library is distributed in the hope that it will be useful,
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 Lesser General Public License for more details.
16 You should have received a copy of the GNU Lesser General Public
17 License along with this library; if not, write to the Free Software
18 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
20 See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com
22 Author: Jean-Philippe Argaud, jean-philippe.argaud@edf.fr, EDF R&D
24 .. _section_ref_operator_requirements:
26 Exigences pour les fonctions décrivant un opérateur
27 ---------------------------------------------------
29 Les opérateurs d'observation et d'évolution sont nécessaires pour mettre en
30 oeuvre les procédures d'assimilation de données ou d'optimisation. Ils
31 comprennent la simulation physique par des calculs numériques, mais aussi le
32 filtrage et de restriction pour comparer la simulation à l'observation.
33 L'opérateur d'évolution est ici considéré dans sa forme incrémentale, qui
34 représente la transition entre deux états successifs, et il est alors similaire
35 à l'opérateur d'observation.
37 Schématiquement, un opérateur doit donner une solution étant donné les
38 paramètres d'entrée. Une partie des paramètres d'entrée peut être modifiée au
39 cours de la procédure d'optimisation. Ainsi, la représentation mathématique d'un
40 tel processus est une fonction. Il a été brièvement décrit dans la section
41 :ref:`section_theory` et il est généralisée ici par la relation:
43 .. math:: \mathbf{y} = O( \mathbf{x} )
45 entre les pseudo-observations :math:`\mathbf{y}` et les paramètres
46 :math:`\mathbf{x}` en utilisant l'opérateur d'observation ou d'évolution
47 :math:`O`. La même représentation fonctionnelle peut être utilisée pour le
48 modèle linéaire tangent :math:`\mathbf{O}` de :math:`O` et son adjoint
49 :math:`\mathbf{O}^*`, qui sont aussi requis par certains algorithmes
50 d'assimilation de données ou d'optimisation.
52 En entrée et en sortie de ces opérateurs, les variables :math:`\mathbf{x}` et
53 :math:`\mathbf{y}` ou leurs incréments sont mathématiquement des vecteurs, et
54 ils sont donc passés comme des vecteurs non-orientés (de type liste ou vecteur
55 Numpy) ou orientés (de type matrice Numpy).
57 Ensuite, **pour décrire complètement un opérateur, l'utilisateur n'a qu'à
58 fournir une fonction qui réalise uniquement l'opération fonctionnelle de manière
61 Cette fonction est généralement donnée comme un script qui peut être exécuté
62 dans un noeud YACS. Ce script peut aussi, sans différences, lancer des codes
63 externes ou utiliser des appels et des méthodes internes SALOME. Si l'algorithme
64 nécessite les 3 aspects de l'opérateur (forme directe, forme tangente et forme
65 adjointe), l'utilisateur doit donner les 3 fonctions ou les approximer.
67 Il existe 3 méthodes effectives pour l'utilisateur de fournir une représentation
68 fonctionnelle de l'opérateur. Ces méthodes sont choisies dans le champ "*FROM*"
69 de chaque opérateur ayant une valeur "*Function*" comme "*INPUT_TYPE*", comme le
70 montre la figure suivante:
72 .. eficas_operator_function:
73 .. image:: images/eficas_operator_function.png
77 **Choisir une représentation fonctionnelle de l'opérateur**
79 Première forme fonctionnelle : utiliser "*ScriptWithOneFunction*"
80 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
82 .. index:: single: ScriptWithOneFunction
83 .. index:: single: DirectOperator
84 .. index:: single: DifferentialIncrement
85 .. index:: single: CenteredFiniteDifference
87 La première consiste à ne fournir qu'une seule fonction potentiellement non
88 linéaire, et d'approximer les opérateurs tangent et adjoint. Ceci est fait en
89 utilisant le mot-clé "*ScriptWithOneFunction*" pour la description de
90 l'opérateur choisi dans l'interface graphique ADAO. L'utilisateur doit fournir
91 la fonction dans un script, avec un nom obligatoire "*DirectOperator*". Par
92 exemple, le script peut suivre le modèle suivant::
94 def DirectOperator( X ):
95 """ Opérateur direct de simulation non-linéaire """
101 Dans ce cas, l'utilisateur doit aussi fournir une valeur pour l'incrément
102 différentiel (ou conserver la valeur par défaut), en utilisant dans l'interface
103 graphique (GUI) le mot-clé "*DifferentialIncrement*", qui a une valeur par
104 défaut de 1%. Ce coefficient est utilisé dans l'approximation différences finies
105 pour construire les opérateurs tangent et adjoint. L'ordre de l'approximation
106 différences finies peut aussi être choisi à travers l'interface, en utilisant le
107 mot-clé "*CenteredFiniteDifference*", avec 0 pour un schéma non centré du
108 premier ordre (qui est la valeur par défaut), et avec 1 pour un schéma centré du
109 second ordre (qui coûte numériquement deux fois plus cher que le premier ordre).
110 Si nécessaire et si possible, on peut :ref:`subsection_ref_parallel_df`.
112 Cette première forme de définition de l'opérateur permet aisément de tester la
113 forme fonctionnelle avant son usage dans un cas ADAO, réduisant notablement la
114 complexité de l'implémentation de l'opérateur. On peut ainsi utiliser
115 l'algorithme ADAO de vérification "*FunctionTest*" (voir la section sur
116 l':ref:`section_ref_algorithm_FunctionTest`) pour ce test.
118 **Avertissement important :** le nom "*DirectOperator*" est obligatoire, et le
119 type de l'argument ``X`` peut être une liste, un vecteur ou une matrice Numpy.
120 La fonction utilisateur doit accepter et traiter tous ces cas.
122 Seconde forme fonctionnelle : utiliser "*ScriptWithFunctions*"
123 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
125 .. index:: single: ScriptWithFunctions
126 .. index:: single: DirectOperator
127 .. index:: single: TangentOperator
128 .. index:: single: AdjointOperator
130 **En général, il est recommandé d'utiliser la première forme fonctionnelle
131 plutôt que la seconde. Un petit accroissement de performances n'est pas une
132 bonne raison pour utiliser l'implémentation détaillée de cette seconde forme
135 La seconde consiste à fournir directement les trois opérateurs liés :math:`O`,
136 :math:`\mathbf{O}` et :math:`\mathbf{O}^*`. C'est effectué en utilisant le
137 mot-clé "*ScriptWithFunctions*" pour la description de l'opérateur choisi dans
138 l'interface graphique (GUI) d'ADAO. L'utilisateur doit fournir trois fonctions
139 dans un script, avec trois noms obligatoires "*DirectOperator*",
140 "*TangentOperator*" et "*AdjointOperator*". Par exemple, le script peut suivre
141 le squelette suivant::
143 def DirectOperator( X ):
144 """ Opérateur direct de simulation non-linéaire """
148 return quelque chose comme Y
150 def TangentOperator( (X, dX) ):
151 """ Opérateur linéaire tangent, autour de X, appliqué à dX """
155 return quelque chose comme Y
157 def AdjointOperator( (X, Y) ):
158 """ Opérateur adjoint, autour de X, appliqué à Y """
162 return quelque chose comme X
164 Un nouvelle fois, cette seconde définition d'opérateur permet aisément de tester
165 les formes fonctionnelles avant de les utiliser dans le cas ADAO, réduisant la
166 complexité de l'implémentation de l'opérateur.
168 Pour certains algorithmes, il faut que les fonctions tangente et adjointe puisse
169 renvoyer les matrices équivalentes à l'opérateur linéaire. Dans ce cas, lorsque,
170 respectivement, les arguments ``dX`` ou ``Y`` valent ``None``, l'utilisateur
171 doit renvoyer la matrice associée.
173 **Avertissement important :** les noms "*DirectOperator*", "*TangentOperator*"
174 et "*AdjointOperator*" sont obligatoires, et le type des arguments ``X``,
175 ``Y``, ``dX`` peut être une liste, un vecteur ou une matrice Numpy.
176 La fonction utilisateur doit accepter et traiter tous ces cas.
178 Troisième forme fonctionnelle : utiliser "*ScriptWithSwitch*"
179 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
181 .. index:: single: ScriptWithSwitch
182 .. index:: single: DirectOperator
183 .. index:: single: TangentOperator
184 .. index:: single: AdjointOperator
186 **Il est recommandé de ne pas utiliser cette troisième forme fonctionnelle sans
187 une solide raison numérique ou physique. Un accroissement de performances n'est
188 pas une bonne raison pour utiliser la complexité de cette troisième forme
189 fonctionnelle. Seule une impossibilité à utiliser les première ou seconde formes
190 justifie l'usage de la troisième.**
192 La troisième forme donne de plus grandes possibilités de contrôle de l'exécution
193 des trois fonctions représentant l'opérateur, permettant un usage et un contrôle
194 avancés sur chaque exécution du code de simulation. C'est réalisable en
195 utilisant le mot-clé "*ScriptWithSwitch*" pour la description de l'opérateur à
196 travers l'interface graphique (GUI) d'ADAO. L'utilisateur doit fournir un script
197 unique aiguillant, selon un contrôle, l'exécution des formes directe, tangente
198 et adjointe du code de simulation. L'utilisateur peut alors, par exemple,
199 utiliser des approximations pour les codes tangent et adjoint, ou introduire une
200 plus grande complexité du traitement des arguments des fonctions. Mais cette
201 démarche sera plus difficile à implémenter et à déboguer.
203 Toutefois, si vous souhaitez utiliser cette troisième forme, on recommande de se
204 baser sur le modèle suivant pour le script d'aiguillage. Il nécessite un fichier
205 script ou un code externe nommé ici "*Physical_simulation_functions.py*",
206 contenant trois fonctions nommées "*DirectOperator*", "*TangentOperator*" et
207 "*AdjointOperator*" comme précédemment. Voici le squelette d'aiguillage::
209 import Physical_simulation_functions
210 import numpy, logging
213 for param in computation["specificParameters"]:
214 if param["name"] == "method":
215 method = param["value"]
216 if method not in ["Direct", "Tangent", "Adjoint"]:
217 raise ValueError("No valid computation method is given")
218 logging.info("Found method is \'%s\'"%method)
220 logging.info("Loading operator functions")
221 Function = Physical_simulation_functions.DirectOperator
222 Tangent = Physical_simulation_functions.TangentOperator
223 Adjoint = Physical_simulation_functions.AdjointOperator
225 logging.info("Executing the possible computations")
227 if method == "Direct":
228 logging.info("Direct computation")
229 Xcurrent = computation["inputValues"][0][0][0]
230 data = Function(numpy.matrix( Xcurrent ).T)
231 if method == "Tangent":
232 logging.info("Tangent computation")
233 Xcurrent = computation["inputValues"][0][0][0]
234 dXcurrent = computation["inputValues"][0][0][1]
235 data = Tangent(numpy.matrix(Xcurrent).T, numpy.matrix(dXcurrent).T)
236 if method == "Adjoint":
237 logging.info("Adjoint computation")
238 Xcurrent = computation["inputValues"][0][0][0]
239 Ycurrent = computation["inputValues"][0][0][1]
240 data = Adjoint((numpy.matrix(Xcurrent).T, numpy.matrix(Ycurrent).T))
242 logging.info("Formatting the output")
243 it = numpy.ravel(data)
244 outputValues = [[[[]]]]
246 outputValues[0][0][0].append(val)
249 result["outputValues"] = outputValues
250 result["specificOutputInfos"] = []
251 result["returnCode"] = 0
252 result["errorMessage"] = ""
254 Toutes les modifications envisageables peuvent être faites à partir de cette
255 hypothèse de squelette.
257 .. _section_ref_operator_control:
259 Cas spécial d'un opérateur d'évolution avec contrôle
260 ++++++++++++++++++++++++++++++++++++++++++++++++++++
262 Dans certains cas, l'opérateur d'évolution ou d'observation doit être contrôlé
263 par un contrôle d'entrée externe, qui est donné *a priori*. Dans ce cas, la
264 forme générique du modèle incrémental est légèrement modifié comme suit:
266 .. math:: \mathbf{y} = O( \mathbf{x}, \mathbf{u})
268 où :math:`\mathbf{u}` est le contrôle sur l'incrément d'état. En effet,
269 l'opérateur direct doit être appliqué à une paire de variables :math:`(X,U)`.
270 Schématiquement, l'opérateur doit être construit comme suit::
272 def DirectOperator( (X, U) ):
273 """ Opérateur direct de simulation non-linéaire """
277 return quelque chose comme X(n+1) (évolution) ou Y(n+1) (observation)
279 Les opérateurs tangent et adjoint ont la même signature que précédemment, en
280 notant que les dérivées doivent être faites seulement partiellement par rapport
281 à :math:`\mathbf{x}`. Dans un tel cas de contrôle explicite, seule la deuxième
282 forme fonctionnelle (en utilisant "*ScriptWithFunctions*") et la troisième forme
283 fonctionnelle (en utilisant "*ScriptWithSwitch*") peuvent être utilisées.