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 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",
71 for ename in self.__Concepts:
72 self.__adaoObject[ename] = None
73 for ename in ("ObservationOperator", "EvolutionModel", "ControlModel"):
74 self.__adaoObject[ename] = {}
75 for ename in ("Observer",):
76 self.__adaoObject[ename] = []
77 self.__StoredInputs[ename] = []
79 # Récupère le chemin du répertoire parent et l'ajoute au path
80 # (Cela complète l'action de la classe PathManagement dans PlatformInfo,
81 # qui est activée dans Persistence)
82 self.__parent = os.path.abspath(os.path.join(os.path.dirname(__file__),".."))
83 sys.path.insert(0, self.__parent)
84 sys.path = PlatformInfo.uniq( sys.path ) # Conserve en unique exemplaire chaque chemin
87 Concept = None, # Premier argument
92 DiagonalSparseMatrix = None,
95 ObjectFunction = None,
99 ScalarSparseMatrix = None,
105 ThreeFunctions = None,
110 "Interface unique de definition de variables d'entrees par argument"
111 self.__case.register("set",dir(),locals(),None,True)
113 if Concept in ("Background", "CheckingPoint", "ControlInput", "Observation"):
114 commande = getattr(self,"set"+Concept)
115 commande(Vector, VectorSerie, Script, Stored, Scheduler, Checked )
116 elif Concept in ("BackgroundError", "ObservationError", "EvolutionError"):
117 commande = getattr(self,"set"+Concept)
118 commande(Matrix, ScalarSparseMatrix, DiagonalSparseMatrix,
119 Script, Stored, ObjectMatrix, Checked )
120 elif Concept == "AlgorithmParameters":
121 self.setAlgorithmParameters( Algorithm, Parameters, Script )
122 elif Concept == "Name":
124 elif Concept == "Directory":
125 self.setDirectory(String)
126 elif Concept == "Debug":
128 elif Concept == "NoDebug":
130 elif Concept == "Observer":
131 self.setObserver( Variable, Template, String, Script, Info, ObjectFunction, Scheduler )
132 elif Concept == "ObservationOperator":
133 self.setObservationOperator(
134 Matrix, OneFunction, ThreeFunctions, AppliedInXb,
135 Parameters, Script, Stored, AvoidRC, Checked )
136 elif Concept in ("EvolutionModel", "ControlModel"):
137 commande = getattr(self,"set"+Concept)
139 Matrix, OneFunction, ThreeFunctions,
140 Parameters, Script, Scheduler, Stored, AvoidRC, Checked )
143 raise ValueError("the variable named '%s' is not allowed."%str(Concept))
144 except Exception as e:
145 if isinstance(e, SyntaxError): msg = "at %s: %s"%(e.offset, e.text)
147 raise ValueError(("during settings, the following error occurs:\n"+\
148 "\n%s %s\n\nSee also the potential messages, "+\
149 "which can show the origin of the above error, "+\
150 "in the launching terminal.")%(str(e),msg))
152 # -----------------------------------------------------------
154 def setBackground(self,
161 "Definition d'un concept de calcul"
162 Concept = "Background"
163 self.__case.register("set"+Concept, dir(), locals())
164 self.__adaoObject[Concept] = State(
167 asPersistentVector = VectorSerie,
168 asScript = self.with_directory(Script),
169 scheduledBy = Scheduler,
170 toBeChecked = Checked,
173 self.__StoredInputs[Concept] = self.__adaoObject[Concept].getO()
176 def setCheckingPoint(self,
183 "Definition d'un concept de calcul"
184 Concept = "CheckingPoint"
185 self.__case.register("set"+Concept, dir(), locals())
186 self.__adaoObject[Concept] = State(
189 asPersistentVector = VectorSerie,
190 asScript = self.with_directory(Script),
191 scheduledBy = Scheduler,
192 toBeChecked = Checked,
195 self.__StoredInputs[Concept] = self.__adaoObject[Concept].getO()
198 def setControlInput(self,
205 "Definition d'un concept de calcul"
206 Concept = "ControlInput"
207 self.__case.register("set"+Concept, dir(), locals())
208 self.__adaoObject[Concept] = State(
211 asPersistentVector = VectorSerie,
212 asScript = self.with_directory(Script),
213 scheduledBy = Scheduler,
214 toBeChecked = Checked,
217 self.__StoredInputs[Concept] = self.__adaoObject[Concept].getO()
220 def setObservation(self,
227 "Definition d'un concept de calcul"
228 Concept = "Observation"
229 self.__case.register("set"+Concept, dir(), locals())
230 self.__adaoObject[Concept] = State(
233 asPersistentVector = VectorSerie,
234 asScript = self.with_directory(Script),
235 scheduledBy = Scheduler,
236 toBeChecked = Checked,
239 self.__StoredInputs[Concept] = self.__adaoObject[Concept].getO()
242 def setBackgroundError(self,
244 ScalarSparseMatrix = None,
245 DiagonalSparseMatrix = None,
250 "Definition d'un concept de calcul"
251 Concept = "BackgroundError"
252 self.__case.register("set"+Concept, dir(), locals())
253 self.__adaoObject[Concept] = Covariance(
255 asCovariance = Matrix,
256 asEyeByScalar = ScalarSparseMatrix,
257 asEyeByVector = DiagonalSparseMatrix,
258 asCovObject = ObjectMatrix,
259 asScript = self.with_directory(Script),
260 toBeChecked = Checked,
263 self.__StoredInputs[Concept] = self.__adaoObject[Concept].getO()
266 def setObservationError(self,
268 ScalarSparseMatrix = None,
269 DiagonalSparseMatrix = None,
274 "Definition d'un concept de calcul"
275 Concept = "ObservationError"
276 self.__case.register("set"+Concept, dir(), locals())
277 self.__adaoObject[Concept] = Covariance(
279 asCovariance = Matrix,
280 asEyeByScalar = ScalarSparseMatrix,
281 asEyeByVector = DiagonalSparseMatrix,
282 asCovObject = ObjectMatrix,
283 asScript = self.with_directory(Script),
284 toBeChecked = Checked,
287 self.__StoredInputs[Concept] = self.__adaoObject[Concept].getO()
290 def setEvolutionError(self,
292 ScalarSparseMatrix = None,
293 DiagonalSparseMatrix = None,
298 "Definition d'un concept de calcul"
299 Concept = "EvolutionError"
300 self.__case.register("set"+Concept, dir(), locals())
301 self.__adaoObject[Concept] = Covariance(
303 asCovariance = Matrix,
304 asEyeByScalar = ScalarSparseMatrix,
305 asEyeByVector = DiagonalSparseMatrix,
306 asCovObject = ObjectMatrix,
307 asScript = self.with_directory(Script),
308 toBeChecked = Checked,
311 self.__StoredInputs[Concept] = self.__adaoObject[Concept].getO()
314 def setObservationOperator(self,
317 ThreeFunctions = None,
324 "Definition d'un concept de calcul"
325 Concept = "ObservationOperator"
326 self.__case.register("set"+Concept, dir(), locals())
327 self.__adaoObject[Concept] = FullOperator(
330 asOneFunction = OneFunction,
331 asThreeFunctions = ThreeFunctions,
332 asScript = self.with_directory(Script),
334 appliedInX = AppliedInXb,
337 toBeChecked = Checked,
340 self.__StoredInputs[Concept] = self.__adaoObject[Concept].getO()
343 def setEvolutionModel(self,
346 ThreeFunctions = None,
353 "Definition d'un concept de calcul"
354 Concept = "EvolutionModel"
355 self.__case.register("set"+Concept, dir(), locals())
356 self.__adaoObject[Concept] = FullOperator(
359 asOneFunction = OneFunction,
360 asThreeFunctions = ThreeFunctions,
361 asScript = self.with_directory(Script),
365 scheduledBy = Scheduler,
366 toBeChecked = Checked,
369 self.__StoredInputs[Concept] = self.__adaoObject[Concept].getO()
372 def setControlModel(self,
375 ThreeFunctions = None,
382 "Definition d'un concept de calcul"
383 Concept = "ControlModel"
384 self.__case.register("set"+Concept, dir(), locals())
385 self.__adaoObject[Concept] = FullOperator(
388 asOneFunction = OneFunction,
389 asThreeFunctions = ThreeFunctions,
390 asScript = self.with_directory(Script),
394 scheduledBy = Scheduler,
395 toBeChecked = Checked,
398 self.__StoredInputs[Concept] = self.__adaoObject[Concept].getO()
401 def setName(self, String=None):
402 "Definition d'un concept de calcul"
403 self.__case.register("setName",dir(),locals())
404 if String is not None:
405 self.__name = str(String)
408 self.__StoredInputs["Name"] = self.__name
410 def setDirectory(self, String=None):
411 "Definition d'un concept de calcul"
412 self.__case.register("setDirectory",dir(),locals())
413 if os.path.isdir(os.path.abspath(str(String))):
414 self.__directory = os.path.abspath(str(String))
416 self.__directory = None
417 self.__StoredInputs["Directory"] = self.__directory
419 def setDebug(self, __level = 10):
420 "NOTSET=0 < DEBUG=10 < INFO=20 < WARNING=30 < ERROR=40 < CRITICAL=50"
421 self.__case.register("setDebug",dir(),locals())
422 log = logging.getLogger()
423 log.setLevel( __level )
424 self.__StoredInputs["Debug"] = __level
425 self.__StoredInputs["NoDebug"] = False
428 def setNoDebug(self):
429 "NOTSET=0 < DEBUG=10 < INFO=20 < WARNING=30 < ERROR=40 < CRITICAL=50"
430 self.__case.register("setNoDebug",dir(),locals())
431 log = logging.getLogger()
432 log.setLevel( logging.WARNING )
433 self.__StoredInputs["Debug"] = logging.WARNING
434 self.__StoredInputs["NoDebug"] = True
437 def setAlgorithmParameters(self,
441 "Definition d'un concept de calcul"
442 Concept = "AlgorithmParameters"
443 self.__case.register("set"+Concept, dir(), locals())
444 self.__adaoObject[Concept] = AlgorithmAndParameters(
446 asAlgorithm = Algorithm,
448 asScript = self.with_directory(Script),
452 def updateAlgorithmParameters(self,
455 "Mise a jour d'un concept de calcul"
456 if "AlgorithmParameters" not in self.__adaoObject:
457 raise ValueError("No algorithm registred, ask for one before updating parameters")
458 self.__adaoObject["AlgorithmParameters"].updateParameters(
460 asScript = self.with_directory(Script),
464 def setObserver(self,
470 ObjectFunction = None,
472 "Definition d'un concept de calcul"
474 self.__case.register("set"+Concept, dir(), locals())
475 self.__adaoObject[Concept].append( DataObserver(
477 onVariable = Variable,
478 asTemplate = Template,
480 asScript = self.with_directory(Script),
481 asObsObject = ObjectFunction,
483 scheduledBy = Scheduler,
484 withAlgo = self.__adaoObject["AlgorithmParameters"]
488 def removeObserver(self,
490 ObjectFunction = None,
492 "Permet de retirer un observer à une ou des variable nommée"
493 if "AlgorithmParameters" not in self.__adaoObject:
494 raise ValueError("No algorithm registred, ask for one before removing observers")
496 # Vérification du nom de variable et typage
497 # -----------------------------------------
498 if isinstance(Variable, str):
499 VariableNames = (Variable,)
500 elif isinstance(Variable, list):
501 VariableNames = tuple(map( str, Variable ))
503 raise ValueError("The observer requires a name or a list of names of variables.")
505 # Association interne de l'observer à la variable
506 # -----------------------------------------------
507 for ename in VariableNames:
508 if ename not in self.__adaoObject["AlgorithmParameters"]:
509 raise ValueError("An observer requires to be removed on a variable named %s which does not exist."%ename)
511 return self.__adaoObject["AlgorithmParameters"].removeObserver( ename, ObjectFunction )
513 # -----------------------------------------------------------
515 def get(self, Concept=None, noDetails=True ):
516 "Recuperation d'une sortie du calcul"
517 if Concept is not None:
519 self.__case.register("get", dir(), locals(), Concept) # Break pickle in Python 2
522 if Concept in self.__StoredInputs:
523 return self.__StoredInputs[Concept]
525 elif self.__adaoObject["AlgorithmParameters"] is not None and Concept == "AlgorithmParameters":
526 return self.__adaoObject["AlgorithmParameters"].get()
528 elif self.__adaoObject["AlgorithmParameters"] is not None and Concept in self.__adaoObject["AlgorithmParameters"]:
529 return self.__adaoObject["AlgorithmParameters"].get( Concept )
531 elif Concept == "AlgorithmRequiredParameters" and self.__adaoObject["AlgorithmParameters"] is not None:
532 return self.__adaoObject["AlgorithmParameters"].getAlgorithmRequiredParameters(noDetails)
535 raise ValueError("The requested key \"%s\" does not exists as an input or a stored variable."%Concept)
538 allvariables.update( {"AlgorithmParameters":self.__adaoObject["AlgorithmParameters"].get()} )
539 # allvariables.update( self.__adaoObject["AlgorithmParameters"].get() )
540 allvariables.update( self.__StoredInputs )
541 allvariables.pop('Observer', None)
544 # -----------------------------------------------------------
546 def get_available_variables(self):
548 Renvoie les variables potentiellement utilisables pour l'étude,
549 initialement stockées comme données d'entrées ou dans les algorithmes,
550 identifiés par les chaînes de caractères. L'algorithme doit avoir été
551 préalablement choisi sinon la méthode renvoie "None".
553 if len(list(self.__adaoObject["AlgorithmParameters"].keys())) == 0 and \
554 len(list(self.__StoredInputs.keys())) == 0:
558 if len(list(self.__adaoObject["AlgorithmParameters"].keys())) > 0:
559 variables.extend(list(self.__adaoObject["AlgorithmParameters"].keys()))
560 if len(list(self.__StoredInputs.keys())) > 0:
561 variables.extend( list(self.__StoredInputs.keys()) )
562 variables.remove('Observer')
566 def get_available_algorithms(self):
568 Renvoie la liste des algorithmes potentiellement utilisables, identifiés
569 par les chaînes de caractères.
572 for directory in sys.path:
573 trypath = os.path.join(directory,"daAlgorithms")
574 if os.path.isdir(trypath):
575 for fname in os.listdir(trypath):
576 if os.path.isfile(os.path.join(trypath,fname)):
577 fc = open(os.path.join(trypath,fname)).read()
578 iselal = bool("class ElementaryAlgorithm" in fc)
579 root, ext = os.path.splitext(fname)
580 if iselal and ext == '.py' and root != '__init__':
585 def get_algorithms_main_path(self):
587 Renvoie le chemin pour le répertoire principal contenant les algorithmes
591 def add_algorithms_path(self, Path=None):
593 Ajoute au chemin de recherche des algorithmes un répertoire dans lequel
594 se trouve un sous-répertoire "daAlgorithms"
596 if not os.path.isdir(Path):
597 raise ValueError("The given "+Path+" argument must exist as a directory")
598 if not os.path.isdir(os.path.join(Path,"daAlgorithms")):
599 raise ValueError("The given \""+Path+"\" argument must contain a subdirectory named \"daAlgorithms\"")
600 if not os.path.isfile(os.path.join(Path,"daAlgorithms","__init__.py")):
601 raise ValueError("The given \""+Path+"/daAlgorithms\" path must contain a file named \"__init__.py\"")
602 sys.path.insert(0, os.path.abspath(Path))
603 sys.path = PlatformInfo.uniq( sys.path ) # Conserve en unique exemplaire chaque chemin
606 # -----------------------------------------------------------
608 def execute(self, Executor=None, SaveCaseInFile=None):
609 "Lancement du calcul"
610 self.__case.register("execute",dir(),locals(),None,True)
611 Operator.CM.clearCache()
613 if Executor == "YACS": self.__executeYACSScheme( SaveCaseInFile )
614 else: self.__executePythonScheme( SaveCaseInFile )
615 except Exception as e:
616 if isinstance(e, SyntaxError): msg = "at %s: %s"%(e.offset, e.text)
618 raise ValueError(("during execution, the following error occurs:\n"+\
619 "\n%s %s\n\nSee also the potential messages, "+\
620 "which can show the origin of the above error, "+\
621 "in the launching terminal.\n")%(str(e),msg))
624 def __executePythonScheme(self, FileName=None):
625 "Lancement du calcul"
626 self.__case.register("executePythonScheme", dir(), locals())
627 if FileName is not None:
628 self.dump( FileName, "TUI")
629 self.__adaoObject["AlgorithmParameters"].executePythonScheme( self.__adaoObject )
632 def __executeYACSScheme(self, FileName=None):
633 "Lancement du calcul"
634 self.__case.register("executeYACSScheme", dir(), locals())
635 self.dump( FileName, "YACS")
636 self.__adaoObject["AlgorithmParameters"].executeYACSScheme( FileName )
639 # -----------------------------------------------------------
641 def dump(self, FileName=None, Formater="TUI"):
642 "Restitution normalisée des commandes"
643 __Upa = "\n".join(self.__PostAnalysis)
644 return self.__case.dump(FileName, Formater, __Upa)
646 def load(self, FileName=None, Content=None, Object=None, Formater="TUI"):
647 "Chargement normalisé des commandes"
648 __commands = self.__case.load(FileName, Content, Object, Formater)
649 from numpy import array, matrix
650 for __command in __commands:
651 if __command.find("set")>-1 and __command.find("set_")<0:
652 # logging.debug('Command loaded: %s'%(__command,))
653 exec("self."+__command)
655 # logging.debug('Command not loaded: %s'%(__command,))
656 self.__PostAnalysis.append(__command)
660 "Effacement du contenu du cas en cours"
661 self.__init__(self.__name)
663 def with_directory(self, __filename=None):
664 if os.path.exists(str(__filename)):
665 __fullpath = __filename
666 elif os.path.exists(os.path.join(str(self.__directory), str(__filename))):
667 __fullpath = os.path.join(self.__directory, str(__filename))
669 __fullpath = __filename
672 # -----------------------------------------------------------
675 "Clarifie la visibilité des méthodes"
676 return ['set', 'get', 'execute', '__doc__', '__init__', '__module__']
678 def prepare_to_pickle(self):
679 "Retire les variables non pickelisables, avec recopie efficace"
680 if self.__adaoObject['AlgorithmParameters'] is not None:
681 for k in self.__adaoObject['AlgorithmParameters'].keys():
682 if k == "Algorithm": continue
683 if k in self.__StoredInputs:
684 raise ValueError("the key \"%s\s to be transfered for pickling will overwrite an existing one.")
685 if self.__adaoObject['AlgorithmParameters'].hasObserver( k ):
686 self.__adaoObject['AlgorithmParameters'].removeObserver( k, "", True )
687 self.__StoredInputs[k] = self.__adaoObject['AlgorithmParameters'].pop(k, None)
688 if sys.version_info[0] == 2:
689 del self.__adaoObject # Because it breaks pickle in Python 2. Not required for Python 3
690 del self.__case # Because it breaks pickle in Python 2. Not required for Python 3
693 # ==============================================================================
694 if __name__ == "__main__":
695 print('\n AUTODIAGNOSTIC \n')