]> SALOME platform Git repositories - modules/adao.git/commitdiff
Salome HOME
Internal modifications and performance improvements V9_8_0a1 V9_8_0a2
authorJean-Philippe ARGAUD <jean-philippe.argaud@edf.fr>
Thu, 14 Oct 2021 18:46:33 +0000 (20:46 +0200)
committerJean-Philippe ARGAUD <jean-philippe.argaud@edf.fr>
Thu, 14 Oct 2021 18:46:33 +0000 (20:46 +0200)
src/daComposant/daCore/Aidsm.py
src/daComposant/daCore/BasicObjects.py
src/daComposant/daCore/Interfaces.py
src/daComposant/daCore/NumericObjects.py

index 6937f322460d7292926156a7fa9d873abe33eebc..1875aefc957a77333aff555189e3adbe1d10f210 100644 (file)
@@ -99,7 +99,6 @@ class Aidsm(object):
             Concept              = None, # Premier argument
             Algorithm            = None,
             AppliedInXb          = None,
-            AvoidRC              = True,
             Checked              = False,
             ColMajor             = False,
             ColNames             = None,
@@ -113,6 +112,7 @@ class Aidsm(object):
             ObjectMatrix         = None,
             OneFunction          = None,
             Parameters           = None,
+            PerformanceProfile   = None,
             ScalarSparseMatrix   = None,
             Scheduler            = None,
             Script               = None,
@@ -156,13 +156,13 @@ class Aidsm(object):
                 self.setObservationOperator(
                     Matrix, OneFunction, ThreeFunctions, AppliedInXb,
                     Parameters, Script, ExtraArguments,
-                    Stored, AvoidRC, InputFunctionAsMulti, Checked )
+                    Stored, PerformanceProfile, InputFunctionAsMulti, Checked )
             elif Concept in ("EvolutionModel", "ControlModel"):
                 commande = getattr(self,"set"+Concept)
                 commande(
                     Matrix, OneFunction, ThreeFunctions,
                     Parameters, Script, Scheduler, ExtraArguments,
-                    Stored, AvoidRC, InputFunctionAsMulti, Checked )
+                    Stored, PerformanceProfile, InputFunctionAsMulti, Checked )
             else:
                 raise ValueError("the variable named '%s' is not allowed."%str(Concept))
         except Exception as e:
@@ -368,7 +368,7 @@ class Aidsm(object):
             Script               = None,
             ExtraArguments       = None,
             Stored               = False,
-            AvoidRC              = True,
+            PerformanceProfile   = None,
             InputFunctionAsMulti = False,
             Checked              = False):
         "Definition d'un concept de calcul"
@@ -383,7 +383,7 @@ class Aidsm(object):
             asDict           = Parameters,
             appliedInX       = AppliedInXb,
             extraArguments   = ExtraArguments,
-            avoidRC          = AvoidRC,
+            performancePrf   = PerformanceProfile,
             inputAsMF        = InputFunctionAsMulti,
             scheduledBy      = None,
             toBeChecked      = Checked,
@@ -401,7 +401,7 @@ class Aidsm(object):
             Scheduler            = None,
             ExtraArguments       = None,
             Stored               = False,
-            AvoidRC              = True,
+            PerformanceProfile   = None,
             InputFunctionAsMulti = False,
             Checked              = False):
         "Definition d'un concept de calcul"
@@ -416,7 +416,7 @@ class Aidsm(object):
             asDict           = Parameters,
             appliedInX       = None,
             extraArguments   = ExtraArguments,
-            avoidRC          = AvoidRC,
+            performancePrf   = PerformanceProfile,
             inputAsMF        = InputFunctionAsMulti,
             scheduledBy      = Scheduler,
             toBeChecked      = Checked,
@@ -434,7 +434,7 @@ class Aidsm(object):
             Scheduler            = None,
             ExtraArguments       = None,
             Stored               = False,
-            AvoidRC              = True,
+            PerformanceProfile   = None,
             InputFunctionAsMulti = False,
             Checked              = False):
         "Definition d'un concept de calcul"
