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 RegulationAndParameters, 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.__directory = None
46 self.__case = CaseLogger(self.__name, "case", addViewers)
48 self.__adaoObject = {}
49 self.__StoredInputs = {}
50 self.__PostAnalysis = []
53 "AlgorithmParameters",
61 "ObservationOperator",
68 "RegulationParameters",
72 for ename in self.__Concepts:
73 self.__adaoObject[ename] = None
74 for ename in ("ObservationOperator", "EvolutionModel", "ControlModel"):
75 self.__adaoObject[ename] = {}
76 for ename in ("Observer",):
77 self.__adaoObject[ename] = []
78 self.__StoredInputs[ename] = []
80 # Récupère le chemin du répertoire parent et l'ajoute au path
81 # (Cela complète l'action de la classe PathManagement dans PlatformInfo,
82 # qui est activée dans Persistence)
83 self.__parent = os.path.abspath(os.path.join(os.path.dirname(__file__),".."))
84 sys.path.insert(0, self.__parent)
85 sys.path = PlatformInfo.uniq( sys.path ) # Conserve en unique exemplaire chaque chemin
88 Concept = None, # Premier argument
93 DiagonalSparseMatrix = None,
96 ObjectFunction = None,
100 ScalarSparseMatrix = None,
106 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"):
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 == "RegulationParameters":
124 self.setRegulationParameters( Algorithm, Parameters, Script )
125 elif Concept == "Name":
127 elif Concept == "Directory":
128 self.setDirectory(String)
129 elif Concept == "Debug":
131 elif Concept == "NoDebug":
133 elif Concept == "Observer":
134 self.setObserver( Variable, Template, String, Script, Info, ObjectFunction, Scheduler )
135 elif Concept == "ObservationOperator":
136 self.setObservationOperator(
137 Matrix, OneFunction, ThreeFunctions, AppliedInXb,
138 Parameters, Script, Stored, AvoidRC, Checked )
139 elif Concept in ("EvolutionModel", "ControlModel"):
140 commande = getattr(self,"set"+Concept)
142 Matrix, OneFunction, ThreeFunctions,
143 Parameters, Script, Scheduler, Stored, AvoidRC, Checked )
146 raise ValueError("the variable named '%s' is not allowed."%str(Concept))
147 except Exception as e:
148 if isinstance(e, SyntaxError): msg = "at %s: %s"%(e.offset, e.text)
150 raise ValueError(("during settings, the following error occurs:\n"+\
151 "\n%s %s\n\nSee also the potential messages, "+\
152 "which can show the origin of the above error, "+\
153 "in the launching terminal.")%(str(e),msg))
155 # -----------------------------------------------------------
157 def setBackground(self,
164 "Definition d'un concept de calcul"
165 Concept = "Background"
166 self.__case.register("set"+Concept, dir(), locals())
167 self.__adaoObject[Concept] = State(
170 asPersistentVector = VectorSerie,
171 asScript = self.__with_directory(Script),
172 scheduledBy = Scheduler,
173 toBeChecked = Checked,
176 self.__StoredInputs[Concept] = self.__adaoObject[Concept].getO()
179 def setCheckingPoint(self,
186 "Definition d'un concept de calcul"
187 Concept = "CheckingPoint"
188 self.__case.register("set"+Concept, dir(), locals())
189 self.__adaoObject[Concept] = State(
192 asPersistentVector = VectorSerie,
193 asScript = self.__with_directory(Script),
194 scheduledBy = Scheduler,
195 toBeChecked = Checked,
198 self.__StoredInputs[Concept] = self.__adaoObject[Concept].getO()
201 def setControlInput(self,
208 "Definition d'un concept de calcul"
209 Concept = "ControlInput"
210 self.__case.register("set"+Concept, dir(), locals())
211 self.__adaoObject[Concept] = State(
214 asPersistentVector = VectorSerie,
215 asScript = self.__with_directory(Script),
216 scheduledBy = Scheduler,
217 toBeChecked = Checked,
220 self.__StoredInputs[Concept] = self.__adaoObject[Concept].getO()
223 def setObservation(self,
230 "Definition d'un concept de calcul"
231 Concept = "Observation"
232 self.__case.register("set"+Concept, dir(), locals())
233 self.__adaoObject[Concept] = State(
236 asPersistentVector = VectorSerie,
237 asScript = self.__with_directory(Script),
238 scheduledBy = Scheduler,
239 toBeChecked = Checked,
242 self.__StoredInputs[Concept] = self.__adaoObject[Concept].getO()
245 def setBackgroundError(self,
247 ScalarSparseMatrix = None,
248 DiagonalSparseMatrix = None,
253 "Definition d'un concept de calcul"
254 Concept = "BackgroundError"
255 self.__case.register("set"+Concept, dir(), locals())
256 self.__adaoObject[Concept] = Covariance(
258 asCovariance = Matrix,
259 asEyeByScalar = ScalarSparseMatrix,
260 asEyeByVector = DiagonalSparseMatrix,
261 asCovObject = ObjectMatrix,
262 asScript = self.__with_directory(Script),
263 toBeChecked = Checked,
266 self.__StoredInputs[Concept] = self.__adaoObject[Concept].getO()
269 def setObservationError(self,
271 ScalarSparseMatrix = None,
272 DiagonalSparseMatrix = None,
277 "Definition d'un concept de calcul"
278 Concept = "ObservationError"
279 self.__case.register("set"+Concept, dir(), locals())
280 self.__adaoObject[Concept] = Covariance(
282 asCovariance = Matrix,
283 asEyeByScalar = ScalarSparseMatrix,
284 asEyeByVector = DiagonalSparseMatrix,
285 asCovObject = ObjectMatrix,
286 asScript = self.__with_directory(Script),
287 toBeChecked = Checked,
290 self.__StoredInputs[Concept] = self.__adaoObject[Concept].getO()
293 def setEvolutionError(self,
295 ScalarSparseMatrix = None,
296 DiagonalSparseMatrix = None,
301 "Definition d'un concept de calcul"
302 Concept = "EvolutionError"
303 self.__case.register("set"+Concept, dir(), locals())
304 self.__adaoObject[Concept] = Covariance(
306 asCovariance = Matrix,
307 asEyeByScalar = ScalarSparseMatrix,
308 asEyeByVector = DiagonalSparseMatrix,
309 asCovObject = ObjectMatrix,
310 asScript = self.__with_directory(Script),
311 toBeChecked = Checked,
314 self.__StoredInputs[Concept] = self.__adaoObject[Concept].getO()
317 def setObservationOperator(self,
320 ThreeFunctions = None,
327 "Definition d'un concept de calcul"
328 Concept = "ObservationOperator"
329 self.__case.register("set"+Concept, dir(), locals())
330 self.__adaoObject[Concept] = FullOperator(
333 asOneFunction = OneFunction,
334 asThreeFunctions = ThreeFunctions,
335 asScript = self.__with_directory(Script),
337 appliedInX = AppliedInXb,
340 toBeChecked = Checked,
343 self.__StoredInputs[Concept] = self.__adaoObject[Concept].getO()
346 def setEvolutionModel(self,
349 ThreeFunctions = None,
356 "Definition d'un concept de calcul"
357 Concept = "EvolutionModel"
358 self.__case.register("set"+Concept, dir(), locals())
359 self.__adaoObject[Concept] = FullOperator(
362 asOneFunction = OneFunction,
363 asThreeFunctions = ThreeFunctions,
364 asScript = self.__with_directory(Script),
368 scheduledBy = Scheduler,
369 toBeChecked = Checked,
372 self.__StoredInputs[Concept] = self.__adaoObject[Concept].getO()
375 def setControlModel(self,
378 ThreeFunctions = None,
385 "Definition d'un concept de calcul"
386 Concept = "ControlModel"
387 self.__case.register("set"+Concept, dir(), locals())
388 self.__adaoObject[Concept] = FullOperator(
391 asOneFunction = OneFunction,
392 asThreeFunctions = ThreeFunctions,
393 asScript = self.__with_directory(Script),
397 scheduledBy = Scheduler,
398 toBeChecked = Checked,
401 self.__StoredInputs[Concept] = self.__adaoObject[Concept].getO()
404 def setName(self, String=None):
405 "Definition d'un concept de calcul"
406 self.__case.register("setName",dir(),locals())
407 if String is not None:
408 self.__name = str(String)
411 self.__StoredInputs["Name"] = self.__name
413 def setDirectory(self, String=None):
414 "Definition d'un concept de calcul"
415 self.__case.register("setDirectory",dir(),locals())
416 if os.path.isdir(os.path.abspath(str(String))):
417 self.__directory = os.path.abspath(str(String))
419 self.__directory = None
420 self.__StoredInputs["Directory"] = self.__directory
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,
451 asScript = self.__with_directory(Script),
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(
463 asScript = self.__with_directory(Script),
467 def setRegulationParameters(self,
471 "Definition d'un concept de calcul"
472 Concept = "RegulationParameters"
473 self.__case.register("set"+Concept, dir(), locals())
474 self.__adaoObject[Concept] = RegulationAndParameters(
476 asAlgorithm = Algorithm,
478 asScript = self.__with_directory(Script),
482 def setObserver(self,
488 ObjectFunction = None,
490 "Definition d'un concept de calcul"
492 self.__case.register("set"+Concept, dir(), locals())
493 self.__adaoObject[Concept].append( DataObserver(
495 onVariable = Variable,
496 asTemplate = Template,
498 asScript = self.__with_directory(Script),
499 asObsObject = ObjectFunction,
501 scheduledBy = Scheduler,
502 withAlgo = self.__adaoObject["AlgorithmParameters"]
506 def removeObserver(self,
508 ObjectFunction = None,
510 "Permet de retirer un observer à une ou des variable nommée"
511 if "AlgorithmParameters" not in self.__adaoObject:
512 raise ValueError("No algorithm registred, ask for one before removing observers")
514 # Vérification du nom de variable et typage
515 # -----------------------------------------
516 if isinstance(Variable, str):
517 VariableNames = (Variable,)
518 elif isinstance(Variable, list):
519 VariableNames = tuple(map( str, Variable ))
521 raise ValueError("The observer requires a name or a list of names of variables.")
523 # Association interne de l'observer à la variable
524 # -----------------------------------------------
525 for ename in VariableNames:
526 if ename not in self.__adaoObject["AlgorithmParameters"]:
527 raise ValueError("An observer requires to be removed on a variable named %s which does not exist."%ename)
529 return self.__adaoObject["AlgorithmParameters"].removeObserver( ename, ObjectFunction )
531 # -----------------------------------------------------------
533 def get(self, Concept=None, noDetails=True ):
534 "Recuperation d'une sortie du calcul"
535 if Concept is not None:
537 self.__case.register("get", dir(), locals(), Concept) # Break pickle in Python 2
540 if Concept in self.__StoredInputs:
541 return self.__StoredInputs[Concept]
543 elif self.__adaoObject["AlgorithmParameters"] is not None and Concept == "AlgorithmParameters":
544 return self.__adaoObject["AlgorithmParameters"].get()
546 elif self.__adaoObject["AlgorithmParameters"] is not None and Concept in self.__adaoObject["AlgorithmParameters"]:
547 return self.__adaoObject["AlgorithmParameters"].get( Concept )
549 elif Concept == "AlgorithmRequiredParameters" and self.__adaoObject["AlgorithmParameters"] is not None:
550 return self.__adaoObject["AlgorithmParameters"].getAlgorithmRequiredParameters(noDetails)
553 raise ValueError("The requested key \"%s\" does not exists as an input or a stored variable."%Concept)
556 allvariables.update( {"AlgorithmParameters":self.__adaoObject["AlgorithmParameters"].get()} )
557 # allvariables.update( self.__adaoObject["AlgorithmParameters"].get() )
558 allvariables.update( self.__StoredInputs )
559 allvariables.pop('Observer', None)
562 # -----------------------------------------------------------
564 def get_available_variables(self):
566 Renvoie les variables potentiellement utilisables pour l'étude,
567 initialement stockées comme données d'entrées ou dans les algorithmes,
568 identifiés par les chaînes de caractères. L'algorithme doit avoir été
569 préalablement choisi sinon la méthode renvoie "None".
571 if len(list(self.__adaoObject["AlgorithmParameters"].keys())) == 0 and \
572 len(list(self.__StoredInputs.keys())) == 0:
576 if len(list(self.__adaoObject["AlgorithmParameters"].keys())) > 0:
577 variables.extend(list(self.__adaoObject["AlgorithmParameters"].keys()))
578 if len(list(self.__StoredInputs.keys())) > 0:
579 variables.extend( list(self.__StoredInputs.keys()) )
580 variables.remove('Observer')
584 def get_available_algorithms(self):
586 Renvoie la liste des algorithmes potentiellement utilisables, identifiés
587 par les chaînes de caractères.
590 for directory in sys.path:
591 trypath = os.path.join(directory,"daAlgorithms")
592 if os.path.isdir(trypath):
593 for fname in os.listdir(trypath):
594 if os.path.isfile(os.path.join(trypath,fname)):
595 fc = open(os.path.join(trypath,fname)).read()
596 iselal = bool("class ElementaryAlgorithm" in fc)
597 root, ext = os.path.splitext(fname)
598 if iselal and ext == '.py' and root != '__init__':
603 def get_algorithms_main_path(self):
605 Renvoie le chemin pour le répertoire principal contenant les algorithmes
609 def add_algorithms_path(self, Path=None):
611 Ajoute au chemin de recherche des algorithmes un répertoire dans lequel
612 se trouve un sous-répertoire "daAlgorithms"
614 if not os.path.isdir(Path):
615 raise ValueError("The given "+Path+" argument must exist as a directory")
616 if not os.path.isdir(os.path.join(Path,"daAlgorithms")):
617 raise ValueError("The given \""+Path+"\" argument must contain a subdirectory named \"daAlgorithms\"")
618 if not os.path.isfile(os.path.join(Path,"daAlgorithms","__init__.py")):
619 raise ValueError("The given \""+Path+"/daAlgorithms\" path must contain a file named \"__init__.py\"")
620 sys.path.insert(0, os.path.abspath(Path))
621 sys.path = PlatformInfo.uniq( sys.path ) # Conserve en unique exemplaire chaque chemin
624 # -----------------------------------------------------------
626 def execute(self, Executor=None, SaveCaseInFile=None):
627 "Lancement du calcul"
628 self.__case.register("execute",dir(),locals(),None,True)
629 Operator.CM.clearCache()
631 if Executor == "YACS": self.__executeYACSScheme( SaveCaseInFile )
632 else: self.__executePythonScheme( SaveCaseInFile )
633 except Exception as e:
634 if isinstance(e, SyntaxError): msg = "at %s: %s"%(e.offset, e.text)
636 raise ValueError(("during execution, the following error occurs:\n"+\
637 "\n%s %s\n\nSee also the potential messages, "+\
638 "which can show the origin of the above error, "+\
639 "in the launching terminal.\n")%(str(e),msg))
642 def __executePythonScheme(self, FileName=None):
643 "Lancement du calcul"
644 self.__case.register("executePythonScheme", dir(), locals())
645 if FileName is not None:
646 self.dump( FileName, "TUI")
647 self.__adaoObject["AlgorithmParameters"].executePythonScheme( self.__adaoObject )
650 def __executeYACSScheme(self, FileName=None):
651 "Lancement du calcul"
652 self.__case.register("executeYACSScheme", dir(), locals())
653 self.dump( FileName, "YACS")
654 self.__adaoObject["AlgorithmParameters"].executeYACSScheme( FileName )
657 # -----------------------------------------------------------
659 def dump(self, FileName=None, Formater="TUI"):
660 "Restitution normalisée des commandes"
661 __Upa = "\n".join(self.__PostAnalysis)
662 return self.__case.dump(FileName, Formater, __Upa)
664 def load(self, FileName=None, Content=None, Object=None, Formater="TUI"):
665 "Chargement normalisé des commandes"
666 __commands = self.__case.load(FileName, Content, Object, Formater)
667 from numpy import array, matrix
668 for __command in __commands:
669 if __command.find("set")>-1 and __command.find("set_")<0:
670 exec("self."+__command)
672 self.__PostAnalysis.append(__command)
676 FileNameFrom=None, ContentFrom=None, ObjectFrom=None, FormaterFrom="TUI",
677 FileNameTo=None, FormaterTo="TUI",
679 "Conversion normalisée des commandes"
681 FileName=FileNameFrom, Content=ContentFrom, Object=ObjectFrom, Formater=FormaterFrom
683 FileName=FileNameTo, Formater=FormaterTo
687 "Effacement du contenu du cas en cours"
688 self.__init__(self.__name)
690 # -----------------------------------------------------------
692 def __with_directory(self, __filename=None):
693 if os.path.exists(str(__filename)):
694 __fullpath = __filename
695 elif os.path.exists(os.path.join(str(self.__directory), str(__filename))):
696 __fullpath = os.path.join(self.__directory, str(__filename))
698 __fullpath = __filename
702 "Clarifie la visibilité des méthodes"
703 return ['set', 'get', 'execute', 'dump', 'load', '__doc__', '__init__', '__module__']
705 def prepare_to_pickle(self):
706 "Retire les variables non pickelisables, avec recopie efficace"
707 if self.__adaoObject['AlgorithmParameters'] is not None:
708 for k in self.__adaoObject['AlgorithmParameters'].keys():
709 if k == "Algorithm": continue
710 if k in self.__StoredInputs:
711 raise ValueError("the key \"%s\s to be transfered for pickling will overwrite an existing one.")
712 if self.__adaoObject['AlgorithmParameters'].hasObserver( k ):
713 self.__adaoObject['AlgorithmParameters'].removeObserver( k, "", True )
714 self.__StoredInputs[k] = self.__adaoObject['AlgorithmParameters'].pop(k, None)
715 if sys.version_info[0] == 2:
716 del self.__adaoObject # Because it breaks pickle in Python 2. Not required for Python 3
717 del self.__case # Because it breaks pickle in Python 2. Not required for Python 3
720 # ==============================================================================
721 if __name__ == "__main__":
722 print('\n AUTODIAGNOSTIC \n')