]> SALOME platform Git repositories - modules/adao.git/blob - src/daComposant/daAlgorithms/ObservationSimulationComparisonTest.py
Salome HOME
Documentation and code update for PSO
[modules/adao.git] / src / daComposant / daAlgorithms / ObservationSimulationComparisonTest.py
1 # -*- coding: utf-8 -*-
2 #
3 # Copyright (C) 2008-2023 EDF R&D
4 #
5 # This library is free software; you can redistribute it and/or
6 # modify it under the terms of the GNU Lesser General Public
7 # License as published by the Free Software Foundation; either
8 # version 2.1 of the License.
9 #
10 # This library is distributed in the hope that it will be useful,
11 # but WITHOUT ANY WARRANTY; without even the implied warranty of
12 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
13 # Lesser General Public License for more details.
14 #
15 # You should have received a copy of the GNU Lesser General Public
16 # License along with this library; if not, write to the Free Software
17 # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
18 #
19 # See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com
20 #
21 # Author: Jean-Philippe Argaud, jean-philippe.argaud@edf.fr, EDF R&D
22
23 import numpy, copy, logging
24 from daCore import BasicObjects, PlatformInfo
25 mpr = PlatformInfo.PlatformInfo().MachinePrecision()
26 mfp = PlatformInfo.PlatformInfo().MaximumPrecision()
27
28 # ==============================================================================
29 class ElementaryAlgorithm(BasicObjects.Algorithm):
30     def __init__(self):
31         BasicObjects.Algorithm.__init__(self, "OBSERVATIONSIMULATIONCOMPARISONTEST")
32         self.defineRequiredParameter(
33             name     = "ShowElementarySummary",
34             default  = True,
35             typecast = bool,
36             message  = "Calcule et affiche un résumé à chaque évaluation élémentaire",
37             )
38         self.defineRequiredParameter(
39             name     = "NumberOfPrintedDigits",
40             default  = 5,
41             typecast = int,
42             message  = "Nombre de chiffres affichés pour les impressions de réels",
43             minval   = 0,
44             )
45         self.defineRequiredParameter(
46             name     = "NumberOfRepetition",
47             default  = 1,
48             typecast = int,
49             message  = "Nombre de fois où l'exécution de la fonction est répétée",
50             minval   = 1,
51             )
52         self.defineRequiredParameter(
53             name     = "ResultTitle",
54             default  = "",
55             typecast = str,
56             message  = "Titre du tableau et de la figure",
57             )
58         self.defineRequiredParameter(
59             name     = "SetDebug",
60             default  = False,
61             typecast = bool,
62             message  = "Activation du mode debug lors de l'exécution",
63             )
64         self.defineRequiredParameter(
65             name     = "StoreSupplementaryCalculations",
66             default  = [],
67             typecast = tuple,
68             message  = "Liste de calculs supplémentaires à stocker et/ou effectuer",
69             listval  = [
70                 "CostFunctionJ",
71                 "CostFunctionJb",
72                 "CostFunctionJo",
73                 "CurrentState",
74                 "Innovation",
75                 "InnovationAtCurrentState",
76                 "OMB",
77                 "SimulatedObservationAtCurrentState",
78                 ]
79             )
80         self.requireInputArguments(
81             mandatory= ("Xb", "Y", "HO", "R", "B"),
82             )
83         self.setAttributes(tags=(
84             "Checking",
85             ))
86
87     def run(self, Xb=None, Y=None, U=None, HO=None, EM=None, CM=None, R=None, B=None, Q=None, Parameters=None):
88         self._pre_run(Parameters, Xb, Y, U, HO, EM, CM, R, B, Q)
89         #
90         Hm = HO["Direct"].appliedTo
91         #
92         X0 = copy.copy( Xb )
93         Y0 = copy.copy( Y )
94         #
95         # ----------
96         if len(self._parameters["StoreSupplementaryCalculations"]) > 0:
97             BI = B.getI()
98             RI = R.getI()
99             def CostFunction(x,HmX):
100                 _X  = numpy.ravel(  x  )
101                 _HX = numpy.ravel( HmX )
102                 _X0 = numpy.ravel( X0 )
103                 _Y0 = numpy.ravel( Y0 )
104                 Jb  = float( 0.5 *  (_X - _X0).T * (BI * (_X - _X0))  )
105                 Jo  = float( 0.5 * (_Y0 - _HX).T * (RI * (_Y0 - _HX)) )
106                 J   = Jb + Jo
107                 self.StoredVariables["CostFunctionJb"].store( Jb )
108                 self.StoredVariables["CostFunctionJo"].store( Jo )
109                 self.StoredVariables["CostFunctionJ" ].store( J )
110                 return J, Jb, Jo
111         # ----------
112         __s = self._parameters["ShowElementarySummary"]
113         __p = self._parameters["NumberOfPrintedDigits"]
114         __r = self._parameters["NumberOfRepetition"]
115         #
116         __marge = 5*u" "
117         __flech = 3*"="+"> "
118         msgs  = ("\n") # 1
119         if len(self._parameters["ResultTitle"]) > 0:
120             __rt = str(self._parameters["ResultTitle"])
121             msgs += (__marge + "====" + "="*len(__rt) + "====\n")
122             msgs += (__marge + "    " + __rt + "\n")
123             msgs += (__marge + "====" + "="*len(__rt) + "====\n")
124         else:
125             msgs += (__marge + "%s\n"%self._name)
126             msgs += (__marge + "%s\n"%("="*len(self._name),))
127         #
128         msgs += ("\n")
129         msgs += (__marge + "This test allows to analyze the (repetition of the) launch of some\n")
130         msgs += (__marge + "given simulation operator F, applied to one single vector argument x,\n")
131         msgs += (__marge + "and its comparison to observations or measures y through the innovation\n")
132         msgs += (__marge + "difference OMB = y - F(x) (Observation minus evaluation at Background)\n")
133         msgs += (__marge + "and (if required) the data assimilation standard cost function J.\n")
134         msgs += (__marge + "The output shows simple statistics related to its successful execution,\n")
135         msgs += (__marge + "or related to the similarities of repetition of its execution.\n")
136         msgs += ("\n")
137         msgs += (__flech + "Information before launching:\n")
138         msgs += (__marge + "-----------------------------\n")
139         msgs += ("\n")
140         msgs += (__marge + "Characteristics of input vector X, internally converted:\n")
141         msgs += (__marge + "  Type...............: %s\n")%type( X0 )
142         msgs += (__marge + "  Length of vector...: %i\n")%max(numpy.ravel( X0 ).shape)
143         msgs += (__marge + "  Minimum value......: %."+str(__p)+"e\n")%numpy.min(  X0 )
144         msgs += (__marge + "  Maximum value......: %."+str(__p)+"e\n")%numpy.max(  X0 )
145         msgs += (__marge + "  Mean of vector.....: %."+str(__p)+"e\n")%numpy.mean( X0, dtype=mfp )
146         msgs += (__marge + "  Standard error.....: %."+str(__p)+"e\n")%numpy.std(  X0, dtype=mfp )
147         msgs += (__marge + "  L2 norm of vector..: %."+str(__p)+"e\n")%numpy.linalg.norm( X0 )
148         msgs += ("\n")
149         msgs += (__marge + "Characteristics of input vector of observations Yobs, internally converted:\n")
150         msgs += (__marge + "  Type...............: %s\n")%type( Y0 )
151         msgs += (__marge + "  Length of vector...: %i\n")%max(numpy.ravel( Y0 ).shape)
152         msgs += (__marge + "  Minimum value......: %."+str(__p)+"e\n")%numpy.min(  Y0 )
153         msgs += (__marge + "  Maximum value......: %."+str(__p)+"e\n")%numpy.max(  Y0 )
154         msgs += (__marge + "  Mean of vector.....: %."+str(__p)+"e\n")%numpy.mean( Y0, dtype=mfp )
155         msgs += (__marge + "  Standard error.....: %."+str(__p)+"e\n")%numpy.std(  Y0, dtype=mfp )
156         msgs += (__marge + "  L2 norm of vector..: %."+str(__p)+"e\n")%numpy.linalg.norm( Y0 )
157         msgs += ("\n")
158         msgs += (__marge + "%s\n\n"%("-"*75,))
159         #
160         if self._parameters["SetDebug"]:
161             CUR_LEVEL = logging.getLogger().getEffectiveLevel()
162             logging.getLogger().setLevel(logging.DEBUG)
163             if __r > 1:
164                 msgs += (__flech + "Beginning of repeated evaluation, activating debug\n")
165             else:
166                 msgs += (__flech + "Beginning of evaluation, activating debug\n")
167         else:
168             if __r > 1:
169                 msgs += (__flech + "Beginning of repeated evaluation, without activating debug\n")
170             else:
171                 msgs += (__flech + "Beginning of evaluation, without activating debug\n")
172         print(msgs) # 1
173         #
174         # ----------
175         HO["Direct"].disableAvoidingRedundancy()
176         # ----------
177         Ys = []
178         Ds = []
179         Js = []
180         _Y0 = numpy.ravel( Y0 )
181         for i in range(__r):
182             if self._toStore("CurrentState"):
183                 self.StoredVariables["CurrentState"].store( X0 )
184             if __s:
185                 msgs  = (__marge + "%s\n"%("-"*75,)) # 2-1
186                 if __r > 1:
187                     msgs += ("\n")
188                     msgs += (__flech + "Repetition step number %i on a total of %i\n"%(i+1,__r))
189                 msgs += ("\n")
190                 msgs += (__flech + "Launching operator sequential evaluation\n")
191                 print(msgs) # 2-1
192             #
193             Yn = Hm( X0 )
194             #
195             if _Y0.size != Yn.size:
196                 raise ValueError("The size %i of observations Y and %i of observed calculation F(X) are different, they have to be identical."%(Y0.size,Yn.size))
197             #
198             Dn = _Y0 - numpy.ravel( Yn )
199             #
200             if len(self._parameters["StoreSupplementaryCalculations"]) > 0:
201                 J, Jb, Jo = CostFunction( X0, Yn )
202                 if self._toStore("CostFunctionJ"):
203                     Js.append( J )
204             if __s:
205                 msgs  = ("\n") # 2-2
206                 msgs += (__flech + "End of operator sequential evaluation\n")
207                 msgs += ("\n")
208                 msgs += (__flech + "Information after evaluation:\n")
209                 msgs += ("\n")
210                 msgs += (__marge + "Characteristics of simulated output vector Y=F(X), to compare to others:\n")
211                 msgs += (__marge + "  Type...............: %s\n")%type( Yn )
212                 msgs += (__marge + "  Length of vector...: %i\n")%max(numpy.ravel( Yn ).shape)
213                 msgs += (__marge + "  Minimum value......: %."+str(__p)+"e\n")%numpy.min(  Yn )
214                 msgs += (__marge + "  Maximum value......: %."+str(__p)+"e\n")%numpy.max(  Yn )
215                 msgs += (__marge + "  Mean of vector.....: %."+str(__p)+"e\n")%numpy.mean( Yn, dtype=mfp )
216                 msgs += (__marge + "  Standard error.....: %."+str(__p)+"e\n")%numpy.std(  Yn, dtype=mfp )
217                 msgs += (__marge + "  L2 norm of vector..: %."+str(__p)+"e\n")%numpy.linalg.norm( Yn )
218                 msgs += ("\n")
219                 msgs += (__marge + "Characteristics of OMB differences between observations Yobs and simulated output vector Y=F(X):\n")
220                 msgs += (__marge + "  Type...............: %s\n")%type( Dn )
221                 msgs += (__marge + "  Length of vector...: %i\n")%max(numpy.ravel( Dn ).shape)
222                 msgs += (__marge + "  Minimum value......: %."+str(__p)+"e\n")%numpy.min(  Dn )
223                 msgs += (__marge + "  Maximum value......: %."+str(__p)+"e\n")%numpy.max(  Dn )
224                 msgs += (__marge + "  Mean of vector.....: %."+str(__p)+"e\n")%numpy.mean( Dn, dtype=mfp )
225                 msgs += (__marge + "  Standard error.....: %."+str(__p)+"e\n")%numpy.std(  Dn, dtype=mfp )
226                 msgs += (__marge + "  L2 norm of vector..: %."+str(__p)+"e\n")%numpy.linalg.norm( Dn )
227                 if len(self._parameters["StoreSupplementaryCalculations"]) > 0:
228                     if self._toStore("CostFunctionJ"):
229                         msgs += ("\n")
230                         msgs += (__marge + "  Cost function J....: %."+str(__p)+"e\n")%J
231                         msgs += (__marge + "  Cost function Jb...: %."+str(__p)+"e\n")%Jb
232                         msgs += (__marge + "  Cost function Jo...: %."+str(__p)+"e\n")%Jo
233                         msgs += (__marge + "  (Remark: the Jb background part of the cost function J is zero by hypothesis)\n")
234                 print(msgs) # 2-2
235             if self._toStore("SimulatedObservationAtCurrentState"):
236                 self.StoredVariables["SimulatedObservationAtCurrentState"].store( numpy.ravel(Yn) )
237             if self._toStore("Innovation"):
238                 self.StoredVariables["Innovation"].store( Dn )
239             if self._toStore("OMB"):
240                 self.StoredVariables["OMB"].store( Dn )
241             if self._toStore("InnovationAtCurrentState"):
242                 self.StoredVariables["InnovationAtCurrentState"].store( Dn )
243             #
244             Ys.append( copy.copy( numpy.ravel(
245                 Yn
246                 ) ) )
247             Ds.append( copy.copy( numpy.ravel(
248                 Dn
249                 ) ) )
250         # ----------
251         HO["Direct"].enableAvoidingRedundancy()
252         # ----------
253         #
254         msgs  = (__marge + "%s\n\n"%("-"*75,)) # 3
255         if self._parameters["SetDebug"]:
256             if __r > 1:
257                 msgs += (__flech + "End of repeated evaluation, deactivating debug if necessary\n")
258             else:
259                 msgs += (__flech + "End of evaluation, deactivating debug if necessary\n")
260             logging.getLogger().setLevel(CUR_LEVEL)
261         else:
262             if __r > 1:
263                 msgs += (__flech + "End of repeated evaluation, without deactivating debug\n")
264             else:
265                 msgs += (__flech + "End of evaluation, without deactivating debug\n")
266         msgs += ("\n")
267         msgs += (__marge + "%s\n"%("-"*75,))
268         #
269         if __r > 1:
270             msgs += ("\n")
271             msgs += (__flech + "Launching statistical summary calculation for %i states\n"%__r)
272             msgs += ("\n")
273             msgs += (__marge + "%s\n"%("-"*75,))
274             msgs += ("\n")
275             msgs += (__flech + "Statistical analysis of the outputs obtained through sequential repeated evaluations\n")
276             msgs += ("\n")
277             msgs += (__marge + "(Remark: numbers that are (about) under %.0e represent 0 to machine precision)\n"%mpr)
278             msgs += ("\n")
279             Yy = numpy.array( Ys )
280             msgs += (__marge + "Number of evaluations...........................: %i\n")%len( Ys )
281             msgs += ("\n")
282             msgs += (__marge + "Characteristics of the whole set of outputs Y:\n")
283             msgs += (__marge + "  Size of each of the outputs...................: %i\n")%Ys[0].size
284             msgs += (__marge + "  Minimum value of the whole set of outputs.....: %."+str(__p)+"e\n")%numpy.min(  Yy )
285             msgs += (__marge + "  Maximum value of the whole set of outputs.....: %."+str(__p)+"e\n")%numpy.max(  Yy )
286             msgs += (__marge + "  Mean of vector of the whole set of outputs....: %."+str(__p)+"e\n")%numpy.mean( Yy, dtype=mfp )
287             msgs += (__marge + "  Standard error of the whole set of outputs....: %."+str(__p)+"e\n")%numpy.std(  Yy, dtype=mfp )
288             msgs += ("\n")
289             Ym = numpy.mean( numpy.array( Ys ), axis=0, dtype=mfp )
290             msgs += (__marge + "Characteristics of the vector Ym, mean of the outputs Y:\n")
291             msgs += (__marge + "  Size of the mean of the outputs...............: %i\n")%Ym.size
292             msgs += (__marge + "  Minimum value of the mean of the outputs......: %."+str(__p)+"e\n")%numpy.min(  Ym )
293             msgs += (__marge + "  Maximum value of the mean of the outputs......: %."+str(__p)+"e\n")%numpy.max(  Ym )
294             msgs += (__marge + "  Mean of the mean of the outputs...............: %."+str(__p)+"e\n")%numpy.mean( Ym, dtype=mfp )
295             msgs += (__marge + "  Standard error of the mean of the outputs.....: %."+str(__p)+"e\n")%numpy.std(  Ym, dtype=mfp )
296             msgs += ("\n")
297             Ye = numpy.mean( numpy.array( Ys ) - Ym, axis=0, dtype=mfp )
298             msgs += (__marge + "Characteristics of the mean of the differences between the outputs Y and their mean Ym:\n")
299             msgs += (__marge + "  Size of the mean of the differences...........: %i\n")%Ye.size
300             msgs += (__marge + "  Minimum value of the mean of the differences..: %."+str(__p)+"e\n")%numpy.min(  Ye )
301             msgs += (__marge + "  Maximum value of the mean of the differences..: %."+str(__p)+"e\n")%numpy.max(  Ye )
302             msgs += (__marge + "  Mean of the mean of the differences...........: %."+str(__p)+"e\n")%numpy.mean( Ye, dtype=mfp )
303             msgs += (__marge + "  Standard error of the mean of the differences.: %."+str(__p)+"e\n")%numpy.std(  Ye, dtype=mfp )
304             msgs += ("\n")
305             msgs += (__marge + "%s\n"%("-"*75,))
306             msgs += ("\n")
307             msgs += (__flech + "Statistical analysis of the OMB differences obtained through sequential repeated evaluations\n")
308             msgs += ("\n")
309             msgs += (__marge + "(Remark: numbers that are (about) under %.0e represent 0 to machine precision)\n"%mpr)
310             msgs += ("\n")
311             Dy = numpy.array( Ds )
312             msgs += (__marge + "Number of evaluations...........................: %i\n")%len( Ds )
313             msgs += ("\n")
314             msgs += (__marge + "Characteristics of the whole set of OMB differences:\n")
315             msgs += (__marge + "  Size of each of the outputs...................: %i\n")%Ds[0].size
316             msgs += (__marge + "  Minimum value of the whole set of differences.: %."+str(__p)+"e\n")%numpy.min(  Dy )
317             msgs += (__marge + "  Maximum value of the whole set of differences.: %."+str(__p)+"e\n")%numpy.max(  Dy )
318             msgs += (__marge + "  Mean of vector of the whole set of differences: %."+str(__p)+"e\n")%numpy.mean( Dy, dtype=mfp )
319             msgs += (__marge + "  Standard error of the whole set of differences: %."+str(__p)+"e\n")%numpy.std(  Dy, dtype=mfp )
320             msgs += ("\n")
321             Dm = numpy.mean( numpy.array( Ds ), axis=0, dtype=mfp )
322             msgs += (__marge + "Characteristics of the vector Dm, mean of the OMB differences:\n")
323             msgs += (__marge + "  Size of the mean of the differences...........: %i\n")%Dm.size
324             msgs += (__marge + "  Minimum value of the mean of the differences..: %."+str(__p)+"e\n")%numpy.min(  Dm )
325             msgs += (__marge + "  Maximum value of the mean of the differences..: %."+str(__p)+"e\n")%numpy.max(  Dm )
326             msgs += (__marge + "  Mean of the mean of the differences...........: %."+str(__p)+"e\n")%numpy.mean( Dm, dtype=mfp )
327             msgs += (__marge + "  Standard error of the mean of the differences.: %."+str(__p)+"e\n")%numpy.std(  Dm, dtype=mfp )
328             msgs += ("\n")
329             De = numpy.mean( numpy.array( Ds ) - Dm, axis=0, dtype=mfp )
330             msgs += (__marge + "Characteristics of the mean of the differences between the OMB differences and their mean Dm:\n")
331             msgs += (__marge + "  Size of the mean of the differences...........: %i\n")%De.size
332             msgs += (__marge + "  Minimum value of the mean of the differences..: %."+str(__p)+"e\n")%numpy.min( De )
333             msgs += (__marge + "  Maximum value of the mean of the differences..: %."+str(__p)+"e\n")%numpy.max( De )
334             msgs += (__marge + "  Mean of the mean of the differences...........: %."+str(__p)+"e\n")%numpy.mean( De, dtype=mfp )
335             msgs += (__marge + "  Standard error of the mean of the differences.: %."+str(__p)+"e\n")%numpy.std( De, dtype=mfp )
336             #
337             if self._toStore("CostFunctionJ"):
338                 msgs += ("\n")
339                 Jj = numpy.array( Js )
340                 msgs += (__marge + "%s\n\n"%("-"*75,))
341                 msgs += (__flech + "Statistical analysis of the cost function J values obtained through sequential repeated evaluations\n")
342                 msgs += ("\n")
343                 msgs += (__marge + "Number of evaluations...........................: %i\n")%len( Js )
344                 msgs += ("\n")
345                 msgs += (__marge + "Characteristics of the whole set of data assimilation cost function J values:\n")
346                 msgs += (__marge + "  Minimum value of the whole set of J...........: %."+str(__p)+"e\n")%numpy.min(  Jj )
347                 msgs += (__marge + "  Maximum value of the whole set of J...........: %."+str(__p)+"e\n")%numpy.max(  Jj )
348                 msgs += (__marge + "  Mean of vector of the whole set of J..........: %."+str(__p)+"e\n")%numpy.mean( Jj, dtype=mfp )
349                 msgs += (__marge + "  Standard error of the whole set of J..........: %."+str(__p)+"e\n")%numpy.std(  Jj, dtype=mfp )
350                 msgs += (__marge + "  (Remark: variations of the cost function J only come from the observation part Jo of J)\n")
351             msgs += ("\n")
352             msgs += (__marge + "%s\n"%("-"*75,))
353         #
354         msgs += ("\n")
355         msgs += (__marge + "End of the \"%s\" verification\n\n"%self._name)
356         msgs += (__marge + "%s\n"%("-"*75,))
357         print(msgs) # 3
358         #
359         self._post_run(HO)
360         return 0
361
362 # ==============================================================================
363 if __name__ == "__main__":
364     print('\n AUTODIAGNOSTIC\n')