@@ -449,7 +449,7 @@ class Aidsm(object):
             asDict           = Parameters,
             appliedInX       = None,
             extraArguments   = ExtraArguments,
-            avoidRC          = AvoidRC,
+            performancePrf   = PerformanceProfile,
             inputAsMF        = InputFunctionAsMulti,
             scheduledBy      = Scheduler,
             toBeChecked      = Checked,
index 4f41743e8adb294abf27565227e7c68cfdfa0ca8..1293b9643a8fe1fc3d6c5aa9c3134c5aafd73c23 100644 (file)
@@ -125,6 +125,7 @@ class Operator(object):
         fromMethod           = None,
         fromMatrix           = None,
         avoidingRedundancy   = True,
+        reducingMemoryUse    = False,
         inputAsMultiFunction = False,
         enableMultiProcess   = False,
         extraArguments       = None,
@@ -138,6 +139,8 @@ class Operator(object):
         - fromMethod : argument de type fonction Python
         - fromMatrix : argument adapté au constructeur numpy.matrix
         - avoidingRedundancy : booléen évitant (ou pas) les calculs redondants
+        - reducingMemoryUse : booléen forçant (ou pas) des calculs moins
+          gourmands en mémoire
         - inputAsMultiFunction : booléen indiquant une fonction explicitement
           définie (ou pas) en multi-fonction
         - extraArguments : arguments supplémentaires passés à la fonction de
