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
627 self.__filenspace = __import__(__basename, globals(), locals(), [])
629 self.__filenspace = ""
630 with open(__filename,'r') as fid:
631 self.__filestring = fid.read()
632 def getvalue(self, __varname=None, __synonym=None ):
633 "Renvoie la variable demandee par son nom ou son synonyme"
634 if __varname is None:
635 raise ValueError("The name of the variable to be read has to be specified. Please check the content of the file and the syntax.")
636 if not hasattr(self.__filenspace, __varname):
637 if __synonym is None:
638 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))
639 elif not hasattr(self.__filenspace, __synonym):
640 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))
642 return getattr(self.__filenspace, __synonym)
644 return getattr(self.__filenspace, __varname)
646 "Renvoie le script complet"
647 return self.__filestring
649 # ==============================================================================
650 class ImportDetector(object):
652 Détection des caractéristiques de fichiers ou objets en entrée
655 "__url", "__usr", "__root", "__end")
656 def __enter__(self): return self
657 def __exit__(self, exc_type, exc_val, exc_tb): return False
659 def __init__(self, __url, UserMime=""):
661 raise ValueError("The name or url of the file object has to be specified.")
663 self.__url = __url.decode()
665 self.__url = str(__url)
666 if UserMime is bytes:
667 self.__usr = UserMime.decode().lower()
669 self.__usr = str(UserMime).lower()
670 (self.__root, self.__end) = os.path.splitext(self.__url)
672 mimetypes.add_type('application/numpy.npy', '.npy')
673 mimetypes.add_type('application/numpy.npz', '.npz')
674 mimetypes.add_type('application/dymola.sdf', '.sdf')
675 if sys.platform.startswith("win"):
676 mimetypes.add_type('text/plain', '.txt')
677 mimetypes.add_type('text/csv', '.csv')
678 mimetypes.add_type('text/tab-separated-values', '.tsv')
682 def is_local_file(self):
683 if os.path.isfile(os.path.realpath(self.__url)):
687 def is_not_local_file(self):
688 if not os.path.isfile(os.path.realpath(self.__url)):
692 def raise_error_if_not_local_file(self):
693 if not os.path.isfile(os.path.realpath(self.__url)):
694 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))
698 # Directory related tests
699 # -----------------------
700 def is_local_dir(self):
701 if os.path.isdir(self.__url):
705 def is_not_local_dir(self):
706 if not os.path.isdir(self.__url):
710 def raise_error_if_not_local_dir(self):
711 if not os.path.isdir(self.__url):
712 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))
716 # Mime related functions
717 # ------------------------
718 def get_standard_mime(self):
719 (__mtype, __encoding) = mimetypes.guess_type(self.__url, strict=False)
721 def get_user_mime(self):
722 __fake = "fake."+self.__usr.lower()
723 (__mtype, __encoding) = mimetypes.guess_type(__fake, strict=False)
725 def get_comprehensive_mime(self):
726 if self.get_standard_mime() is not None:
727 return self.get_standard_mime()
728 elif self.get_user_mime() is not None:
729 return self.get_user_mime()
733 # Name related functions
734 # ----------------------
735 def get_user_name(self):
737 def get_absolute_name(self):
738 return os.path.abspath(os.path.realpath(self.__url))
739 def get_extension(self):
742 class ImportFromFile(object):
744 Obtention de variables disrétisées en 1D, définies par une ou des variables
745 nommées, et sous la forme d'une série de points éventuellement indexés. La
746 lecture d'un fichier au format spécifié (ou intuité) permet de charger ces
748 - des fichiers textes en colonnes de type TXT, CSV, TSV...
749 - des fichiers de données binaires NPY, NPZ, SDF...
750 La lecture du fichier complet ne se fait que si nécessaire, pour assurer la
751 performance tout en disposant de l'interprétation du contenu. Les fichiers
752 textes doivent présenter en première ligne (hors commentaire ou ligne vide)
753 les noms des variables de colonnes. Les commentaires commencent par un "#".
756 "_filename", "_colnames", "_colindex", "_varsline", "_format",
757 "_delimiter", "_skiprows", "__url", "__filestring", "__header",
758 "__allowvoid", "__binaryformats", "__supportedformats")
759 def __enter__(self): return self
760 def __exit__(self, exc_type, exc_val, exc_tb): return False
762 def __init__(self, Filename=None, ColNames=None, ColIndex=None, Format="Guess", AllowVoidNameList=True):
764 Verifie l'existence et les informations de définition du fichier. Les
765 noms de colonnes ou de variables sont ignorées si le format ne permet
768 - Filename : nom du fichier
769 - ColNames : noms de la ou des colonnes/variables à lire
770 - ColIndex : nom unique de la colonne/variable servant d'index
771 - Format : format du fichier et/ou des données inclues
772 - AllowVoidNameList : permet, si la liste de noms est vide, de
773 prendre par défaut toutes les colonnes
775 self.__binaryformats =(
776 "application/numpy.npy",
777 "application/numpy.npz",
778 "application/dymola.sdf",
780 self.__url = ImportDetector( Filename, Format)
781 self.__url.raise_error_if_not_local_file()
782 self._filename = self.__url.get_absolute_name()
783 PlatformInfo.checkFileNameConformity( self._filename )
785 self._format = self.__url.get_comprehensive_mime()
787 self.__header, self._varsline, self._skiprows = self.__getentete()
789 if self._format == "text/csv" or Format.upper() == "CSV":
790 self._format = "text/csv"
791 self.__filestring = "".join(self.__header)
792 if self.__filestring.count(",") > 1:
793 self._delimiter = ","
794 elif self.__filestring.count(";") > 1:
795 self._delimiter = ";"
797 self._delimiter = None
798 elif self._format == "text/tab-separated-values" or Format.upper() == "TSV":
799 self._format = "text/tab-separated-values"
800 self._delimiter = "\t"
802 self._delimiter = None
804 if ColNames is not None: self._colnames = tuple(ColNames)
805 else: self._colnames = None
807 if ColIndex is not None: self._colindex = str(ColIndex)
808 else: self._colindex = None
810 self.__allowvoid = bool(AllowVoidNameList)
812 def __getentete(self, __nblines = 3):
813 "Lit l'entête du fichier pour trouver la définition des variables"
814 # La première ligne non vide non commentée est toujours considérée
815 # porter les labels de colonne, donc pas des valeurs
816 __header, __varsline, __skiprows = [], "", 1
817 if self._format in self.__binaryformats:
820 with open(self._filename,'r') as fid:
821 __line = fid.readline().strip()
822 while "#" in __line or len(__line) < 1:
823 __header.append(__line)
825 __line = fid.readline().strip()
827 for i in range(max(0,__nblines)):
828 __header.append(fid.readline())
829 return (__header, __varsline, __skiprows)
831 def __getindices(self, __colnames, __colindex, __delimiter=None ):
832 "Indices de colonnes correspondants à l'index et aux variables"
833 if __delimiter is None:
834 __varserie = self._varsline.strip('#').strip().split()
836 __varserie = self._varsline.strip('#').strip().split(str(__delimiter))
838 if __colnames is not None:
840 __colnames = tuple(__colnames)
842 for i, n in enumerate(__varserie):
843 if v == n: __usecols.append(i)
844 __usecols = tuple(__usecols)
845 if len(__usecols) == 0:
849 raise ValueError("Can not found any column corresponding to the required names %s"%(__colnames,))
853 if __colindex is not None:
855 __colindex = str(__colindex)
856 for i, n in enumerate(__varserie):
857 if __colindex == n: __useindex = i
861 return (__usecols, __useindex)
863 def getsupported(self):
864 self.__supportedformats = {}
865 self.__supportedformats["text/plain"] = True
866 self.__supportedformats["text/csv"] = True
867 self.__supportedformats["text/tab-separated-values"] = True
868 self.__supportedformats["application/numpy.npy"] = True
869 self.__supportedformats["application/numpy.npz"] = True
870 self.__supportedformats["application/dymola.sdf"] = PlatformInfo.has_sdf
871 return self.__supportedformats
873 def getvalue(self, ColNames=None, ColIndex=None ):
874 "Renvoie la ou les variables demandees par la liste de leurs noms"
875 # Uniquement si mise à jour
876 if ColNames is not None: self._colnames = tuple(ColNames)
877 if ColIndex is not None: self._colindex = str(ColIndex)
880 if self._format == "application/numpy.npy":
881 __columns = numpy.load(self._filename)
883 elif self._format == "application/numpy.npz":
885 with numpy.load(self._filename) as __allcolumns:
886 if self._colnames is None:
887 self._colnames = __allcolumns.files
888 for nom in self._colnames: # Si une variable demandée n'existe pas
889 if nom not in __allcolumns.files:
890 self._colnames = tuple( __allcolumns.files )
891 for nom in self._colnames:
892 if nom in __allcolumns.files:
893 if __columns is not None:
894 # Attention : toutes les variables doivent avoir la même taille
895 __columns = numpy.vstack((__columns, numpy.reshape(__allcolumns[nom], (1,-1))))
898 __columns = numpy.reshape(__allcolumns[nom], (1,-1))
899 if self._colindex is not None and self._colindex in __allcolumns.files:
900 __index = numpy.array(numpy.reshape(__allcolumns[self._colindex], (1,-1)), dtype=bytes)
901 elif self._format == "text/plain":
902 __usecols, __useindex = self.__getindices(self._colnames, self._colindex)
903 __columns = numpy.loadtxt(self._filename, usecols = __usecols, skiprows=self._skiprows)
904 if __useindex is not None:
905 __index = numpy.loadtxt(self._filename, dtype = bytes, usecols = (__useindex,), skiprows=self._skiprows)
906 if __usecols is None: # Si une variable demandée n'existe pas
907 self._colnames = None
909 elif self._format == "application/dymola.sdf" and PlatformInfo.has_sdf:
911 __content = sdf.load(self._filename)
913 if self._colnames is None:
914 self._colnames = [__content.datasets[i].name for i in range(len(__content.datasets))]
915 for nom in self._colnames:
917 if __columns is not None:
918 # Attention : toutes les variables doivent avoir la même taille
919 __columns = numpy.vstack((__columns, numpy.reshape(__content[nom].data, (1,-1))))
922 __columns = numpy.reshape(__content[nom].data, (1,-1))
923 if self._colindex is not None and self._colindex in __content:
924 __index = __content[self._colindex].data
926 elif self._format == "text/csv":
927 __usecols, __useindex = self.__getindices(self._colnames, self._colindex, self._delimiter)
928 __columns = numpy.loadtxt(self._filename, usecols = __usecols, delimiter = self._delimiter, skiprows=self._skiprows)
929 if __useindex is not None:
930 __index = numpy.loadtxt(self._filename, dtype = bytes, usecols = (__useindex,), delimiter = self._delimiter, skiprows=self._skiprows)
931 if __usecols is None: # Si une variable demandée n'existe pas
932 self._colnames = None
934 elif self._format == "text/tab-separated-values":
935 __usecols, __useindex = self.__getindices(self._colnames, self._colindex, self._delimiter)
936 __columns = numpy.loadtxt(self._filename, usecols = __usecols, delimiter = self._delimiter, skiprows=self._skiprows)
937 if __useindex is not None:
938 __index = numpy.loadtxt(self._filename, dtype = bytes, usecols = (__useindex,), delimiter = self._delimiter, skiprows=self._skiprows)
939 if __usecols is None: # Si une variable demandée n'existe pas
940 self._colnames = None
942 raise ValueError("Unkown file format \"%s\" or no reader available"%self._format)
943 if __columns is None: __columns = ()
947 return value.decode()
950 if __index is not None:
951 __index = tuple([toString(v) for v in __index])
953 return (self._colnames, __columns, self._colindex, __index)
956 "Renvoie le fichier texte complet"
957 if self._format in self.__binaryformats:
960 with open(self._filename,'r') as fid:
966 class ImportScalarLinesFromFile(ImportFromFile):
968 Importation de fichier contenant des variables scalaires nommées. Le
969 fichier comporte soit 2, soit 4 colonnes, obligatoirement nommées "Name",
970 "Value", "Minimum", "Maximum" si les noms sont précisés. Sur chaque ligne
971 est indiqué le nom, la valeur, et éventuelement deux bornes min et max (ou
972 None si nécessaire pour une borne).
974 Seule la méthode "getvalue" est changée.
976 def __enter__(self): return self
977 def __exit__(self, exc_type, exc_val, exc_tb): return False
979 def __init__(self, Filename=None, ColNames=None, ColIndex=None, Format="Guess"):
980 ImportFromFile.__init__(self, Filename, ColNames, ColIndex, Format)
981 if self._format not in ["text/plain", "text/csv", "text/tab-separated-values"]:
982 raise ValueError("Unkown file format \"%s\""%self._format)
984 def getvalue(self, VarNames = None, HeaderNames=()):
985 "Renvoie la ou les variables demandees par la liste de leurs noms"
986 if VarNames is not None: __varnames = tuple(VarNames)
987 else: __varnames = None
989 if "Name" in self._varsline and "Value" in self._varsline and "Minimum" in self._varsline and "Maximum" in self._varsline:
990 __ftype = "NamValMinMax"
991 __dtypes = {'names' : ('Name', 'Value', 'Minimum', 'Maximum'),
992 'formats': ('S128', 'g', 'g', 'g')}
993 __usecols = (0, 1, 2, 3)
994 def __replaceNoneN( s ):
995 if s.strip() == b'None': return numpy.NINF
997 def __replaceNoneP( s ):
998 if s.strip() == b'None': return numpy.PINF
1000 __converters = {2: __replaceNoneN, 3: __replaceNoneP}
1001 elif "Name" in self._varsline and "Value" in self._varsline and ("Minimum" not in self._varsline or "Maximum" not in self._varsline):
1003 __dtypes = {'names' : ('Name', 'Value'),
1004 'formats': ('S128', 'g')}
1007 elif len(HeaderNames)>0 and numpy.all([kw in self._varsline for kw in HeaderNames]):
1008 __ftype = "NamLotOfVals"
1009 __dtypes = {'names' : HeaderNames,
1010 'formats': tuple(['S128',]+['g']*(len(HeaderNames)-1))}
1011 __usecols = tuple(range(len(HeaderNames)))
1012 def __replaceNone( s ):
1013 if s.strip() == b'None': return numpy.NAN
1015 __converters = dict()
1016 for i in range(1,len(HeaderNames)):
1017 __converters[i] = __replaceNone
1019 raise ValueError("Can not find names of columns for initial values. Wrong first line is:\n \"%s\""%__firstline)
1021 if self._format == "text/plain":
1022 __content = numpy.loadtxt(self._filename, dtype = __dtypes, usecols = __usecols, skiprows = self._skiprows, converters = __converters)
1023 elif self._format in ["text/csv", "text/tab-separated-values"]:
1024 __content = numpy.loadtxt(self._filename, dtype = __dtypes, usecols = __usecols, skiprows = self._skiprows, converters = __converters, delimiter = self._delimiter)
1026 raise ValueError("Unkown file format \"%s\""%self._format)
1028 __names, __thevalue, __bounds = [], [], []
1029 for sub in __content:
1030 if len(__usecols) == 4:
1031 na, va, mi, ma = sub
1032 if numpy.isneginf(mi): mi = None # Réattribue les variables None
1033 elif numpy.isnan(mi): mi = None # Réattribue les variables None
1034 if numpy.isposinf(ma): ma = None # Réattribue les variables None
1035 elif numpy.isnan(ma): ma = None # Réattribue les variables None
1036 elif len(__usecols) == 2 and __ftype == "NamVal":
1042 for i, v in enumerate(nsub[1:]):
1043 if numpy.isnan(v): nsub[i+1] = None
1047 if (__varnames is None or na in __varnames) and (na not in __names):
1048 # Ne stocke que la premiere occurence d'une variable
1050 __thevalue.append(va)
1051 __bounds.append((mi,ma))
1053 __names = tuple(__names)
1054 __thevalue = numpy.array(__thevalue)
1055 __bounds = tuple(__bounds)
1057 return (__names, __thevalue, __bounds)
1059 # ==============================================================================
1060 class EficasGUI(object):
1062 Lancement autonome de l'interface EFICAS/ADAO
1064 def __init__(self, __addpath = None):
1065 # Chemin pour l'installation (ordre important)
1067 self.__path_settings_ok = False
1069 if "EFICAS_ROOT" in os.environ:
1070 __EFICAS_ROOT = os.environ["EFICAS_ROOT"]
1073 self.__msg += "\nKeyError:\n"+\
1074 " the required environment variable EFICAS_ROOT is unknown.\n"+\
1075 " You have either to be in SALOME environment, or to set\n"+\
1076 " this variable in your environment to the right path \"<...>\"\n"+\
1077 " to find an installed EFICAS application. For example:\n"+\
1078 " EFICAS_ROOT=\"<...>\" command\n"
1082 __path_ok = True and __path_ok
1084 self.__msg += "\nImportError:\n"+\
1085 " the required ADAO library can not be found to be imported.\n"+\
1086 " You have either to be in ADAO environment, or to be in SALOME\n"+\
1087 " environment, or to set manually in your Python 3 environment the\n"+\
1088 " right path \"<...>\" to find an installed ADAO application. For\n"+\
1090 " PYTHONPATH=\"<...>:${PYTHONPATH}\" command\n"
1094 __path_ok = True and __path_ok
1096 self.__msg += "\nImportError:\n"+\
1097 " the required PyQt5 library can not be found to be imported.\n"+\
1098 " You have either to have a raisonable up-to-date Python 3\n"+\
1099 " installation (less than 5 years), or to be in SALOME environment.\n"
1103 self.__msg += "\nWarning:\n"+\
1104 " It seems you have some troubles with your installation.\n"+\
1105 " Be aware that some other errors may exist, that are not\n"+\
1106 " explained as above, like some incomplete or obsolete\n"+\
1107 " Python 3, or incomplete module installation.\n"+\
1109 " Please correct the above error(s) before launching the\n"+\
1110 " standalone EFICAS/ADAO interface.\n"
1111 logging.debug("Some of the ADAO/EFICAS/QT5 paths have not been found")
1112 self.__path_settings_ok = False
1114 logging.debug("All the ADAO/EFICAS/QT5 paths have been found")
1115 self.__path_settings_ok = True
1117 if self.__path_settings_ok:
1118 sys.path.insert(0,__EFICAS_ROOT)
1119 sys.path.insert(0,os.path.join(adao.adao_py_dir,"daEficas"))
1120 if __addpath is not None and os.path.exists(os.path.abspath(__addpath)):
1121 sys.path.insert(0,os.path.abspath(__addpath))
1122 logging.debug("All the paths have been correctly set up")
1125 logging.debug("Errors in path settings have been found")
1128 if self.__path_settings_ok:
1129 logging.debug("Launching standalone EFICAS/ADAO interface...")
1130 from daEficas import prefs
1131 from InterfaceQT4 import eficas_go
1132 eficas_go.lanceEficas(code=prefs.code)
1134 logging.debug("Can not launch standalone EFICAS/ADAO interface for path errors.")
1136 # ==============================================================================
1137 if __name__ == "__main__":
1138 print('\n AUTODIAGNOSTIC\n')