1 # -*- coding: utf-8 -*-
3 # Copyright (C) 2008-2018 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 Normalized interface for ADAO scripting (generic API)
26 __author__ = "Jean-Philippe ARGAUD"
32 from daCore.BasicObjects import State, Covariance, FullOperator, Operator
33 from daCore.BasicObjects import AlgorithmAndParameters, DataObserver
34 from daCore.BasicObjects import DiagnosticAndParameters, CaseLogger
35 from daCore import PlatformInfo
37 from daCore import ExtendedLogging ; ExtendedLogging.ExtendedLogging() # A importer en premier
40 # ==============================================================================
42 """ ADAO Internal Data Structure Model """
43 def __init__(self, name = "", addViewers=None):
44 self.__name = str(name)
45 self.__case = CaseLogger(self.__name, "case", addViewers)
47 self.__adaoObject = {}
48 self.__StoredInputs = {}
51 "AlgorithmParameters",
60 "ObservationOperator",
68 for ename in self.__Concepts:
69 self.__adaoObject[ename] = None
70 for ename in ("ObservationOperator", "EvolutionModel", "ControlModel"):
71 self.__adaoObject[ename] = {}
72 for ename in ("Diagnostic", "Observer"):
73 self.__adaoObject[ename] = []
74 self.__StoredInputs[ename] = []
76 # Récupère le chemin du répertoire parent et l'ajoute au path
77 # (Cela complète l'action de la classe PathManagement dans PlatformInfo,
78 # qui est activée dans Persistence)
79 self.__parent = os.path.abspath(os.path.join(os.path.dirname(__file__),".."))
80 sys.path.insert(0, self.__parent)
81 sys.path = PlatformInfo.uniq( sys.path ) # Conserve en unique exemplaire chaque chemin
84 Concept = None, # Premier argument
91 DiagonalSparseMatrix = None,
95 ObjectFunction = None,
99 ScalarSparseMatrix = None,
105 ThreeFunctions = None,
111 "Interface unique de definition de variables d'entrees par argument"
112 self.__case.register("set",dir(),locals(),None,True)
114 if Concept in ("Background", "CheckingPoint", "ControlInput", "Observation", "Controls"):
115 commande = getattr(self,"set"+Concept)
116 commande(Vector, VectorSerie, Script, Scheduler, Stored, Checked )
117 elif Concept in ("BackgroundError", "ObservationError", "EvolutionError"):
118 commande = getattr(self,"set"+Concept)
119 commande(Matrix, ScalarSparseMatrix, DiagonalSparseMatrix,
120 ObjectMatrix, Script, Stored, Checked )
121 elif Concept == "AlgorithmParameters":
122 self.setAlgorithmParameters( Algorithm, Parameters, Script )
123 elif Concept == "Debug":
125 elif Concept == "NoDebug":
127 elif Concept == "Observer":
128 self.setObserver( Variable, Template, String, Script, ObjectFunction, Scheduler, Info )
129 elif Concept == "Diagnostic":
130 self.setDiagnostic( Diagnostic, Identifier, Parameters, Script, Unit, BaseType )
131 elif Concept == "ObservationOperator":
132 self.setObservationOperator(
133 Matrix, OneFunction, ThreeFunctions, AppliedInXb,
134 Parameters, Script, AvoidRC, Stored, Checked )
135 elif Concept in ("EvolutionModel", "ControlModel"):
136 commande = getattr(self,"set"+Concept)
138 Matrix, OneFunction, ThreeFunctions,
139 Parameters, Script, Scheduler, AvoidRC, Stored, Checked )
142 raise ValueError("the variable named '%s' is not allowed."%str(Concept))
143 except Exception as e:
144 if isinstance(e, SyntaxError): msg = "at %s: %s"%(e.offset, e.text)
146 raise ValueError("during settings, the following error occurs:\n"+\
147 "\n%s %s\n\nSee also the potential messages, "+\
148 "which can show the origin of the above error, "+\
149 "in the launching terminal."%(str(e),msg))
151 # -----------------------------------------------------------
153 def setBackground(self,
160 "Definition d'un concept de calcul"
161 Concept = "Background"
162 self.__case.register("set"+Concept, dir(), locals())
163 self.__adaoObject[Concept] = State(
166 asPersistentVector = VectorSerie,
168 scheduledBy = Scheduler,
169 toBeChecked = Checked,
172 self.__StoredInputs[Concept] = self.__adaoObject[Concept].getO()
175 def setCheckingPoint(self,
182 "Definition d'un concept de calcul"
183 Concept = "CheckingPoint"
184 self.__case.register("set"+Concept, dir(), locals())
185 self.__adaoObject[Concept] = State(
188 asPersistentVector = VectorSerie,
190 scheduledBy = Scheduler,
191 toBeChecked = Checked,
194 self.__StoredInputs[Concept] = self.__adaoObject[Concept].getO()
197 def setControlInput(self,
204 "Definition d'un concept de calcul"
205 Concept = "ControlInput"
206 self.__case.register("set"+Concept, dir(), locals())
207 self.__adaoObject[Concept] = State(
210 asPersistentVector = VectorSerie,
212 scheduledBy = Scheduler,
213 toBeChecked = Checked,
216 self.__StoredInputs[Concept] = self.__adaoObject[Concept].getO()
219 def setObservation(self,
226 "Definition d'un concept de calcul"
227 Concept = "Observation"
228 self.__case.register("set"+Concept, dir(), locals())
229 self.__adaoObject[Concept] = State(
232 asPersistentVector = VectorSerie,
234 scheduledBy = Scheduler,
235 toBeChecked = Checked,
238 self.__StoredInputs[Concept] = self.__adaoObject[Concept].getO()
241 def setControls(self,
242 Vector = (), # Valeur par defaut pour un vecteur vide
248 "Definition d'un concept de calcul"
250 self.__case.register("set"+Concept, dir(), locals())
251 self.__adaoObject[Concept] = State(
254 asPersistentVector = VectorSerie,
256 scheduledBy = Scheduler,
257 toBeChecked = Checked,
260 self.__StoredInputs[Concept] = self.__adaoObject[Concept].getO()
263 def setBackgroundError(self,
265 ScalarSparseMatrix = None,
266 DiagonalSparseMatrix = None,
271 "Definition d'un concept de calcul"
272 Concept = "BackgroundError"
273 self.__case.register("set"+Concept, dir(), locals())
274 self.__adaoObject[Concept] = Covariance(
276 asCovariance = Matrix,
277 asEyeByScalar = ScalarSparseMatrix,
278 asEyeByVector = DiagonalSparseMatrix,
279 asCovObject = ObjectMatrix,
281 toBeChecked = Checked,
284 self.__StoredInputs[Concept] = self.__adaoObject[Concept].getO()
287 def setObservationError(self,
289 ScalarSparseMatrix = None,
290 DiagonalSparseMatrix = None,
295 "Definition d'un concept de calcul"
296 Concept = "ObservationError"
297 self.__case.register("set"+Concept, dir(), locals())
298 self.__adaoObject[Concept] = Covariance(
300 asCovariance = Matrix,
301 asEyeByScalar = ScalarSparseMatrix,
302 asEyeByVector = DiagonalSparseMatrix,
303 asCovObject = ObjectMatrix,
305 toBeChecked = Checked,
308 self.__StoredInputs[Concept] = self.__adaoObject[Concept].getO()
311 def setEvolutionError(self,
313 ScalarSparseMatrix = None,
314 DiagonalSparseMatrix = None,
319 "Definition d'un concept de calcul"
320 Concept = "EvolutionError"
321 self.__case.register("set"+Concept, dir(), locals())
322 self.__adaoObject[Concept] = Covariance(
324 asCovariance = Matrix,
325 asEyeByScalar = ScalarSparseMatrix,
326 asEyeByVector = DiagonalSparseMatrix,
327 asCovObject = ObjectMatrix,
329 toBeChecked = Checked,
332 self.__StoredInputs[Concept] = self.__adaoObject[Concept].getO()
335 def setObservationOperator(self,
338 ThreeFunctions = None,
345 "Definition d'un concept de calcul"
346 Concept = "ObservationOperator"
347 self.__case.register("set"+Concept, dir(), locals())
348 self.__adaoObject[Concept] = FullOperator(
351 asOneFunction = OneFunction,
352 asThreeFunctions = ThreeFunctions,
355 appliedInX = AppliedInXb,
358 toBeChecked = Checked,
361 self.__StoredInputs[Concept] = self.__adaoObject[Concept].getO()
364 def setEvolutionModel(self,
367 ThreeFunctions = None,
374 "Definition d'un concept de calcul"
375 Concept = "EvolutionModel"
376 self.__case.register("set"+Concept, dir(), locals())
377 self.__adaoObject[Concept] = FullOperator(
380 asOneFunction = OneFunction,
381 asThreeFunctions = ThreeFunctions,
386 scheduledBy = Scheduler,
387 toBeChecked = Checked,
390 self.__StoredInputs[Concept] = self.__adaoObject[Concept].getO()
393 def setControlModel(self,
396 ThreeFunctions = None,
403 "Definition d'un concept de calcul"
404 Concept = "ControlModel"
405 self.__case.register("set"+Concept, dir(), locals())
406 self.__adaoObject[Concept] = FullOperator(
409 asOneFunction = OneFunction,
410 asThreeFunctions = ThreeFunctions,
415 scheduledBy = Scheduler,
416 toBeChecked = Checked,
419 self.__StoredInputs[Concept] = self.__adaoObject[Concept].getO()
422 def setDebug(self, level = 10):
423 "NOTSET=0 < DEBUG=10 < INFO=20 < WARNING=30 < ERROR=40 < CRITICAL=50"
424 self.__case.register("setDebug",dir(),locals())
425 log = logging.getLogger()
426 log.setLevel( level )
427 self.__StoredInputs["Debug"] = level
428 self.__StoredInputs["NoDebug"] = False
431 def setNoDebug(self):
432 "NOTSET=0 < DEBUG=10 < INFO=20 < WARNING=30 < ERROR=40 < CRITICAL=50"
433 self.__case.register("setNoDebug",dir(),locals())
434 log = logging.getLogger()
435 log.setLevel( logging.WARNING )
436 self.__StoredInputs["Debug"] = logging.WARNING
437 self.__StoredInputs["NoDebug"] = True
440 def setAlgorithmParameters(self,
444 "Definition d'un concept de calcul"
445 Concept = "AlgorithmParameters"
446 self.__case.register("set"+Concept, dir(), locals())
447 self.__adaoObject[Concept] = AlgorithmAndParameters(
449 asAlgorithm = Algorithm,
455 def updateAlgorithmParameters(self,
458 "Mise a jour d'un concept de calcul"
459 if "AlgorithmParameters" not in self.__adaoObject:
460 raise ValueError("No algorithm registred, ask for one before updating parameters")
461 self.__adaoObject["AlgorithmParameters"].updateParameters(
467 def setObserver(self,
472 ObjectFunction = None,
475 "Definition d'un concept de calcul"
477 self.__case.register("set"+Concept, dir(), locals())
478 self.__adaoObject[Concept].append( DataObserver(
480 onVariable = Variable,
481 asTemplate = Template,
484 asObsObject = ObjectFunction,
486 scheduledBy = Scheduler,
487 withAlgo = self.__adaoObject["AlgorithmParameters"]
491 def removeObserver(self,
493 ObjectFunction = None,
495 "Permet de retirer un observer à une ou des variable nommée"
496 if "AlgorithmParameters" not in self.__adaoObject:
497 raise ValueError("No algorithm registred, ask for one before removing observers")
499 # Vérification du nom de variable et typage
500 # -----------------------------------------
501 if isinstance(Variable, str):
502 VariableNames = (Variable,)
503 elif isinstance(Variable, list):
504 VariableNames = tuple(map( str, Variable ))
506 raise ValueError("The observer requires a name or a list of names of variables.")
508 # Association interne de l'observer à la variable
509 # -----------------------------------------------
510 for ename in VariableNames:
511 if ename not in self.__adaoObject["AlgorithmParameters"]:
512 raise ValueError("An observer requires to be removed on a variable named %s which does not exist."%ename)
514 return self.__adaoObject["AlgorithmParameters"].removeObserver( ename, ObjectFunction )
516 # -----------------------------------------------------------
518 def setDiagnostic(self,
525 "Definition d'un concept de calcul"
526 Concept = "Diagnostic"
527 self.__case.register("set"+Concept, dir(), locals())
528 self.__adaoObject[Concept].append( DiagnosticAndParameters(
530 asDiagnostic = Diagnostic,
531 asIdentifier = Identifier,
535 asBaseType = BaseType,
536 asExistingDiags = self.__StoredInputs[Concept],
538 self.__StoredInputs[Concept].append(str(Identifier))
541 def get(self, Concept=None, noDetails=True ):
542 "Recuperation d'une sortie du calcul"
543 if Concept is not None:
545 self.__case.register("get", dir(), locals(), Concept) # Break pickle in Python 2
548 if Concept in self.__StoredInputs:
549 return self.__StoredInputs[Concept]
551 elif self.__adaoObject["AlgorithmParameters"] is not None and Concept == "AlgorithmParameters":
552 return self.__adaoObject["AlgorithmParameters"].get()
554 elif self.__adaoObject["AlgorithmParameters"] is not None and Concept in self.__adaoObject["AlgorithmParameters"]:
555 return self.__adaoObject["AlgorithmParameters"].get( Concept )
557 elif Concept == "AlgorithmRequiredParameters" and self.__adaoObject["AlgorithmParameters"] is not None:
558 return self.__adaoObject["AlgorithmParameters"].getAlgorithmRequiredParameters(noDetails)
560 elif Concept in self.__StoredInputs["Diagnostic"]:
561 indice = self.__StoredInputs["Diagnostic"].index(Concept)
562 return self.__adaoObject["Diagnostic"][indice].get()
565 raise ValueError("The requested key \"%s\" does not exists as an input, a diagnostic or a stored variable."%Concept)
568 allvariables.update( {"AlgorithmParameters":self.__adaoObject["AlgorithmParameters"].get()} )
569 # allvariables.update( self.__adaoObject["AlgorithmParameters"].get() )
570 allvariables.update( self.__StoredInputs )
571 allvariables.pop('Diagnostic', None)
572 allvariables.pop('Observer', None)
575 # -----------------------------------------------------------
577 def get_available_variables(self):
579 Renvoie les variables potentiellement utilisables pour l'étude,
580 initialement stockées comme données d'entrées ou dans les algorithmes,
581 identifiés par les chaînes de caractères. L'algorithme doit avoir été
582 préalablement choisi sinon la méthode renvoie "None".
584 if len(list(self.__adaoObject["AlgorithmParameters"].keys())) == 0 and \
585 len(list(self.__StoredInputs.keys())) == 0:
589 if len(list(self.__adaoObject["AlgorithmParameters"].keys())) > 0:
590 variables.extend(list(self.__adaoObject["AlgorithmParameters"].keys()))
591 if len(list(self.__StoredInputs.keys())) > 0:
592 variables.extend( list(self.__StoredInputs.keys()) )
593 variables.remove('Diagnostic')
594 variables.remove('Observer')
598 def get_available_algorithms(self):
600 Renvoie la liste des algorithmes potentiellement utilisables, identifiés
601 par les chaînes de caractères.
604 for directory in sys.path:
605 if os.path.isdir(os.path.join(directory,"daAlgorithms")):
606 for fname in os.listdir(os.path.join(directory,"daAlgorithms")):
607 root, ext = os.path.splitext(fname)
608 if ext == '.py' and root != '__init__':
613 def get_available_diagnostics(self):
615 Renvoie la liste des diagnostics potentiellement utilisables, identifiés
616 par les chaînes de caractères.
619 for directory in sys.path:
620 if os.path.isdir(os.path.join(directory,"daDiagnostics")):
621 for fname in os.listdir(os.path.join(directory,"daDiagnostics")):
622 root, ext = os.path.splitext(fname)
623 if ext == '.py' and root != '__init__':
628 # -----------------------------------------------------------
630 def get_algorithms_main_path(self):
632 Renvoie le chemin pour le répertoire principal contenant les algorithmes
633 dans un sous-répertoire "daAlgorithms"
637 def add_algorithms_path(self, Path=None):
639 Ajoute au chemin de recherche des algorithmes un répertoire dans lequel
640 se trouve un sous-répertoire "daAlgorithms"
642 Remarque : si le chemin a déjà été ajouté pour les diagnostics, il n'est
643 pas indispensable de le rajouter ici.
645 if not os.path.isdir(Path):
646 raise ValueError("The given "+Path+" argument must exist as a directory")
647 if not os.path.isdir(os.path.join(Path,"daAlgorithms")):
648 raise ValueError("The given \""+Path+"\" argument must contain a subdirectory named \"daAlgorithms\"")
649 if not os.path.isfile(os.path.join(Path,"daAlgorithms","__init__.py")):
650 raise ValueError("The given \""+Path+"/daAlgorithms\" path must contain a file named \"__init__.py\"")
651 sys.path.insert(0, os.path.abspath(Path))
652 sys.path = PlatformInfo.uniq( sys.path ) # Conserve en unique exemplaire chaque chemin
655 def get_diagnostics_main_path(self):
657 Renvoie le chemin pour le répertoire principal contenant les diagnostics
658 dans un sous-répertoire "daDiagnostics"
662 def add_diagnostics_path(self, Path=None):
664 Ajoute au chemin de recherche des algorithmes un répertoire dans lequel
665 se trouve un sous-répertoire "daDiagnostics"
667 Remarque : si le chemin a déjà été ajouté pour les algorithmes, il n'est
668 pas indispensable de le rajouter ici.
670 if not os.path.isdir(Path):
671 raise ValueError("The given "+Path+" argument must exist as a directory")
672 if not os.path.isdir(os.path.join(Path,"daDiagnostics")):
673 raise ValueError("The given \""+Path+"\" argument must contain a subdirectory named \"daDiagnostics\"")
674 if not os.path.isfile(os.path.join(Path,"daDiagnostics","__init__.py")):
675 raise ValueError("The given \""+Path+"/daDiagnostics\" path must contain a file named \"__init__.py\"")
676 sys.path.insert(0, os.path.abspath(Path))
677 sys.path = PlatformInfo.uniq( sys.path ) # Conserve en unique exemplaire chaque chemin
680 # -----------------------------------------------------------
682 def execute(self, Executor=None, SaveCaseInFile=None):
683 "Lancement du calcul"
684 self.__case.register("execute",dir(),locals(),None,True)
685 Operator.CM.clearCache()
687 if Executor == "YACS": self.__executeYACSScheme( SaveCaseInFile )
688 else: self.__executePythonScheme( SaveCaseInFile )
689 except Exception as e:
690 if isinstance(e, SyntaxError): msg = "at %s: %s"%(e.offset, e.text)
692 raise ValueError(("during execution, the following error occurs:\n"+\
693 "\n%s %s\n\nSee also the potential messages, "+\
694 "which can show the origin of the above error, "+\
695 "in the launching terminal.\n")%(str(e),msg))
698 def __executePythonScheme(self, FileName=None):
699 "Lancement du calcul"
700 self.__case.register("executePythonScheme", dir(), locals())
701 if FileName is not None:
702 self.dump( FileName, "TUI")
703 self.__adaoObject["AlgorithmParameters"].executePythonScheme( self.__adaoObject )
706 def __executeYACSScheme(self, FileName=None):
707 "Lancement du calcul"
708 self.__case.register("executeYACSScheme", dir(), locals())
709 self.dump( FileName, "YACS")
710 self.__adaoObject["AlgorithmParameters"].executeYACSScheme( FileName )
713 # -----------------------------------------------------------
715 def dump(self, FileName=None, Formater="TUI"):
716 "Restitution normalisée des commandes"
717 return self.__case.dump(FileName, Formater)
719 def load(self, FileName=None, Formater="TUI"):
720 "Chargement normalisé des commandes"
721 __commands = self.__case.load(FileName, Formater)
722 from numpy import array, matrix
723 for __command in __commands:
724 exec("self."+__command)
728 "Effacement du contenu du cas en cours"
729 self.__init__(self.__name)
731 # -----------------------------------------------------------
734 "Clarifie la visibilité des méthodes"
735 return ['set', 'get', 'execute', '__doc__', '__init__', '__module__']
737 def prepare_to_pickle(self):
738 "Retire les variables non pickelisables, avec recopie efficace"
739 if self.__adaoObject['AlgorithmParameters'] is not None:
740 for k in self.__adaoObject['AlgorithmParameters'].keys():
741 if k == "Algorithm": continue
742 if k in self.__StoredInputs:
743 raise ValueError("the key \"%s\s to be transfered for pickling will overwrite an existing one.")
744 if self.__adaoObject['AlgorithmParameters'].hasObserver( k ):
745 self.__adaoObject['AlgorithmParameters'].removeObserver( k, "", True )
746 self.__StoredInputs[k] = self.__adaoObject['AlgorithmParameters'].pop(k, None)
747 if sys.version_info[0] == 2:
748 del self.__adaoObject # Because it breaks pickle in Python 2. Not required for Python 3
749 del self.__case # Because it breaks pickle in Python 2. Not required for Python 3
752 # ==============================================================================
753 if __name__ == "__main__":
754 print('\n AUTODIAGNOSTIC \n')