@@ -145,7 +148,8 @@ class Operator(object):
         """
         self.__name      = str(name)
         self.__NbCallsAsMatrix, self.__NbCallsAsMethod, self.__NbCallsOfCached = 0, 0, 0
-        self.__AvoidRC   = bool( avoidingRedundancy )
+        self.__reduceM   = bool( reducingMemoryUse )
+        self.__avoidRC   = bool( avoidingRedundancy )
         self.__inputAsMF = bool( inputAsMultiFunction )
         self.__mpEnabled = bool( enableMultiProcess )
         self.__extraArgs = extraArguments
@@ -172,7 +176,7 @@ class Operator(object):
 
     def enableAvoidingRedundancy(self):
         "Active le cache"
-        if self.__AvoidRC:
+        if self.__avoidRC:
             Operator.CM.enable()
         else:
             Operator.CM.disable()
@@ -208,14 +212,14 @@ class Operator(object):
             _HxValue = []
             for i in range(len(_HValue)):
                 _HxValue.append( numpy.asmatrix( numpy.ravel( _HValue[i] ) ).T )
-                if self.__AvoidRC:
+                if self.__avoidRC:
                     Operator.CM.storeValueInX(_xValue[i],_HxValue[-1],self.__name)
         else:
             _HxValue = []
             _xserie = []
             _hindex = []
             for i, xv in enumerate(_xValue):
-                if self.__AvoidRC:
+                if self.__avoidRC:
                     __alreadyCalculated, __HxV = Operator.CM.wasCalculatedIn(xv,self.__name)
                 else:
                     __alreadyCalculated = False
@@ -246,7 +250,7 @@ class Operator(object):
                     _xv = _xserie.pop(0)
                     _hv = _hserie.pop(0)
                     _HxValue[i] = _hv
-                    if self.__AvoidRC:
+                    if self.__avoidRC:
                         Operator.CM.storeValueInX(_xv,_hv,self.__name)
         #
         if returnSerieAsArrayMatrix:
@@ -417,7 +421,7 @@ class FullOperator(object):
                  asDict           = None, # Parameters
                  appliedInX       = None,
                  extraArguments   = None,
-                 avoidRC          = True,
+                 performancePrf   = None,
                  inputAsMF        = False,# Fonction(s) as Multi-Functions
                  scheduledBy      = None,
                  toBeChecked      = False,
@@ -444,6 +448,15 @@ class FullOperator(object):
             __Parameters["EnableMultiProcessingInEvaluation"]  = False
         if "withIncrement" in __Parameters: # Temporaire
             __Parameters["DifferentialIncrement"] = __Parameters["withIncrement"]
+        # Le défaut est équivalent à "ReducedOverallRequirements"
+        __reduceM, __avoidRC = True, True
+        if performancePrf is not None:
+            if   performancePrf == "ReducedAmountOfCalculation":
+                __reduceM, __avoidRC = False, True
+            elif performancePrf == "ReducedMemoryFootprint":
+                __reduceM, __avoidRC = True, False
+            elif performancePrf == "NoSavings":
+                __reduceM, __avoidRC = False, False
         #
         if asScript is not None:
             __Matrix, __Function = None, None
@@ -512,7 +525,8 @@ class FullOperator(object):
             if "CenteredFiniteDifference"           not in __Function: __Function["CenteredFiniteDifference"]           = False
             if "DifferentialIncrement"              not in __Function: __Function["DifferentialIncrement"]              = 0.01
             if "withdX"                             not in __Function: __Function["withdX"]                             = None
-            if "withAvoidingRedundancy"             not in __Function: __Function["withAvoidingRedundancy"]             = avoidRC
+            if "withReducingMemoryUse"              not in __Function: __Function["withReducingMemoryUse"]              = __reduceM
+            if "withAvoidingRedundancy"             not in __Function: __Function["withAvoidingRedundancy"]             = __avoidRC
             if "withToleranceInRedundancy"          not in __Function: __Function["withToleranceInRedundancy"]          = 1.e-18
             if "withLenghtOfRedundancy"             not in __Function: __Function["withLenghtOfRedundancy"]             = -1
             if "NumberOfProcesses"                  not in __Function: __Function["NumberOfProcesses"]                  = None
@@ -525,6 +539,7 @@ class FullOperator(object):
                 increment             = __Function["DifferentialIncrement"],
                 dX                    = __Function["withdX"],
                 extraArguments        = self.__extraArgs,
+                reducingMemoryUse     = __Function["withReducingMemoryUse"],
                 avoidingRedundancy    = __Function["withAvoidingRedundancy"],
                 toleranceInRedundancy = __Function["withToleranceInRedundancy"],
                 lenghtOfRedundancy    = __Function["withLenghtOfRedundancy"],
@@ -532,20 +547,20 @@ class FullOperator(object):
                 mpWorkers             = __Function["NumberOfProcesses"],
                 mfEnabled             = __Function["withmfEnabled"],
                 )
-            self.__FO["Direct"]  = Operator( name = self.__name,           fromMethod = FDA.DirectOperator,  avoidingRedundancy = avoidRC, inputAsMultiFunction = inputAsMF, extraArguments = self.__extraArgs, enableMultiProcess = __Parameters["EnableMultiProcessingInEvaluation"] )
-            self.__FO["Tangent"] = Operator( name = self.__name+"Tangent", fromMethod = FDA.TangentOperator, avoidingRedundancy = avoidRC, inputAsMultiFunction = inputAsMF, extraArguments = self.__extraArgs )
-            self.__FO["Adjoint"] = Operator( name = self.__name+"Adjoint", fromMethod = FDA.AdjointOperator, avoidingRedundancy = avoidRC, inputAsMultiFunction = inputAsMF, extraArguments = self.__extraArgs )
+            self.__FO["Direct"]  = Operator( name = self.__name,           fromMethod = FDA.DirectOperator,  reducingMemoryUse = __reduceM, avoidingRedundancy = __avoidRC, inputAsMultiFunction = inputAsMF, extraArguments = self.__extraArgs, enableMultiProcess = __Parameters["EnableMultiProcessingInEvaluation"] )
+            self.__FO["Tangent"] = Operator( name = self.__name+"Tangent", fromMethod = FDA.TangentOperator, reducingMemoryUse = __reduceM, avoidingRedundancy = __avoidRC, inputAsMultiFunction = inputAsMF, extraArguments = self.__extraArgs )
+            self.__FO["Adjoint"] = Operator( name = self.__name+"Adjoint", fromMethod = FDA.AdjointOperator, reducingMemoryUse = __reduceM, avoidingRedundancy = __avoidRC, inputAsMultiFunction = inputAsMF, extraArguments = self.__extraArgs )
         elif isinstance(__Function, dict) and \
                 ("Direct" in __Function) and ("Tangent" in __Function) and ("Adjoint" in __Function) and \
                 (__Function["Direct"] is not None) and (__Function["Tangent"] is not None) and (__Function["Adjoint"] is not None):
-            self.__FO["Direct"]  = Operator( name = self.__name,           fromMethod = __Function["Direct"],  avoidingRedundancy = avoidRC, inputAsMultiFunction = inputAsMF, extraArguments = self.__extraArgs, enableMultiProcess = __Parameters["EnableMultiProcessingInEvaluation"] )
-            self.__FO["Tangent"] = Operator( name = self.__name+"Tangent", fromMethod = __Function["Tangent"], avoidingRedundancy = avoidRC, inputAsMultiFunction = inputAsMF, extraArguments = self.__extraArgs )
-            self.__FO["Adjoint"] = Operator( name = self.__name+"Adjoint", fromMethod = __Function["Adjoint"], avoidingRedundancy = avoidRC, inputAsMultiFunction = inputAsMF, extraArguments = self.__extraArgs )
+            self.__FO["Direct"]  = Operator( name = self.__name,           fromMethod = __Function["Direct"],  reducingMemoryUse = __reduceM, avoidingRedundancy = __avoidRC, inputAsMultiFunction = inputAsMF, extraArguments = self.__extraArgs, enableMultiProcess = __Parameters["EnableMultiProcessingInEvaluation"] )
+            self.__FO["Tangent"] = Operator( name = self.__name+"Tangent", fromMethod = __Function["Tangent"], reducingMemoryUse = __reduceM, avoidingRedundancy = __avoidRC, inputAsMultiFunction = inputAsMF, extraArguments = self.__extraArgs )
+            self.__FO["Adjoint"] = Operator( name = self.__name+"Adjoint", fromMethod = __Function["Adjoint"], reducingMemoryUse = __reduceM, avoidingRedundancy = __avoidRC, inputAsMultiFunction = inputAsMF, extraArguments = self.__extraArgs )
         elif asMatrix is not None:
             __matrice = numpy.matrix( __Matrix, numpy.float )
-            self.__FO["Direct"]  = Operator( name = self.__name,           fromMatrix = __matrice,   avoidingRedundancy = avoidRC, inputAsMultiFunction = inputAsMF, enableMultiProcess = __Parameters["EnableMultiProcessingInEvaluation"] )
-            self.__FO["Tangent"] = Operator( name = self.__name+"Tangent", fromMatrix = __matrice,   avoidingRedundancy = avoidRC, inputAsMultiFunction = inputAsMF )
-            self.__FO["Adjoint"] = Operator( name = self.__name+"Adjoint", fromMatrix = __matrice.T, avoidingRedundancy = avoidRC, inputAsMultiFunction = inputAsMF )
+            self.__FO["Direct"]  = Operator( name = self.__name,           fromMatrix = __matrice,   reducingMemoryUse = __reduceM, avoidingRedundancy = __avoidRC, inputAsMultiFunction = inputAsMF, enableMultiProcess = __Parameters["EnableMultiProcessingInEvaluation"] )
+            self.__FO["Tangent"] = Operator( name = self.__name+"Tangent", fromMatrix = __matrice,   reducingMemoryUse = __reduceM, avoidingRedundancy = __avoidRC, inputAsMultiFunction = inputAsMF )
+            self.__FO["Adjoint"] = Operator( name = self.__name+"Adjoint", fromMatrix = __matrice.T, reducingMemoryUse = __reduceM, avoidingRedundancy = __avoidRC, inputAsMultiFunction = inputAsMF )
             del __matrice
         else:
             raise ValueError("The %s object is improperly defined or undefined, it requires at minima either a matrix, a Direct operator for approximate derivatives or a Tangent/Adjoint operators pair. Please check your operator input."%self.__name)
@@ -1010,7 +1025,10 @@ class Algorithm(object):
                 self._parameters[k] = self.setParameterValue(k)
             else:
                 pass
-            logging.debug("%s %s : %s", self._name, self.__required_parameters[k]["message"], self._parameters[k])
+            if hasattr(self._parameters[k],"__len__") and len(self._parameters[k]) > 100:
+                logging.debug("%s %s de longueur %s", self._name, self.__required_parameters[k]["message"], len(self._parameters[k]))
+            else:
+                logging.debug("%s %s : %s", self._name, self.__required_parameters[k]["message"], self._parameters[k])
 
     def _setInternalState(self, key=None, value=None, fromDico={}, reset=False):
         """
