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 Définit les outils d'interfaces normalisées de cas.
26 __author__ = "Jean-Philippe ARGAUD"
35 from daCore import Persistence
36 from daCore import PlatformInfo
37 from daCore import Templates
39 # ==============================================================================
40 class GenericCaseViewer(object):
42 Gestion des commandes de création d'une vue de cas
44 def __init__(self, __name="", __objname="case", __content=None, __object=None):
45 "Initialisation et enregistrement de l'entete"
46 self._name = str(__name)
47 self._objname = str(__objname)
49 self._switchoff = False
50 self._numobservers = 2
51 self._content = __content
52 self._object = __object
53 self._missing = """raise ValueError("This case requires beforehand to import or define the variable named <%s>. When corrected, remove this command, correct and uncomment the following one.")\n# """
54 def _append(self, *args):
55 "Transformation d'une commande individuelle en un enregistrement"
56 raise NotImplementedError()
57 def _extract(self, *args):
58 "Transformation d'enregistrement(s) en commande(s) individuelle(s)"
59 raise NotImplementedError()
60 def _finalize(self, __upa=None):
61 "Enregistrement du final"
62 __hasNotExecute = True
63 for l in self._lineSerie:
64 if "%s.execute"%(self._objname,) in l: __hasNotExecute = False
66 self._lineSerie.append("%s.execute()"%(self._objname,))
67 if __upa is not None and len(__upa)>0:
68 __upa = __upa.replace("ADD.",str(self._objname)+".")
69 self._lineSerie.append(__upa)
70 def _addLine(self, line=""):
71 "Ajoute un enregistrement individuel"
72 self._lineSerie.append(line)
73 def _get_objname(self):
75 def dump(self, __filename=None, __upa=None):
76 "Restitution normalisée des commandes"
78 __text = "\n".join(self._lineSerie)
80 if __filename is not None:
81 __file = os.path.abspath(__filename)
82 __fid = open(__file,"w")
86 def load(self, __filename=None, __content=None, __object=None):
87 "Chargement normalisé des commandes"
88 if __filename is not None and os.path.exists(__filename):
89 self._content = open(__filename, 'r').read()
90 elif __content is not None and type(__content) is str:
91 self._content = __content
92 elif __object is not None and type(__object) is dict:
93 self._object = copy.deepcopy(__object)
95 pass # use "self._content" from initialization
96 __commands = self._extract(self._content, self._object)
99 class _TUIViewer(GenericCaseViewer):
101 Établissement des commandes d'un cas ADAO TUI (Cas<->TUI)
103 def __init__(self, __name="", __objname="case", __content=None, __object=None):
104 "Initialisation et enregistrement de l'entete"
105 GenericCaseViewer.__init__(self, __name, __objname, __content, __object)
106 self._addLine("# -*- coding: utf-8 -*-")
107 self._addLine("#\n# Python script using ADAO TUI\n#")
108 self._addLine("from numpy import array, matrix")
109 self._addLine("from adao import adaoBuilder")
110 self._addLine("%s = adaoBuilder.New('%s')"%(self._objname, self._name))
111 if self._content is not None:
112 for command in self._content:
113 self._append(*command)
114 def _append(self, __command=None, __keys=None, __local=None, __pre=None, __switchoff=False):
115 "Transformation d'une commande individuelle en un enregistrement"
116 if __command is not None and __keys is not None and __local is not None:
117 if "Concept" in __keys:
118 logging.debug("TUI Order processed: %s"%(__local["Concept"],))
120 if __pre is not None:
121 __text += "%s = "%__pre
122 __text += "%s.%s( "%(self._objname,str(__command))
123 if "self" in __keys: __keys.remove("self")
124 if __command not in ("set","get") and "Concept" in __keys: __keys.remove("Concept")
126 if k not in __local: continue
128 if __v is None: continue
129 if k == "Checked" and not __v: continue
130 if k == "Stored" and not __v: continue
131 if k == "ColMajor" and not __v: continue
132 if k == "InputFunctionAsMulti" and not __v: continue
133 if k == "nextStep" and not __v: continue
134 if k == "AvoidRC" and __v: continue
135 if k == "noDetails": continue
136 if isinstance(__v,Persistence.Persistence): __v = __v.values()
137 if callable(__v): __text = self._missing%__v.__name__+__text
138 if isinstance(__v,dict):
139 for val in __v.values():
140 if callable(val): __text = self._missing%val.__name__+__text
141 numpy.set_printoptions(precision=15,threshold=1000000,linewidth=1000*15)
142 __text += "%s=%s, "%(k,repr(__v))
143 numpy.set_printoptions(precision=8,threshold=1000,linewidth=75)
144 __text = __text.rstrip(", ")
146 self._addLine(__text)
147 def _extract(self, __multilines="", __object=None):
148 "Transformation d'enregistrement(s) en commande(s) individuelle(s)"
151 __multilines = __multilines.replace("\r\n","\n")
152 for line in __multilines.split("\n"):
153 if "adaoBuilder.New" in line and "=" in line:
154 self._objname = line.split("=")[0].strip()
156 logging.debug("TUI Extracting commands of '%s' object..."%(self._objname,))
160 if self._objname+".set" in line:
161 __commands.append( line.replace(self._objname+".","",1) )
162 logging.debug("TUI Extracted command: %s"%(__commands[-1],))
165 class _COMViewer(GenericCaseViewer):
167 Établissement des commandes d'un cas COMM (Eficas Native Format/Cas<-COM)
169 def __init__(self, __name="", __objname="case", __content=None, __object=None):
170 "Initialisation et enregistrement de l'entete"
171 GenericCaseViewer.__init__(self, __name, __objname, __content, __object)
172 self._observerIndex = 0
173 self._addLine("# -*- coding: utf-8 -*-")
174 self._addLine("#\n# Python script using ADAO COMM\n#")
175 self._addLine("from numpy import array, matrix")
177 self._addLine("%s = {}"%__objname)
178 if self._content is not None:
179 for command in self._content:
180 self._append(*command)
181 def _extract(self, __multilines=None, __object=None):
182 "Transformation d'enregistrement(s) en commande(s) individuelle(s)"
183 __suppparameters = {}
184 if __multilines is not None:
185 if "ASSIMILATION_STUDY" in __multilines:
186 __suppparameters.update({'StudyType':"ASSIMILATION_STUDY"})
187 __multilines = __multilines.replace("ASSIMILATION_STUDY","dict")
188 elif "CHECKING_STUDY" in __multilines:
189 __suppparameters.update({'StudyType':"CHECKING_STUDY"})
190 __multilines = __multilines.replace("CHECKING_STUDY", "dict")
192 __multilines = __multilines.replace("ASSIMILATION_STUDY","dict")
194 __multilines = __multilines.replace("_F(", "dict(")
195 __multilines = __multilines.replace(",),);", ",),)")
197 for line in __multilines.split("\n"):
198 if len(line) < 1: continue
199 __fulllines += line + "\n"
200 __multilines = __fulllines
201 self._objname = "case"
203 exec("self._objdata = "+__multilines)
205 if self._objdata is None or not(type(self._objdata) is dict) or not('AlgorithmParameters' in self._objdata):
206 raise ValueError("Impossible to load given content as an ADAO COMM one (no dictionnary or no 'AlgorithmParameters' key found).")
207 # ----------------------------------------------------------------------
208 logging.debug("COMM Extracting commands of '%s' object..."%(self._objname,))
210 __UserPostAnalysis = ""
211 for k,r in self._objdata.items():
213 logging.debug("COMM Extracted command: %s:%s"%(k, r))
214 if __command == "StudyName" and len(str(r))>0:
215 __commands.append( "set( Concept='Name', String='%s')"%(str(r),) )
216 elif __command == "StudyRepertory":
217 __commands.append( "set( Concept='Directory', String='%s')"%(str(r),) )
218 elif __command == "Debug" and str(r) == "0":
219 __commands.append( "set( Concept='NoDebug' )" )
220 elif __command == "Debug" and str(r) == "1":
221 __commands.append( "set( Concept='Debug' )" )
222 elif __command == "ExecuteInContainer":
223 __suppparameters.update({'ExecuteInContainer':r})
225 elif __command == "UserPostAnalysis" and type(r) is dict:
227 __UserPostAnalysis = r['STRING'].replace("ADD.",str(self._objname)+".")
228 __commands.append( "set( Concept='UserPostAnalysis', String=\"\"\"%s\"\"\" )"%(__UserPostAnalysis,) )
229 elif 'SCRIPT_FILE' in r and os.path.exists(r['SCRIPT_FILE']):
230 __UserPostAnalysis = open(r['SCRIPT_FILE'],'r').read()
231 __commands.append( "set( Concept='UserPostAnalysis', Script='%s' )"%(r['SCRIPT_FILE'],) )
232 elif 'Template' in r and not 'ValueTemplate' in r:
234 if r['Template'] not in Templates.UserPostAnalysisTemplates:
235 raise ValueError("User post-analysis template \"%s\" does not exist."%(r['Template'],))
237 __UserPostAnalysis = Templates.UserPostAnalysisTemplates[r['Template']]
238 __commands.append( "set( Concept='UserPostAnalysis', Template='%s' )"%(r['Template'],) )
239 elif 'Template' in r and 'ValueTemplate' in r:
240 # Le template ayant pu être modifié, donc on ne prend que le ValueTemplate...
241 __UserPostAnalysis = r['ValueTemplate']
242 __commands.append( "set( Concept='UserPostAnalysis', String=\"\"\"%s\"\"\" )"%(__UserPostAnalysis,) )
244 __UserPostAnalysis = ""
246 elif __command == "AlgorithmParameters" and type(r) is dict and 'Algorithm' in r:
247 if 'data' in r and r['Parameters'] == 'Dict':
249 if 'STRING' in __from:
250 __parameters = ", Parameters=%s"%(repr(eval(__from['STRING'])),)
251 elif 'SCRIPT_FILE' in __from and os.path.exists(__from['SCRIPT_FILE']):
252 __parameters = ", Script='%s'"%(__from['SCRIPT_FILE'],)
253 else: # if 'Parameters' in r and r['Parameters'] == 'Defaults':
254 __Dict = copy.deepcopy(r)
255 __Dict.pop('Algorithm','')
256 __Dict.pop('Parameters','')
257 if 'SetSeed' in __Dict:__Dict['SetSeed'] = int(__Dict['SetSeed'])
258 if 'BoxBounds' in __Dict and type(__Dict['BoxBounds']) is str:
259 __Dict['BoxBounds'] = eval(__Dict['BoxBounds'])
261 __parameters = ', Parameters=%s'%(repr(__Dict),)
264 __commands.append( "set( Concept='AlgorithmParameters', Algorithm='%s'%s )"%(r['Algorithm'],__parameters) )
266 elif __command == "Observers" and type(r) is dict and 'SELECTION' in r:
267 if type(r['SELECTION']) is str:
268 __selection = (r['SELECTION'],)
270 __selection = tuple(r['SELECTION'])
271 for sk in __selection:
272 __idata = r['%s_data'%sk]
273 if __idata['NodeType'] == 'Template' and 'Template' in __idata:
274 __template = __idata['Template']
275 if 'Info' in __idata:
276 __info = ", Info='%s'"%(__idata['Info'],)
279 __commands.append( "set( Concept='Observer', Variable='%s', Template='%s'%s )"%(sk,__template,__info) )
280 if __idata['NodeType'] == 'String' and 'Value' in __idata:
281 __value =__idata['Value']
282 __commands.append( "set( Concept='Observer', Variable='%s', String='%s' )"%(sk,__value) )
284 # Background, ObservationError, ObservationOperator...
285 elif type(r) is dict:
287 if 'Stored' in r and bool(r['Stored']):
288 __argumentsList.append(['Stored',True])
289 if 'INPUT_TYPE' in r and 'data' in r:
290 # Vector, Matrix, ScalarSparseMatrix, DiagonalSparseMatrix, Function
291 __itype = r['INPUT_TYPE']
293 if 'FROM' in __idata:
294 # String, Script, DataFile, Template, ScriptWithOneFunction, ScriptWithFunctions
295 __ifrom = __idata['FROM']
296 __idata.pop('FROM','')
297 if __ifrom == 'String' or __ifrom == 'Template':
298 __argumentsList.append([__itype,__idata['STRING']])
299 if __ifrom == 'Script':
300 __argumentsList.append([__itype,True])
301 __argumentsList.append(['Script',__idata['SCRIPT_FILE']])
302 if __ifrom == 'DataFile':
303 __argumentsList.append([__itype,True])
304 __argumentsList.append(['DataFile',__idata['DATA_FILE']])
305 if __ifrom == 'ScriptWithOneFunction':
306 __argumentsList.append(['OneFunction',True])
307 __argumentsList.append(['Script',__idata.pop('SCRIPTWITHONEFUNCTION_FILE')])
309 __argumentsList.append(['Parameters',__idata])
310 if __ifrom == 'ScriptWithFunctions':
311 __argumentsList.append(['ThreeFunctions',True])
312 __argumentsList.append(['Script',__idata.pop('SCRIPTWITHFUNCTIONS_FILE')])
314 __argumentsList.append(['Parameters',__idata])
315 __arguments = ["%s = %s"%(k,repr(v)) for k,v in __argumentsList]
316 __commands.append( "set( Concept='%s', %s )"%(__command, ", ".join(__arguments)))
318 __commands.append( "set( Concept='%s', Parameters=%s )"%('SupplementaryParameters', repr(__suppparameters)))
320 # ----------------------------------------------------------------------
321 __commands.sort() # Pour commencer par 'AlgorithmParameters'
322 __commands.append(__UserPostAnalysis)
325 class _SCDViewer(GenericCaseViewer):
327 Établissement des commandes d'un cas SCD (Study Config Dictionary/Cas->SCD)
329 Remarque : le fichier généré est différent de celui obtenu par EFICAS
331 def __init__(self, __name="", __objname="case", __content=None, __object=None):
332 "Initialisation et enregistrement de l'entête"
333 GenericCaseViewer.__init__(self, __name, __objname, __content, __object)
335 if __content is not None:
336 for command in __content:
337 if command[0] == "set": __command = command[2]["Concept"]
338 else: __command = command[0].replace("set", "", 1)
339 if __command == 'Name':
340 self._name = command[2]["String"]
342 self.__DebugCommandNotSet = True
343 self.__ObserverCommandNotSet = True
344 self.__UserPostAnalysisNotSet = True
346 self._addLine("# -*- coding: utf-8 -*-")
347 self._addLine("#\n# Input for ADAO converter to SCD\n#")
349 self._addLine("study_config = {}")
350 self._addLine("study_config['Name'] = '%s'"%self._name)
352 self._addLine("inputvariables_config = {}")
353 self._addLine("inputvariables_config['Order'] =['adao_default']")
354 self._addLine("inputvariables_config['adao_default'] = -1")
355 self._addLine("study_config['InputVariables'] = inputvariables_config")
357 self._addLine("outputvariables_config = {}")
358 self._addLine("outputvariables_config['Order'] = ['adao_default']")
359 self._addLine("outputvariables_config['adao_default'] = -1")
360 self._addLine("study_config['OutputVariables'] = outputvariables_config")
361 if __content is not None:
362 for command in __content:
363 self._append(*command)
364 def _append(self, __command=None, __keys=None, __local=None, __pre=None, __switchoff=False):
365 "Transformation d'une commande individuelle en un enregistrement"
366 if __command == "set": __command = __local["Concept"]
367 else: __command = __command.replace("set", "", 1)
368 logging.debug("SCD Order processed: %s"%(__command))
371 if __command in (None, 'execute', 'executePythonScheme', 'executeYACSScheme', 'get', 'Name'):
373 elif __command in ['Directory',]:
374 __text = "#\nstudy_config['Repertory'] = %s"%(repr(__local['String']))
375 elif __command in ['Debug', 'setDebug']:
376 __text = "#\nstudy_config['Debug'] = '1'"
377 self.__DebugCommandNotSet = False
378 elif __command in ['NoDebug', 'setNoDebug']:
379 __text = "#\nstudy_config['Debug'] = '0'"
380 self.__DebugCommandNotSet = False
381 elif __command in ['Observer', 'setObserver']:
382 if self.__ObserverCommandNotSet:
383 self._addLine("observers = {}")
384 self._addLine("study_config['Observers'] = observers")
385 self.__ObserverCommandNotSet = False
386 __obs = __local['Variable']
387 self._numobservers += 1
389 __text += "observers['%s'] = {}\n"%__obs
390 if __local['String'] is not None:
391 __text += "observers['%s']['nodetype'] = '%s'\n"%(__obs, 'String')
392 __text += "observers['%s']['String'] = \"\"\"%s\"\"\"\n"%(__obs, __local['String'])
393 if __local['Script'] is not None:
394 __text += "observers['%s']['nodetype'] = '%s'\n"%(__obs, 'Script')
395 __text += "observers['%s']['Script'] = \"%s\"\n"%(__obs, __local['Script'])
396 if __local['Template'] is not None and __local['Template'] in Templates.ObserverTemplates:
397 __text += "observers['%s']['nodetype'] = '%s'\n"%(__obs, 'String')
398 __text += "observers['%s']['String'] = \"\"\"%s\"\"\"\n"%(__obs, Templates.ObserverTemplates[__local['Template']])
399 if __local['Info'] is not None:
400 __text += "observers['%s']['info'] = \"\"\"%s\"\"\"\n"%(__obs, __local['Info'])
402 __text += "observers['%s']['info'] = \"\"\"%s\"\"\"\n"%(__obs, __obs)
403 __text += "observers['%s']['number'] = %s"%(__obs, self._numobservers)
404 elif __command in ['UserPostAnalysis', 'setUserPostAnalysis']:
406 __text += "Analysis_config = {}\n"
407 if __local['String'] is not None:
408 __text += "Analysis_config['From'] = 'String'\n"
409 __text += "Analysis_config['Data'] = \"\"\"%s\"\"\"\n"%(__local['String'],)
410 if __local['Script'] is not None:
411 __text += "Analysis_config['From'] = 'Script'\n"
412 __text += "Analysis_config['Data'] = \"\"\"%s\"\"\"\n"%(__local['Script'],)
413 if __local['Template'] is not None and __local['Template'] in Templates.UserPostAnalysisTemplates:
414 __text += "Analysis_config['From'] = 'String'\n"
415 __text += "Analysis_config['Data'] = \"\"\"%s\"\"\"\n"%(Templates.UserPostAnalysisTemplates[__local['Template']],)
416 __text += "study_config['UserPostAnalysis'] = Analysis_config"
417 self.__UserPostAnalysisNotSet = False
418 elif __local is not None: # __keys is not None and
419 numpy.set_printoptions(precision=15,threshold=1000000,linewidth=1000*15)
421 __text += "%s_config = {}\n"%__command
422 __local.pop('self','')
424 __vectorIsDataFile = False
425 __vectorIsScript = False
426 for __k,__v in __local.items():
427 if __v is None: __to_be_removed.append(__k)
428 for __k in __to_be_removed:
430 for __k,__v in __local.items():
431 if __k == "Concept": continue
432 if __k in ['ScalarSparseMatrix','DiagonalSparseMatrix','Matrix','OneFunction','ThreeFunctions'] and 'Script' in __local and __local['Script'] is not None: continue
433 if __k in ['Vector','VectorSerie'] and 'DataFile' in __local and __local['DataFile'] is not None: continue
434 if __k == 'Parameters' and not (__command in ['AlgorithmParameters','SupplementaryParameters']): continue
435 if __k == 'Algorithm':
436 __text += "study_config['Algorithm'] = %s\n"%(repr(__v))
437 elif __k == 'DataFile':
440 __v = "'"+repr(__v)+"'"
441 for __lk in ['Vector','VectorSerie']:
442 if __lk in __local and __local[__lk]: __k = __lk
443 __text += "%s_config['Type'] = '%s'\n"%(__command,__k)
444 __text += "%s_config['From'] = '%s'\n"%(__command,__f)
445 __text += "%s_config['Data'] = %s\n"%(__command,__v)
446 __text = __text.replace("''","'")
447 __vectorIsDataFile = True
448 elif __k == 'Script':
451 __v = "'"+repr(__v)+"'"
452 for __lk in ['ScalarSparseMatrix','DiagonalSparseMatrix','Matrix']:
453 if __lk in __local and __local[__lk]: __k = __lk
454 if __command == "AlgorithmParameters": __k = "Dict"
455 if 'OneFunction' in __local and __local['OneFunction']:
456 __text += "%s_ScriptWithOneFunction = {}\n"%(__command,)
457 __text += "%s_ScriptWithOneFunction['Function'] = ['Direct', 'Tangent', 'Adjoint']\n"%(__command,)
458 __text += "%s_ScriptWithOneFunction['Script'] = {}\n"%(__command,)
459 __text += "%s_ScriptWithOneFunction['Script']['Direct'] = %s\n"%(__command,__v)
460 __text += "%s_ScriptWithOneFunction['Script']['Tangent'] = %s\n"%(__command,__v)
461 __text += "%s_ScriptWithOneFunction['Script']['Adjoint'] = %s\n"%(__command,__v)
462 __text += "%s_ScriptWithOneFunction['DifferentialIncrement'] = 1e-06\n"%(__command,)
463 __text += "%s_ScriptWithOneFunction['CenteredFiniteDifference'] = 0\n"%(__command,)
465 __f = 'ScriptWithOneFunction'
466 __v = '%s_ScriptWithOneFunction'%(__command,)
467 if 'ThreeFunctions' in __local and __local['ThreeFunctions']:
468 __text += "%s_ScriptWithFunctions = {}\n"%(__command,)
469 __text += "%s_ScriptWithFunctions['Function'] = ['Direct', 'Tangent', 'Adjoint']\n"%(__command,)
470 __text += "%s_ScriptWithFunctions['Script'] = {}\n"%(__command,)
471 __text += "%s_ScriptWithFunctions['Script']['Direct'] = %s\n"%(__command,__v)
472 __text += "%s_ScriptWithFunctions['Script']['Tangent'] = %s\n"%(__command,__v)
473 __text += "%s_ScriptWithFunctions['Script']['Adjoint'] = %s\n"%(__command,__v)
475 __f = 'ScriptWithFunctions'
476 __v = '%s_ScriptWithFunctions'%(__command,)
477 __text += "%s_config['Type'] = '%s'\n"%(__command,__k)
478 __text += "%s_config['From'] = '%s'\n"%(__command,__f)
479 __text += "%s_config['Data'] = %s\n"%(__command,__v)
480 __text = __text.replace("''","'")
481 __vectorIsScript = True
482 elif __k in ('Stored', 'Checked', 'ColMajor', 'InputFunctionAsMulti', 'nextStep'):
484 __text += "%s_config['%s'] = '%s'\n"%(__command,__k,int(bool(__v)))
485 elif __k in ('AvoidRC', 'noDetails'):
487 __text += "%s_config['%s'] = '%s'\n"%(__command,__k,int(bool(__v)))
489 if __k == 'Vector' and __vectorIsScript: continue
490 if __k == 'Vector' and __vectorIsDataFile: continue
491 if __k == 'Parameters': __k = "Dict"
492 if isinstance(__v,Persistence.Persistence): __v = __v.values()
493 if callable(__v): __text = self._missing%__v.__name__+__text
494 if isinstance(__v,dict):
495 for val in __v.values():
496 if callable(val): __text = self._missing%val.__name__+__text
497 __text += "%s_config['Type'] = '%s'\n"%(__command,__k)
498 __text += "%s_config['From'] = '%s'\n"%(__command,'String')
499 __text += "%s_config['Data'] = \"\"\"%s\"\"\"\n"%(__command,repr(__v))
500 __text += "study_config['%s'] = %s_config"%(__command,__command)
501 numpy.set_printoptions(precision=8,threshold=1000,linewidth=75)
503 self._switchoff = True
504 if __text is not None: self._addLine(__text)
506 self._switchoff = False
507 def _finalize(self, *__args):
508 self.__loadVariablesByScript()
509 if self.__DebugCommandNotSet:
510 self._addLine("#\nstudy_config['Debug'] = '0'")
511 if self.__UserPostAnalysisNotSet:
513 self._addLine("Analysis_config = {}")
514 self._addLine("Analysis_config['From'] = 'String'")
515 self._addLine("Analysis_config['Data'] = \"\"\"import numpy")
516 self._addLine("xa=numpy.ravel(ADD.get('Analysis')[-1])")
517 self._addLine("print('Analysis:',xa)\"\"\"")
518 self._addLine("study_config['UserPostAnalysis'] = Analysis_config")
519 def __loadVariablesByScript(self):
520 __ExecVariables = {} # Necessaire pour recuperer la variable
521 exec("\n".join(self._lineSerie), __ExecVariables)
522 study_config = __ExecVariables['study_config']
523 # Pour Python 3 : self.__hasAlgorithm = bool(study_config['Algorithm'])
524 if 'Algorithm' in study_config:
525 self.__hasAlgorithm = True
527 self.__hasAlgorithm = False
528 if not self.__hasAlgorithm and \
529 "AlgorithmParameters" in study_config and \
530 isinstance(study_config['AlgorithmParameters'], dict) and \
531 "From" in study_config['AlgorithmParameters'] and \
532 "Data" in study_config['AlgorithmParameters'] and \
533 study_config['AlgorithmParameters']['From'] == 'Script':
534 __asScript = study_config['AlgorithmParameters']['Data']
535 __var = ImportFromScript(__asScript).getvalue( "Algorithm" )
536 __text = "#\nstudy_config['Algorithm'] = '%s'"%(__var,)
537 self._addLine(__text)
538 if self.__hasAlgorithm and \
539 "AlgorithmParameters" in study_config and \
540 isinstance(study_config['AlgorithmParameters'], dict) and \
541 "From" not in study_config['AlgorithmParameters'] and \
542 "Data" not in study_config['AlgorithmParameters']:
544 __text += "AlgorithmParameters_config['Type'] = 'Dict'\n"
545 __text += "AlgorithmParameters_config['From'] = 'String'\n"
546 __text += "AlgorithmParameters_config['Data'] = '{}'\n"
547 self._addLine(__text)
548 if 'SupplementaryParameters' in study_config and \
549 isinstance(study_config['SupplementaryParameters'], dict) and \
550 "From" in study_config['SupplementaryParameters'] and \
551 study_config['SupplementaryParameters']["From"] == 'String' and \
552 "Data" in study_config['SupplementaryParameters']:
553 __dict = eval(study_config['SupplementaryParameters']["Data"])
554 if 'ExecuteInContainer' in __dict:
555 self._addLine("#\nstudy_config['ExecuteInContainer'] = '%s'"%__dict['ExecuteInContainer'])
557 self._addLine("#\nstudy_config['ExecuteInContainer'] = 'No'")
558 if 'StudyType' in __dict:
559 self._addLine("#\nstudy_config['StudyType'] = '%s'"%__dict['StudyType'])
560 if 'StudyType' in __dict and __dict['StudyType'] != "ASSIMILATION_STUDY":
561 self.__UserPostAnalysisNotSet = False
564 class _YACSViewer(GenericCaseViewer):
566 Etablissement des commandes d'un cas YACS (Cas->SCD->YACS)
568 def __init__(self, __name="", __objname="case", __content=None, __object=None):
569 "Initialisation et enregistrement de l'entete"
570 GenericCaseViewer.__init__(self, __name, __objname, __content, __object)
571 self.__internalSCD = _SCDViewer(__name, __objname, __content, __object)
572 self._append = self.__internalSCD._append
573 def dump(self, __filename=None, __upa=None):
574 "Restitution normalisée des commandes"
576 if __filename is None:
577 raise ValueError("A file name has to be given for YACS XML output.")
579 __file = os.path.abspath(__filename)
580 if os.path.isfile(__file) or os.path.islink(__file):
583 if not PlatformInfo.has_salome or \
584 not PlatformInfo.has_adao:
586 "Unable to get SALOME or ADAO environnement for YACS conversion.\n"+\
587 "Please load the right SALOME environnement before trying to use it.")
589 from daYacsSchemaCreator.run import create_schema_from_content
591 self.__internalSCD._finalize(__upa)
592 __SCDdump = self.__internalSCD.dump()
593 create_schema_from_content(__SCDdump, __file)
595 if not os.path.exists(__file):
596 __msg = "An error occured during the ADAO YACS Schema build for\n"
597 __msg += "the target output file:\n"
598 __msg += " %s\n"%__file
599 __msg += "See errors details in your launching terminal log.\n"
600 raise ValueError(__msg)
602 __fid = open(__file,"r")
603 __text = __fid.read()
607 # ==============================================================================
608 class ImportFromScript(object):
610 Obtention d'une variable nommee depuis un fichier script importé
612 __slots__ = ("__basename", "__filenspace", "__filestring")
613 def __init__(self, __filename=None):
614 "Verifie l'existence et importe le script"
615 if __filename is None:
616 raise ValueError("The name of the file, containing the variable to be read, has to be specified.")
617 if not os.path.isfile(__filename):
618 raise ValueError("The file containing the variable to be imported doesn't seem to exist. Please check the file. The given file name is:\n \"%s\""%str(__filename))
619 if os.path.dirname(__filename) != '':
620 sys.path.insert(0, os.path.dirname(__filename))
621 __basename = os.path.basename(__filename).rstrip(".py")
623 __basename = __filename.rstrip(".py")
624 PlatformInfo.checkFileNameImportability( __basename+".py" )
625 self.__basename = __basename
626 self.__filenspace = __import__(__basename, globals(), locals(), [])
627 self.__filestring = open(__filename,'r').read()
628 def getvalue(self, __varname=None, __synonym=None ):
629 "Renvoie la variable demandee par son nom ou son synonyme"
630 if __varname is None:
631 raise ValueError("The name of the variable to be read has to be specified. Please check the content of the file and the syntax.")
632 if not hasattr(self.__filenspace, __varname):
633 if __synonym is None:
634 raise ValueError("The imported script file \"%s\" doesn't contain the mandatory variable \"%s\" to be read. Please check the content of the file and the syntax."%(str(self.__basename)+".py",__varname))
635 elif not hasattr(self.__filenspace, __synonym):
636 raise ValueError("The imported script file \"%s\" doesn't contain the mandatory variable \"%s\" to be read. Please check the content of the file and the syntax."%(str(self.__basename)+".py",__synonym))
638 return getattr(self.__filenspace, __synonym)
640 return getattr(self.__filenspace, __varname)
642 "Renvoie le script complet"
643 return self.__filestring
645 # ==============================================================================
646 class ImportDetector(object):
648 Détection des caractéristiques de fichiers ou objets en entrée
651 "__url", "__usr", "__root", "__end")
652 def __enter__(self): return self
653 def __exit__(self, exc_type, exc_val, exc_tb): return False
655 def __init__(self, __url, UserMime=""):
657 raise ValueError("The name or url of the file object has to be specified.")
659 self.__url = __url.decode()
661 self.__url = str(__url)
662 if UserMime is bytes:
663 self.__usr = UserMime.decode().lower()
665 self.__usr = str(UserMime).lower()
666 (self.__root, self.__end) = os.path.splitext(self.__url)
668 mimetypes.add_type('application/numpy.npy', '.npy')
669 mimetypes.add_type('application/numpy.npz', '.npz')
670 mimetypes.add_type('application/dymola.sdf', '.sdf')
671 if sys.platform.startswith("win"):
672 mimetypes.add_type('text/plain', '.txt')
673 mimetypes.add_type('text/csv', '.csv')
674 mimetypes.add_type('text/tab-separated-values', '.tsv')
678 def is_local_file(self):
679 if os.path.isfile(os.path.realpath(self.__url)):
683 def is_not_local_file(self):
684 if not os.path.isfile(os.path.realpath(self.__url)):
688 def raise_error_if_not_local_file(self):
689 if not os.path.isfile(os.path.realpath(self.__url)):
690 raise ValueError("The name or the url of the file object doesn't seem to exist. The given name is:\n \"%s\""%str(self.__url))
694 # Directory related tests
695 # -----------------------
696 def is_local_dir(self):
697 if os.path.isdir(self.__url):
701 def is_not_local_dir(self):
702 if not os.path.isdir(self.__url):
706 def raise_error_if_not_local_dir(self):
707 if not os.path.isdir(self.__url):
708 raise ValueError("The name or the url of the directory object doesn't seem to exist. The given name is:\n \"%s\""%str(self.__url))
712 # Mime related functions
713 # ------------------------
714 def get_standard_mime(self):
715 (__mtype, __encoding) = mimetypes.guess_type(self.__url, strict=False)
717 def get_user_mime(self):
718 __fake = "fake."+self.__usr.lower()
719 (__mtype, __encoding) = mimetypes.guess_type(__fake, strict=False)
721 def get_comprehensive_mime(self):
722 if self.get_standard_mime() is not None:
723 return self.get_standard_mime()
724 elif self.get_user_mime() is not None:
725 return self.get_user_mime()
729 # Name related functions
730 # ----------------------
731 def get_user_name(self):
733 def get_absolute_name(self):
734 return os.path.abspath(os.path.realpath(self.__url))
735 def get_extension(self):
738 class ImportFromFile(object):
740 Obtention de variables disrétisées en 1D, définies par une ou des variables
741 nommées, et sous la forme d'une série de points éventuellement indexés. La
742 lecture d'un fichier au format spécifié (ou intuité) permet de charger ces
744 - des fichiers textes en colonnes de type TXT, CSV, TSV...
745 - des fichiers de données binaires NPY, NPZ, SDF...
746 La lecture du fichier complet ne se fait que si nécessaire, pour assurer la
747 performance tout en disposant de l'interprétation du contenu. Les fichiers
748 textes doivent présenter en première ligne (hors commentaire ou ligne vide)
749 les noms des variables de colonnes. Les commentaires commencent par un "#".
752 "_filename", "_colnames", "_colindex", "_varsline", "_format",
753 "_delimiter", "_skiprows", "__url", "__filestring", "__header",
754 "__allowvoid", "__binaryformats", "__supportedformats")
755 def __enter__(self): return self
756 def __exit__(self, exc_type, exc_val, exc_tb): return False
758 def __init__(self, Filename=None, ColNames=None, ColIndex=None, Format="Guess", AllowVoidNameList=True):
760 Verifie l'existence et les informations de définition du fichier. Les
761 noms de colonnes ou de variables sont ignorées si le format ne permet
764 - Filename : nom du fichier
765 - ColNames : noms de la ou des colonnes/variables à lire
766 - ColIndex : nom unique de la colonne/variable servant d'index
767 - Format : format du fichier et/ou des données inclues
768 - AllowVoidNameList : permet, si la liste de noms est vide, de
769 prendre par défaut toutes les colonnes
771 self.__binaryformats =(
772 "application/numpy.npy",
773 "application/numpy.npz",
774 "application/dymola.sdf",
776 self.__url = ImportDetector( Filename, Format)
777 self.__url.raise_error_if_not_local_file()
778 self._filename = self.__url.get_absolute_name()
779 PlatformInfo.checkFileNameConformity( self._filename )
781 self._format = self.__url.get_comprehensive_mime()
783 self.__header, self._varsline, self._skiprows = self.__getentete()
785 if self._format == "text/csv" or Format.upper() == "CSV":
786 self._format = "text/csv"
787 self.__filestring = "".join(self.__header)
788 if self.__filestring.count(",") > 1:
789 self._delimiter = ","
790 elif self.__filestring.count(";") > 1:
791 self._delimiter = ";"
793 self._delimiter = None
794 elif self._format == "text/tab-separated-values" or Format.upper() == "TSV":
795 self._format = "text/tab-separated-values"
796 self._delimiter = "\t"
798 self._delimiter = None
800 if ColNames is not None: self._colnames = tuple(ColNames)
801 else: self._colnames = None
803 if ColIndex is not None: self._colindex = str(ColIndex)
804 else: self._colindex = None
806 self.__allowvoid = bool(AllowVoidNameList)
808 def __getentete(self, __nblines = 3):
809 "Lit l'entête du fichier pour trouver la définition des variables"
810 # La première ligne non vide non commentée est toujours considérée
811 # porter les labels de colonne, donc pas des valeurs
812 __header, __varsline, __skiprows = [], "", 1
813 if self._format in self.__binaryformats:
816 with open(self._filename,'r') as fid:
817 __line = fid.readline().strip()
818 while "#" in __line or len(__line) < 1:
819 __header.append(__line)
821 __line = fid.readline().strip()
823 for i in range(max(0,__nblines)):
824 __header.append(fid.readline())
825 return (__header, __varsline, __skiprows)
827 def __getindices(self, __colnames, __colindex, __delimiter=None ):
828 "Indices de colonnes correspondants à l'index et aux variables"
829 if __delimiter is None:
830 __varserie = self._varsline.strip('#').strip().split()
832 __varserie = self._varsline.strip('#').strip().split(str(__delimiter))
834 if __colnames is not None:
836 __colnames = tuple(__colnames)
838 for i, n in enumerate(__varserie):
839 if v == n: __usecols.append(i)
840 __usecols = tuple(__usecols)
841 if len(__usecols) == 0:
845 raise ValueError("Can not found any column corresponding to the required names %s"%(__colnames,))
849 if __colindex is not None:
851 __colindex = str(__colindex)
852 for i, n in enumerate(__varserie):
853 if __colindex == n: __useindex = i
857 return (__usecols, __useindex)
859 def getsupported(self):
860 self.__supportedformats = {}
861 self.__supportedformats["text/plain"] = True
862 self.__supportedformats["text/csv"] = True
863 self.__supportedformats["text/tab-separated-values"] = True
864 self.__supportedformats["application/numpy.npy"] = True
865 self.__supportedformats["application/numpy.npz"] = True
866 self.__supportedformats["application/dymola.sdf"] = PlatformInfo.has_sdf
867 return self.__supportedformats
869 def getvalue(self, ColNames=None, ColIndex=None ):
870 "Renvoie la ou les variables demandees par la liste de leurs noms"
871 # Uniquement si mise à jour
872 if ColNames is not None: self._colnames = tuple(ColNames)
873 if ColIndex is not None: self._colindex = str(ColIndex)
876 if self._format == "application/numpy.npy":
877 __columns = numpy.load(self._filename)
879 elif self._format == "application/numpy.npz":
881 with numpy.load(self._filename) as __allcolumns:
882 if self._colnames is None:
883 self._colnames = __allcolumns.files
884 for nom in self._colnames: # Si une variable demandée n'existe pas
885 if nom not in __allcolumns.files:
886 self._colnames = tuple( __allcolumns.files )
887 for nom in self._colnames:
888 if nom in __allcolumns.files:
889 if __columns is not None:
890 # Attention : toutes les variables doivent avoir la même taille
891 __columns = numpy.vstack((__columns, numpy.reshape(__allcolumns[nom], (1,-1))))
894 __columns = numpy.reshape(__allcolumns[nom], (1,-1))
895 if self._colindex is not None and self._colindex in __allcolumns.files:
896 __index = numpy.array(numpy.reshape(__allcolumns[self._colindex], (1,-1)), dtype=bytes)
897 elif self._format == "text/plain":
898 __usecols, __useindex = self.__getindices(self._colnames, self._colindex)
899 __columns = numpy.loadtxt(self._filename, usecols = __usecols, skiprows=self._skiprows)
900 if __useindex is not None:
901 __index = numpy.loadtxt(self._filename, dtype = bytes, usecols = (__useindex,), skiprows=self._skiprows)
902 if __usecols is None: # Si une variable demandée n'existe pas
903 self._colnames = None
905 elif self._format == "application/dymola.sdf" and PlatformInfo.has_sdf:
907 __content = sdf.load(self._filename)
909 if self._colnames is None:
910 self._colnames = [__content.datasets[i].name for i in range(len(__content.datasets))]
911 for nom in self._colnames:
913 if __columns is not None:
914 # Attention : toutes les variables doivent avoir la même taille
915 __columns = numpy.vstack((__columns, numpy.reshape(__content[nom].data, (1,-1))))
918 __columns = numpy.reshape(__content[nom].data, (1,-1))
919 if self._colindex is not None and self._colindex in __content:
920 __index = __content[self._colindex].data
922 elif self._format == "text/csv":
923 __usecols, __useindex = self.__getindices(self._colnames, self._colindex, self._delimiter)
924 __columns = numpy.loadtxt(self._filename, usecols = __usecols, delimiter = self._delimiter, skiprows=self._skiprows)
925 if __useindex is not None:
926 __index = numpy.loadtxt(self._filename, dtype = bytes, usecols = (__useindex,), delimiter = self._delimiter, skiprows=self._skiprows)
927 if __usecols is None: # Si une variable demandée n'existe pas
928 self._colnames = None
930 elif self._format == "text/tab-separated-values":
931 __usecols, __useindex = self.__getindices(self._colnames, self._colindex, self._delimiter)
932 __columns = numpy.loadtxt(self._filename, usecols = __usecols, delimiter = self._delimiter, skiprows=self._skiprows)
933 if __useindex is not None:
934 __index = numpy.loadtxt(self._filename, dtype = bytes, usecols = (__useindex,), delimiter = self._delimiter, skiprows=self._skiprows)
935 if __usecols is None: # Si une variable demandée n'existe pas
936 self._colnames = None
938 raise ValueError("Unkown file format \"%s\" or no reader available"%self._format)
939 if __columns is None: __columns = ()
943 return value.decode()
946 if __index is not None:
947 __index = tuple([toString(v) for v in __index])
949 return (self._colnames, __columns, self._colindex, __index)
952 "Renvoie le fichier texte complet"
953 if self._format in self.__binaryformats:
956 with open(self._filename,'r') as fid:
962 class ImportScalarLinesFromFile(ImportFromFile):
964 Importation de fichier contenant des variables scalaires nommées. Le
965 fichier comporte soit 2, soit 4 colonnes, obligatoirement nommées "Name",
966 "Value", "Minimum", "Maximum" si les noms sont précisés. Sur chaque ligne
967 est indiqué le nom, la valeur, et éventuelement deux bornes min et max (ou
968 None si nécessaire pour une borne).
970 Seule la méthode "getvalue" est changée.
972 def __enter__(self): return self
973 def __exit__(self, exc_type, exc_val, exc_tb): return False
975 def __init__(self, Filename=None, ColNames=None, ColIndex=None, Format="Guess"):
976 ImportFromFile.__init__(self, Filename, ColNames, ColIndex, Format)
977 if self._format not in ["text/plain", "text/csv", "text/tab-separated-values"]:
978 raise ValueError("Unkown file format \"%s\""%self._format)
980 def getvalue(self, VarNames = None, HeaderNames=()):
981 "Renvoie la ou les variables demandees par la liste de leurs noms"
982 if VarNames is not None: __varnames = tuple(VarNames)
983 else: __varnames = None
985 if "Name" in self._varsline and "Value" in self._varsline and "Minimum" in self._varsline and "Maximum" in self._varsline:
986 __ftype = "NamValMinMax"
987 __dtypes = {'names' : ('Name', 'Value', 'Minimum', 'Maximum'),
988 'formats': ('S128', 'g', 'g', 'g')}
989 __usecols = (0, 1, 2, 3)
990 def __replaceNoneN( s ):
991 if s.strip() == b'None': return numpy.NINF
993 def __replaceNoneP( s ):
994 if s.strip() == b'None': return numpy.PINF
996 __converters = {2: __replaceNoneN, 3: __replaceNoneP}
997 elif "Name" in self._varsline and "Value" in self._varsline and ("Minimum" not in self._varsline or "Maximum" not in self._varsline):
999 __dtypes = {'names' : ('Name', 'Value'),
1000 'formats': ('S128', 'g')}
1003 elif len(HeaderNames)>0 and numpy.all([kw in self._varsline for kw in HeaderNames]):
1004 __ftype = "NamLotOfVals"
1005 __dtypes = {'names' : HeaderNames,
1006 'formats': tuple(['S128',]+['g']*(len(HeaderNames)-1))}
1007 __usecols = tuple(range(len(HeaderNames)))
1008 def __replaceNone( s ):
1009 if s.strip() == b'None': return numpy.NAN
1011 __converters = dict()
1012 for i in range(1,len(HeaderNames)):
1013 __converters[i] = __replaceNone
1015 raise ValueError("Can not find names of columns for initial values. Wrong first line is:\n \"%s\""%__firstline)
1017 if self._format == "text/plain":
1018 __content = numpy.loadtxt(self._filename, dtype = __dtypes, usecols = __usecols, skiprows = self._skiprows, converters = __converters)
1019 elif self._format in ["text/csv", "text/tab-separated-values"]:
1020 __content = numpy.loadtxt(self._filename, dtype = __dtypes, usecols = __usecols, skiprows = self._skiprows, converters = __converters, delimiter = self._delimiter)
1022 raise ValueError("Unkown file format \"%s\""%self._format)
1024 __names, __thevalue, __bounds = [], [], []
1025 for sub in __content:
1026 if len(__usecols) == 4:
1027 na, va, mi, ma = sub
1028 if numpy.isneginf(mi): mi = None # Réattribue les variables None
1029 elif numpy.isnan(mi): mi = None # Réattribue les variables None
1030 if numpy.isposinf(ma): ma = None # Réattribue les variables None
1031 elif numpy.isnan(ma): ma = None # Réattribue les variables None
1032 elif len(__usecols) == 2 and __ftype == "NamVal":
1038 for i, v in enumerate(nsub[1:]):
1039 if numpy.isnan(v): nsub[i+1] = None
1043 if (__varnames is None or na in __varnames) and (na not in __names):
1044 # Ne stocke que la premiere occurence d'une variable
1046 __thevalue.append(va)
1047 __bounds.append((mi,ma))
1049 __names = tuple(__names)
1050 __thevalue = numpy.array(__thevalue)
1051 __bounds = tuple(__bounds)
1053 return (__names, __thevalue, __bounds)
1055 # ==============================================================================
1056 class EficasGUI(object):
1058 Lancement autonome de l'interface EFICAS/ADAO
1060 def __init__(self, __addpath = None):
1061 # Chemin pour l'installation (ordre important)
1063 self.__path_settings_ok = False
1065 if "EFICAS_ROOT" in os.environ:
1066 __EFICAS_ROOT = os.environ["EFICAS_ROOT"]
1069 self.__msg += "\nKeyError:\n"+\
1070 " the required environment variable EFICAS_ROOT is unknown.\n"+\
1071 " You have either to be in SALOME environment, or to set\n"+\
1072 " this variable in your environment to the right path \"<...>\"\n"+\
1073 " to find an installed EFICAS application. For example:\n"+\
1074 " EFICAS_ROOT=\"<...>\" command\n"
1078 __path_ok = True and __path_ok
1080 self.__msg += "\nImportError:\n"+\
1081 " the required ADAO library can not be found to be imported.\n"+\
1082 " You have either to be in ADAO environment, or to be in SALOME\n"+\
1083 " environment, or to set manually in your Python 3 environment the\n"+\
1084 " right path \"<...>\" to find an installed ADAO application. For\n"+\
1086 " PYTHONPATH=\"<...>:${PYTHONPATH}\" command\n"
1090 __path_ok = True and __path_ok
1092 self.__msg += "\nImportError:\n"+\
1093 " the required PyQt5 library can not be found to be imported.\n"+\
1094 " You have either to have a raisonable up-to-date Python 3\n"+\
1095 " installation (less than 5 years), or to be in SALOME environment.\n"
1099 self.__msg += "\nWarning:\n"+\
1100 " It seems you have some troubles with your installation.\n"+\
1101 " Be aware that some other errors may exist, that are not\n"+\
1102 " explained as above, like some incomplete or obsolete\n"+\
1103 " Python 3, or incomplete module installation.\n"+\
1105 " Please correct the above error(s) before launching the\n"+\
1106 " standalone EFICAS/ADAO interface.\n"
1107 logging.debug("Some of the ADAO/EFICAS/QT5 paths have not been found")
1108 self.__path_settings_ok = False
1110 logging.debug("All the ADAO/EFICAS/QT5 paths have been found")
1111 self.__path_settings_ok = True
1113 if self.__path_settings_ok:
1114 sys.path.insert(0,__EFICAS_ROOT)
1115 sys.path.insert(0,os.path.join(adao.adao_py_dir,"daEficas"))
1116 if __addpath is not None and os.path.exists(os.path.abspath(__addpath)):
1117 sys.path.insert(0,os.path.abspath(__addpath))
1118 logging.debug("All the paths have been correctly set up")
1121 logging.debug("Errors in path settings have been found")
1124 if self.__path_settings_ok:
1125 logging.debug("Launching standalone EFICAS/ADAO interface...")
1126 from daEficas import prefs
1127 from InterfaceQT4 import eficas_go
1128 eficas_go.lanceEficas(code=prefs.code)
1130 logging.debug("Can not launch standalone EFICAS/ADAO interface for path errors.")
1132 # ==============================================================================
1133 if __name__ == "__main__":
1134 print('\n AUTODIAGNOSTIC\n')