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, Stored, Scheduler, Checked )
117 elif Concept in ("BackgroundError", "ObservationError", "EvolutionError"):
118 commande = getattr(self,"set"+Concept)
119 commande(Matrix, ScalarSparseMatrix, DiagonalSparseMatrix,
120 Script, Stored, ObjectMatrix, 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, Info, ObjectFunction, Scheduler )
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, Stored, AvoidRC, Checked )
135 elif Concept in ("EvolutionModel", "ControlModel"):
136 commande = getattr(self,"set"+Concept)
138 Matrix, OneFunction, ThreeFunctions,
139 Parameters, Script, Scheduler, Stored, AvoidRC, 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,
473 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 trypath = os.path.join(directory,"daAlgorithms")
606 if os.path.isdir(trypath):
607 for fname in os.listdir(trypath):
608 if os.path.isfile(os.path.join(trypath,fname)):
609 fc = open(os.path.join(trypath,fname)).read()
610 iselal = bool("class ElementaryAlgorithm" in fc)
611 root, ext = os.path.splitext(fname)
612 if iselal and ext == '.py' and root != '__init__':
617 def get_available_diagnostics(self):
619 Renvoie la liste des diagnostics potentiellement utilisables, identifiés
620 par les chaînes de caractères.
623 for directory in sys.path:
624 if os.path.isdir(os.path.join(directory,"daDiagnostics")):
625 for fname in os.listdir(os.path.join(directory,"daDiagnostics")):
626 root, ext = os.path.splitext(fname)
627 if ext == '.py' and root != '__init__':
632 # -----------------------------------------------------------
634 def get_algorithms_main_path(self):
636 Renvoie le chemin pour le répertoire principal contenant les algorithmes
637 dans un sous-répertoire "daAlgorithms"
641 def add_algorithms_path(self, Path=None):
643 Ajoute au chemin de recherche des algorithmes un répertoire dans lequel
644 se trouve un sous-répertoire "daAlgorithms"
646 Remarque : si le chemin a déjà été ajouté pour les diagnostics, il n'est
647 pas indispensable de le rajouter ici.
649 if not os.path.isdir(Path):
650 raise ValueError("The given "+Path+" argument must exist as a directory")
651 if not os.path.isdir(os.path.join(Path,"daAlgorithms")):
652 raise ValueError("The given \""+Path+"\" argument must contain a subdirectory named \"daAlgorithms\"")
653 if not os.path.isfile(os.path.join(Path,"daAlgorithms","__init__.py")):
654 raise ValueError("The given \""+Path+"/daAlgorithms\" path must contain a file named \"__init__.py\"")
655 sys.path.insert(0, os.path.abspath(Path))
656 sys.path = PlatformInfo.uniq( sys.path ) # Conserve en unique exemplaire chaque chemin
659 def get_diagnostics_main_path(self):
661 Renvoie le chemin pour le répertoire principal contenant les diagnostics
662 dans un sous-répertoire "daDiagnostics"
666 def add_diagnostics_path(self, Path=None):
668 Ajoute au chemin de recherche des algorithmes un répertoire dans lequel
669 se trouve un sous-répertoire "daDiagnostics"
671 Remarque : si le chemin a déjà été ajouté pour les algorithmes, il n'est
672 pas indispensable de le rajouter ici.
674 if not os.path.isdir(Path):
675 raise ValueError("The given "+Path+" argument must exist as a directory")
676 if not os.path.isdir(os.path.join(Path,"daDiagnostics")):
677 raise ValueError("The given \""+Path+"\" argument must contain a subdirectory named \"daDiagnostics\"")
678 if not os.path.isfile(os.path.join(Path,"daDiagnostics","__init__.py")):
679 raise ValueError("The given \""+Path+"/daDiagnostics\" path must contain a file named \"__init__.py\"")
680 sys.path.insert(0, os.path.abspath(Path))
681 sys.path = PlatformInfo.uniq( sys.path ) # Conserve en unique exemplaire chaque chemin
684 # -----------------------------------------------------------
686 def execute(self, Executor=None, SaveCaseInFile=None):
687 "Lancement du calcul"
688 self.__case.register("execute",dir(),locals(),None,True)
689 Operator.CM.clearCache()
691 if Executor == "YACS": self.__executeYACSScheme( SaveCaseInFile )
692 else: self.__executePythonScheme( SaveCaseInFile )
693 except Exception as e:
694 if isinstance(e, SyntaxError): msg = "at %s: %s"%(e.offset, e.text)
696 raise ValueError(("during execution, the following error occurs:\n"+\
697 "\n%s %s\n\nSee also the potential messages, "+\
698 "which can show the origin of the above error, "+\
699 "in the launching terminal.\n")%(str(e),msg))
702 def __executePythonScheme(self, FileName=None):
703 "Lancement du calcul"
704 self.__case.register("executePythonScheme", dir(), locals())
705 if FileName is not None:
706 self.dump( FileName, "TUI")
707 self.__adaoObject["AlgorithmParameters"].executePythonScheme( self.__adaoObject )
710 def __executeYACSScheme(self, FileName=None):
711 "Lancement du calcul"
712 self.__case.register("executeYACSScheme", dir(), locals())
713 self.dump( FileName, "YACS")
714 self.__adaoObject["AlgorithmParameters"].executeYACSScheme( FileName )
717 # -----------------------------------------------------------
719 def dump(self, FileName=None, Formater="TUI"):
720 "Restitution normalisée des commandes"
721 return self.__case.dump(FileName, Formater)
723 def load(self, FileName=None, Formater="TUI"):
724 "Chargement normalisé des commandes"
725 __commands = self.__case.load(FileName, Formater)
726 from numpy import array, matrix
727 for __command in __commands:
728 exec("self."+__command)
732 "Effacement du contenu du cas en cours"
733 self.__init__(self.__name)
735 # -----------------------------------------------------------
738 "Clarifie la visibilité des méthodes"
739 return ['set', 'get', 'execute', '__doc__', '__init__', '__module__']
741 def prepare_to_pickle(self):
742 "Retire les variables non pickelisables, avec recopie efficace"
743 if self.__adaoObject['AlgorithmParameters'] is not None:
744 for k in self.__adaoObject['AlgorithmParameters'].keys():
745 if k == "Algorithm": continue
746 if k in self.__StoredInputs:
747 raise ValueError("the key \"%s\s to be transfered for pickling will overwrite an existing one.")
748 if self.__adaoObject['AlgorithmParameters'].hasObserver( k ):
749 self.__adaoObject['AlgorithmParameters'].removeObserver( k, "", True )
750 self.__StoredInputs[k] = self.__adaoObject['AlgorithmParameters'].pop(k, None)
751 if sys.version_info[0] == 2:
752 del self.__adaoObject # Because it breaks pickle in Python 2. Not required for Python 3
753 del self.__case # Because it breaks pickle in Python 2. Not required for Python 3
756 # ==============================================================================
757 if __name__ == "__main__":
758 print('\n AUTODIAGNOSTIC \n')