index 3a6895ce4677f277cb58fa70de19f82257356091..6d301aed426e3b1a121e040957ff3d3db1f50c25 100644 (file)
@@ -132,7 +132,7 @@ class _TUIViewer(GenericCaseViewer):
                 if   k == "ColMajor"             and not __v: continue
                 if   k == "InputFunctionAsMulti" and not __v: continue
                 if   k == "nextStep"             and not __v: continue
-                if   k == "AvoidRC"              and     __v: continue
+                if   k == "PerformanceProfile"   and     __v: continue
                 if   k == "noDetails":                        continue
                 if isinstance(__v,Persistence.Persistence): __v = __v.values()
                 if callable(__v): __text = self._missing%__v.__name__+__text
@@ -491,7 +491,7 @@ class _SCDViewer(GenericCaseViewer):
                 elif __k in ('Stored', 'Checked', 'ColMajor', 'InputFunctionAsMulti', 'nextStep'):
                     if bool(__v):
                         __text += "%s_config['%s'] = '%s'\n"%(__command,__k,int(bool(__v)))
-                elif __k in ('AvoidRC', 'noDetails'):
+                elif __k in ('PerformanceProfile', 'noDetails'):
                     if not bool(__v):
                         __text += "%s_config['%s'] = '%s'\n"%(__command,__k,int(bool(__v)))
                 else:
