Salome HOME
Python 3 compatibility improvement (UTF-8) and data interface changes
[modules/adao.git] / src / daComposant / daCore / Aidsm.py
1 # -*- coding: utf-8 -*-
2 #
3 # Copyright (C) 2008-2017 EDF R&D
4 #
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.
9 #
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.
14 #
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
18 #
19 # See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com
20 #
21 # Author: Jean-Philippe Argaud, jean-philippe.argaud@edf.fr, EDF R&D
22
23 """
24     Normalized interface for ADAO scripting (generic API)
25 """
26 __author__ = "Jean-Philippe ARGAUD"
27 __all__ = ["Aidsm"]
28
29 import os, sys
30 from daCore import ExtendedLogging ; ExtendedLogging.ExtendedLogging() # A importer en premier
31 import logging
32 #
33 from daCore.BasicObjects import State, Covariance, FullOperator, Operator
34 from daCore.BasicObjects import AlgorithmAndParameters, DataObserver
35 from daCore.BasicObjects import DiagnosticAndParameters, ImportFromScript
36 from daCore.Templates    import ObserverTemplates
37 from daCore import PlatformInfo
38
39 # ==============================================================================
40 class Aidsm(object):
41     """ ADAO Internal Data Structure Model """
42     def __init__(self, name = ""):
43         self.__name = str(name)
44         self.__case = _CaseLogger(self.__name)
45         #
46         self.__adaoObject   = {}
47         self.__StoredInputs = {}
48         #
49         self.__Concepts = [
50             "AlgorithmParameters",
51             "Background",
52             "CheckingPoint",
53             "ControlInput",
54             "Observation",
55             "Controls",
56             "BackgroundError",
57             "ObservationError",
58             "EvolutionError",
59             "ObservationOperator",
60             "EvolutionModel",
61             "ControlModel",
62             "Debug",
63             "NoDebug",
64             "Observer",
65             ]
66         #
67         for ename in self.__Concepts:
68             self.__adaoObject[ename] = None
69         for ename in ("ObservationOperator", "EvolutionModel", "ControlModel", "Observer"):
70             self.__adaoObject[ename] = {}
71         for ename in ("Diagnostic", "Observer"):
72             self.__adaoObject[ename]   = []
73             self.__StoredInputs[ename] = []
74         #
75         # Récupère le chemin du répertoire parent et l'ajoute au path
76         # (Cela complète l'action de la classe PathManagement dans PlatformInfo,
77         # qui est activée dans Persistence)
78         self.__parent = os.path.abspath(os.path.join(os.path.dirname(__file__),".."))
79         sys.path.insert(0, self.__parent)
80         sys.path = PlatformInfo.uniq( sys.path ) # Conserve en unique exemplaire chaque chemin
81
82     def set(self,
83             Concept              = None, # Premier argument
84             Algorithm            = None,
85             AppliedInXb          = None,
86             AvoidRC              = True,
87             BaseType             = None,
88             Checked              = False,
89             Diagnostic           = None,
90             DiagonalSparseMatrix = None,
91             Identifier           = None,
92             Info                 = None,
93             Matrix               = None,
94             ObjectFunction       = None,
95             ObjectMatrix         = None,
96             OneFunction          = None,
97             Parameters           = None,
98             ScalarSparseMatrix   = None,
99             Scheduler            = None,
100             Script               = None,
101             Stored               = False,
102             String               = None,
103             Template             = None,
104             ThreeFunctions       = None,
105             Unit                 = None,
106             Variable             = None,
107             Vector               = None,
108             VectorSerie          = None,
109             ):
110         "Interface unique de definition de variables d'entrees par argument"
111         self.__case.register("set",dir(),locals(),None,True)
112         try:
113             if   Concept in ("Background", "CheckingPoint", "ControlInput", "Observation", "Controls"):
114                 commande = getattr(self,"set"+Concept)
115                 commande(Vector, VectorSerie, Script, Scheduler, Stored, Checked )
116             elif Concept in ("BackgroundError", "ObservationError", "EvolutionError"):
117                 commande = getattr(self,"set"+Concept)
118                 commande(Matrix, ScalarSparseMatrix, DiagonalSparseMatrix,
119                          ObjectMatrix, Script, Stored, Checked )
120             elif Concept == "AlgorithmParameters":
121                 self.setAlgorithmParameters( Algorithm, Parameters, Script )
122             elif Concept == "Debug":
123                 self.setDebug()
124             elif Concept == "NoDebug":
125                 self.setNoDebug()
126             elif Concept == "Observer":
127                 self.setObserver( Variable, Template, String, Script, ObjectFunction, Scheduler, Info )
128             elif Concept == "Diagnostic":
129                 self.setDiagnostic( Diagnostic, Identifier, Parameters, Script, Unit, BaseType )
130             elif Concept == "ObservationOperator":
131                 self.setObservationOperator(
132                     Matrix, OneFunction, ThreeFunctions, AppliedInXb,
133                     Parameters, Script, AvoidRC, Stored, Checked )
134             elif Concept in ("EvolutionModel", "ControlModel"):
135                 commande = getattr(self,"set"+Concept)
136                 commande(
137                     Matrix, OneFunction, ThreeFunctions,
138                     Parameters, Script, Scheduler, AvoidRC, Stored, Checked )
139
140             else:
141                 raise ValueError("the variable named '%s' is not allowed."%str(Concept))
142         except Exception as e:
143             if isinstance(e, SyntaxError): msg = "at %s: %s"%(e.offset, e.text)
144             else: msg = ""
145             raise ValueError("during settings, the following error occurs:\n\n%s %s\n\nSee also the potential messages, which can show the origin of the above error, in the launching terminal."%(str(e),msg))
146
147     # -----------------------------------------------------------
148
149     def setBackground(self,
150             Vector         = None,
151             VectorSerie    = None,
152             Script         = None,
153             Scheduler      = None,
154             Stored         = False,
155             Checked        = False):
156         "Definition d'un concept de calcul"
157         Concept = "Background"
158         self.__case.register("set"+Concept, dir(), locals())
159         self.__adaoObject[Concept] = State(
160             name               = Concept,
161             asVector           = Vector,
162             asPersistentVector = VectorSerie,
163             asScript           = Script,
164             scheduledBy        = Scheduler,
165             toBeChecked        = Checked,
166             )
167         if Stored:
168             self.__StoredInputs[Concept] = self.__adaoObject[Concept].getO()
169         return 0
170
171     def setCheckingPoint(self,
172             Vector         = None,
173             VectorSerie    = None,
174             Script         = None,
175             Scheduler      = None,
176             Stored         = False,
177             Checked        = False):
178         "Definition d'un concept de calcul"
179         Concept = "CheckingPoint"
180         self.__case.register("set"+Concept, dir(), locals())
181         self.__adaoObject[Concept] = State(
182             name               = Concept,
183             asVector           = Vector,
184             asPersistentVector = VectorSerie,
185             asScript           = Script,
186             scheduledBy        = Scheduler,
187             toBeChecked        = Checked,
188             )
189         if Stored:
190             self.__StoredInputs[Concept] = self.__adaoObject[Concept].getO()
191         return 0
192
193     def setControlInput(self,
194             Vector         = None,
195             VectorSerie    = None,
196             Script         = None,
197             Scheduler      = None,
198             Stored         = False,
199             Checked        = False):
200         "Definition d'un concept de calcul"
201         Concept = "ControlInput"
202         self.__case.register("set"+Concept, dir(), locals())
203         self.__adaoObject[Concept] = State(
204             name               = Concept,
205             asVector           = Vector,
206             asPersistentVector = VectorSerie,
207             asScript           = Script,
208             scheduledBy        = Scheduler,
209             toBeChecked        = Checked,
210             )
211         if Stored:
212             self.__StoredInputs[Concept] = self.__adaoObject[Concept].getO()
213         return 0
214
215     def setObservation(self,
216             Vector         = None,
217             VectorSerie    = None,
218             Script         = None,
219             Scheduler      = None,
220             Stored         = False,
221             Checked        = False):
222         "Definition d'un concept de calcul"
223         Concept = "Observation"
224         self.__case.register("set"+Concept, dir(), locals())
225         self.__adaoObject[Concept] = State(
226             name               = Concept,
227             asVector           = Vector,
228             asPersistentVector = VectorSerie,
229             asScript           = Script,
230             scheduledBy        = Scheduler,
231             toBeChecked        = Checked,
232             )
233         if Stored:
234             self.__StoredInputs[Concept] = self.__adaoObject[Concept].getO()
235         return 0
236
237     def setControls(self,
238             Vector         = (), # Valeur par defaut pour un vecteur vide
239             VectorSerie    = None,
240             Script         = None,
241             Scheduler      = None,
242             Stored         = False,
243             Checked        = False):
244         "Definition d'un concept de calcul"
245         Concept = "Controls"
246         self.__case.register("set"+Concept, dir(), locals())
247         self.__adaoObject[Concept] = State(
248             name               = Concept,
249             asVector           = Vector,
250             asPersistentVector = VectorSerie,
251             asScript           = Script,
252             scheduledBy        = Scheduler,
253             toBeChecked        = Checked,
254             )
255         if Stored:
256             self.__StoredInputs[Concept] = self.__adaoObject[Concept].getO()
257         return 0
258
259     def setBackgroundError(self,
260             Matrix               = None,
261             ScalarSparseMatrix   = None,
262             DiagonalSparseMatrix = None,
263             ObjectMatrix         = None,
264             Script               = None,
265             Stored               = False,
266             Checked              = False):
267         "Definition d'un concept de calcul"
268         Concept = "BackgroundError"
269         self.__case.register("set"+Concept, dir(), locals())
270         self.__adaoObject[Concept] = Covariance(
271             name          = Concept,
272             asCovariance  = Matrix,
273             asEyeByScalar = ScalarSparseMatrix,
274             asEyeByVector = DiagonalSparseMatrix,
275             asCovObject   = ObjectMatrix,
276             asScript      = Script,
277             toBeChecked   = Checked,
278             )
279         if Stored:
280             self.__StoredInputs[Concept] = self.__adaoObject[Concept].getO()
281         return 0
282
283     def setObservationError(self,
284             Matrix               = None,
285             ScalarSparseMatrix   = None,
286             DiagonalSparseMatrix = None,
287             ObjectMatrix         = None,
288             Script               = None,
289             Stored               = False,
290             Checked              = False):
291         "Definition d'un concept de calcul"
292         Concept = "ObservationError"
293         self.__case.register("set"+Concept, dir(), locals())
294         self.__adaoObject[Concept] = Covariance(
295             name          = Concept,
296             asCovariance  = Matrix,
297             asEyeByScalar = ScalarSparseMatrix,
298             asEyeByVector = DiagonalSparseMatrix,
299             asCovObject   = ObjectMatrix,
300             asScript      = Script,
301             toBeChecked   = Checked,
302             )
303         if Stored:
304             self.__StoredInputs[Concept] = self.__adaoObject[Concept].getO()
305         return 0
306
307     def setEvolutionError(self,
308             Matrix               = None,
309             ScalarSparseMatrix   = None,
310             DiagonalSparseMatrix = None,
311             ObjectMatrix         = None,
312             Script               = None,
313             Stored               = False,
314             Checked              = False):
315         "Definition d'un concept de calcul"
316         Concept = "EvolutionError"
317         self.__case.register("set"+Concept, dir(), locals())
318         self.__adaoObject[Concept] = Covariance(
319             name          = Concept,
320             asCovariance  = Matrix,
321             asEyeByScalar = ScalarSparseMatrix,
322             asEyeByVector = DiagonalSparseMatrix,
323             asCovObject   = ObjectMatrix,
324             asScript      = Script,
325             toBeChecked   = Checked,
326             )
327         if Stored:
328             self.__StoredInputs[Concept] = self.__adaoObject[Concept].getO()
329         return 0
330
331     def setObservationOperator(self,
332             Matrix         = None,
333             OneFunction    = None,
334             ThreeFunctions = None,
335             AppliedInXb    = None,
336             Parameters     = None,
337             Script         = None,
338             AvoidRC        = True,
339             Stored         = False,
340             Checked        = False):
341         "Definition d'un concept de calcul"
342         Concept = "ObservationOperator"
343         self.__case.register("set"+Concept, dir(), locals())
344         self.__adaoObject[Concept] = FullOperator(
345             name             = Concept,
346             asMatrix         = Matrix,
347             asOneFunction    = OneFunction,
348             asThreeFunctions = ThreeFunctions,
349             asScript         = Script,
350             asDict           = Parameters,
351             appliedInX       = AppliedInXb,
352             avoidRC          = AvoidRC,
353             scheduledBy      = None,
354             toBeChecked      = Checked,
355             )
356         if Stored:
357             self.__StoredInputs[Concept] = self.__adaoObject[Concept].getO()
358         return 0
359
360     def setEvolutionModel(self,
361             Matrix         = None,
362             OneFunction    = None,
363             ThreeFunctions = None,
364             Parameters     = None,
365             Script         = None,
366             Scheduler      = None,
367             AvoidRC        = True,
368             Stored         = False,
369             Checked        = False):
370         "Definition d'un concept de calcul"
371         Concept = "EvolutionModel"
372         self.__case.register("set"+Concept, dir(), locals())
373         self.__adaoObject[Concept] = FullOperator(
374             name             = Concept,
375             asMatrix         = Matrix,
376             asOneFunction    = OneFunction,
377             asThreeFunctions = ThreeFunctions,
378             asScript         = Script,
379             asDict           = Parameters,
380             appliedInX       = None,
381             avoidRC          = AvoidRC,
382             scheduledBy      = Scheduler,
383             toBeChecked      = Checked,
384             )
385         if Stored:
386             self.__StoredInputs[Concept] = self.__adaoObject[Concept].getO()
387         return 0
388
389     def setControlModel(self,
390             Matrix         = None,
391             OneFunction    = None,
392             ThreeFunctions = None,
393             Parameters     = None,
394             Script         = None,
395             Scheduler      = None,
396             AvoidRC        = True,
397             Stored         = False,
398             Checked        = False):
399         "Definition d'un concept de calcul"
400         Concept = "ControlModel"
401         self.__case.register("set"+Concept, dir(), locals())
402         self.__adaoObject[Concept] = FullOperator(
403             name             = Concept,
404             asMatrix         = Matrix,
405             asOneFunction    = OneFunction,
406             asThreeFunctions = ThreeFunctions,
407             asScript         = Script,
408             asDict           = Parameters,
409             appliedInX       = None,
410             avoidRC          = AvoidRC,
411             scheduledBy      = Scheduler,
412             toBeChecked      = Checked,
413             )
414         if Stored:
415             self.__StoredInputs[Concept] = self.__adaoObject[Concept].getO()
416         return 0
417
418     def setDebug(self, level = 10):
419         "NOTSET=0 < DEBUG=10 < INFO=20 < WARNING=30 < ERROR=40 < CRITICAL=50"
420         self.__case.register("setDebug",dir(),locals())
421         log = logging.getLogger()
422         log.setLevel( level )
423         self.__StoredInputs["Debug"]   = level
424         self.__StoredInputs["NoDebug"] = False
425         return 0
426
427     def setNoDebug(self):
428         "NOTSET=0 < DEBUG=10 < INFO=20 < WARNING=30 < ERROR=40 < CRITICAL=50"
429         self.__case.register("setNoDebug",dir(),locals())
430         log = logging.getLogger()
431         log.setLevel( logging.WARNING )
432         self.__StoredInputs["Debug"]   = logging.WARNING
433         self.__StoredInputs["NoDebug"] = True
434         return 0
435
436     def setAlgorithmParameters(self,
437             Algorithm  = None,
438             Parameters = None,
439             Script     = None):
440         "Definition d'un concept de calcul"
441         Concept = "AlgorithmParameters"
442         self.__case.register("set"+Concept, dir(), locals())
443         self.__adaoObject[Concept] = AlgorithmAndParameters(
444             name          = Concept,
445             asAlgorithm   = Algorithm,
446             asDict        = Parameters,
447             asScript      = Script,
448             )
449         return 0
450
451     def updateAlgorithmParameters(self,
452             Parameters = None,
453             Script     = None):
454         "Mise a jour d'un concept de calcul"
455         if "AlgorithmParameters" not in self.__adaoObject:
456             raise ValueError("No algorithm registred, ask for one before updating parameters")
457         self.__adaoObject["AlgorithmParameters"].updateParameters(
458             asDict        = Parameters,
459             asScript      = Script,
460             )
461         return 0
462
463     def setObserver(self,
464             Variable       = None,
465             Template       = None,
466             String         = None,
467             Script         = None,
468             ObjectFunction = None,
469             Scheduler      = None,
470             Info           = None):
471         "Definition d'un concept de calcul"
472         Concept = "Observer"
473         self.__case.register("set"+Concept, dir(), locals())
474         self.__adaoObject[Concept].append( DataObserver(
475             name        = Concept,
476             onVariable  = Variable,
477             asTemplate  = Template,
478             asString    = String,
479             asScript    = Script,
480             asObsObject = ObjectFunction,
481             withInfo    = Info,
482             scheduledBy = Scheduler,
483             withAlgo    = self.__adaoObject["AlgorithmParameters"]
484             ))
485         return 0
486
487     def removeObserver(self,
488             Variable       = None,
489             ObjectFunction = None,
490             ):
491         """
492         Permet de retirer un observer à une ou des variable nommée.
493         """
494         if "AlgorithmParameters" not in self.__adaoObject:
495             raise ValueError("No algorithm registred, ask for one before removing observers")
496         #
497         # Vérification du nom de variable et typage
498         # -----------------------------------------
499         if isinstance(Variable, str):
500             VariableNames = (Variable,)
501         elif isinstance(Variable, list):
502             VariableNames = tuple(map( str, Variable ))
503         else:
504             raise ValueError("The observer requires a name or a list of names of variables.")
505         #
506         # Association interne de l'observer à la variable
507         # -----------------------------------------------
508         for ename in VariableNames:
509             if ename not in self.__adaoObject["AlgorithmParameters"]:
510                 raise ValueError("An observer requires to be removed on a variable named %s which does not exist."%ename)
511             else:
512                 return self.__adaoObject["AlgorithmParameters"].removeObserver( ename, ObjectFunction )
513
514     # -----------------------------------------------------------
515
516     def setDiagnostic(self,
517             Diagnostic = None,
518             Identifier = None,
519             Parameters = None,
520             Script     = None,
521             Unit       = None,
522             BaseType   = None):
523         "Definition d'un concept de calcul"
524         Concept = "Diagnostic"
525         self.__case.register("set"+Concept, dir(), locals())
526         self.__adaoObject[Concept].append( DiagnosticAndParameters(
527                  name               = Concept,
528                  asDiagnostic       = Diagnostic,
529                  asIdentifier       = Identifier,
530                  asDict             = Parameters,
531                  asScript           = Script,
532                  asUnit             = Unit,
533                  asBaseType         = BaseType,
534                  asExistingDiags    = self.__StoredInputs[Concept],
535                 ))
536         self.__StoredInputs[Concept].append(str(Identifier))
537         return 0
538
539     def get(self, Concept=None, noDetails=True ):
540         "Recuperation d'une sortie du calcul"
541         """
542         Permet d'accéder aux informations stockées, diagnostics et résultats
543         disponibles après l'exécution du calcul. Attention, quand un diagnostic
544         porte le même nom qu'une variable stockée (paramètre ou résultat),
545         c'est la variable stockée qui est renvoyée, et le diagnostic est
546         inatteignable.
547         """
548         if Concept is not None:
549             try:
550                 self.__case.register("get", dir(), locals(), Concept) # Break pickle in Python 2
551             except:
552                 pass
553             if Concept in self.__StoredInputs:
554                 return self.__StoredInputs[Concept]
555                 #
556             elif self.__adaoObject["AlgorithmParameters"] is not None and Concept == "AlgorithmParameters":
557                 return self.__adaoObject["AlgorithmParameters"].get()
558                 #
559             elif self.__adaoObject["AlgorithmParameters"] is not None and Concept in self.__adaoObject["AlgorithmParameters"]:
560                 return self.__adaoObject["AlgorithmParameters"].get( Concept )
561                 #
562             elif Concept == "AlgorithmRequiredParameters" and self.__adaoObject["AlgorithmParameters"] is not None:
563                 return self.__adaoObject["AlgorithmParameters"].getAlgorithmRequiredParameters(noDetails)
564                 #
565             elif Concept in self.__StoredInputs["Diagnostic"]:
566                 indice = self.__StoredInputs["Diagnostic"].index(Concept)
567                 return self.__adaoObject["Diagnostic"][indice].get()
568                 #
569             else:
570                 raise ValueError("The requested key \"%s\" does not exists as an input, a diagnostic or a stored variable."%Concept)
571         else:
572             allvariables = {}
573             allvariables.update( {"AlgorithmParameters":self.__adaoObject["AlgorithmParameters"].get()} )
574             allvariables.update( self.__adaoObject["AlgorithmParameters"].get() )
575             allvariables.update( self.__StoredInputs )
576             allvariables.pop('Diagnostic', None)
577             allvariables.pop('Observer', None)
578             return allvariables
579
580     # -----------------------------------------------------------
581
582     def get_available_variables(self):
583         """
584         Renvoie les variables potentiellement utilisables pour l'étude,
585         initialement stockées comme données d'entrées ou dans les algorithmes,
586         identifiés par les chaînes de caractères. L'algorithme doit avoir été
587         préalablement choisi sinon la méthode renvoie "None".
588         """
589         if len(list(self.__adaoObject["AlgorithmParameters"].keys())) == 0 and \
590             len(list(self.__StoredInputs.keys())) == 0:
591             return None
592         else:
593             variables = []
594             if len(list(self.__adaoObject["AlgorithmParameters"].keys())) > 0:
595                 variables.extend(list(self.__adaoObject["AlgorithmParameters"].keys()))
596             if len(list(self.__StoredInputs.keys())) > 0:
597                 variables.extend( list(self.__StoredInputs.keys()) )
598             variables.remove('Diagnostic')
599             variables.remove('Observer')
600             variables.sort()
601             return variables
602
603     def get_available_algorithms(self):
604         """
605         Renvoie la liste des algorithmes potentiellement utilisables, identifiés
606         par les chaînes de caractères.
607         """
608         files = []
609         for directory in sys.path:
610             if os.path.isdir(os.path.join(directory,"daAlgorithms")):
611                 for fname in os.listdir(os.path.join(directory,"daAlgorithms")):
612                     root, ext = os.path.splitext(fname)
613                     if ext == '.py' and root != '__init__':
614                         files.append(root)
615         files.sort()
616         return files
617
618     def get_available_diagnostics(self):
619         """
620         Renvoie la liste des diagnostics potentiellement utilisables, identifiés
621         par les chaînes de caractères.
622         """
623         files = []
624         for directory in sys.path:
625             if os.path.isdir(os.path.join(directory,"daDiagnostics")):
626                 for fname in os.listdir(os.path.join(directory,"daDiagnostics")):
627                     root, ext = os.path.splitext(fname)
628                     if ext == '.py' and root != '__init__':
629                         files.append(root)
630         files.sort()
631         return files
632
633     # -----------------------------------------------------------
634
635     def get_algorithms_main_path(self):
636         """
637         Renvoie le chemin pour le répertoire principal contenant les algorithmes
638         dans un sous-répertoire "daAlgorithms"
639         """
640         return self.__parent
641
642     def add_algorithms_path(self, Path=None):
643         """
644         Ajoute au chemin de recherche des algorithmes un répertoire dans lequel
645         se trouve un sous-répertoire "daAlgorithms"
646
647         Remarque : si le chemin a déjà été ajouté pour les diagnostics, il n'est
648         pas indispensable de le rajouter ici.
649         """
650         if not os.path.isdir(Path):
651             raise ValueError("The given "+Path+" argument must exist as a directory")
652         if not os.path.isdir(os.path.join(Path,"daAlgorithms")):
653             raise ValueError("The given \""+Path+"\" argument must contain a subdirectory named \"daAlgorithms\"")
654         if not os.path.isfile(os.path.join(Path,"daAlgorithms","__init__.py")):
655             raise ValueError("The given \""+Path+"/daAlgorithms\" path must contain a file named \"__init__.py\"")
656         sys.path.insert(0, os.path.abspath(Path))
657         sys.path = PlatformInfo.uniq( sys.path ) # Conserve en unique exemplaire chaque chemin
658         return 0
659
660     def get_diagnostics_main_path(self):
661         """
662         Renvoie le chemin pour le répertoire principal contenant les diagnostics
663         dans un sous-répertoire "daDiagnostics"
664         """
665         return self.__parent
666
667     def add_diagnostics_path(self, Path=None):
668         """
669         Ajoute au chemin de recherche des algorithmes un répertoire dans lequel
670         se trouve un sous-répertoire "daDiagnostics"
671
672         Remarque : si le chemin a déjà été ajouté pour les algorithmes, il n'est
673         pas indispensable de le rajouter ici.
674         """
675         if not os.path.isdir(Path):
676             raise ValueError("The given "+Path+" argument must exist as a directory")
677         if not os.path.isdir(os.path.join(Path,"daDiagnostics")):
678             raise ValueError("The given \""+Path+"\" argument must contain a subdirectory named \"daDiagnostics\"")
679         if not os.path.isfile(os.path.join(Path,"daDiagnostics","__init__.py")):
680             raise ValueError("The given \""+Path+"/daDiagnostics\" path must contain a file named \"__init__.py\"")
681         sys.path.insert(0, os.path.abspath(Path))
682         sys.path = PlatformInfo.uniq( sys.path ) # Conserve en unique exemplaire chaque chemin
683         return 0
684
685     # -----------------------------------------------------------
686
687     def execute(self, Executor=None, FileName=None):
688         "Lancement du calcul"
689         self.__case.register("execute",dir(),locals(),None,True)
690         Operator.CM.clearCache()
691         #~ try:
692         if   Executor == "YACS": self.__executeYACSScheme( FileName )
693         else:                    self.__executePythonScheme()
694         #~ except Exception as e:
695             #~ if isinstance(e, SyntaxError): msg = "at %s: %s"%(e.offset, e.text)
696             #~ else: msg = ""
697             #~ raise ValueError("during execution, the following error occurs:\n\n%s %s\n\nSee also the potential messages, which can show the origin of the above error, in the launching terminal.\n"%(str(e),msg))
698         return 0
699
700     def __executePythonScheme(self, FileName=None):
701         "Lancement du calcul"
702         self.__case.register("executePythonScheme", dir(), locals())
703         if FileName is not None:
704             self.dump( FileName, "TUI")
705         self.__adaoObject["AlgorithmParameters"].executePythonScheme( self.__adaoObject )
706         return 0
707
708     def __executeYACSScheme(self, FileName=None):
709         "Lancement du calcul"
710         self.__case.register("executeYACSScheme", dir(), locals())
711         if FileName is not None:
712             self.dump( FileName, "DIC")
713         self.__adaoObject["AlgorithmParameters"].executeYACSScheme( FileName )
714         return 0
715
716     # -----------------------------------------------------------
717
718     def dump(self, FileName=None, Formater="TUI"):
719         "Récupération normalisée de la liste des commandes"
720         return self.__case.dump(FileName, Formater)
721
722     def __dir__(self):
723         "Clarifie la visibilité des méthodes"
724         return ['set', 'get', 'execute', '__doc__', '__init__', '__module__']
725
726     def prepare_to_pickle(self):
727         "Retire les variables non pickelisables, avec recopie efficace"
728         if self.__adaoObject['AlgorithmParameters'] is not None:
729             for k in self.__adaoObject['AlgorithmParameters'].keys():
730                 if k == "Algorithm": continue
731                 if k in self.__StoredInputs:
732                     raise ValueError("the key \"%s\s to be transfered for pickling will overwrite an existing one.")
733                 if self.__adaoObject['AlgorithmParameters'].hasObserver( k ):
734                     self.__adaoObject['AlgorithmParameters'].removeObserver( k, "", True )
735                 self.__StoredInputs[k] = self.__adaoObject['AlgorithmParameters'].pop(k, None)
736         del self.__adaoObject # Break pickle in Python 2
737         del self.__case       # Break pickle in Python 2
738         return 0
739
740 # ==============================================================================
741 class _CaseLogger(object):
742     """
743     Conservation des commandes de creation d'un cas
744     """
745     def __init__(self, __name="", __objname="case"):
746         self.__name     = str(__name)
747         self.__objname  = str(__objname)
748         self.__logSerie = []
749         self.__switchoff = False
750
751     def register(self, __command=None, __keys=None, __local=None, __pre=None, __switchoff=False):
752         "Enregistrement d'une commande individuelle"
753         if __command is not None and __keys is not None and __local is not None and not self.__switchoff:
754             if "self" in __keys: __keys.remove("self")
755             self.__logSerie.append( (str(__command), __keys, __local, __pre, __switchoff) )
756             if __switchoff:
757                 self.__switchoff = True
758         if not __switchoff:
759             self.__switchoff = False
760
761     def dump(self, __filename=None, __format="TUI"):
762         """
763         Récupération normalisée de la liste des commandes selon le Formater :
764         - TUI (API de référence)
765         - DIC (Transitoire, pour passer vers XML YACS)
766         - XML (Experimental. Structured AIDSM)
767         """
768         if   __format == "TUI":
769             self.__dumper = _TUIViewer(self.__name, self.__objname, self.__logSerie)
770             __text = self.__dumper.dump(__filename)
771         elif __format == "DIC":
772             self.__dumper = _DICViewer(self.__name, self.__objname, self.__logSerie)
773             __text = self.__dumper.dump(__filename)
774         elif __format == "XML":
775             self.__dumper = _XMLViewer(self.__name, self.__objname, self.__logSerie)
776             __text = self.__dumper.dump(__filename)
777         else:
778             raise ValueError("Dumping as \"%s\" is not available"%__format)
779         return __text
780
781 # ==============================================================================
782 class _GenericCaseViewer(object):
783     """
784     Etablissement des commandes de creation d'une vue
785     """
786     def __init__(self, __name="", __objname="case", __content=None):
787         "Initialisation et enregistrement de l'entete"
788         self._name     = str(__name)
789         self._objname  = str(__objname)
790         self._lineSerie = []
791         self._switchoff = False
792         self._numobservers = 2
793     def _addLine(self, line=""):
794         "Ajoute un enregistrement individuel"
795         self._lineSerie.append(line)
796     def _finalize(self):
797         "Enregistrement du final"
798         pass
799     def _append(self):
800         "Transformation d'une commande individuelle en un enregistrement"
801         raise NotImplementedError()
802     def dump(self, __filename=None):
803         "Restitution de la liste des commandes de creation d'un cas"
804         self._finalize()
805         __text = "\n".join(self._lineSerie)
806         if __filename is not None:
807             __file = os.path.abspath(__filename)
808             fid = open(__file,"w")
809             fid.write(__text)
810             fid.close()
811         return __text
812
813 class _TUIViewer(_GenericCaseViewer):
814     """
815     Etablissement des commandes de creation d'un cas TUI
816     """
817     def __init__(self, __name="", __objname="case", __content=None):
818         "Initialisation et enregistrement de l'entete"
819         _GenericCaseViewer.__init__(self, __name, __objname, __content)
820         self._addLine("#\n# Python script for ADAO TUI\n#")
821         self._addLine("from numpy import array, matrix")
822         self._addLine("import adaoBuilder")
823         self._addLine("%s = adaoBuilder.New('%s')"%(self._objname, self._name))
824         if __content is not None:
825             for command in __content:
826                 self._append(*command)
827     def _append(self, __command=None, __keys=None, __local=None, __pre=None, __switchoff=False):
828         "Transformation d'une commande individuelle en un enregistrement"
829         if __command is not None and __keys is not None and __local is not None:
830             __text  = ""
831             if __pre is not None:
832                 __text += "%s = "%__pre
833             __text += "%s.%s( "%(self._objname,str(__command))
834             if "self" in __keys: __keys.remove("self")
835             if __command not in ("set","get") and "Concept" in __keys: __keys.remove("Concept")
836             for k in __keys:
837                 __v = __local[k]
838                 if __v is None: continue
839                 if   k == "Checked" and not __v: continue
840                 if   k == "Stored"  and not __v: continue
841                 if   k == "AvoidRC" and __v: continue
842                 if   k == "noDetails": continue
843                 __text += "%s=%s, "%(k,repr(__v))
844             __text.rstrip(", ")
845             __text += ")"
846             self._addLine(__text)
847
848 class _DICViewer(_GenericCaseViewer):
849     """
850     Etablissement des commandes de creation d'un cas DIC
851     """
852     def __init__(self, __name="", __objname="case", __content=None):
853         "Initialisation et enregistrement de l'entete"
854         _GenericCaseViewer.__init__(self, __name, __objname, __content)
855         self._addLine("# -*- coding: utf-8 -*-")
856         self._addLine("#\n# Input for ADAO converter to YACS\n#")
857         self._addLine("from numpy import array, matrix")
858         self._addLine("#")
859         self._addLine("study_config = {}")
860         self._addLine("study_config['StudyType'] = 'ASSIMILATION_STUDY'")
861         self._addLine("study_config['Name'] = '%s'"%self._name)
862         self._addLine("observers = {}")
863         self._addLine("study_config['Observers'] = observers")
864         self._addLine("#")
865         self._addLine("inputvariables_config = {}")
866         self._addLine("inputvariables_config['Order'] =['adao_default']")
867         self._addLine("inputvariables_config['adao_default'] = -1")
868         self._addLine("study_config['InputVariables'] = inputvariables_config")
869         self._addLine("#")
870         self._addLine("outputvariables_config = {}")
871         self._addLine("outputvariables_config['Order'] = ['adao_default']")
872         self._addLine("outputvariables_config['adao_default'] = -1")
873         self._addLine("study_config['OutputVariables'] = outputvariables_config")
874         if __content is not None:
875             for command in __content:
876                 self._append(*command)
877     def _append(self, __command=None, __keys=None, __local=None, __pre=None, __switchoff=False):
878         "Transformation d'une commande individuelle en un enregistrement"
879         if __command == "set": __command = __local["Concept"]
880         else:                  __command = __command.replace("set", "", 1)
881         #
882         __text  = None
883         if __command in (None, 'execute', 'executePythonScheme', 'executeYACSScheme', 'get'):
884             return
885         elif __command in ['Debug', 'setDebug']:
886             __text  = "#\nstudy_config['Debug'] = '1'"
887         elif __command in ['NoDebug', 'setNoDebug']:
888             __text  = "#\nstudy_config['Debug'] = '0'"
889         elif __command in ['Observer', 'setObserver']:
890             __obs   = __local['Variable']
891             self._numobservers += 1
892             __text  = "#\n"
893             __text += "observers['%s'] = {}\n"%__obs
894             if __local['String'] is not None:
895                 __text += "observers['%s']['nodetype'] = '%s'\n"%(__obs, 'String')
896                 __text += "observers['%s']['String'] = \"\"\"%s\"\"\"\n"%(__obs, __local['String'])
897             if __local['Script'] is not None:
898                 __text += "observers['%s']['nodetype'] = '%s'\n"%(__obs, 'Script')
899                 __text += "observers['%s']['Script'] = \"%s\"\n"%(__obs, __local['Script'])
900             if __local['Template'] is not None:
901                 __text += "observers['%s']['nodetype'] = '%s'\n"%(__obs, 'String')
902                 __text += "observers['%s']['String'] = \"\"\"%s\"\"\"\n"%(__obs, ObserverTemplates[__local['Template']])
903             if __local['Info'] is not None:
904                 __text += "observers['%s']['info'] = \"\"\"%s\"\"\"\n"%(__obs, __local['Info'])
905             else:
906                 __text += "observers['%s']['info'] = \"\"\"%s\"\"\"\n"%(__obs, __obs)
907             __text += "observers['%s']['number'] = %s"%(__obs, self._numobservers)
908         elif __local is not None: # __keys is not None and
909             __text  = "#\n"
910             __text += "%s_config = {}\n"%__command
911             if 'self' in __local: __local.pop('self')
912             __to_be_removed = []
913             for __k,__v in __local.items():
914                 if __v is None: __to_be_removed.append(__k)
915             for __k in __to_be_removed:
916                     __local.pop(__k)
917             for __k,__v in __local.items():
918                 if __k == "Concept": continue
919                 if __k in ['ScalarSparseMatrix','DiagonalSparseMatrix','Matrix'] and 'Script' in __local: continue
920                 if __k == 'Algorithm':
921                     __text += "study_config['Algorithm'] = %s\n"%(repr(__v))
922                 elif __k == 'Script':
923                     __k = 'Vector'
924                     for __lk in ['ScalarSparseMatrix','DiagonalSparseMatrix','Matrix']:
925                         if __lk in __local and __local[__lk]: __k = __lk
926                     if __command == "AlgorithmParameters": __k = "Dict"
927                     __text += "%s_config['Type'] = '%s'\n"%(__command,__k)
928                     __text += "%s_config['From'] = '%s'\n"%(__command,'Script')
929                     __text += "%s_config['Data'] = '%s'\n"%(__command,repr(__v))
930                     __text = __text.replace("''","'")
931                 elif __k in ('Stored', 'Checked'):
932                     if bool(__v):
933                         __text += "%s_config['%s'] = '%s'\n"%(__command,__k,int(bool(__v)))
934                 elif __k in ('AvoidRC', 'noDetails'):
935                     if not bool(__v):
936                         __text += "%s_config['%s'] = '%s'\n"%(__command,__k,int(bool(__v)))
937                 else:
938                     if __k is 'Parameters': __k = "Dict"
939                     __text += "%s_config['Type'] = '%s'\n"%(__command,__k)
940                     __text += "%s_config['From'] = '%s'\n"%(__command,'String')
941                     __text += "%s_config['Data'] = \"\"\"%s\"\"\"\n"%(__command,repr(__v))
942             __text += "study_config['%s'] = %s_config"%(__command,__command)
943             if __switchoff:
944                 self._switchoff = True
945         if __text is not None: self._addLine(__text)
946         if not __switchoff:
947             self._switchoff = False
948     def _finalize(self):
949         self.__loadVariablesByScript()
950         self._addLine("#")
951         self._addLine("Analysis_config = {}")
952         self._addLine("Analysis_config['From'] = 'String'")
953         self._addLine("Analysis_config['Data'] = \"\"\"import numpy")
954         self._addLine("xa=numpy.ravel(ADD.get('Analysis')[-1])")
955         self._addLine("print 'Analysis:',xa\"\"\"")
956         self._addLine("study_config['UserPostAnalysis'] = Analysis_config")
957     def __loadVariablesByScript(self):
958         exec("\n".join(self._lineSerie))
959         if "Algorithm" in study_config and len(study_config['Algorithm'])>0:
960             self.__hasAlgorithm = True
961         else:
962             self.__hasAlgorithm = False
963         if not self.__hasAlgorithm and \
964                 "AlgorithmParameters" in study_config and \
965                 isinstance(study_config['AlgorithmParameters'], dict) and \
966                 "From" in study_config['AlgorithmParameters'] and \
967                 "Data" in study_config['AlgorithmParameters'] and \
968                 study_config['AlgorithmParameters']['From'] == 'Script':
969             __asScript = study_config['AlgorithmParameters']['Data']
970             __var = ImportFromScript(__asScript).getvalue( "Algorithm" )
971             __text = "#\nstudy_config['Algorithm'] = '%s'"%(__var,)
972             self._addLine(__text)
973         if self.__hasAlgorithm and \
974                 "AlgorithmParameters" in study_config and \
975                 isinstance(study_config['AlgorithmParameters'], dict) and \
976                 "From" not in study_config['AlgorithmParameters'] and \
977                 "Data" not in study_config['AlgorithmParameters']:
978             __text  = "#\n"
979             __text += "AlgorithmParameters_config['Type'] = 'Dict'\n"
980             __text += "AlgorithmParameters_config['From'] = 'String'\n"
981             __text += "AlgorithmParameters_config['Data'] = '{}'\n"
982             self._addLine(__text)
983         del study_config
984
985 class _XMLViewer(_GenericCaseViewer):
986     """
987     Etablissement des commandes de creation d'un cas DIC
988     """
989     def __init__(self, __name="", __objname="case", __content=None):
990         "Initialisation et enregistrement de l'entete"
991         _GenericCaseViewer.__init__(self, __name, __objname, __content)
992         raise NotImplementedError()
993
994 # ==============================================================================
995 if __name__ == "__main__":
996     print('\n AUTODIAGNOSTIC \n')