1 # -*- coding: utf-8 -*-
3 # Copyright (C) 2008-2023 EDF R&D
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.
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.
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
19 # See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com
21 # Author: Jean-Philippe Argaud, jean-philippe.argaud@edf.fr, EDF R&D
24 Empirical Interpolation Method EIM & lcEIM
26 __author__ = "Jean-Philippe ARGAUD"
29 import daCore.Persistence
30 from daCore.NumericObjects import FindIndexesFromNames
32 # ==============================================================================
33 def EIM_offline(selfA, EOS = None, Verbose = False):
35 Établissement de la base
40 if isinstance(EOS, (numpy.ndarray, numpy.matrix)):
41 __EOS = numpy.asarray(EOS)
42 elif isinstance(EOS, (list, tuple, daCore.Persistence.Persistence)):
43 __EOS = numpy.stack([numpy.ravel(_sn) for _sn in EOS], axis=1)
44 # __EOS = numpy.asarray(EOS).T
46 raise ValueError("EnsembleOfSnapshots has to be an array/matrix (each column being a vector) or a list/tuple (each element being a vector).")
47 __dimS, __nbmS = __EOS.shape
48 logging.debug("%s Building a RB using a collection of %i snapshots of individual size of %i"%(selfA._name,__nbmS,__dimS))
50 if selfA._parameters["ErrorNorm"] == "L2":
51 MaxNormByColumn = MaxL2NormByColumn
53 MaxNormByColumn = MaxLinfNormByColumn
55 if selfA._parameters["Variant"] in ["EIM", "PositioningByEIM"]:
59 if __LcCsts and "ExcludeLocations" in selfA._parameters:
60 __ExcludedMagicPoints = selfA._parameters["ExcludeLocations"]
62 __ExcludedMagicPoints = ()
63 if __LcCsts and "NameOfLocations" in selfA._parameters:
64 if isinstance(selfA._parameters["NameOfLocations"], (list, numpy.ndarray, tuple)) and len(selfA._parameters["NameOfLocations"]) == __dimS:
65 __NameOfLocations = selfA._parameters["NameOfLocations"]
67 __NameOfLocations = ()
69 __NameOfLocations = ()
70 if __LcCsts and len(__ExcludedMagicPoints) > 0:
71 __ExcludedMagicPoints = FindIndexesFromNames( __NameOfLocations, __ExcludedMagicPoints )
72 __ExcludedMagicPoints = numpy.ravel(numpy.asarray(__ExcludedMagicPoints, dtype=int))
73 __IncludedMagicPoints = numpy.setdiff1d(
74 numpy.arange(__EOS.shape[0]),
75 __ExcludedMagicPoints,
79 __IncludedMagicPoints = []
81 if "MaximumNumberOfLocations" in selfA._parameters and "MaximumRBSize" in selfA._parameters:
82 selfA._parameters["MaximumRBSize"] = min(selfA._parameters["MaximumNumberOfLocations"],selfA._parameters["MaximumRBSize"])
83 elif "MaximumNumberOfLocations" in selfA._parameters:
84 selfA._parameters["MaximumRBSize"] = selfA._parameters["MaximumNumberOfLocations"]
85 elif "MaximumRBSize" in selfA._parameters:
88 selfA._parameters["MaximumRBSize"] = __nbmS
89 __maxM = min(selfA._parameters["MaximumRBSize"], __dimS, __nbmS)
90 if "ErrorNormTolerance" in selfA._parameters:
91 selfA._parameters["EpsilonEIM"] = selfA._parameters["ErrorNormTolerance"]
93 selfA._parameters["EpsilonEIM"] = 1.e-2
97 __Q = numpy.empty(__dimS).reshape((-1,1))
102 __rhoM = numpy.empty(__dimS)
104 __eM, __muM = MaxNormByColumn(__EOS, __LcCsts, __IncludedMagicPoints)
105 __residuM = __EOS[:,__muM]
106 __errors.append(__eM)
110 while __M < __maxM and __eM > selfA._parameters["EpsilonEIM"]:
115 # Détermination du point et de la fonction magiques
116 __abs_residuM = numpy.abs(__residuM)
117 __iM = numpy.argmax(__abs_residuM)
118 __rhoM = __residuM / __residuM[__iM]
120 if __LcCsts and __iM in __ExcludedMagicPoints:
121 __sIndices = numpy.argsort(__abs_residuM)
123 assert __iM == __sIndices[__rang]
124 while __iM in __ExcludedMagicPoints and __rang >= -len(__abs_residuM):
126 __iM = __sIndices[__rang]
129 __Q = numpy.column_stack((__Q, __rhoM))
131 __Q = __rhoM.reshape((-1,1))
134 __restrictedQi = __Q[__I,:]
136 __Qi_inv = numpy.linalg.inv(__restrictedQi)
138 __Qi_inv = 1. / __restrictedQi
140 __restrictedEOSi = __EOS[__I,:]
143 __interpolator = numpy.dot(__Q,numpy.dot(__Qi_inv,__restrictedEOSi))
145 __interpolator = numpy.outer(__Q,numpy.outer(__Qi_inv,__restrictedEOSi))
147 __dataForNextIter = __EOS - __interpolator
148 __eM, __muM = MaxNormByColumn(__dataForNextIter, __LcCsts, __IncludedMagicPoints)
149 __errors.append(__eM)
151 __residuM = __dataForNextIter[:,__muM]
153 #--------------------------
154 if __errors[-1] < selfA._parameters["EpsilonEIM"]:
155 logging.debug("%s %s (%.1e)"%(selfA._name,"The convergence is obtained when reaching the required EIM tolerance",selfA._parameters["EpsilonEIM"]))
157 logging.debug("%s %s (%i)"%(selfA._name,"The convergence is obtained when reaching the maximum number of RB dimension",__maxM))
158 logging.debug("%s The RB of size %i has been correctly build"%(selfA._name,__Q.shape[1]))
159 logging.debug("%s There are %i points that have been excluded from the potential optimal points"%(selfA._name,len(__ExcludedMagicPoints)))
160 if hasattr(selfA, "StoredVariables"):
161 selfA.StoredVariables["OptimalPoints"].store( __I )
162 if selfA._toStore("ReducedBasis"):
163 selfA.StoredVariables["ReducedBasis"].store( __Q )
164 if selfA._toStore("Residus"):
165 selfA.StoredVariables["Residus"].store( __errors )
166 if selfA._toStore("ExcludedPoints"):
167 selfA.StoredVariables["ExcludedPoints"].store( __ExcludedMagicPoints )
169 return __mu, __I, __Q, __errors
171 # ==============================================================================
172 def EIM_online(selfA, QEIM, gJmu = None, mPoints = None, mu = None, PseudoInverse = True, rbDimension = None, Verbose = False):
174 Reconstruction du champ complet
176 if gJmu is None and mu is None:
177 raise ValueError("Either measurements or parameters has to be given as a list, both can not be None simultaneously.")
179 raise ValueError("List of optimal locations for measurements has to be given.")
181 if len(gJmu) > len(mPoints):
182 raise ValueError("The number of measurements (%i) has to be less or equal to the number of optimal locations (%i)."%(len(gJmu),len(mPoints)))
183 if len(gJmu) > QEIM.shape[1]:
184 raise ValueError("The number of measurements (%i) in optimal locations has to be less or equal to the dimension of the RB (%i)."%(len(gJmu),QEIM.shape[1]))
185 __gJmu = numpy.ravel(gJmu)
188 raise NotImplementedError()
189 if rbDimension is not None:
190 rbDimension = min(QEIM.shape[1], rbDimension)
192 rbDimension = QEIM.shape[1]
193 __rbDim = min(QEIM.shape[1],len(mPoints),len(gJmu),rbDimension) # Modulation
194 #--------------------------
196 # Restriction aux mesures
198 __QJinv = numpy.linalg.pinv( QEIM[mPoints,0:__rbDim] )
199 __gammaMu = numpy.dot( __QJinv, __gJmu[0:__rbDim])
201 __gammaMu = numpy.linalg.solve( QEIM[mPoints,0:__rbDim], __gJmu[0:__rbDim] )
203 # Interpolation du champ complet
204 __gMmu = numpy.dot( QEIM[:,0:__rbDim], __gammaMu )
206 #--------------------------
207 logging.debug("%s The full field of size %i has been correctly build"%(selfA._name,__gMmu.size))
208 if hasattr(selfA, "StoredVariables"):
209 selfA.StoredVariables["Analysis"].store( __gMmu )
210 if selfA._toStore("ReducedCoordinates"):
211 selfA.StoredVariables["ReducedCoordinates"].store( __gammaMu )
215 # ==============================================================================
216 def MaxL2NormByColumn(Ensemble, LcCsts = False, IncludedPoints = []):
218 if LcCsts and len(IncludedPoints) > 0:
219 for indice in range(Ensemble.shape[1]):
220 norme = numpy.linalg.norm(
221 numpy.take(Ensemble[:,indice], IncludedPoints, mode='clip'),
224 nmax, imax, = norme, indice
226 for indice in range(Ensemble.shape[1]):
227 norme = numpy.linalg.norm(
231 nmax, imax, = norme, indice
234 def MaxLinfNormByColumn(Ensemble, LcCsts = False, IncludedPoints = []):
236 if LcCsts and len(IncludedPoints) > 0:
237 for indice in range(Ensemble.shape[1]):
238 norme = numpy.linalg.norm(
239 numpy.take(Ensemble[:,indice], IncludedPoints, mode='clip'),
243 nmax, imax, = norme, indice
245 for indice in range(Ensemble.shape[1]):
246 norme = numpy.linalg.norm(
251 nmax, imax, = norme, indice
254 # ==============================================================================
255 if __name__ == "__main__":
256 print('\n AUTODIAGNOSTIC\n')