@@ -646,7 +646,7 @@ class _ReportViewer(GenericCaseViewer):
                 if   k == "ColMajor"             and not __v: continue
                 if   k == "InputFunctionAsMulti" and not __v: continue
                 if   k == "nextStep"             and not __v: continue
-                if   k == "AvoidRC"              and     __v: continue
+                if   k == "PerformanceProfile"   and     __v: continue
                 if   k == "noDetails":                        continue
                 if   k == "Concept":                          continue
                 if   k == "self":                             continue
index 1a34b32df7bf25af0c3c9a85ce24f9218f62bd68..58d723e6f6ae230a3ae4891a12efe63c702e7ee4 100644 (file)
@@ -66,6 +66,7 @@ class FDApproximation(object):
             increment             = 0.01,
             dX                    = None,
             extraArguments        = None,
+            reducingMemoryUse     = False,
             avoidingRedundancy    = True,
             toleranceInRedundancy = 1.e-18,
             lenghtOfRedundancy    = -1,
@@ -75,6 +76,7 @@ class FDApproximation(object):
             ):
         self.__name = str(name)
         self.__extraArgs = extraArguments
+        #
         if mpEnabled:
             try:
                 import multiprocessing
@@ -88,12 +90,12 @@ class FDApproximation(object):
             self.__mpWorkers = None
         logging.debug("FDA Calculs en multiprocessing : %s (nombre de processus : %s)"%(self.__mpEnabled,self.__mpWorkers))
         #
-        if mfEnabled:
-            self.__mfEnabled = True
-        else:
-            self.__mfEnabled = False
+        self.__mfEnabled = bool(mfEnabled)
         logging.debug("FDA Calculs en multifonctions : %s"%(self.__mfEnabled,))
         #
+        self.__rmEnabled = bool(reducingMemoryUse)
+        logging.debug("FDA Calculs avec réduction mémoire : %s"%(self.__rmEnabled,))
+        #
         if avoidingRedundancy:
             self.__avoidRC = True
             self.__tolerBP = float(toleranceInRedundancy)
@@ -105,6 +107,9 @@ class FDApproximation(object):
             self.__listJPIN = [] # Jacobian Previous Calculated Increment Norms
         else:
             self.__avoidRC = False
