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,
354 "Definition d'un concept de calcul"
355 Concept = "ObservationOperator"
356 self.__case.register("set"+Concept, dir(), locals())
357 self.__adaoObject[Concept] = FullOperator(
360 asOneFunction = OneFunction,
361 asThreeFunctions = ThreeFunctions,
362 asScript = self.__with_directory(Script),
364 appliedInX = AppliedInXb,
367 toBeChecked = Checked,
370 self.__StoredInputs[Concept] = self.__adaoObject[Concept].getO()
373 def setEvolutionModel(self,
376 ThreeFunctions = None,
383 "Definition d'un concept de calcul"
384 Concept = "EvolutionModel"
385 self.__case.register("set"+Concept, dir(), locals())
386 self.__adaoObject[Concept] = FullOperator(
389 asOneFunction = OneFunction,
390 asThreeFunctions = ThreeFunctions,
391 asScript = self.__with_directory(Script),
395 scheduledBy = Scheduler,
396 toBeChecked = Checked,
399 self.__StoredInputs[Concept] = self.__adaoObject[Concept].getO()
402 def setControlModel(self,
405 ThreeFunctions = None,
412 "Definition d'un concept de calcul"
413 Concept = "ControlModel"
414 self.__case.register("set"+Concept, dir(), locals())
415 self.__adaoObject[Concept] = FullOperator(
418 asOneFunction = OneFunction,
419 asThreeFunctions = ThreeFunctions,
420 asScript = self.__with_directory(Script),
424 scheduledBy = Scheduler,
425 toBeChecked = Checked,
428 self.__StoredInputs[Concept] = self.__adaoObject[Concept].getO()
431 def setName(self, String=None):
432 "Definition d'un concept de calcul"
433 self.__case.register("setName",dir(),locals())
434 if String is not None:
435 self.__name = str(String)
438 self.__StoredInputs["Name"] = self.__name
440 def setDirectory(self, String=None):
441 "Definition d'un concept de calcul"
442 self.__case.register("setDirectory",dir(),locals())
443 if os.path.isdir(os.path.abspath(str(String))):
444 self.__directory = os.path.abspath(str(String))
446 self.__directory = None
447 self.__StoredInputs["Directory"] = self.__directory
449 def setDebug(self, __level = 10):
450 "NOTSET=0 < DEBUG=10 < INFO=20 < WARNING=30 < ERROR=40 < CRITICAL=50"
451 self.__case.register("setDebug",dir(),locals())
452 log = logging.getLogger()
453 log.setLevel( __level )
454 self.__StoredInputs["Debug"] = __level
455 self.__StoredInputs["NoDebug"] = False
458 def setNoDebug(self):
459 "NOTSET=0 < DEBUG=10 < INFO=20 < WARNING=30 < ERROR=40 < CRITICAL=50"
460 self.__case.register("setNoDebug",dir(),locals())
461 log = logging.getLogger()
462 log.setLevel( logging.WARNING )
463 self.__StoredInputs["Debug"] = logging.WARNING
464 self.__StoredInputs["NoDebug"] = True
467 def setAlgorithmParameters(self,
471 "Definition d'un concept de calcul"
472 Concept = "AlgorithmParameters"
473 self.__case.register("set"+Concept, dir(), locals())
474 self.__adaoObject[Concept] = AlgorithmAndParameters(
476 asAlgorithm = Algorithm,
478 asScript = self.__with_directory(Script),
482 def updateAlgorithmParameters(self,
485 "Mise a jour d'un concept de calcul"
486 if "AlgorithmParameters" not in self.__adaoObject:
487 raise ValueError("No algorithm registred, ask for one before updating parameters")
488 self.__adaoObject["AlgorithmParameters"].updateParameters(
490 asScript = self.__with_directory(Script),
494 def setRegulationParameters(self,
498 "Definition d'un concept de calcul"
499 Concept = "RegulationParameters"
500 self.__case.register("set"+Concept, dir(), locals())
501 self.__adaoObject[Concept] = RegulationAndParameters(
503 asAlgorithm = Algorithm,
505 asScript = self.__with_directory(Script),
509 def setObserver(self,
515 ObjectFunction = None,
517 "Definition d'un concept de calcul"
519 self.__case.register("set"+Concept, dir(), locals())
520 self.__adaoObject[Concept].append( DataObserver(
522 onVariable = Variable,
523 asTemplate = Template,
525 asScript = self.__with_directory(Script),
526 asObsObject = ObjectFunction,
528 scheduledBy = Scheduler,
529 withAlgo = self.__adaoObject["AlgorithmParameters"]
533 def removeObserver(self,
535 ObjectFunction = None,
537 "Permet de retirer un observer à une ou des variable nommée"
538 if "AlgorithmParameters" not in self.__adaoObject:
539 raise ValueError("No algorithm registred, ask for one before removing observers")
541 # Vérification du nom de variable et typage
542 # -----------------------------------------
543 if isinstance(Variable, str):
544 VariableNames = (Variable,)
545 elif isinstance(Variable, list):
546 VariableNames = tuple(map( str, Variable ))
548 raise ValueError("The observer requires a name or a list of names of variables.")
550 # Association interne de l'observer à la variable
551 # -----------------------------------------------
552 for ename in VariableNames:
553 if ename not in self.__adaoObject["AlgorithmParameters"]:
554 raise ValueError("An observer requires to be removed on a variable named %s which does not exist."%ename)
556 return self.__adaoObject["AlgorithmParameters"].removeObserver( ename, ObjectFunction )
558 # -----------------------------------------------------------
560 def get(self, Concept=None, noDetails=True ):
561 "Recuperation d'une sortie du calcul"
562 if Concept is not None:
564 self.__case.register("get", dir(), locals(), Concept) # Break pickle in Python 2
567 if Concept in self.__StoredInputs:
568 return self.__StoredInputs[Concept]
570 elif self.__adaoObject["AlgorithmParameters"] is not None and Concept == "AlgorithmParameters":
571 return self.__adaoObject["AlgorithmParameters"].get()
573 elif self.__adaoObject["AlgorithmParameters"] is not None and Concept in self.__adaoObject["AlgorithmParameters"]:
574 return self.__adaoObject["AlgorithmParameters"].get( Concept )
576 elif Concept == "AlgorithmRequiredParameters" and self.__adaoObject["AlgorithmParameters"] is not None:
577 return self.__adaoObject["AlgorithmParameters"].getAlgorithmRequiredParameters(noDetails)
580 raise ValueError("The requested key \"%s\" does not exists as an input or a stored variable."%Concept)
583 allvariables.update( {"AlgorithmParameters":self.__adaoObject["AlgorithmParameters"].get()} )
584 # allvariables.update( self.__adaoObject["AlgorithmParameters"].get() )
585 allvariables.update( self.__StoredInputs )
586 allvariables.pop('Observer', None)
589 # -----------------------------------------------------------
591 def get_available_variables(self):
593 Renvoie les variables potentiellement utilisables pour l'étude,
594 initialement stockées comme données d'entrées ou dans les algorithmes,
595 identifiés par les chaînes de caractères. L'algorithme doit avoir été
596 préalablement choisi sinon la méthode renvoie "None".
598 if len(list(self.__adaoObject["AlgorithmParameters"].keys())) == 0 and \
599 len(list(self.__StoredInputs.keys())) == 0:
603 if len(list(self.__adaoObject["AlgorithmParameters"].keys())) > 0:
604 variables.extend(list(self.__adaoObject["AlgorithmParameters"].keys()))
605 if len(list(self.__StoredInputs.keys())) > 0:
606 variables.extend( list(self.__StoredInputs.keys()) )
607 variables.remove('Observer')
611 def get_available_algorithms(self):
613 Renvoie la liste des algorithmes potentiellement utilisables, identifiés
614 par les chaînes de caractères.
617 for directory in sys.path:
618 trypath = os.path.join(directory,"daAlgorithms")
619 if os.path.isdir(trypath):
620 for fname in os.listdir(trypath):
621 if os.path.isfile(os.path.join(trypath,fname)):
622 fc = open(os.path.join(trypath,fname)).read()
623 iselal = bool("class ElementaryAlgorithm" in fc)
624 root, ext = os.path.splitext(fname)
625 if iselal and ext == '.py' and root != '__init__':
630 def get_algorithms_main_path(self):
632 Renvoie le chemin pour le répertoire principal contenant les algorithmes
636 def add_algorithms_path(self, Path=None):
638 Ajoute au chemin de recherche des algorithmes un répertoire dans lequel
639 se trouve un sous-répertoire "daAlgorithms"
641 if not os.path.isdir(Path):
642 raise ValueError("The given "+Path+" argument must exist as a directory")
643 if not os.path.isdir(os.path.join(Path,"daAlgorithms")):
644 raise ValueError("The given \""+Path+"\" argument must contain a subdirectory named \"daAlgorithms\"")
645 if not os.path.isfile(os.path.join(Path,"daAlgorithms","__init__.py")):
646 raise ValueError("The given \""+Path+"/daAlgorithms\" path must contain a file named \"__init__.py\"")
647 sys.path.insert(0, os.path.abspath(Path))
648 sys.path = PlatformInfo.uniq( sys.path ) # Conserve en unique exemplaire chaque chemin
651 # -----------------------------------------------------------
653 def execute(self, Executor=None, SaveCaseInFile=None):
654 "Lancement du calcul"
655 self.__case.register("execute",dir(),locals(),None,True)
656 Operator.CM.clearCache()
658 if Executor == "YACS": self.__executeYACSScheme( SaveCaseInFile )
659 else: self.__executePythonScheme( SaveCaseInFile )
660 except Exception as e:
661 if isinstance(e, SyntaxError): msg = "at %s: %s"%(e.offset, e.text)
663 raise ValueError(("during execution, the following error occurs:\n"+\
664 "\n%s %s\n\nSee also the potential messages, "+\
665 "which can show the origin of the above error, "+\
666 "in the launching terminal.\n")%(str(e),msg))
669 def __executePythonScheme(self, FileName=None):
670 "Lancement du calcul"
671 self.__case.register("executePythonScheme", dir(), locals())
672 if FileName is not None:
673 self.dump( FileName, "TUI")
674 self.__adaoObject["AlgorithmParameters"].executePythonScheme( self.__adaoObject )
677 def __executeYACSScheme(self, FileName=None):
678 "Lancement du calcul"
679 self.__case.register("executeYACSScheme", dir(), locals())
680 self.dump( FileName, "YACS")
681 self.__adaoObject["AlgorithmParameters"].executeYACSScheme( FileName )
684 # -----------------------------------------------------------
686 def dump(self, FileName=None, Formater="TUI"):
687 "Restitution normalisée des commandes"
688 __Upa = "\n".join(self.__PostAnalysis)
689 return self.__case.dump(FileName, Formater, __Upa)
691 def load(self, FileName=None, Content=None, Object=None, Formater="TUI"):
692 "Chargement normalisé des commandes"
693 __commands = self.__case.load(FileName, Content, Object, Formater)
694 from numpy import array, matrix
695 for __command in __commands:
696 if __command.find("set")>-1 and __command.find("set_")<0:
697 exec("self."+__command)
699 self.__PostAnalysis.append(__command)
703 FileNameFrom=None, ContentFrom=None, ObjectFrom=None, FormaterFrom="TUI",
704 FileNameTo=None, FormaterTo="TUI",
706 "Conversion normalisée des commandes"
708 FileName=FileNameFrom, Content=ContentFrom, Object=ObjectFrom, Formater=FormaterFrom
710 FileName=FileNameTo, Formater=FormaterTo
714 "Effacement du contenu du cas en cours"
715 self.__init__(self.__name)
717 # -----------------------------------------------------------
719 def __with_directory(self, __filename=None):
720 if os.path.exists(str(__filename)):
721 __fullpath = __filename
722 elif os.path.exists(os.path.join(str(self.__directory), str(__filename))):
723 __fullpath = os.path.join(self.__directory, str(__filename))
725 __fullpath = __filename
729 "Clarifie la visibilité des méthodes"
730 return ['set', 'get', 'execute', 'dump', 'load', '__doc__', '__init__', '__module__']
732 def prepare_to_pickle(self):
733 "Retire les variables non pickelisables, avec recopie efficace"
734 if self.__adaoObject['AlgorithmParameters'] is not None:
735 for k in self.__adaoObject['AlgorithmParameters'].keys():
736 if k == "Algorithm": continue
737 if k in self.__StoredInputs:
738 raise ValueError("the key \"%s\s to be transfered for pickling will overwrite an existing one.")
739 if self.__adaoObject['AlgorithmParameters'].hasObserver( k ):
740 self.__adaoObject['AlgorithmParameters'].removeObserver( k, "", True )
741 self.__StoredInputs[k] = self.__adaoObject['AlgorithmParameters'].pop(k, None)
742 if sys.version_info[0] == 2:
743 del self.__adaoObject # Because it breaks pickle in Python 2. Not required for Python 3
744 del self.__case # Because it breaks pickle in Python 2. Not required for Python 3
747 # ==============================================================================
748 if __name__ == "__main__":
749 print('\n AUTODIAGNOSTIC \n')