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
96 DiagonalSparseMatrix = None,
99 ObjectFunction = None,
103 ScalarSparseMatrix = None,
109 ThreeFunctions = None,
114 "Interface unique de definition de variables d'entrees par argument"
115 self.__case.register("set",dir(),locals(),None,True)
117 if Concept in ("Background", "CheckingPoint", "ControlInput", "Observation"):
118 commande = getattr(self,"set"+Concept)
119 commande(Vector, VectorSerie, Script, DataFile, ColNames, ColMajor, Stored, Scheduler, Checked )
120 elif Concept in ("BackgroundError", "ObservationError", "EvolutionError"):
121 commande = getattr(self,"set"+Concept)
122 commande(Matrix, ScalarSparseMatrix, DiagonalSparseMatrix,
123 Script, Stored, ObjectMatrix, Checked )
124 elif Concept == "AlgorithmParameters":
125 self.setAlgorithmParameters( Algorithm, Parameters, Script )
126 elif Concept == "RegulationParameters":
127 self.setRegulationParameters( Algorithm, Parameters, Script )
128 elif Concept == "Name":
130 elif Concept == "Directory":
131 self.setDirectory(String)
132 elif Concept == "Debug":
134 elif Concept == "NoDebug":
136 elif Concept == "Observer":
137 self.setObserver( Variable, Template, String, Script, Info, ObjectFunction, Scheduler )
138 elif Concept == "ObservationOperator":
139 self.setObservationOperator(
140 Matrix, OneFunction, ThreeFunctions, AppliedInXb,
141 Parameters, Script, Stored, AvoidRC, Checked )
142 elif Concept in ("EvolutionModel", "ControlModel"):
143 commande = getattr(self,"set"+Concept)
145 Matrix, OneFunction, ThreeFunctions,
146 Parameters, Script, Scheduler, Stored, AvoidRC, Checked )
149 raise ValueError("the variable named '%s' is not allowed."%str(Concept))
150 except Exception as e:
151 if isinstance(e, SyntaxError): msg = "at %s: %s"%(e.offset, e.text)
153 raise ValueError(("during settings, the following error occurs:\n"+\
154 "\n%s %s\n\nSee also the potential messages, "+\
155 "which can show the origin of the above error, "+\
156 "in the launching terminal.")%(str(e),msg))
158 # -----------------------------------------------------------
160 def setBackground(self,
170 "Definition d'un concept de calcul"
171 Concept = "Background"
172 self.__case.register("set"+Concept, dir(), locals())
173 self.__adaoObject[Concept] = State(
176 asPersistentVector = VectorSerie,
177 asScript = self.__with_directory(Script),
178 asDataFile = DataFile,
181 scheduledBy = Scheduler,
182 toBeChecked = Checked,
185 self.__StoredInputs[Concept] = self.__adaoObject[Concept].getO()
188 def setCheckingPoint(self,
198 "Definition d'un concept de calcul"
199 Concept = "CheckingPoint"
200 self.__case.register("set"+Concept, dir(), locals())
201 self.__adaoObject[Concept] = State(
204 asPersistentVector = VectorSerie,
205 asScript = self.__with_directory(Script),
206 asDataFile = DataFile,
209 scheduledBy = Scheduler,
210 toBeChecked = Checked,
213 self.__StoredInputs[Concept] = self.__adaoObject[Concept].getO()
216 def setControlInput(self,
226 "Definition d'un concept de calcul"
227 Concept = "ControlInput"
228 self.__case.register("set"+Concept, dir(), locals())
229 self.__adaoObject[Concept] = State(
232 asPersistentVector = VectorSerie,
233 asScript = self.__with_directory(Script),
234 asDataFile = DataFile,
237 scheduledBy = Scheduler,
238 toBeChecked = Checked,
241 self.__StoredInputs[Concept] = self.__adaoObject[Concept].getO()
244 def setObservation(self,
254 "Definition d'un concept de calcul"
255 Concept = "Observation"
256 self.__case.register("set"+Concept, dir(), locals())
257 self.__adaoObject[Concept] = State(
260 asPersistentVector = VectorSerie,
261 asScript = self.__with_directory(Script),
262 asDataFile = DataFile,
265 scheduledBy = Scheduler,
266 toBeChecked = Checked,
269 self.__StoredInputs[Concept] = self.__adaoObject[Concept].getO()
272 def setBackgroundError(self,
274 ScalarSparseMatrix = None,
275 DiagonalSparseMatrix = None,
280 "Definition d'un concept de calcul"
281 Concept = "BackgroundError"
282 self.__case.register("set"+Concept, dir(), locals())
283 self.__adaoObject[Concept] = Covariance(
285 asCovariance = Matrix,
286 asEyeByScalar = ScalarSparseMatrix,
287 asEyeByVector = DiagonalSparseMatrix,
288 asCovObject = ObjectMatrix,
289 asScript = self.__with_directory(Script),
290 toBeChecked = Checked,
293 self.__StoredInputs[Concept] = self.__adaoObject[Concept].getO()
296 def setObservationError(self,
298 ScalarSparseMatrix = None,
299 DiagonalSparseMatrix = None,
304 "Definition d'un concept de calcul"
305 Concept = "ObservationError"
306 self.__case.register("set"+Concept, dir(), locals())
307 self.__adaoObject[Concept] = Covariance(
309 asCovariance = Matrix,
310 asEyeByScalar = ScalarSparseMatrix,
311 asEyeByVector = DiagonalSparseMatrix,
312 asCovObject = ObjectMatrix,
313 asScript = self.__with_directory(Script),
314 toBeChecked = Checked,
317 self.__StoredInputs[Concept] = self.__adaoObject[Concept].getO()
320 def setEvolutionError(self,
322 ScalarSparseMatrix = None,
323 DiagonalSparseMatrix = None,
328 "Definition d'un concept de calcul"
329 Concept = "EvolutionError"
330 self.__case.register("set"+Concept, dir(), locals())
331 self.__adaoObject[Concept] = Covariance(
333 asCovariance = Matrix,
334 asEyeByScalar = ScalarSparseMatrix,
335 asEyeByVector = DiagonalSparseMatrix,
336 asCovObject = ObjectMatrix,
337 asScript = self.__with_directory(Script),
338 toBeChecked = Checked,
341 self.__StoredInputs[Concept] = self.__adaoObject[Concept].getO()
344 def setObservationOperator(self,
347 ThreeFunctions = None,
355 "Definition d'un concept de calcul"
356 Concept = "ObservationOperator"
357 self.__case.register("set"+Concept, dir(), locals())
358 self.__adaoObject[Concept] = FullOperator(
361 asOneFunction = OneFunction,
362 asThreeFunctions = ThreeFunctions,
363 asScript = self.__with_directory(Script),
365 appliedInX = AppliedInXb,
367 inputAsMF = InputAsMF,
369 toBeChecked = Checked,
372 self.__StoredInputs[Concept] = self.__adaoObject[Concept].getO()
375 def setEvolutionModel(self,
378 ThreeFunctions = None,
386 "Definition d'un concept de calcul"
387 Concept = "EvolutionModel"
388 self.__case.register("set"+Concept, dir(), locals())
389 self.__adaoObject[Concept] = FullOperator(
392 asOneFunction = OneFunction,
393 asThreeFunctions = ThreeFunctions,
394 asScript = self.__with_directory(Script),
398 inputAsMF = InputAsMF,
399 scheduledBy = Scheduler,
400 toBeChecked = Checked,
403 self.__StoredInputs[Concept] = self.__adaoObject[Concept].getO()
406 def setControlModel(self,
409 ThreeFunctions = None,
417 "Definition d'un concept de calcul"
418 Concept = "ControlModel"
419 self.__case.register("set"+Concept, dir(), locals())
420 self.__adaoObject[Concept] = FullOperator(
423 asOneFunction = OneFunction,
424 asThreeFunctions = ThreeFunctions,
425 asScript = self.__with_directory(Script),
429 inputAsMF = InputAsMF,
430 scheduledBy = Scheduler,
431 toBeChecked = Checked,
434 self.__StoredInputs[Concept] = self.__adaoObject[Concept].getO()
437 def setName(self, String=None):
438 "Definition d'un concept de calcul"
439 self.__case.register("setName",dir(),locals())
440 if String is not None:
441 self.__name = str(String)
444 self.__StoredInputs["Name"] = self.__name
446 def setDirectory(self, String=None):
447 "Definition d'un concept de calcul"
448 self.__case.register("setDirectory",dir(),locals())
449 if os.path.isdir(os.path.abspath(str(String))):
450 self.__directory = os.path.abspath(str(String))
452 self.__directory = None
453 self.__StoredInputs["Directory"] = self.__directory
455 def setDebug(self, __level = 10):
456 "NOTSET=0 < DEBUG=10 < INFO=20 < WARNING=30 < ERROR=40 < CRITICAL=50"
457 self.__case.register("setDebug",dir(),locals())
458 log = logging.getLogger()
459 log.setLevel( __level )
460 self.__StoredInputs["Debug"] = __level
461 self.__StoredInputs["NoDebug"] = False
464 def setNoDebug(self):
465 "NOTSET=0 < DEBUG=10 < INFO=20 < WARNING=30 < ERROR=40 < CRITICAL=50"
466 self.__case.register("setNoDebug",dir(),locals())
467 log = logging.getLogger()
468 log.setLevel( logging.WARNING )
469 self.__StoredInputs["Debug"] = logging.WARNING
470 self.__StoredInputs["NoDebug"] = True
473 def setAlgorithmParameters(self,
477 "Definition d'un concept de calcul"
478 Concept = "AlgorithmParameters"
479 self.__case.register("set"+Concept, dir(), locals())
480 self.__adaoObject[Concept] = AlgorithmAndParameters(
482 asAlgorithm = Algorithm,
484 asScript = self.__with_directory(Script),
488 def updateAlgorithmParameters(self,
491 "Mise a jour d'un concept de calcul"
492 if "AlgorithmParameters" not in self.__adaoObject:
493 raise ValueError("No algorithm registred, ask for one before updating parameters")
494 self.__adaoObject["AlgorithmParameters"].updateParameters(
496 asScript = self.__with_directory(Script),
500 def setRegulationParameters(self,
504 "Definition d'un concept de calcul"
505 Concept = "RegulationParameters"
506 self.__case.register("set"+Concept, dir(), locals())
507 self.__adaoObject[Concept] = RegulationAndParameters(
509 asAlgorithm = Algorithm,
511 asScript = self.__with_directory(Script),
515 def setObserver(self,
521 ObjectFunction = None,
523 "Definition d'un concept de calcul"
525 self.__case.register("set"+Concept, dir(), locals())
526 self.__adaoObject[Concept].append( DataObserver(
528 onVariable = Variable,
529 asTemplate = Template,
531 asScript = self.__with_directory(Script),
532 asObsObject = ObjectFunction,
534 scheduledBy = Scheduler,
535 withAlgo = self.__adaoObject["AlgorithmParameters"]
539 def removeObserver(self,
541 ObjectFunction = None,
543 "Permet de retirer un observer à une ou des variable nommée"
544 if "AlgorithmParameters" not in self.__adaoObject:
545 raise ValueError("No algorithm registred, ask for one before removing observers")
547 # Vérification du nom de variable et typage
548 # -----------------------------------------
549 if isinstance(Variable, str):
550 VariableNames = (Variable,)
551 elif isinstance(Variable, list):
552 VariableNames = tuple(map( str, Variable ))
554 raise ValueError("The observer requires a name or a list of names of variables.")
556 # Association interne de l'observer à la variable
557 # -----------------------------------------------
558 for ename in VariableNames:
559 if ename not in self.__adaoObject["AlgorithmParameters"]:
560 raise ValueError("An observer requires to be removed on a variable named %s which does not exist."%ename)
562 return self.__adaoObject["AlgorithmParameters"].removeObserver( ename, ObjectFunction )
564 # -----------------------------------------------------------
566 def get(self, Concept=None, noDetails=True ):
567 "Recuperation d'une sortie du calcul"
568 if Concept is not None:
570 self.__case.register("get", dir(), locals(), Concept) # Break pickle in Python 2
573 if Concept in self.__StoredInputs:
574 return self.__StoredInputs[Concept]
576 elif self.__adaoObject["AlgorithmParameters"] is not None and Concept == "AlgorithmParameters":
577 return self.__adaoObject["AlgorithmParameters"].get()
579 elif self.__adaoObject["AlgorithmParameters"] is not None and Concept in self.__adaoObject["AlgorithmParameters"]:
580 return self.__adaoObject["AlgorithmParameters"].get( Concept )
582 elif Concept == "AlgorithmRequiredParameters" and self.__adaoObject["AlgorithmParameters"] is not None:
583 return self.__adaoObject["AlgorithmParameters"].getAlgorithmRequiredParameters(noDetails)
586 raise ValueError("The requested key \"%s\" does not exists as an input or a stored variable."%Concept)
589 allvariables.update( {"AlgorithmParameters":self.__adaoObject["AlgorithmParameters"].get()} )
590 # allvariables.update( self.__adaoObject["AlgorithmParameters"].get() )
591 allvariables.update( self.__StoredInputs )
592 allvariables.pop('Observer', None)
595 # -----------------------------------------------------------
597 def get_available_variables(self):
599 Renvoie les variables potentiellement utilisables pour l'étude,
600 initialement stockées comme données d'entrées ou dans les algorithmes,
601 identifiés par les chaînes de caractères. L'algorithme doit avoir été
602 préalablement choisi sinon la méthode renvoie "None".
604 if len(list(self.__adaoObject["AlgorithmParameters"].keys())) == 0 and \
605 len(list(self.__StoredInputs.keys())) == 0:
609 if len(list(self.__adaoObject["AlgorithmParameters"].keys())) > 0:
610 variables.extend(list(self.__adaoObject["AlgorithmParameters"].keys()))
611 if len(list(self.__StoredInputs.keys())) > 0:
612 variables.extend( list(self.__StoredInputs.keys()) )
613 variables.remove('Observer')
617 def get_available_algorithms(self):
619 Renvoie la liste des algorithmes potentiellement utilisables, identifiés
620 par les chaînes de caractères.
623 for directory in sys.path:
624 trypath = os.path.join(directory,"daAlgorithms")
625 if os.path.isdir(trypath):
626 for fname in os.listdir(trypath):
627 if os.path.isfile(os.path.join(trypath,fname)):
628 fc = open(os.path.join(trypath,fname)).read()
629 iselal = bool("class ElementaryAlgorithm" in fc)
630 root, ext = os.path.splitext(fname)
631 if iselal and ext == '.py' and root != '__init__':
636 def get_algorithms_main_path(self):
638 Renvoie le chemin pour le répertoire principal contenant les algorithmes
642 def add_algorithms_path(self, Path=None):
644 Ajoute au chemin de recherche des algorithmes un répertoire dans lequel
645 se trouve un sous-répertoire "daAlgorithms"
647 if not os.path.isdir(Path):
648 raise ValueError("The given "+Path+" argument must exist as a directory")
649 if not os.path.isdir(os.path.join(Path,"daAlgorithms")):
650 raise ValueError("The given \""+Path+"\" argument must contain a subdirectory named \"daAlgorithms\"")
651 if not os.path.isfile(os.path.join(Path,"daAlgorithms","__init__.py")):
652 raise ValueError("The given \""+Path+"/daAlgorithms\" path must contain a file named \"__init__.py\"")
653 sys.path.insert(0, os.path.abspath(Path))
654 sys.path = PlatformInfo.uniq( sys.path ) # Conserve en unique exemplaire chaque chemin
657 # -----------------------------------------------------------
659 def execute(self, Executor=None, SaveCaseInFile=None):
660 "Lancement du calcul"
661 self.__case.register("execute",dir(),locals(),None,True)
662 Operator.CM.clearCache()
664 if Executor == "YACS": self.__executeYACSScheme( SaveCaseInFile )
665 else: self.__executePythonScheme( SaveCaseInFile )
666 except Exception as e:
667 if isinstance(e, SyntaxError): msg = "at %s: %s"%(e.offset, e.text)
669 raise ValueError(("during execution, the following error occurs:\n"+\
670 "\n%s %s\n\nSee also the potential messages, "+\
671 "which can show the origin of the above error, "+\
672 "in the launching terminal.\n")%(str(e),msg))
675 def __executePythonScheme(self, FileName=None):
676 "Lancement du calcul"
677 self.__case.register("executePythonScheme", dir(), locals())
678 if FileName is not None:
679 self.dump( FileName, "TUI")
680 self.__adaoObject["AlgorithmParameters"].executePythonScheme( self.__adaoObject )
683 def __executeYACSScheme(self, FileName=None):
684 "Lancement du calcul"
685 self.__case.register("executeYACSScheme", dir(), locals())
686 self.dump( FileName, "YACS")
687 self.__adaoObject["AlgorithmParameters"].executeYACSScheme( FileName )
690 # -----------------------------------------------------------
692 def dump(self, FileName=None, Formater="TUI"):
693 "Restitution normalisée des commandes"
694 __Upa = "\n".join(self.__PostAnalysis)
695 return self.__case.dump(FileName, Formater, __Upa)
697 def load(self, FileName=None, Content=None, Object=None, Formater="TUI"):
698 "Chargement normalisé des commandes"
699 __commands = self.__case.load(FileName, Content, Object, Formater)
700 from numpy import array, matrix
701 for __command in __commands:
702 if __command.find("set")>-1 and __command.find("set_")<0:
703 exec("self."+__command)
705 self.__PostAnalysis.append(__command)
709 FileNameFrom=None, ContentFrom=None, ObjectFrom=None, FormaterFrom="TUI",
710 FileNameTo=None, FormaterTo="TUI",
712 "Conversion normalisée des commandes"
714 FileName=FileNameFrom, Content=ContentFrom, Object=ObjectFrom, Formater=FormaterFrom
716 FileName=FileNameTo, Formater=FormaterTo
720 "Effacement du contenu du cas en cours"
721 self.__init__(self.__name)
723 # -----------------------------------------------------------
725 def __with_directory(self, __filename=None):
726 if os.path.exists(str(__filename)):
727 __fullpath = __filename
728 elif os.path.exists(os.path.join(str(self.__directory), str(__filename))):
729 __fullpath = os.path.join(self.__directory, str(__filename))
731 __fullpath = __filename
735 "Clarifie la visibilité des méthodes"
736 return ['set', 'get', 'execute', 'dump', 'load', '__doc__', '__init__', '__module__']
738 def prepare_to_pickle(self):
739 "Retire les variables non pickelisables, avec recopie efficace"
740 if self.__adaoObject['AlgorithmParameters'] is not None:
741 for k in self.__adaoObject['AlgorithmParameters'].keys():
742 if k == "Algorithm": continue
743 if k in self.__StoredInputs:
744 raise ValueError("the key \"%s\s to be transfered for pickling will overwrite an existing one.")
745 if self.__adaoObject['AlgorithmParameters'].hasObserver( k ):
746 self.__adaoObject['AlgorithmParameters'].removeObserver( k, "", True )
747 self.__StoredInputs[k] = self.__adaoObject['AlgorithmParameters'].pop(k, None)
748 if sys.version_info[0] == 2:
749 del self.__adaoObject # Because it breaks pickle in Python 2. Not required for Python 3
750 del self.__case # Because it breaks pickle in Python 2. Not required for Python 3
751 if sys.version_info.major < 3:
754 return self.__StoredInputs
756 # ==============================================================================
757 if __name__ == "__main__":
758 print('\n AUTODIAGNOSTIC \n')