+        logging.debug("FDA Calculs avec réduction des doublons : %s"%self.__avoidRC)
+        if self.__avoidRC:
+            logging.debug("FDA Tolérance de détermination des doublons : %.2e"%self.__tolerBP)
         #
         if self.__mpEnabled:
             if isinstance(Function,types.FunctionType):
@@ -150,9 +155,6 @@ class FDApproximation(object):
             self.__dX     = None
         else:
             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)
 
     # ---------------------------------------------------------
     def __doublon__(self, e, l, n, v=None):
@@ -164,6 +166,29 @@ class FDApproximation(object):
                 break
         return __ac, __iac
 
+    # ---------------------------------------------------------
+    def __listdotwith__(self, __LMatrix, __dotWith = None, __dotTWith = None):
+        "Produit incrémental d'une matrice liste de colonnes avec un vecteur"
+        if not isinstance(__LMatrix, (list,tuple)):
+            raise TypeError("Columnwise list matrix has not the proper type: %s"%type(__LMatrix))
+        if __dotWith is not None:
+            __Idwx = numpy.ravel( __dotWith )
+            assert len(__LMatrix) == __Idwx.size, "Incorrect size of elements"
+            __Produit = numpy.zeros(__LMatrix[0].size)
+            for i, col in enumerate(__LMatrix):
+                __Produit += float(__Idwx[i]) * col
+            return __Produit
+        elif __dotTWith is not None:
+            _Idwy = numpy.ravel( __dotTWith ).T
+            assert __LMatrix[0].size == _Idwy.size, "Incorrect size of elements"
+            __Produit = numpy.zeros(len(__LMatrix))
+            for i, col in enumerate(__LMatrix):
+                __Produit[i] = float( _Idwy @ col)
+            return __Produit
+        else:
+            __Produit = None
+        return __Produit
+
     # ---------------------------------------------------------
     def DirectOperator(self, X, **extraArgs ):
         """
@@ -181,7 +206,7 @@ class FDApproximation(object):
         return _HX
 
     # ---------------------------------------------------------
-    def TangentMatrix(self, X ):
+    def TangentMatrix(self, X, dotWith = None, dotTWith = None ):
         """
         Calcul de l'opérateur tangent comme la Jacobienne par différences finies,
         c'est-à-dire le gradient de H en X. On utilise des différences finies
@@ -240,6 +265,11 @@ class FDApproximation(object):
         if __alreadyCalculated:
             logging.debug("FDA   Calcul Jacobienne (par récupération du doublon %i)"%__i)
             _Jacobienne = self.__listJPCR[__i]
+            logging.debug("FDA Fin du calcul de la Jacobienne")
+            if dotWith is not None:
+                return numpy.dot(_Jacobienne,   numpy.ravel( dotWith ))
+            elif dotTWith is not None:
+                return numpy.dot(_Jacobienne.T, numpy.ravel( dotTWith ))
         else:
             logging.debug("FDA   Calcul Jacobienne (explicite)")
             if self.__centeredDF:
@@ -359,24 +389,29 @@ class FDApproximation(object):
                         _HX_plus_dXi = self.DirectOperator( _X_plus_dXi )
                         #
                         _Jacobienne.append( numpy.ravel(( _HX_plus_dXi - _HX ) / _dXi) )
-                #
             #
