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 with open(__filename,'r') as fid:
628 self.__filestring = fid.read()
629 def getvalue(self, __varname=None, __synonym=None ):
630 "Renvoie la variable demandee par son nom ou son synonyme"
631 if __varname is None:
632 raise ValueError("The name of the variable to be read has to be specified. Please check the content of the file and the syntax.")
633 if not hasattr(self.__filenspace, __varname):
634 if __synonym is None:
635 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))
636 elif not hasattr(self.__filenspace, __synonym):
637 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))
639 return getattr(self.__filenspace, __synonym)
641 return getattr(self.__filenspace, __varname)
643 "Renvoie le script complet"
644 return self.__filestring
646 # ==============================================================================
647 class ImportDetector(object):
649 Détection des caractéristiques de fichiers ou objets en entrée
652 "__url", "__usr", "__root", "__end")
653 def __enter__(self): return self
654 def __exit__(self, exc_type, exc_val, exc_tb): return False
656 def __init__(self, __url, UserMime=""):
658 raise ValueError("The name or url of the file object has to be specified.")
660 self.__url = __url.decode()
662 self.__url = str(__url)
663 if UserMime is bytes:
664 self.__usr = UserMime.decode().lower()
666 self.__usr = str(UserMime).lower()
667 (self.__root, self.__end) = os.path.splitext(self.__url)
669 mimetypes.add_type('application/numpy.npy', '.npy')
670 mimetypes.add_type('application/numpy.npz', '.npz')
671 mimetypes.add_type('application/dymola.sdf', '.sdf')
672 if sys.platform.startswith("win"):
673 mimetypes.add_type('text/plain', '.txt')
674 mimetypes.add_type('text/csv', '.csv')
675 mimetypes.add_type('text/tab-separated-values', '.tsv')
679 def is_local_file(self):
680 if os.path.isfile(os.path.realpath(self.__url)):
684 def is_not_local_file(self):
685 if not os.path.isfile(os.path.realpath(self.__url)):
689 def raise_error_if_not_local_file(self):
690 if not os.path.isfile(os.path.realpath(self.__url)):
691 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))
695 # Directory related tests
696 # -----------------------
697 def is_local_dir(self):
698 if os.path.isdir(self.__url):
702 def is_not_local_dir(self):
703 if not os.path.isdir(self.__url):
707 def raise_error_if_not_local_dir(self):
708 if not os.path.isdir(self.__url):
709 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))
713 # Mime related functions
714 # ------------------------
715 def get_standard_mime(self):
716 (__mtype, __encoding) = mimetypes.guess_type(self.__url, strict=False)
718 def get_user_mime(self):
719 __fake = "fake."+self.__usr.lower()
720 (__mtype, __encoding) = mimetypes.guess_type(__fake, strict=False)
722 def get_comprehensive_mime(self):
723 if self.get_standard_mime() is not None:
724 return self.get_standard_mime()
725 elif self.get_user_mime() is not None:
726 return self.get_user_mime()
730 # Name related functions
731 # ----------------------
732 def get_user_name(self):
734 def get_absolute_name(self):
735 return os.path.abspath(os.path.realpath(self.__url))
736 def get_extension(self):
739 class ImportFromFile(object):
741 Obtention de variables disrétisées en 1D, définies par une ou des variables
742 nommées, et sous la forme d'une série de points éventuellement indexés. La
743 lecture d'un fichier au format spécifié (ou intuité) permet de charger ces
745 - des fichiers textes en colonnes de type TXT, CSV, TSV...
746 - des fichiers de données binaires NPY, NPZ, SDF...
747 La lecture du fichier complet ne se fait que si nécessaire, pour assurer la
748 performance tout en disposant de l'interprétation du contenu. Les fichiers
749 textes doivent présenter en première ligne (hors commentaire ou ligne vide)
750 les noms des variables de colonnes. Les commentaires commencent par un "#".
753 "_filename", "_colnames", "_colindex", "_varsline", "_format",
754 "_delimiter", "_skiprows", "__url", "__filestring", "__header",
755 "__allowvoid", "__binaryformats", "__supportedformats")
756 def __enter__(self): return self
757 def __exit__(self, exc_type, exc_val, exc_tb): return False
759 def __init__(self, Filename=None, ColNames=None, ColIndex=None, Format="Guess", AllowVoidNameList=True):
761 Verifie l'existence et les informations de définition du fichier. Les
762 noms de colonnes ou de variables sont ignorées si le format ne permet
765 - Filename : nom du fichier
766 - ColNames : noms de la ou des colonnes/variables à lire
767 - ColIndex : nom unique de la colonne/variable servant d'index
768 - Format : format du fichier et/ou des données inclues
769 - AllowVoidNameList : permet, si la liste de noms est vide, de
770 prendre par défaut toutes les colonnes
772 self.__binaryformats =(
773 "application/numpy.npy",
774 "application/numpy.npz",
775 "application/dymola.sdf",
777 self.__url = ImportDetector( Filename, Format)
778 self.__url.raise_error_if_not_local_file()
779 self._filename = self.__url.get_absolute_name()
780 PlatformInfo.checkFileNameConformity( self._filename )
782 self._format = self.__url.get_comprehensive_mime()
784 self.__header, self._varsline, self._skiprows = self.__getentete()
786 if self._format == "text/csv" or Format.upper() == "CSV":
787 self._format = "text/csv"
788 self.__filestring = "".join(self.__header)
789 if self.__filestring.count(",") > 1:
790 self._delimiter = ","
791 elif self.__filestring.count(";") > 1:
792 self._delimiter = ";"
794 self._delimiter = None
795 elif self._format == "text/tab-separated-values" or Format.upper() == "TSV":
796 self._format = "text/tab-separated-values"
797 self._delimiter = "\t"
799 self._delimiter = None
801 if ColNames is not None: self._colnames = tuple(ColNames)
802 else: self._colnames = None
804 if ColIndex is not None: self._colindex = str(ColIndex)
805 else: self._colindex = None
807 self.__allowvoid = bool(AllowVoidNameList)
809 def __getentete(self, __nblines = 3):
810 "Lit l'entête du fichier pour trouver la définition des variables"
811 # La première ligne non vide non commentée est toujours considérée
812 # porter les labels de colonne, donc pas des valeurs
813 __header, __varsline, __skiprows = [], "", 1
814 if self._format in self.__binaryformats:
817 with open(self._filename,'r') as fid:
818 __line = fid.readline().strip()
819 while "#" in __line or len(__line) < 1:
820 __header.append(__line)
822 __line = fid.readline().strip()
824 for i in range(max(0,__nblines)):
825 __header.append(fid.readline())
826 return (__header, __varsline, __skiprows)
828 def __getindices(self, __colnames, __colindex, __delimiter=None ):
829 "Indices de colonnes correspondants à l'index et aux variables"
830 if __delimiter is None:
831 __varserie = self._varsline.strip('#').strip().split()
833 __varserie = self._varsline.strip('#').strip().split(str(__delimiter))
835 if __colnames is not None:
837 __colnames = tuple(__colnames)
839 for i, n in enumerate(__varserie):
840 if v == n: __usecols.append(i)
841 __usecols = tuple(__usecols)
842 if len(__usecols) == 0:
846 raise ValueError("Can not found any column corresponding to the required names %s"%(__colnames,))
850 if __colindex is not None:
852 __colindex = str(__colindex)
853 for i, n in enumerate(__varserie):
854 if __colindex == n: __useindex = i
858 return (__usecols, __useindex)
860 def getsupported(self):
861 self.__supportedformats = {}
862 self.__supportedformats["text/plain"] = True
863 self.__supportedformats["text/csv"] = True
864 self.__supportedformats["text/tab-separated-values"] = True
865 self.__supportedformats["application/numpy.npy"] = True
866 self.__supportedformats["application/numpy.npz"] = True
867 self.__supportedformats["application/dymola.sdf"] = PlatformInfo.has_sdf
868 return self.__supportedformats
870 def getvalue(self, ColNames=None, ColIndex=None ):
871 "Renvoie la ou les variables demandees par la liste de leurs noms"
872 # Uniquement si mise à jour
873 if ColNames is not None: self._colnames = tuple(ColNames)
874 if ColIndex is not None: self._colindex = str(ColIndex)
877 if self._format == "application/numpy.npy":
878 __columns = numpy.load(self._filename)
880 elif self._format == "application/numpy.npz":
882 with numpy.load(self._filename) as __allcolumns:
883 if self._colnames is None:
884 self._colnames = __allcolumns.files
885 for nom in self._colnames: # Si une variable demandée n'existe pas
886 if nom not in __allcolumns.files:
887 self._colnames = tuple( __allcolumns.files )
888 for nom in self._colnames:
889 if nom in __allcolumns.files:
890 if __columns is not None:
891 # Attention : toutes les variables doivent avoir la même taille
892 __columns = numpy.vstack((__columns, numpy.reshape(__allcolumns[nom], (1,-1))))
895 __columns = numpy.reshape(__allcolumns[nom], (1,-1))
896 if self._colindex is not None and self._colindex in __allcolumns.files:
897 __index = numpy.array(numpy.reshape(__allcolumns[self._colindex], (1,-1)), dtype=bytes)
898 elif self._format == "text/plain":
899 __usecols, __useindex = self.__getindices(self._colnames, self._colindex)
900 __columns = numpy.loadtxt(self._filename, usecols = __usecols, skiprows=self._skiprows)
901 if __useindex is not None:
902 __index = numpy.loadtxt(self._filename, dtype = bytes, usecols = (__useindex,), skiprows=self._skiprows)
903 if __usecols is None: # Si une variable demandée n'existe pas
904 self._colnames = None
906 elif self._format == "application/dymola.sdf" and PlatformInfo.has_sdf:
908 __content = sdf.load(self._filename)
910 if self._colnames is None:
911 self._colnames = [__content.datasets[i].name for i in range(len(__content.datasets))]
912 for nom in self._colnames:
914 if __columns is not None:
915 # Attention : toutes les variables doivent avoir la même taille
916 __columns = numpy.vstack((__columns, numpy.reshape(__content[nom].data, (1,-1))))
919 __columns = numpy.reshape(__content[nom].data, (1,-1))
920 if self._colindex is not None and self._colindex in __content:
921 __index = __content[self._colindex].data
923 elif self._format == "text/csv":
924 __usecols, __useindex = self.__getindices(self._colnames, self._colindex, self._delimiter)
925 __columns = numpy.loadtxt(self._filename, usecols = __usecols, delimiter = self._delimiter, skiprows=self._skiprows)
926 if __useindex is not None:
927 __index = numpy.loadtxt(self._filename, dtype = bytes, usecols = (__useindex,), delimiter = self._delimiter, skiprows=self._skiprows)
928 if __usecols is None: # Si une variable demandée n'existe pas
929 self._colnames = None
931 elif self._format == "text/tab-separated-values":
932 __usecols, __useindex = self.__getindices(self._colnames, self._colindex, self._delimiter)
933 __columns = numpy.loadtxt(self._filename, usecols = __usecols, delimiter = self._delimiter, skiprows=self._skiprows)
934 if __useindex is not None:
935 __index = numpy.loadtxt(self._filename, dtype = bytes, usecols = (__useindex,), delimiter = self._delimiter, skiprows=self._skiprows)
936 if __usecols is None: # Si une variable demandée n'existe pas
937 self._colnames = None
939 raise ValueError("Unkown file format \"%s\" or no reader available"%self._format)
940 if __columns is None: __columns = ()
944 return value.decode()
947 if __index is not None:
948 __index = tuple([toString(v) for v in __index])
950 return (self._colnames, __columns, self._colindex, __index)
953 "Renvoie le fichier texte complet"
954 if self._format in self.__binaryformats:
957 with open(self._filename,'r') as fid:
963 class ImportScalarLinesFromFile(ImportFromFile):
965 Importation de fichier contenant des variables scalaires nommées. Le
966 fichier comporte soit 2, soit 4 colonnes, obligatoirement nommées "Name",
967 "Value", "Minimum", "Maximum" si les noms sont précisés. Sur chaque ligne
968 est indiqué le nom, la valeur, et éventuelement deux bornes min et max (ou
969 None si nécessaire pour une borne).
971 Seule la méthode "getvalue" est changée.
973 def __enter__(self): return self
974 def __exit__(self, exc_type, exc_val, exc_tb): return False
976 def __init__(self, Filename=None, ColNames=None, ColIndex=None, Format="Guess"):
977 ImportFromFile.__init__(self, Filename, ColNames, ColIndex, Format)
978 if self._format not in ["text/plain", "text/csv", "text/tab-separated-values"]:
979 raise ValueError("Unkown file format \"%s\""%self._format)
981 def getvalue(self, VarNames = None, HeaderNames=()):
982 "Renvoie la ou les variables demandees par la liste de leurs noms"
983 if VarNames is not None: __varnames = tuple(VarNames)
984 else: __varnames = None
986 if "Name" in self._varsline and "Value" in self._varsline and "Minimum" in self._varsline and "Maximum" in self._varsline:
987 __ftype = "NamValMinMax"
988 __dtypes = {'names' : ('Name', 'Value', 'Minimum', 'Maximum'),
989 'formats': ('S128', 'g', 'g', 'g')}
990 __usecols = (0, 1, 2, 3)
991 def __replaceNoneN( s ):
992 if s.strip() == b'None': return numpy.NINF
994 def __replaceNoneP( s ):
995 if s.strip() == b'None': return numpy.PINF
997 __converters = {2: __replaceNoneN, 3: __replaceNoneP}
998 elif "Name" in self._varsline and "Value" in self._varsline and ("Minimum" not in self._varsline or "Maximum" not in self._varsline):
1000 __dtypes = {'names' : ('Name', 'Value'),
1001 'formats': ('S128', 'g')}
1004 elif len(HeaderNames)>0 and numpy.all([kw in self._varsline for kw in HeaderNames]):
1005 __ftype = "NamLotOfVals"
1006 __dtypes = {'names' : HeaderNames,
1007 'formats': tuple(['S128',]+['g']*(len(HeaderNames)-1))}
1008 __usecols = tuple(range(len(HeaderNames)))
1009 def __replaceNone( s ):
1010 if s.strip() == b'None': return numpy.NAN
1012 __converters = dict()
1013 for i in range(1,len(HeaderNames)):
1014 __converters[i] = __replaceNone
1016 raise ValueError("Can not find names of columns for initial values. Wrong first line is:\n \"%s\""%__firstline)
1018 if self._format == "text/plain":
1019 __content = numpy.loadtxt(self._filename, dtype = __dtypes, usecols = __usecols, skiprows = self._skiprows, converters = __converters)
1020 elif self._format in ["text/csv", "text/tab-separated-values"]:
1021 __content = numpy.loadtxt(self._filename, dtype = __dtypes, usecols = __usecols, skiprows = self._skiprows, converters = __converters, delimiter = self._delimiter)
1023 raise ValueError("Unkown file format \"%s\""%self._format)
1025 __names, __thevalue, __bounds = [], [], []
1026 for sub in __content:
1027 if len(__usecols) == 4:
1028 na, va, mi, ma = sub
1029 if numpy.isneginf(mi): mi = None # Réattribue les variables None
1030 elif numpy.isnan(mi): mi = None # Réattribue les variables None
1031 if numpy.isposinf(ma): ma = None # Réattribue les variables None
1032 elif numpy.isnan(ma): ma = None # Réattribue les variables None
1033 elif len(__usecols) == 2 and __ftype == "NamVal":
1039 for i, v in enumerate(nsub[1:]):
1040 if numpy.isnan(v): nsub[i+1] = None
1044 if (__varnames is None or na in __varnames) and (na not in __names):
1045 # Ne stocke que la premiere occurence d'une variable
1047 __thevalue.append(va)
1048 __bounds.append((mi,ma))
1050 __names = tuple(__names)
1051 __thevalue = numpy.array(__thevalue)
1052 __bounds = tuple(__bounds)
1054 return (__names, __thevalue, __bounds)
1056 # ==============================================================================
1057 class EficasGUI(object):
1059 Lancement autonome de l'interface EFICAS/ADAO
1061 def __init__(self, __addpath = None):
1062 # Chemin pour l'installation (ordre important)
1064 self.__path_settings_ok = False
1066 if "EFICAS_ROOT" in os.environ:
1067 __EFICAS_ROOT = os.environ["EFICAS_ROOT"]
1070 self.__msg += "\nKeyError:\n"+\
1071 " the required environment variable EFICAS_ROOT is unknown.\n"+\
1072 " You have either to be in SALOME environment, or to set\n"+\
1073 " this variable in your environment to the right path \"<...>\"\n"+\
1074 " to find an installed EFICAS application. For example:\n"+\
1075 " EFICAS_ROOT=\"<...>\" command\n"
1079 __path_ok = True and __path_ok
1081 self.__msg += "\nImportError:\n"+\
1082 " the required ADAO library can not be found to be imported.\n"+\
1083 " You have either to be in ADAO environment, or to be in SALOME\n"+\
1084 " environment, or to set manually in your Python 3 environment the\n"+\
1085 " right path \"<...>\" to find an installed ADAO application. For\n"+\
1087 " PYTHONPATH=\"<...>:${PYTHONPATH}\" command\n"
1091 __path_ok = True and __path_ok
1093 self.__msg += "\nImportError:\n"+\
1094 " the required PyQt5 library can not be found to be imported.\n"+\
1095 " You have either to have a raisonable up-to-date Python 3\n"+\
1096 " installation (less than 5 years), or to be in SALOME environment.\n"
1100 self.__msg += "\nWarning:\n"+\
1101 " It seems you have some troubles with your installation.\n"+\
1102 " Be aware that some other errors may exist, that are not\n"+\
1103 " explained as above, like some incomplete or obsolete\n"+\
1104 " Python 3, or incomplete module installation.\n"+\
1106 " Please correct the above error(s) before launching the\n"+\
1107 " standalone EFICAS/ADAO interface.\n"
1108 logging.debug("Some of the ADAO/EFICAS/QT5 paths have not been found")
1109 self.__path_settings_ok = False
1111 logging.debug("All the ADAO/EFICAS/QT5 paths have been found")
1112 self.__path_settings_ok = True
1114 if self.__path_settings_ok:
1115 sys.path.insert(0,__EFICAS_ROOT)
1116 sys.path.insert(0,os.path.join(adao.adao_py_dir,"daEficas"))
1117 if __addpath is not None and os.path.exists(os.path.abspath(__addpath)):
1118 sys.path.insert(0,os.path.abspath(__addpath))
1119 logging.debug("All the paths have been correctly set up")
1122 logging.debug("Errors in path settings have been found")
1125 if self.__path_settings_ok:
1126 logging.debug("Launching standalone EFICAS/ADAO interface...")
1127 from daEficas import prefs
1128 from InterfaceQT4 import eficas_go
1129 eficas_go.lanceEficas(code=prefs.code)
1131 logging.debug("Can not launch standalone EFICAS/ADAO interface for path errors.")
1133 # ==============================================================================
1134 if __name__ == "__main__":
1135 print('\n AUTODIAGNOSTIC\n')