1 # -*- coding: utf-8 -*-
3 # Copyright (C) 2008-2020 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] = []
79 self.__StoredInputs["Name"] = self.__name
80 self.__StoredInputs["Directory"] = self.__directory
82 # Récupère le chemin du répertoire parent et l'ajoute au path
83 # (Cela complète l'action de la classe PathManagement dans PlatformInfo,
84 # qui est activée dans Persistence)
85 self.__parent = os.path.abspath(os.path.join(os.path.dirname(__file__),".."))
86 sys.path.insert(0, self.__parent)
87 sys.path = PlatformInfo.uniq( sys.path ) # Conserve en unique exemplaire chaque chemin
90 Concept = None, # Premier argument
98 DiagonalSparseMatrix = None,
99 ExtraArguments = None,
101 InputFunctionAsMulti = False,
103 ObjectFunction = None,
107 ScalarSparseMatrix = None,
113 ThreeFunctions = None,
118 "Interface unique de definition de variables d'entrees par argument"
119 self.__case.register("set",dir(),locals(),None,True)
121 if Concept in ("Background", "CheckingPoint", "ControlInput", "Observation"):
122 commande = getattr(self,"set"+Concept)
123 commande(Vector, VectorSerie, Script, DataFile, ColNames, ColMajor, Stored, Scheduler, Checked )
124 elif Concept in ("BackgroundError", "ObservationError", "EvolutionError"):
125 commande = getattr(self,"set"+Concept)
126 commande(Matrix, ScalarSparseMatrix, DiagonalSparseMatrix,
127 Script, Stored, ObjectMatrix, Checked )
128 elif Concept == "AlgorithmParameters":
129 self.setAlgorithmParameters( Algorithm, Parameters, Script )
130 elif Concept == "RegulationParameters":
131 self.setRegulationParameters( Algorithm, Parameters, Script )
132 elif Concept == "Name":
134 elif Concept == "Directory":
135 self.setDirectory(String)
136 elif Concept == "Debug":
138 elif Concept == "NoDebug":
140 elif Concept == "Observer":
141 self.setObserver( Variable, Template, String, Script, Info, ObjectFunction, Scheduler )
142 elif Concept == "ObservationOperator":
143 self.setObservationOperator(
144 Matrix, OneFunction, ThreeFunctions, AppliedInXb,
145 Parameters, Script, ExtraArguments,
146 Stored, AvoidRC, InputFunctionAsMulti, Checked )
147 elif Concept in ("EvolutionModel", "ControlModel"):
148 commande = getattr(self,"set"+Concept)
150 Matrix, OneFunction, ThreeFunctions,
151 Parameters, Script, Scheduler, ExtraArguments,
152 Stored, AvoidRC, InputFunctionAsMulti, Checked )
154 raise ValueError("the variable named '%s' is not allowed."%str(Concept))
155 except Exception as e:
156 if isinstance(e, SyntaxError): msg = "at %s: %s"%(e.offset, e.text)
158 raise ValueError(("during settings, the following error occurs:\n"+\
159 "\n%s %s\n\nSee also the potential messages, "+\
160 "which can show the origin of the above error, "+\
161 "in the launching terminal.")%(str(e),msg))
163 # -----------------------------------------------------------
165 def setBackground(self,
175 "Definition d'un concept de calcul"
176 Concept = "Background"
177 self.__case.register("set"+Concept, dir(), locals())
178 self.__adaoObject[Concept] = State(
181 asPersistentVector = VectorSerie,
182 asScript = self.__with_directory(Script),
183 asDataFile = DataFile,
186 scheduledBy = Scheduler,
187 toBeChecked = Checked,
190 self.__StoredInputs[Concept] = self.__adaoObject[Concept].getO()
193 def setCheckingPoint(self,
203 "Definition d'un concept de calcul"
204 Concept = "CheckingPoint"
205 self.__case.register("set"+Concept, dir(), locals())
206 self.__adaoObject[Concept] = State(
209 asPersistentVector = VectorSerie,
210 asScript = self.__with_directory(Script),
211 asDataFile = DataFile,
214 scheduledBy = Scheduler,
215 toBeChecked = Checked,
218 self.__StoredInputs[Concept] = self.__adaoObject[Concept].getO()
221 def setControlInput(self,
231 "Definition d'un concept de calcul"
232 Concept = "ControlInput"
233 self.__case.register("set"+Concept, dir(), locals())
234 self.__adaoObject[Concept] = State(
237 asPersistentVector = VectorSerie,
238 asScript = self.__with_directory(Script),
239 asDataFile = DataFile,
242 scheduledBy = Scheduler,
243 toBeChecked = Checked,
246 self.__StoredInputs[Concept] = self.__adaoObject[Concept].getO()
249 def setObservation(self,
259 "Definition d'un concept de calcul"
260 Concept = "Observation"
261 self.__case.register("set"+Concept, dir(), locals())
262 self.__adaoObject[Concept] = State(
265 asPersistentVector = VectorSerie,
266 asScript = self.__with_directory(Script),
267 asDataFile = DataFile,
270 scheduledBy = Scheduler,
271 toBeChecked = Checked,
274 self.__StoredInputs[Concept] = self.__adaoObject[Concept].getO()
277 def setBackgroundError(self,
279 ScalarSparseMatrix = None,
280 DiagonalSparseMatrix = None,
285 "Definition d'un concept de calcul"
286 Concept = "BackgroundError"
287 self.__case.register("set"+Concept, dir(), locals())
288 self.__adaoObject[Concept] = Covariance(
290 asCovariance = Matrix,
291 asEyeByScalar = ScalarSparseMatrix,
292 asEyeByVector = DiagonalSparseMatrix,
293 asCovObject = ObjectMatrix,
294 asScript = self.__with_directory(Script),
295 toBeChecked = Checked,
298 self.__StoredInputs[Concept] = self.__adaoObject[Concept].getO()
301 def setObservationError(self,
303 ScalarSparseMatrix = None,
304 DiagonalSparseMatrix = None,
309 "Definition d'un concept de calcul"
310 Concept = "ObservationError"
311 self.__case.register("set"+Concept, dir(), locals())
312 self.__adaoObject[Concept] = Covariance(
314 asCovariance = Matrix,
315 asEyeByScalar = ScalarSparseMatrix,
316 asEyeByVector = DiagonalSparseMatrix,
317 asCovObject = ObjectMatrix,
318 asScript = self.__with_directory(Script),
319 toBeChecked = Checked,
322 self.__StoredInputs[Concept] = self.__adaoObject[Concept].getO()
325 def setEvolutionError(self,
327 ScalarSparseMatrix = None,
328 DiagonalSparseMatrix = None,
333 "Definition d'un concept de calcul"
334 Concept = "EvolutionError"
335 self.__case.register("set"+Concept, dir(), locals())
336 self.__adaoObject[Concept] = Covariance(
338 asCovariance = Matrix,
339 asEyeByScalar = ScalarSparseMatrix,
340 asEyeByVector = DiagonalSparseMatrix,
341 asCovObject = ObjectMatrix,
342 asScript = self.__with_directory(Script),
343 toBeChecked = Checked,
346 self.__StoredInputs[Concept] = self.__adaoObject[Concept].getO()
349 def setObservationOperator(self,
352 ThreeFunctions = None,
356 ExtraArguments = None,
359 InputFunctionAsMulti = False,
361 "Definition d'un concept de calcul"
362 Concept = "ObservationOperator"
363 self.__case.register("set"+Concept, dir(), locals())
364 self.__adaoObject[Concept] = FullOperator(
367 asOneFunction = OneFunction,
368 asThreeFunctions = ThreeFunctions,
369 asScript = self.__with_directory(Script),
371 appliedInX = AppliedInXb,
372 extraArguments = ExtraArguments,
374 inputAsMF = InputFunctionAsMulti,
376 toBeChecked = Checked,
379 self.__StoredInputs[Concept] = self.__adaoObject[Concept].getO()
382 def setEvolutionModel(self,
385 ThreeFunctions = None,
389 ExtraArguments = None,
392 InputFunctionAsMulti = False,
394 "Definition d'un concept de calcul"
395 Concept = "EvolutionModel"
396 self.__case.register("set"+Concept, dir(), locals())
397 self.__adaoObject[Concept] = FullOperator(
400 asOneFunction = OneFunction,
401 asThreeFunctions = ThreeFunctions,
402 asScript = self.__with_directory(Script),
405 extraArguments = ExtraArguments,
407 inputAsMF = InputFunctionAsMulti,
408 scheduledBy = Scheduler,
409 toBeChecked = Checked,
412 self.__StoredInputs[Concept] = self.__adaoObject[Concept].getO()
415 def setControlModel(self,
418 ThreeFunctions = None,
422 ExtraArguments = None,
425 InputFunctionAsMulti = False,
427 "Definition d'un concept de calcul"
428 Concept = "ControlModel"
429 self.__case.register("set"+Concept, dir(), locals())
430 self.__adaoObject[Concept] = FullOperator(
433 asOneFunction = OneFunction,
434 asThreeFunctions = ThreeFunctions,
435 asScript = self.__with_directory(Script),
438 extraArguments = ExtraArguments,
440 inputAsMF = InputFunctionAsMulti,
441 scheduledBy = Scheduler,
442 toBeChecked = Checked,
445 self.__StoredInputs[Concept] = self.__adaoObject[Concept].getO()
448 def setName(self, String=None):
449 "Definition d'un concept de calcul"
450 self.__case.register("setName",dir(),locals())
451 if String is not None:
452 self.__name = str(String)
455 self.__StoredInputs["Name"] = self.__name
457 def setDirectory(self, String=None):
458 "Definition d'un concept de calcul"
459 self.__case.register("setDirectory",dir(),locals())
460 if os.path.isdir(os.path.abspath(str(String))):
461 self.__directory = os.path.abspath(str(String))
463 self.__directory = None
464 self.__StoredInputs["Directory"] = self.__directory
466 def setDebug(self, __level = 10):
467 "NOTSET=0 < DEBUG=10 < INFO=20 < WARNING=30 < ERROR=40 < CRITICAL=50"
468 self.__case.register("setDebug",dir(),locals())
469 log = logging.getLogger()
470 log.setLevel( __level )
471 self.__StoredInputs["Debug"] = __level
472 self.__StoredInputs["NoDebug"] = False
475 def setNoDebug(self):
476 "NOTSET=0 < DEBUG=10 < INFO=20 < WARNING=30 < ERROR=40 < CRITICAL=50"
477 self.__case.register("setNoDebug",dir(),locals())
478 log = logging.getLogger()
479 log.setLevel( logging.WARNING )
480 self.__StoredInputs["Debug"] = logging.WARNING
481 self.__StoredInputs["NoDebug"] = True
484 def setAlgorithmParameters(self,
488 "Definition d'un concept de calcul"
489 Concept = "AlgorithmParameters"
490 self.__case.register("set"+Concept, dir(), locals())
491 self.__adaoObject[Concept] = AlgorithmAndParameters(
493 asAlgorithm = Algorithm,
495 asScript = self.__with_directory(Script),
499 def updateAlgorithmParameters(self,
502 "Mise a jour d'un concept de calcul"
503 if "AlgorithmParameters" not in self.__adaoObject:
504 raise ValueError("No algorithm registred, ask for one before updating parameters")
505 self.__adaoObject["AlgorithmParameters"].updateParameters(
507 asScript = self.__with_directory(Script),
511 def setRegulationParameters(self,
515 "Definition d'un concept de calcul"
516 Concept = "RegulationParameters"
517 self.__case.register("set"+Concept, dir(), locals())
518 self.__adaoObject[Concept] = RegulationAndParameters(
520 asAlgorithm = Algorithm,
522 asScript = self.__with_directory(Script),
526 def setObserver(self,
532 ObjectFunction = None,
534 "Definition d'un concept de calcul"
536 self.__case.register("set"+Concept, dir(), locals())
537 self.__adaoObject[Concept].append( DataObserver(
539 onVariable = Variable,
540 asTemplate = Template,
542 asScript = self.__with_directory(Script),
543 asObsObject = ObjectFunction,
545 scheduledBy = Scheduler,
546 withAlgo = self.__adaoObject["AlgorithmParameters"]
550 def removeObserver(self,
552 ObjectFunction = None,
554 "Permet de retirer un observer à une ou des variable nommée"
555 if "AlgorithmParameters" not in self.__adaoObject:
556 raise ValueError("No algorithm registred, ask for one before removing observers")
558 # Vérification du nom de variable et typage
559 # -----------------------------------------
560 if isinstance(Variable, str):
561 VariableNames = (Variable,)
562 elif isinstance(Variable, list):
563 VariableNames = tuple(map( str, Variable ))
565 raise ValueError("The observer requires a name or a list of names of variables.")
567 # Association interne de l'observer à la variable
568 # -----------------------------------------------
569 for ename in VariableNames:
570 if ename not in self.__adaoObject["AlgorithmParameters"]:
571 raise ValueError("An observer requires to be removed on a variable named %s which does not exist."%ename)
573 return self.__adaoObject["AlgorithmParameters"].removeObserver( ename, ObjectFunction )
575 # -----------------------------------------------------------
577 def get(self, Concept=None, noDetails=True ):
578 "Recuperation d'une sortie du calcul"
579 if Concept is not None:
581 self.__case.register("get", dir(), locals(), Concept) # Break pickle in Python 2
584 if Concept in self.__StoredInputs:
585 return self.__StoredInputs[Concept]
587 elif self.__adaoObject["AlgorithmParameters"] is not None and Concept == "AlgorithmParameters":
588 return self.__adaoObject["AlgorithmParameters"].get()
590 elif self.__adaoObject["AlgorithmParameters"] is not None and Concept in self.__adaoObject["AlgorithmParameters"]:
591 return self.__adaoObject["AlgorithmParameters"].get( Concept )
593 elif Concept == "AlgorithmRequiredParameters" and self.__adaoObject["AlgorithmParameters"] is not None:
594 return self.__adaoObject["AlgorithmParameters"].getAlgorithmRequiredParameters(noDetails)
597 raise ValueError("The requested key \"%s\" does not exists as an input or a stored variable."%Concept)
600 allvariables.update( {"AlgorithmParameters":self.__adaoObject["AlgorithmParameters"].get()} )
601 # allvariables.update( self.__adaoObject["AlgorithmParameters"].get() )
602 allvariables.update( self.__StoredInputs )
603 allvariables.pop('Observer', None)
606 # -----------------------------------------------------------
608 def get_available_variables(self):
610 Renvoie les variables potentiellement utilisables pour l'étude,
611 initialement stockées comme données d'entrées ou dans les algorithmes,
612 identifiés par les chaînes de caractères. L'algorithme doit avoir été
613 préalablement choisi sinon la méthode renvoie "None".
615 if len(list(self.__adaoObject["AlgorithmParameters"].keys())) == 0 and \
616 len(list(self.__StoredInputs.keys())) == 0:
620 if len(list(self.__adaoObject["AlgorithmParameters"].keys())) > 0:
621 variables.extend(list(self.__adaoObject["AlgorithmParameters"].keys()))
622 if len(list(self.__StoredInputs.keys())) > 0:
623 variables.extend( list(self.__StoredInputs.keys()) )
624 variables.remove('Observer')
628 def get_available_algorithms(self):
630 Renvoie la liste des algorithmes potentiellement utilisables, identifiés
631 par les chaînes de caractères.
634 for directory in sys.path:
635 trypath = os.path.join(directory,"daAlgorithms")
636 if os.path.isdir(trypath):
637 for fname in os.listdir(trypath):
638 if os.path.isfile(os.path.join(trypath,fname)):
639 root, ext = os.path.splitext(fname)
640 if ext != ".py": continue
641 fc = open(os.path.join(trypath,fname)).read()
642 iselal = bool("class ElementaryAlgorithm" in fc)
643 if iselal and ext == '.py' and root != '__init__':
648 def get_algorithms_main_path(self):
650 Renvoie le chemin pour le répertoire principal contenant les algorithmes
654 def add_algorithms_path(self, Path=None):
656 Ajoute au chemin de recherche des algorithmes un répertoire dans lequel
657 se trouve un sous-répertoire "daAlgorithms"
659 if not os.path.isdir(Path):
660 raise ValueError("The given "+Path+" argument must exist as a directory")
661 if not os.path.isdir(os.path.join(Path,"daAlgorithms")):
662 raise ValueError("The given \""+Path+"\" argument must contain a subdirectory named \"daAlgorithms\"")
663 if not os.path.isfile(os.path.join(Path,"daAlgorithms","__init__.py")):
664 raise ValueError("The given \""+Path+"/daAlgorithms\" path must contain a file named \"__init__.py\"")
665 sys.path.insert(0, os.path.abspath(Path))
666 sys.path = PlatformInfo.uniq( sys.path ) # Conserve en unique exemplaire chaque chemin
669 # -----------------------------------------------------------
671 def execute(self, Executor=None, SaveCaseInFile=None, nextStep=False):
672 "Lancement du calcul"
673 self.__case.register("execute",dir(),locals(),None,True)
674 self.updateAlgorithmParameters(Parameters={"nextStep":bool(nextStep)})
675 if not nextStep: Operator.CM.clearCache()
677 if Executor == "YACS": self.__executeYACSScheme( SaveCaseInFile )
678 else: self.__executePythonScheme( SaveCaseInFile )
679 except Exception as e:
680 if isinstance(e, SyntaxError): msg = "at %s: %s"%(e.offset, e.text)
682 raise ValueError(("during execution, the following error occurs:\n"+\
683 "\n%s %s\n\nSee also the potential messages, "+\
684 "which can show the origin of the above error, "+\
685 "in the launching terminal.\n")%(str(e),msg))
688 def __executePythonScheme(self, FileName=None):
689 "Lancement du calcul"
690 self.__case.register("executePythonScheme", dir(), locals())
691 if FileName is not None:
692 self.dump( FileName, "TUI")
693 self.__adaoObject["AlgorithmParameters"].executePythonScheme( self.__adaoObject )
696 def __executeYACSScheme(self, FileName=None):
697 "Lancement du calcul"
698 self.__case.register("executeYACSScheme", dir(), locals())
699 self.dump( FileName, "YACS")
700 self.__adaoObject["AlgorithmParameters"].executeYACSScheme( FileName )
703 # -----------------------------------------------------------
705 def dump(self, FileName=None, Formater="TUI"):
706 "Restitution normalisée des commandes"
707 __Upa = "\n".join(self.__PostAnalysis)
708 return self.__case.dump(FileName, Formater, __Upa)
710 def load(self, FileName=None, Content=None, Object=None, Formater="TUI"):
711 "Chargement normalisé des commandes"
712 __commands = self.__case.load(FileName, Content, Object, Formater)
713 from numpy import array, matrix
714 for __command in __commands:
715 if __command.find("set")>-1 and __command.find("set_")<0:
716 exec("self."+__command)
718 self.__PostAnalysis.append(__command)
722 FileNameFrom=None, ContentFrom=None, ObjectFrom=None, FormaterFrom="TUI",
723 FileNameTo=None, FormaterTo="TUI",
725 "Conversion normalisée des commandes"
727 FileName=FileNameFrom, Content=ContentFrom, Object=ObjectFrom, Formater=FormaterFrom
729 FileName=FileNameTo, Formater=FormaterTo
733 "Effacement du contenu du cas en cours"
734 self.__init__(self.__name)
736 # -----------------------------------------------------------
738 def __with_directory(self, __filename=None):
739 if os.path.exists(str(__filename)):
740 __fullpath = __filename
741 elif os.path.exists(os.path.join(str(self.__directory), str(__filename))):
742 __fullpath = os.path.join(self.__directory, str(__filename))
744 __fullpath = __filename
748 "Clarifie la visibilité des méthodes"
749 return ['set', 'get', 'execute', 'dump', 'load', '__doc__', '__init__', '__module__']
751 def prepare_to_pickle(self):
752 "Retire les variables non pickelisables, avec recopie efficace"
753 if self.__adaoObject['AlgorithmParameters'] is not None:
754 for k in self.__adaoObject['AlgorithmParameters'].keys():
755 if k == "Algorithm": continue
756 if k in self.__StoredInputs:
757 raise ValueError("The key \"%s\" to be transfered for pickling will overwrite an existing one."%(k,))
758 if self.__adaoObject['AlgorithmParameters'].hasObserver( k ):
759 self.__adaoObject['AlgorithmParameters'].removeObserver( k, "", True )
760 self.__StoredInputs[k] = self.__adaoObject['AlgorithmParameters'].pop(k, None)
761 if sys.version_info[0] == 2:
762 del self.__adaoObject # Because it breaks pickle in Python 2. Not required for Python 3
763 del self.__case # Because it breaks pickle in Python 2. Not required for Python 3
764 if sys.version_info.major < 3:
767 return self.__StoredInputs
769 # ==============================================================================
770 if __name__ == "__main__":
771 print('\n AUTODIAGNOSTIC\n')