-            _Jacobienne = numpy.transpose( numpy.vstack( _Jacobienne ) )
-            if self.__avoidRC:
-                if self.__lenghtRJ < 0: self.__lenghtRJ = 2 * _X.size
-                while len(self.__listJPCP) > self.__lenghtRJ:
-                    self.__listJPCP.pop(0)
-                    self.__listJPCI.pop(0)
-                    self.__listJPCR.pop(0)
-                    self.__listJPPN.pop(0)
-                    self.__listJPIN.pop(0)
-                self.__listJPCP.append( copy.copy(_X) )
-                self.__listJPCI.append( copy.copy(_dX) )
-                self.__listJPCR.append( copy.copy(_Jacobienne) )
-                self.__listJPPN.append( numpy.linalg.norm(_X) )
-                self.__listJPIN.append( numpy.linalg.norm(_Jacobienne) )
-        #
-        logging.debug("FDA Fin du calcul de la Jacobienne")
+            if (dotWith is not None) or (dotTWith is not None):
+                __Produit = self.__listdotwith__(_Jacobienne, dotWith, dotTWith)
+            else:
+                __Produit = None
+            if __Produit is None or self.__avoidRC:
+                _Jacobienne = numpy.transpose( numpy.vstack( _Jacobienne ) )
+                if self.__avoidRC:
+                    if self.__lenghtRJ < 0: self.__lenghtRJ = 2 * _X.size
+                    while len(self.__listJPCP) > self.__lenghtRJ:
+                        self.__listJPCP.pop(0)
+                        self.__listJPCI.pop(0)
+                        self.__listJPCR.pop(0)
+                        self.__listJPPN.pop(0)
+                        self.__listJPIN.pop(0)
+                    self.__listJPCP.append( copy.copy(_X) )
+                    self.__listJPCI.append( copy.copy(_dX) )
+                    self.__listJPCR.append( copy.copy(_Jacobienne) )
+                    self.__listJPPN.append( numpy.linalg.norm(_X) )
+                    self.__listJPIN.append( numpy.linalg.norm(_Jacobienne) )
+            logging.debug("FDA Fin du calcul de la Jacobienne")
+            if __Produit is not None:
+                return __Produit
         #
         return _Jacobienne
 
@@ -389,26 +424,25 @@ class FDApproximation(object):
         ne doivent pas être données ici à la fonction utilisateur.
         """
         if self.__mfEnabled:
-            assert len(paire) == 1, "Incorrect lenght of arguments"
+            assert len(paire) == 1, "Incorrect length of arguments"
             _paire = paire[0]
             assert len(_paire) == 2, "Incorrect number of arguments"
         else:
             assert len(paire) == 2, "Incorrect number of arguments"
             _paire = paire
         X, dX = _paire
-        _Jacobienne = self.TangentMatrix( X )
         if dX is None or len(dX) == 0:
             #
             # Calcul de la forme matricielle si le second argument est None
             # -------------------------------------------------------------
+            _Jacobienne = self.TangentMatrix( X )
             if self.__mfEnabled: return [_Jacobienne,]
             else:                return _Jacobienne
         else:
             #
             # Calcul de la valeur linéarisée de H en X appliqué à dX
             # ------------------------------------------------------
-            _dX = numpy.ravel( dX )
-            _HtX = numpy.dot(_Jacobienne, _dX)
+            _HtX = self.TangentMatrix( X, dotWith = dX )
             if self.__mfEnabled: return [_HtX,]
             else:                return _HtX
 
@@ -421,26 +455,25 @@ class FDApproximation(object):
         ne doivent pas être données ici à la fonction utilisateur.
         """
         if self.__mfEnabled:
-            assert len(paire) == 1, "Incorrect lenght of arguments"
+            assert len(paire) == 1, "Incorrect length of arguments"
             _paire = paire[0]
             assert len(_paire) == 2, "Incorrect number of arguments"
         else:
             assert len(paire) == 2, "Incorrect number of arguments"
             _paire = paire
         X, Y = _paire
-        _JacobienneT = self.TangentMatrix( X ).T
         if Y is None or len(Y) == 0:
             #
             # Calcul de la forme matricielle si le second argument est None
             # -------------------------------------------------------------
+            _JacobienneT = self.TangentMatrix( X ).T
             if self.__mfEnabled: return [_JacobienneT,]
             else:                return _JacobienneT
         else:
             #
             # Calcul de la valeur de l'adjoint en X appliqué à Y
             # --------------------------------------------------
-            _Y = numpy.ravel( Y )
-            _HaY = numpy.dot(_JacobienneT, _Y)
+            _HaY = self.TangentMatrix( X, dotTWith = Y )
             if self.__mfEnabled: return [_HaY,]
             else:                return _HaY