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)
596 elif Concept == "AlgorithmRequiredInputs" and self.__adaoObject["AlgorithmParameters"] is not None:
597 return self.__adaoObject["AlgorithmParameters"].getAlgorithmInputArguments()
599 elif Concept == "AlgorithmAttributes" and self.__adaoObject["AlgorithmParameters"] is not None:
600 return self.__adaoObject["AlgorithmParameters"].getAlgorithmAttributes()
603 raise ValueError("The requested key \"%s\" does not exists as an input or a stored variable."%Concept)
606 allvariables.update( {"AlgorithmParameters":self.__adaoObject["AlgorithmParameters"].get()} )
607 # allvariables.update( self.__adaoObject["AlgorithmParameters"].get() )
608 allvariables.update( self.__StoredInputs )
609 allvariables.pop('Observer', None)
612 # -----------------------------------------------------------
614 def get_available_variables(self):
616 Renvoie les variables potentiellement utilisables pour l'étude,
617 initialement stockées comme données d'entrées ou dans les algorithmes,
618 identifiés par les chaînes de caractères. L'algorithme doit avoir été
619 préalablement choisi sinon la méthode renvoie "None".
621 if len(list(self.__adaoObject["AlgorithmParameters"].keys())) == 0 and \
622 len(list(self.__StoredInputs.keys())) == 0:
626 if len(list(self.__adaoObject["AlgorithmParameters"].keys())) > 0:
627 variables.extend(list(self.__adaoObject["AlgorithmParameters"].keys()))
628 if len(list(self.__StoredInputs.keys())) > 0:
629 variables.extend( list(self.__StoredInputs.keys()) )
630 variables.remove('Observer')
634 def get_available_algorithms(self):
636 Renvoie la liste des algorithmes potentiellement utilisables, identifiés
637 par les chaînes de caractères.
640 for directory in sys.path:
641 trypath = os.path.join(directory,"daAlgorithms")
642 if os.path.isdir(trypath):
643 for fname in os.listdir(trypath):
644 if os.path.isfile(os.path.join(trypath,fname)):
645 root, ext = os.path.splitext(fname)
646 if ext != ".py": continue
647 fc = open(os.path.join(trypath,fname)).read()
648 iselal = bool("class ElementaryAlgorithm" in fc)
649 if iselal and ext == '.py' and root != '__init__':
654 def get_algorithms_main_path(self):
656 Renvoie le chemin pour le répertoire principal contenant les algorithmes
660 def add_algorithms_path(self, Path=None):
662 Ajoute au chemin de recherche des algorithmes un répertoire dans lequel
663 se trouve un sous-répertoire "daAlgorithms"
665 if not os.path.isdir(Path):
666 raise ValueError("The given "+Path+" argument must exist as a directory")
667 if not os.path.isdir(os.path.join(Path,"daAlgorithms")):
668 raise ValueError("The given \""+Path+"\" argument must contain a subdirectory named \"daAlgorithms\"")
669 if not os.path.isfile(os.path.join(Path,"daAlgorithms","__init__.py")):
670 raise ValueError("The given \""+Path+"/daAlgorithms\" path must contain a file named \"__init__.py\"")
671 sys.path.insert(0, os.path.abspath(Path))
672 sys.path = PlatformInfo.uniq( sys.path ) # Conserve en unique exemplaire chaque chemin
675 # -----------------------------------------------------------
677 def execute(self, Executor=None, SaveCaseInFile=None, nextStep=False):
678 "Lancement du calcul"
679 self.__case.register("execute",dir(),locals(),None,True)
680 self.updateAlgorithmParameters(Parameters={"nextStep":bool(nextStep)})
681 if not nextStep: Operator.CM.clearCache()
683 if Executor == "YACS": self.__executeYACSScheme( SaveCaseInFile )
684 else: self.__executePythonScheme( SaveCaseInFile )
685 except Exception as e:
686 if isinstance(e, SyntaxError): msg = "at %s: %s"%(e.offset, e.text)
688 raise ValueError(("during execution, the following error occurs:\n"+\
689 "\n%s %s\n\nSee also the potential messages, "+\
690 "which can show the origin of the above error, "+\
691 "in the launching terminal.\n")%(str(e),msg))
694 def __executePythonScheme(self, FileName=None):
695 "Lancement du calcul"
696 self.__case.register("executePythonScheme", dir(), locals())
697 if FileName is not None:
698 self.dump( FileName, "TUI")
699 self.__adaoObject["AlgorithmParameters"].executePythonScheme( self.__adaoObject )
702 def __executeYACSScheme(self, FileName=None):
703 "Lancement du calcul"
704 self.__case.register("executeYACSScheme", dir(), locals())
705 self.dump( FileName, "YACS")
706 self.__adaoObject["AlgorithmParameters"].executeYACSScheme( FileName )
709 # -----------------------------------------------------------
711 def dump(self, FileName=None, Formater="TUI"):
712 "Restitution normalisée des commandes"
713 __Upa = "\n".join(self.__PostAnalysis)
714 return self.__case.dump(FileName, Formater, __Upa)
716 def load(self, FileName=None, Content=None, Object=None, Formater="TUI"):
717 "Chargement normalisé des commandes"
718 __commands = self.__case.load(FileName, Content, Object, Formater)
719 from numpy import array, matrix
720 for __command in __commands:
721 if __command.find("set")>-1 and __command.find("set_")<0:
722 exec("self."+__command)
724 self.__PostAnalysis.append(__command)
728 FileNameFrom=None, ContentFrom=None, ObjectFrom=None, FormaterFrom="TUI",
729 FileNameTo=None, FormaterTo="TUI",
731 "Conversion normalisée des commandes"
733 FileName=FileNameFrom, Content=ContentFrom, Object=ObjectFrom, Formater=FormaterFrom
735 FileName=FileNameTo, Formater=FormaterTo
739 "Effacement du contenu du cas en cours"
740 self.__init__(self.__name)
742 # -----------------------------------------------------------
744 def __with_directory(self, __filename=None):
745 if os.path.exists(str(__filename)):
746 __fullpath = __filename
747 elif os.path.exists(os.path.join(str(self.__directory), str(__filename))):
748 __fullpath = os.path.join(self.__directory, str(__filename))
750 __fullpath = __filename
754 "Clarifie la visibilité des méthodes"
755 return ['set', 'get', 'execute', 'dump', 'load', '__doc__', '__init__', '__module__']
757 def prepare_to_pickle(self):
758 "Retire les variables non pickelisables, avec recopie efficace"
759 if self.__adaoObject['AlgorithmParameters'] is not None:
760 for k in self.__adaoObject['AlgorithmParameters'].keys():
761 if k == "Algorithm": continue
762 if k in self.__StoredInputs:
763 raise ValueError("The key \"%s\" to be transfered for pickling will overwrite an existing one."%(k,))
764 if self.__adaoObject['AlgorithmParameters'].hasObserver( k ):
765 self.__adaoObject['AlgorithmParameters'].removeObserver( k, "", True )
766 self.__StoredInputs[k] = self.__adaoObject['AlgorithmParameters'].pop(k, None)
767 if sys.version_info[0] == 2:
768 del self.__adaoObject # Because it breaks pickle in Python 2. Not required for Python 3
769 del self.__case # Because it breaks pickle in Python 2. Not required for Python 3
770 if sys.version_info.major < 3:
773 return self.__StoredInputs
775 # ==============================================================================
776 if __name__ == "__main__":
777 print('\n AUTODIAGNOSTIC\n')