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,
100 ObjectFunction = None,
104 ScalarSparseMatrix = None,
110 ThreeFunctions = None,
115 "Interface unique de definition de variables d'entrees par argument"
116 self.__case.register("set",dir(),locals(),None,True)
118 if Concept in ("Background", "CheckingPoint", "ControlInput", "Observation"):
119 commande = getattr(self,"set"+Concept)
120 commande(Vector, VectorSerie, Script, DataFile, ColNames, ColMajor, Stored, Scheduler, Checked )
121 elif Concept in ("BackgroundError", "ObservationError", "EvolutionError"):
122 commande = getattr(self,"set"+Concept)
123 commande(Matrix, ScalarSparseMatrix, DiagonalSparseMatrix,
124 Script, Stored, ObjectMatrix, Checked )
125 elif Concept == "AlgorithmParameters":
126 self.setAlgorithmParameters( Algorithm, Parameters, Script )
127 elif Concept == "RegulationParameters":
128 self.setRegulationParameters( Algorithm, Parameters, Script )
129 elif Concept == "Name":
131 elif Concept == "Directory":
132 self.setDirectory(String)
133 elif Concept == "Debug":
135 elif Concept == "NoDebug":
137 elif Concept == "Observer":
138 self.setObserver( Variable, Template, String, Script, Info, ObjectFunction, Scheduler )
139 elif Concept == "ObservationOperator":
140 self.setObservationOperator(
141 Matrix, OneFunction, ThreeFunctions, AppliedInXb,
143 Stored, AvoidRC, InputAsMF, Checked )
144 elif Concept in ("EvolutionModel", "ControlModel"):
145 commande = getattr(self,"set"+Concept)
147 Matrix, OneFunction, ThreeFunctions,
148 Parameters, Script, Scheduler, Stored, AvoidRC, Checked )
151 raise ValueError("the variable named '%s' is not allowed."%str(Concept))
152 except Exception as e:
153 if isinstance(e, SyntaxError): msg = "at %s: %s"%(e.offset, e.text)
155 raise ValueError(("during settings, the following error occurs:\n"+\
156 "\n%s %s\n\nSee also the potential messages, "+\
157 "which can show the origin of the above error, "+\
158 "in the launching terminal.")%(str(e),msg))
160 # -----------------------------------------------------------
162 def setBackground(self,
172 "Definition d'un concept de calcul"
173 Concept = "Background"
174 self.__case.register("set"+Concept, dir(), locals())
175 self.__adaoObject[Concept] = State(
178 asPersistentVector = VectorSerie,
179 asScript = self.__with_directory(Script),
180 asDataFile = DataFile,
183 scheduledBy = Scheduler,
184 toBeChecked = Checked,
187 self.__StoredInputs[Concept] = self.__adaoObject[Concept].getO()
190 def setCheckingPoint(self,
200 "Definition d'un concept de calcul"
201 Concept = "CheckingPoint"
202 self.__case.register("set"+Concept, dir(), locals())
203 self.__adaoObject[Concept] = State(
206 asPersistentVector = VectorSerie,
207 asScript = self.__with_directory(Script),
208 asDataFile = DataFile,
211 scheduledBy = Scheduler,
212 toBeChecked = Checked,
215 self.__StoredInputs[Concept] = self.__adaoObject[Concept].getO()
218 def setControlInput(self,
228 "Definition d'un concept de calcul"
229 Concept = "ControlInput"
230 self.__case.register("set"+Concept, dir(), locals())
231 self.__adaoObject[Concept] = State(
234 asPersistentVector = VectorSerie,
235 asScript = self.__with_directory(Script),
236 asDataFile = DataFile,
239 scheduledBy = Scheduler,
240 toBeChecked = Checked,
243 self.__StoredInputs[Concept] = self.__adaoObject[Concept].getO()
246 def setObservation(self,
256 "Definition d'un concept de calcul"
257 Concept = "Observation"
258 self.__case.register("set"+Concept, dir(), locals())
259 self.__adaoObject[Concept] = State(
262 asPersistentVector = VectorSerie,
263 asScript = self.__with_directory(Script),
264 asDataFile = DataFile,
267 scheduledBy = Scheduler,
268 toBeChecked = Checked,
271 self.__StoredInputs[Concept] = self.__adaoObject[Concept].getO()
274 def setBackgroundError(self,
276 ScalarSparseMatrix = None,
277 DiagonalSparseMatrix = None,
282 "Definition d'un concept de calcul"
283 Concept = "BackgroundError"
284 self.__case.register("set"+Concept, dir(), locals())
285 self.__adaoObject[Concept] = Covariance(
287 asCovariance = Matrix,
288 asEyeByScalar = ScalarSparseMatrix,
289 asEyeByVector = DiagonalSparseMatrix,
290 asCovObject = ObjectMatrix,
291 asScript = self.__with_directory(Script),
292 toBeChecked = Checked,
295 self.__StoredInputs[Concept] = self.__adaoObject[Concept].getO()
298 def setObservationError(self,
300 ScalarSparseMatrix = None,
301 DiagonalSparseMatrix = None,
306 "Definition d'un concept de calcul"
307 Concept = "ObservationError"
308 self.__case.register("set"+Concept, dir(), locals())
309 self.__adaoObject[Concept] = Covariance(
311 asCovariance = Matrix,
312 asEyeByScalar = ScalarSparseMatrix,
313 asEyeByVector = DiagonalSparseMatrix,
314 asCovObject = ObjectMatrix,
315 asScript = self.__with_directory(Script),
316 toBeChecked = Checked,
319 self.__StoredInputs[Concept] = self.__adaoObject[Concept].getO()
322 def setEvolutionError(self,
324 ScalarSparseMatrix = None,
325 DiagonalSparseMatrix = None,
330 "Definition d'un concept de calcul"
331 Concept = "EvolutionError"
332 self.__case.register("set"+Concept, dir(), locals())
333 self.__adaoObject[Concept] = Covariance(
335 asCovariance = Matrix,
336 asEyeByScalar = ScalarSparseMatrix,
337 asEyeByVector = DiagonalSparseMatrix,
338 asCovObject = ObjectMatrix,
339 asScript = self.__with_directory(Script),
340 toBeChecked = Checked,
343 self.__StoredInputs[Concept] = self.__adaoObject[Concept].getO()
346 def setObservationOperator(self,
349 ThreeFunctions = None,
357 "Definition d'un concept de calcul"
358 Concept = "ObservationOperator"
359 self.__case.register("set"+Concept, dir(), locals())
360 self.__adaoObject[Concept] = FullOperator(
363 asOneFunction = OneFunction,
364 asThreeFunctions = ThreeFunctions,
365 asScript = self.__with_directory(Script),
367 appliedInX = AppliedInXb,
369 inputAsMF = InputAsMF,
371 toBeChecked = Checked,
374 self.__StoredInputs[Concept] = self.__adaoObject[Concept].getO()
377 def setEvolutionModel(self,
380 ThreeFunctions = None,
388 "Definition d'un concept de calcul"
389 Concept = "EvolutionModel"
390 self.__case.register("set"+Concept, dir(), locals())
391 self.__adaoObject[Concept] = FullOperator(
394 asOneFunction = OneFunction,
395 asThreeFunctions = ThreeFunctions,
396 asScript = self.__with_directory(Script),
400 inputAsMF = InputAsMF,
401 scheduledBy = Scheduler,
402 toBeChecked = Checked,
405 self.__StoredInputs[Concept] = self.__adaoObject[Concept].getO()
408 def setControlModel(self,
411 ThreeFunctions = None,
419 "Definition d'un concept de calcul"
420 Concept = "ControlModel"
421 self.__case.register("set"+Concept, dir(), locals())
422 self.__adaoObject[Concept] = FullOperator(
425 asOneFunction = OneFunction,
426 asThreeFunctions = ThreeFunctions,
427 asScript = self.__with_directory(Script),
431 inputAsMF = InputAsMF,
432 scheduledBy = Scheduler,
433 toBeChecked = Checked,
436 self.__StoredInputs[Concept] = self.__adaoObject[Concept].getO()
439 def setName(self, String=None):
440 "Definition d'un concept de calcul"
441 self.__case.register("setName",dir(),locals())
442 if String is not None:
443 self.__name = str(String)
446 self.__StoredInputs["Name"] = self.__name
448 def setDirectory(self, String=None):
449 "Definition d'un concept de calcul"
450 self.__case.register("setDirectory",dir(),locals())
451 if os.path.isdir(os.path.abspath(str(String))):
452 self.__directory = os.path.abspath(str(String))
454 self.__directory = None
455 self.__StoredInputs["Directory"] = self.__directory
457 def setDebug(self, __level = 10):
458 "NOTSET=0 < DEBUG=10 < INFO=20 < WARNING=30 < ERROR=40 < CRITICAL=50"
459 self.__case.register("setDebug",dir(),locals())
460 log = logging.getLogger()
461 log.setLevel( __level )
462 self.__StoredInputs["Debug"] = __level
463 self.__StoredInputs["NoDebug"] = False
466 def setNoDebug(self):
467 "NOTSET=0 < DEBUG=10 < INFO=20 < WARNING=30 < ERROR=40 < CRITICAL=50"
468 self.__case.register("setNoDebug",dir(),locals())
469 log = logging.getLogger()
470 log.setLevel( logging.WARNING )
471 self.__StoredInputs["Debug"] = logging.WARNING
472 self.__StoredInputs["NoDebug"] = True
475 def setAlgorithmParameters(self,
479 "Definition d'un concept de calcul"
480 Concept = "AlgorithmParameters"
481 self.__case.register("set"+Concept, dir(), locals())
482 self.__adaoObject[Concept] = AlgorithmAndParameters(
484 asAlgorithm = Algorithm,
486 asScript = self.__with_directory(Script),
490 def updateAlgorithmParameters(self,
493 "Mise a jour d'un concept de calcul"
494 if "AlgorithmParameters" not in self.__adaoObject:
495 raise ValueError("No algorithm registred, ask for one before updating parameters")
496 self.__adaoObject["AlgorithmParameters"].updateParameters(
498 asScript = self.__with_directory(Script),
502 def setRegulationParameters(self,
506 "Definition d'un concept de calcul"
507 Concept = "RegulationParameters"
508 self.__case.register("set"+Concept, dir(), locals())
509 self.__adaoObject[Concept] = RegulationAndParameters(
511 asAlgorithm = Algorithm,
513 asScript = self.__with_directory(Script),
517 def setObserver(self,
523 ObjectFunction = None,
525 "Definition d'un concept de calcul"
527 self.__case.register("set"+Concept, dir(), locals())
528 self.__adaoObject[Concept].append( DataObserver(
530 onVariable = Variable,
531 asTemplate = Template,
533 asScript = self.__with_directory(Script),
534 asObsObject = ObjectFunction,
536 scheduledBy = Scheduler,
537 withAlgo = self.__adaoObject["AlgorithmParameters"]
541 def removeObserver(self,
543 ObjectFunction = None,
545 "Permet de retirer un observer à une ou des variable nommée"
546 if "AlgorithmParameters" not in self.__adaoObject:
547 raise ValueError("No algorithm registred, ask for one before removing observers")
549 # Vérification du nom de variable et typage
550 # -----------------------------------------
551 if isinstance(Variable, str):
552 VariableNames = (Variable,)
553 elif isinstance(Variable, list):
554 VariableNames = tuple(map( str, Variable ))
556 raise ValueError("The observer requires a name or a list of names of variables.")
558 # Association interne de l'observer à la variable
559 # -----------------------------------------------
560 for ename in VariableNames:
561 if ename not in self.__adaoObject["AlgorithmParameters"]:
562 raise ValueError("An observer requires to be removed on a variable named %s which does not exist."%ename)
564 return self.__adaoObject["AlgorithmParameters"].removeObserver( ename, ObjectFunction )
566 # -----------------------------------------------------------
568 def get(self, Concept=None, noDetails=True ):
569 "Recuperation d'une sortie du calcul"
570 if Concept is not None:
572 self.__case.register("get", dir(), locals(), Concept) # Break pickle in Python 2
575 if Concept in self.__StoredInputs:
576 return self.__StoredInputs[Concept]
578 elif self.__adaoObject["AlgorithmParameters"] is not None and Concept == "AlgorithmParameters":
579 return self.__adaoObject["AlgorithmParameters"].get()
581 elif self.__adaoObject["AlgorithmParameters"] is not None and Concept in self.__adaoObject["AlgorithmParameters"]:
582 return self.__adaoObject["AlgorithmParameters"].get( Concept )
584 elif Concept == "AlgorithmRequiredParameters" and self.__adaoObject["AlgorithmParameters"] is not None:
585 return self.__adaoObject["AlgorithmParameters"].getAlgorithmRequiredParameters(noDetails)
588 raise ValueError("The requested key \"%s\" does not exists as an input or a stored variable."%Concept)
591 allvariables.update( {"AlgorithmParameters":self.__adaoObject["AlgorithmParameters"].get()} )
592 # allvariables.update( self.__adaoObject["AlgorithmParameters"].get() )
593 allvariables.update( self.__StoredInputs )
594 allvariables.pop('Observer', None)
597 # -----------------------------------------------------------
599 def get_available_variables(self):
601 Renvoie les variables potentiellement utilisables pour l'étude,
602 initialement stockées comme données d'entrées ou dans les algorithmes,
603 identifiés par les chaînes de caractères. L'algorithme doit avoir été
604 préalablement choisi sinon la méthode renvoie "None".
606 if len(list(self.__adaoObject["AlgorithmParameters"].keys())) == 0 and \
607 len(list(self.__StoredInputs.keys())) == 0:
611 if len(list(self.__adaoObject["AlgorithmParameters"].keys())) > 0:
612 variables.extend(list(self.__adaoObject["AlgorithmParameters"].keys()))
613 if len(list(self.__StoredInputs.keys())) > 0:
614 variables.extend( list(self.__StoredInputs.keys()) )
615 variables.remove('Observer')
619 def get_available_algorithms(self):
621 Renvoie la liste des algorithmes potentiellement utilisables, identifiés
622 par les chaînes de caractères.
625 for directory in sys.path:
626 trypath = os.path.join(directory,"daAlgorithms")
627 if os.path.isdir(trypath):
628 for fname in os.listdir(trypath):
629 if os.path.isfile(os.path.join(trypath,fname)):
630 fc = open(os.path.join(trypath,fname)).read()
631 iselal = bool("class ElementaryAlgorithm" in fc)
632 root, ext = os.path.splitext(fname)
633 if iselal and ext == '.py' and root != '__init__':
638 def get_algorithms_main_path(self):
640 Renvoie le chemin pour le répertoire principal contenant les algorithmes
644 def add_algorithms_path(self, Path=None):
646 Ajoute au chemin de recherche des algorithmes un répertoire dans lequel
647 se trouve un sous-répertoire "daAlgorithms"
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 # -----------------------------------------------------------
661 def execute(self, Executor=None, SaveCaseInFile=None):
662 "Lancement du calcul"
663 self.__case.register("execute",dir(),locals(),None,True)
664 Operator.CM.clearCache()
666 if Executor == "YACS": self.__executeYACSScheme( SaveCaseInFile )
667 else: self.__executePythonScheme( SaveCaseInFile )
668 except Exception as e:
669 if isinstance(e, SyntaxError): msg = "at %s: %s"%(e.offset, e.text)
671 raise ValueError(("during execution, the following error occurs:\n"+\
672 "\n%s %s\n\nSee also the potential messages, "+\
673 "which can show the origin of the above error, "+\
674 "in the launching terminal.\n")%(str(e),msg))
677 def __executePythonScheme(self, FileName=None):
678 "Lancement du calcul"
679 self.__case.register("executePythonScheme", dir(), locals())
680 if FileName is not None:
681 self.dump( FileName, "TUI")
682 self.__adaoObject["AlgorithmParameters"].executePythonScheme( self.__adaoObject )
685 def __executeYACSScheme(self, FileName=None):
686 "Lancement du calcul"
687 self.__case.register("executeYACSScheme", dir(), locals())
688 self.dump( FileName, "YACS")
689 self.__adaoObject["AlgorithmParameters"].executeYACSScheme( FileName )
692 # -----------------------------------------------------------
694 def dump(self, FileName=None, Formater="TUI"):
695 "Restitution normalisée des commandes"
696 __Upa = "\n".join(self.__PostAnalysis)
697 return self.__case.dump(FileName, Formater, __Upa)
699 def load(self, FileName=None, Content=None, Object=None, Formater="TUI"):
700 "Chargement normalisé des commandes"
701 __commands = self.__case.load(FileName, Content, Object, Formater)
702 from numpy import array, matrix
703 for __command in __commands:
704 if __command.find("set")>-1 and __command.find("set_")<0:
705 exec("self."+__command)
707 self.__PostAnalysis.append(__command)
711 FileNameFrom=None, ContentFrom=None, ObjectFrom=None, FormaterFrom="TUI",
712 FileNameTo=None, FormaterTo="TUI",
714 "Conversion normalisée des commandes"
716 FileName=FileNameFrom, Content=ContentFrom, Object=ObjectFrom, Formater=FormaterFrom
718 FileName=FileNameTo, Formater=FormaterTo
722 "Effacement du contenu du cas en cours"
723 self.__init__(self.__name)
725 # -----------------------------------------------------------
727 def __with_directory(self, __filename=None):
728 if os.path.exists(str(__filename)):
729 __fullpath = __filename
730 elif os.path.exists(os.path.join(str(self.__directory), str(__filename))):
731 __fullpath = os.path.join(self.__directory, str(__filename))
733 __fullpath = __filename
737 "Clarifie la visibilité des méthodes"
738 return ['set', 'get', 'execute', 'dump', 'load', '__doc__', '__init__', '__module__']
740 def prepare_to_pickle(self):
741 "Retire les variables non pickelisables, avec recopie efficace"
742 if self.__adaoObject['AlgorithmParameters'] is not None:
743 for k in self.__adaoObject['AlgorithmParameters'].keys():
744 if k == "Algorithm": continue
745 if k in self.__StoredInputs:
746 raise ValueError("the key \"%s\s to be transfered for pickling will overwrite an existing one.")
747 if self.__adaoObject['AlgorithmParameters'].hasObserver( k ):
748 self.__adaoObject['AlgorithmParameters'].removeObserver( k, "", True )
749 self.__StoredInputs[k] = self.__adaoObject['AlgorithmParameters'].pop(k, None)
750 if sys.version_info[0] == 2:
751 del self.__adaoObject # Because it breaks pickle in Python 2. Not required for Python 3
752 del self.__case # Because it breaks pickle in Python 2. Not required for Python 3
753 if sys.version_info.major < 3:
756 return self.__StoredInputs
758 # ==============================================================================
759 if __name__ == "__main__":
760 print('\n AUTODIAGNOSTIC \n')