Salome HOME
Improvement and extension of EnKF algorithm (KFF)
[modules/adao.git] / src / daComposant / daAlgorithms / EnsembleKalmanFilter.py
1 # -*- coding: utf-8 -*-
2 #
3 # Copyright (C) 2008-2020 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 logging
24 from daCore import BasicObjects, NumericObjects
25 import numpy
26
27 # ==============================================================================
28 class ElementaryAlgorithm(BasicObjects.Algorithm):
29     def __init__(self):
30         BasicObjects.Algorithm.__init__(self, "ENSEMBLEKALMANFILTER")
31         self.defineRequiredParameter(
32             name     = "Minimizer",
33             default  = "StochasticEnKF",
34             typecast = str,
35             message  = "Minimiseur utilisé",
36             listval  = [
37                 "StochasticEnKF",
38                 "ETKF",
39                 "ETKF-KFF",
40                 ],
41             )
42         self.defineRequiredParameter(
43             name     = "NumberOfMembers",
44             default  = 100,
45             typecast = int,
46             message  = "Nombre de membres dans l'ensemble",
47             minval   = -1,
48             )
49         self.defineRequiredParameter(
50             name     = "EstimationOf",
51             default  = "State",
52             typecast = str,
53             message  = "Estimation d'etat ou de parametres",
54             listval  = ["State", "Parameters"],
55             )
56         self.defineRequiredParameter(
57             name     = "InflationType",
58             default  = "MultiplicativeOnAnalysisCovariance",
59             typecast = str,
60             message  = "Méthode d'inflation d'ensemble",
61             listval  = [
62                 "MultiplicativeOnAnalysisCovariance",
63                 "MultiplicativeOnBackgroundCovariance",
64                 "MultiplicativeOnAnalysisAnomalies",
65                 "MultiplicativeOnBackgroundAnomalies",
66                 "AdditiveOnBackgroundCovariance",
67                 "AdditiveOnAnalysisCovariance",
68                 "HybridOnBackgroundCovariance",
69                 ],
70             )
71         self.defineRequiredParameter(
72             name     = "InflationFactor",
73             default  = 1.,
74             typecast = float,
75             message  = "Facteur d'inflation",
76             minval   = 0.,
77             )
78         self.defineRequiredParameter(
79             name     = "LocalizationType",
80             default  = "SchurLocalization",
81             typecast = str,
82             message  = "Méthode d'inflation d'ensemble",
83             listval  = [
84                 "CovarianceLocalization",
85                 "DomainLocalization",
86                 "SchurLocalization",
87                 "GaspariCohnLocalization",
88                 ],
89             )
90         self.defineRequiredParameter(
91             name     = "LocalizationFactor",
92             default  = 1.,
93             typecast = float,
94             message  = "Facteur de localisation",
95             minval   = 0.,
96             )
97         self.defineRequiredParameter( # Pas de type
98             name     = "LocalizationMatrix",
99             message  = "Matrice de localisation ou de distances",
100             )
101         self.defineRequiredParameter(
102             name     = "SetSeed",
103             typecast = numpy.random.seed,
104             message  = "Graine fixée pour le générateur aléatoire",
105             )
106         self.defineRequiredParameter(
107             name     = "StoreInternalVariables",
108             default  = False,
109             typecast = bool,
110             message  = "Stockage des variables internes ou intermédiaires du calcul",
111             )
112         self.defineRequiredParameter(
113             name     = "StoreSupplementaryCalculations",
114             default  = [],
115             typecast = tuple,
116             message  = "Liste de calculs supplémentaires à stocker et/ou effectuer",
117             listval  = [
118                 "Analysis",
119                 "APosterioriCorrelations",
120                 "APosterioriCovariance",
121                 "APosterioriStandardDeviations",
122                 "APosterioriVariances",
123                 "BMA",
124                 "CostFunctionJ",
125                 "CostFunctionJAtCurrentOptimum",
126                 "CostFunctionJb",
127                 "CostFunctionJbAtCurrentOptimum",
128                 "CostFunctionJo",
129                 "CostFunctionJoAtCurrentOptimum",
130                 "CurrentIterationNumber",
131                 "CurrentOptimum",
132                 "CurrentState",
133                 "ForecastState",
134                 "IndexOfOptimum",
135                 "InnovationAtCurrentAnalysis",
136                 "InnovationAtCurrentState",
137                 "SimulatedObservationAtCurrentAnalysis",
138                 "SimulatedObservationAtCurrentOptimum",
139                 "SimulatedObservationAtCurrentState",
140                 ]
141             )
142         self.requireInputArguments(
143             mandatory= ("Xb", "Y", "HO", "R", "B"),
144             optional = ("U", "EM", "CM", "Q"),
145             )
146         self.setAttributes(tags=(
147             "DataAssimilation",
148             "NonLinear",
149             "Filter",
150             "Ensemble",
151             "Dynamic",
152             ))
153
154     def run(self, Xb=None, Y=None, U=None, HO=None, EM=None, CM=None, R=None, B=None, Q=None, Parameters=None):
155         self._pre_run(Parameters, Xb, Y, U, HO, EM, CM, R, B, Q)
156         #
157         if self._parameters["Minimizer"] == "StochasticEnKF":
158             NumericObjects.senkf(self, Xb, Y, U, HO, EM, CM, R, B, Q)
159         elif self._parameters["Minimizer"] in ["ETKF", "ETKF-KFF"]:
160             NumericObjects.etkf(self, Xb, Y, U, HO, EM, CM, R, B, Q, KorV="KalmanFilterFormula")
161         else:
162             raise ValueError("Error in Minimizer name: %s"%self._parameters["Minimizer"])
163         #
164         self._post_run(HO)
165         return 0
166
167 # ==============================================================================
168 if __name__ == "__main__":
169     print('\n AUTODIAGNOSTIC\n')