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 if __upa is not None and len(__upa)>0:
63 self._lineSerie.append("%s.execute()"%(self._objname,))
64 self._lineSerie.append(__upa)
65 def _addLine(self, line=""):
66 "Ajoute un enregistrement individuel"
67 self._lineSerie.append(line)
68 def _get_objname(self):
70 def dump(self, __filename=None, __upa=None):
71 "Restitution normalisée des commandes"
73 __text = "\n".join(self._lineSerie)
75 if __filename is not None:
76 __file = os.path.abspath(__filename)
77 __fid = open(__file,"w")
81 def load(self, __filename=None, __content=None, __object=None):
82 "Chargement normalisé des commandes"
83 if __filename is not None and os.path.exists(__filename):
84 self._content = open(__filename, 'r').read()
85 elif __content is not None and type(__content) is str:
86 self._content = __content
87 elif __object is not None and type(__object) is dict:
88 self._object = copy.deepcopy(__object)
90 pass # use "self._content" from initialization
91 __commands = self._extract(self._content, self._object)
94 class _TUIViewer(GenericCaseViewer):
96 Établissement des commandes d'un cas ADAO TUI (Cas<->TUI)
98 def __init__(self, __name="", __objname="case", __content=None, __object=None):
99 "Initialisation et enregistrement de l'entete"
100 GenericCaseViewer.__init__(self, __name, __objname, __content, __object)
101 self._addLine("# -*- coding: utf-8 -*-")
102 self._addLine("#\n# Python script using ADAO TUI\n#")
103 self._addLine("from numpy import array, matrix")
104 self._addLine("from adao import adaoBuilder")
105 self._addLine("%s = adaoBuilder.New('%s')"%(self._objname, self._name))
106 if self._content is not None:
107 for command in self._content:
108 self._append(*command)
109 def _append(self, __command=None, __keys=None, __local=None, __pre=None, __switchoff=False):
110 "Transformation d'une commande individuelle en un enregistrement"
111 if __command is not None and __keys is not None and __local is not None:
113 if __pre is not None:
114 __text += "%s = "%__pre
115 __text += "%s.%s( "%(self._objname,str(__command))
116 if "self" in __keys: __keys.remove("self")
117 if __command not in ("set","get") and "Concept" in __keys: __keys.remove("Concept")
120 if __v is None: continue
121 if k == "Checked" and not __v: continue
122 if k == "Stored" and not __v: continue
123 if k == "ColMajor" and not __v: continue
124 if k == "InputFunctionAsMulti" and not __v: continue
125 if k == "nextStep" and not __v: continue
126 if k == "AvoidRC" and __v: continue
127 if k == "noDetails": continue
128 if isinstance(__v,Persistence.Persistence): __v = __v.values()
129 if callable(__v): __text = self._missing%__v.__name__+__text
130 if isinstance(__v,dict):
131 for val in __v.values():
132 if callable(val): __text = self._missing%val.__name__+__text
133 numpy.set_printoptions(precision=15,threshold=1000000,linewidth=1000*15)
134 __text += "%s=%s, "%(k,repr(__v))
135 numpy.set_printoptions(precision=8,threshold=1000,linewidth=75)
138 self._addLine(__text)
139 def _extract(self, __multilines="", __object=None):
140 "Transformation d'enregistrement(s) en commande(s) individuelle(s)"
143 __multilines = __multilines.replace("\r\n","\n")
144 for line in __multilines.split("\n"):
145 if "adaoBuilder.New" in line and "=" in line:
146 self._objname = line.split("=")[0].strip()
148 logging.debug("TUI Extracting commands of '%s' object..."%(self._objname,))
152 if self._objname+".set" in line:
153 __commands.append( line.replace(self._objname+".","",1) )
154 logging.debug("TUI Extracted command: %s"%(__commands[-1],))
157 class _COMViewer(GenericCaseViewer):
159 Établissement des commandes d'un cas COMM (Eficas Native Format/Cas<-COM)
161 def __init__(self, __name="", __objname="case", __content=None, __object=None):
162 "Initialisation et enregistrement de l'entete"
163 GenericCaseViewer.__init__(self, __name, __objname, __content, __object)
164 self._observerIndex = 0
165 self._addLine("# -*- coding: utf-8 -*-")
166 self._addLine("#\n# Python script using ADAO COMM\n#")
167 self._addLine("from numpy import array, matrix")
169 self._addLine("%s = {}"%__objname)
170 if self._content is not None:
171 for command in self._content:
172 self._append(*command)
173 def _extract(self, __multilines=None, __object=None):
174 "Transformation d'enregistrement(s) en commande(s) individuelle(s)"
175 if __multilines is not None:
176 if "ASSIMILATION_STUDY" in __multilines:
177 __multilines = __multilines.replace("ASSIMILATION_STUDY","dict")
178 if "CHECKING_STUDY" in __multilines:
179 __multilines = __multilines.replace("CHECKING_STUDY", "dict")
180 __multilines = __multilines.replace("_F(", "dict(")
181 __multilines = __multilines.replace(",),);", ",),)")
183 for line in __multilines.split("\n"):
184 if len(line) < 1: continue
185 __fulllines += line + "\n"
186 __multilines = __fulllines
187 self._objname = "case"
189 exec("self._objdata = "+__multilines)
191 if self._objdata is None or not(type(self._objdata) is dict) or not('AlgorithmParameters' in self._objdata):
192 raise ValueError("Impossible to load given content as an ADAO COMM one (no dictionnary or no 'AlgorithmParameters' key found).")
193 # ----------------------------------------------------------------------
194 logging.debug("COMM Extracting commands of '%s' object..."%(self._objname,))
196 __UserPostAnalysis = ""
197 for k,r in self._objdata.items():
199 logging.debug("COMM Extracted command: %s:%s"%(k, r))
200 if __command == "StudyName" and len(str(r))>0:
201 __commands.append( "set( Concept='Name', String='%s')"%(str(r),) )
202 elif __command == "StudyRepertory":
203 __commands.append( "set( Concept='Directory', String='%s')"%(str(r),) )
204 elif __command == "Debug" and str(r) == "0":
205 __commands.append( "set( Concept='NoDebug' )" )
206 elif __command == "Debug" and str(r) == "1":
207 __commands.append( "set( Concept='Debug' )" )
209 elif __command == "UserPostAnalysis" and type(r) is dict:
211 __UserPostAnalysis = r['STRING']
212 elif 'SCRIPT_FILE' in r and os.path.exists(r['SCRIPT_FILE']):
213 __UserPostAnalysis = open(r['SCRIPT_FILE'],'r').read()
214 elif 'Template' in r and 'ValueTemplate' in r:
216 __UserPostAnalysis = r['ValueTemplate']
218 __UserPostAnalysis = ""
219 __UserPostAnalysis = __UserPostAnalysis.replace("ADD",self._objname)
221 elif __command == "AlgorithmParameters" and type(r) is dict and 'Algorithm' in r:
222 if 'data' in r and r['Parameters'] == 'Dict':
224 if 'STRING' in __from:
225 __parameters = ", Parameters=%s"%(repr(eval(__from['STRING'])),)
226 elif 'SCRIPT_FILE' in __from and os.path.exists(__from['SCRIPT_FILE']):
227 __parameters = ", Script='%s'"%(__from['SCRIPT_FILE'],)
228 else: # if 'Parameters' in r and r['Parameters'] == 'Defaults':
229 __Dict = copy.deepcopy(r)
230 __Dict.pop('Algorithm','')
231 __Dict.pop('Parameters','')
232 if 'SetSeed' in __Dict:__Dict['SetSeed'] = int(__Dict['SetSeed'])
233 if 'BoxBounds' in __Dict and type(__Dict['BoxBounds']) is str:
234 __Dict['BoxBounds'] = eval(__Dict['BoxBounds'])
236 __parameters = ', Parameters=%s'%(repr(__Dict),)
239 __commands.append( "set( Concept='AlgorithmParameters', Algorithm='%s'%s )"%(r['Algorithm'],__parameters) )
241 elif __command == "Observers" and type(r) is dict and 'SELECTION' in r:
242 if type(r['SELECTION']) is str:
243 __selection = (r['SELECTION'],)
245 __selection = tuple(r['SELECTION'])
246 for sk in __selection:
247 __idata = r['%s_data'%sk]
248 if __idata['NodeType'] == 'Template' and 'Template' in __idata:
249 __template = __idata['Template']
250 if 'Info' in __idata:
251 __info = ", Info='%s'"%(__idata['Info'],)
254 __commands.append( "set( Concept='Observer', Variable='%s', Template='%s'%s )"%(sk,__template,__info) )
255 if __idata['NodeType'] == 'String' and 'Value' in __idata:
256 __value =__idata['Value']
257 __commands.append( "set( Concept='Observer', Variable='%s', String='%s' )"%(sk,__value) )
259 # Background, ObservationError, ObservationOperator...
260 elif type(r) is dict:
262 if 'Stored' in r and bool(r['Stored']):
263 __argumentsList.append(['Stored',True])
264 if 'INPUT_TYPE' in r and 'data' in r:
265 # Vector, Matrix, ScalarSparseMatrix, DiagonalSparseMatrix, Function
266 __itype = r['INPUT_TYPE']
268 if 'FROM' in __idata:
269 # String, Script, DataFile, Template, ScriptWithOneFunction, ScriptWithFunctions
270 __ifrom = __idata['FROM']
271 __idata.pop('FROM','')
272 if __ifrom == 'String' or __ifrom == 'Template':
273 __argumentsList.append([__itype,__idata['STRING']])
274 if __ifrom == 'Script':
275 __argumentsList.append([__itype,True])
276 __argumentsList.append(['Script',__idata['SCRIPT_FILE']])
277 if __ifrom == 'DataFile':
278 __argumentsList.append([__itype,True])
279 __argumentsList.append(['DataFile',__idata['DATA_FILE']])
280 if __ifrom == 'ScriptWithOneFunction':
281 __argumentsList.append(['OneFunction',True])
282 __argumentsList.append(['Script',__idata.pop('SCRIPTWITHONEFUNCTION_FILE')])
284 __argumentsList.append(['Parameters',__idata])
285 if __ifrom == 'ScriptWithFunctions':
286 __argumentsList.append(['ThreeFunctions',True])
287 __argumentsList.append(['Script',__idata.pop('SCRIPTWITHFUNCTIONS_FILE')])
289 __argumentsList.append(['Parameters',__idata])
290 __arguments = ["%s = %s"%(k,repr(v)) for k,v in __argumentsList]
291 __commands.append( "set( Concept='%s', %s )"%(__command, ", ".join(__arguments)))
293 # ----------------------------------------------------------------------
294 __commands.sort() # Pour commencer par 'AlgorithmParameters'
295 __commands.append(__UserPostAnalysis)
298 class _SCDViewer(GenericCaseViewer):
300 Établissement des commandes d'un cas SCD (Study Config Dictionary/Cas->SCD)
302 Remarque : le fichier généré est différent de celui obtenu par EFICAS
304 def __init__(self, __name="", __objname="case", __content=None, __object=None):
305 "Initialisation et enregistrement de l'entête"
306 GenericCaseViewer.__init__(self, __name, __objname, __content, __object)
307 self._addLine("# -*- coding: utf-8 -*-")
308 self._addLine("#\n# Input for ADAO converter to YACS\n#")
309 self._addLine("from numpy import array, matrix")
311 self._addLine("study_config = {}")
312 self._addLine("study_config['StudyType'] = 'ASSIMILATION_STUDY'")
313 self._addLine("study_config['Name'] = '%s'"%self._name)
314 self._addLine("observers = {}")
315 self._addLine("study_config['Observers'] = observers")
317 self._addLine("inputvariables_config = {}")
318 self._addLine("inputvariables_config['Order'] =['adao_default']")
319 self._addLine("inputvariables_config['adao_default'] = -1")
320 self._addLine("study_config['InputVariables'] = inputvariables_config")
322 self._addLine("outputvariables_config = {}")
323 self._addLine("outputvariables_config['Order'] = ['adao_default']")
324 self._addLine("outputvariables_config['adao_default'] = -1")
325 self._addLine("study_config['OutputVariables'] = outputvariables_config")
326 if __content is not None:
327 for command in __content:
328 self._append(*command)
329 def _append(self, __command=None, __keys=None, __local=None, __pre=None, __switchoff=False):
330 "Transformation d'une commande individuelle en un enregistrement"
331 if __command == "set": __command = __local["Concept"]
332 else: __command = __command.replace("set", "", 1)
335 if __command in (None, 'execute', 'executePythonScheme', 'executeYACSScheme', 'get', 'Name'):
337 elif __command in ['Debug', 'setDebug']:
338 __text = "#\nstudy_config['Debug'] = '1'"
339 elif __command in ['NoDebug', 'setNoDebug']:
340 __text = "#\nstudy_config['Debug'] = '0'"
341 elif __command in ['Observer', 'setObserver']:
342 __obs = __local['Variable']
343 self._numobservers += 1
345 __text += "observers['%s'] = {}\n"%__obs
346 if __local['String'] is not None:
347 __text += "observers['%s']['nodetype'] = '%s'\n"%(__obs, 'String')
348 __text += "observers['%s']['String'] = \"\"\"%s\"\"\"\n"%(__obs, __local['String'])
349 if __local['Script'] is not None:
350 __text += "observers['%s']['nodetype'] = '%s'\n"%(__obs, 'Script')
351 __text += "observers['%s']['Script'] = \"%s\"\n"%(__obs, __local['Script'])
352 if __local['Template'] is not None and __local['Template'] in Templates.ObserverTemplates:
353 __text += "observers['%s']['nodetype'] = '%s'\n"%(__obs, 'String')
354 __text += "observers['%s']['String'] = \"\"\"%s\"\"\"\n"%(__obs, Templates.ObserverTemplates[__local['Template']])
355 if __local['Info'] is not None:
356 __text += "observers['%s']['info'] = \"\"\"%s\"\"\"\n"%(__obs, __local['Info'])
358 __text += "observers['%s']['info'] = \"\"\"%s\"\"\"\n"%(__obs, __obs)
359 __text += "observers['%s']['number'] = %s"%(__obs, self._numobservers)
360 elif __local is not None: # __keys is not None and
361 numpy.set_printoptions(precision=15,threshold=1000000,linewidth=1000*15)
363 __text += "%s_config = {}\n"%__command
364 __local.pop('self','')
366 for __k,__v in __local.items():
367 if __v is None: __to_be_removed.append(__k)
368 for __k in __to_be_removed:
370 for __k,__v in __local.items():
371 if __k == "Concept": continue
372 if __k in ['ScalarSparseMatrix','DiagonalSparseMatrix','Matrix','OneFunction','ThreeFunctions'] and 'Script' in __local and __local['Script'] is not None: continue
373 if __k in ['Vector','VectorSerie'] and 'DataFile' in __local and __local['DataFile'] is not None: continue
374 if __k == 'Parameters' and not (__command in ['AlgorithmParameters','SupplementaryParameters']): continue
375 if __k == 'Algorithm':
376 __text += "study_config['Algorithm'] = %s\n"%(repr(__v))
377 elif __k == 'DataFile':
380 __v = "'"+repr(__v)+"'"
381 for __lk in ['Vector','VectorSerie']:
382 if __lk in __local and __local[__lk]: __k = __lk
383 __text += "%s_config['Type'] = '%s'\n"%(__command,__k)
384 __text += "%s_config['From'] = '%s'\n"%(__command,__f)
385 __text += "%s_config['Data'] = %s\n"%(__command,__v)
386 __text = __text.replace("''","'")
387 elif __k == 'Script':
390 __v = "'"+repr(__v)+"'"
391 for __lk in ['ScalarSparseMatrix','DiagonalSparseMatrix','Matrix']:
392 if __lk in __local and __local[__lk]: __k = __lk
393 if __command == "AlgorithmParameters": __k = "Dict"
394 if 'OneFunction' in __local and __local['OneFunction']:
395 __text += "%s_ScriptWithOneFunction = {}\n"%(__command,)
396 __text += "%s_ScriptWithOneFunction['Function'] = ['Direct', 'Tangent', 'Adjoint']\n"%(__command,)
397 __text += "%s_ScriptWithOneFunction['Script'] = {}\n"%(__command,)
398 __text += "%s_ScriptWithOneFunction['Script']['Direct'] = %s\n"%(__command,__v)
399 __text += "%s_ScriptWithOneFunction['Script']['Tangent'] = %s\n"%(__command,__v)
400 __text += "%s_ScriptWithOneFunction['Script']['Adjoint'] = %s\n"%(__command,__v)
401 __text += "%s_ScriptWithOneFunction['DifferentialIncrement'] = 1e-06\n"%(__command,)
402 __text += "%s_ScriptWithOneFunction['CenteredFiniteDifference'] = 0\n"%(__command,)
404 __f = 'ScriptWithOneFunction'
405 __v = '%s_ScriptWithOneFunction'%(__command,)
406 if 'ThreeFunctions' in __local and __local['ThreeFunctions']:
407 __text += "%s_ScriptWithFunctions = {}\n"%(__command,)
408 __text += "%s_ScriptWithFunctions['Function'] = ['Direct', 'Tangent', 'Adjoint']\n"%(__command,)
409 __text += "%s_ScriptWithFunctions['Script'] = {}\n"%(__command,)
410 __text += "%s_ScriptWithFunctions['Script']['Direct'] = %s\n"%(__command,__v)
411 __text += "%s_ScriptWithFunctions['Script']['Tangent'] = %s\n"%(__command,__v)
412 __text += "%s_ScriptWithFunctions['Script']['Adjoint'] = %s\n"%(__command,__v)
414 __f = 'ScriptWithFunctions'
415 __v = '%s_ScriptWithFunctions'%(__command,)
416 __text += "%s_config['Type'] = '%s'\n"%(__command,__k)
417 __text += "%s_config['From'] = '%s'\n"%(__command,__f)
418 __text += "%s_config['Data'] = %s\n"%(__command,__v)
419 __text = __text.replace("''","'")
420 elif __k in ('Stored', 'Checked', 'ColMajor', 'InputFunctionAsMulti', 'nextStep'):
422 __text += "%s_config['%s'] = '%s'\n"%(__command,__k,int(bool(__v)))
423 elif __k in ('AvoidRC', 'noDetails'):
425 __text += "%s_config['%s'] = '%s'\n"%(__command,__k,int(bool(__v)))
427 if __k == 'Parameters': __k = "Dict"
428 if isinstance(__v,Persistence.Persistence): __v = __v.values()
429 if callable(__v): __text = self._missing%__v.__name__+__text
430 if isinstance(__v,dict):
431 for val in __v.values():
432 if callable(val): __text = self._missing%val.__name__+__text
433 __text += "%s_config['Type'] = '%s'\n"%(__command,__k)
434 __text += "%s_config['From'] = '%s'\n"%(__command,'String')
435 __text += "%s_config['Data'] = \"\"\"%s\"\"\"\n"%(__command,repr(__v))
436 __text += "study_config['%s'] = %s_config"%(__command,__command)
437 numpy.set_printoptions(precision=8,threshold=1000,linewidth=75)
439 self._switchoff = True
440 if __text is not None: self._addLine(__text)
442 self._switchoff = False
443 def _finalize(self, *__args):
444 self.__loadVariablesByScript()
446 self._addLine("Analysis_config = {}")
447 self._addLine("Analysis_config['From'] = 'String'")
448 self._addLine("Analysis_config['Data'] = \"\"\"import numpy")
449 self._addLine("xa=numpy.ravel(ADD.get('Analysis')[-1])")
450 self._addLine("print('Analysis:',xa)\"\"\"")
451 self._addLine("study_config['UserPostAnalysis'] = Analysis_config")
452 def __loadVariablesByScript(self):
453 __ExecVariables = {} # Necessaire pour recuperer la variable
454 exec("\n".join(self._lineSerie), __ExecVariables)
455 study_config = __ExecVariables['study_config']
456 # Pour Python 3 : self.__hasAlgorithm = bool(study_config['Algorithm'])
457 if 'Algorithm' in study_config:
458 self.__hasAlgorithm = True
460 self.__hasAlgorithm = False
461 if not self.__hasAlgorithm and \
462 "AlgorithmParameters" in study_config and \
463 isinstance(study_config['AlgorithmParameters'], dict) and \
464 "From" in study_config['AlgorithmParameters'] and \
465 "Data" in study_config['AlgorithmParameters'] and \
466 study_config['AlgorithmParameters']['From'] == 'Script':
467 __asScript = study_config['AlgorithmParameters']['Data']
468 __var = ImportFromScript(__asScript).getvalue( "Algorithm" )
469 __text = "#\nstudy_config['Algorithm'] = '%s'"%(__var,)
470 self._addLine(__text)
471 if self.__hasAlgorithm and \
472 "AlgorithmParameters" in study_config and \
473 isinstance(study_config['AlgorithmParameters'], dict) and \
474 "From" not in study_config['AlgorithmParameters'] and \
475 "Data" not in study_config['AlgorithmParameters']:
477 __text += "AlgorithmParameters_config['Type'] = 'Dict'\n"
478 __text += "AlgorithmParameters_config['From'] = 'String'\n"
479 __text += "AlgorithmParameters_config['Data'] = '{}'\n"
480 self._addLine(__text)
483 class _YACSViewer(GenericCaseViewer):
485 Etablissement des commandes d'un cas YACS (Cas->SCD->YACS)
487 def __init__(self, __name="", __objname="case", __content=None, __object=None):
488 "Initialisation et enregistrement de l'entete"
489 GenericCaseViewer.__init__(self, __name, __objname, __content, __object)
490 self.__internalSCD = _SCDViewer(__name, __objname, __content, __object)
491 self._append = self.__internalSCD._append
492 def dump(self, __filename=None, __upa=None):
493 "Restitution normalisée des commandes"
495 if __filename is None:
496 raise ValueError("A file name has to be given for YACS XML output.")
498 __file = os.path.abspath(__filename)
499 if os.path.isfile(__file) or os.path.islink(__file):
502 if not PlatformInfo.has_salome or \
503 not PlatformInfo.has_adao:
505 "Unable to get SALOME or ADAO environnement variables for YACS conversion.\n"+\
506 "Please load the right environnement before trying to use it.")
508 from daYacsSchemaCreator.run import create_schema_from_content
510 self.__internalSCD._finalize(__upa)
511 __SCDdump = self.__internalSCD.dump()
512 create_schema_from_content(__SCDdump, __file)
514 if not os.path.exists(__file):
515 __msg = "An error occured during the ADAO YACS Schema build for\n"
516 __msg += "the target output file:\n"
517 __msg += " %s\n"%__file
518 __msg += "See errors details in your launching terminal log.\n"
519 raise ValueError(__msg)
521 __fid = open(__file,"r")
522 __text = __fid.read()
526 # ==============================================================================
527 class ImportFromScript(object):
529 Obtention d'une variable nommee depuis un fichier script importé
531 __slots__ = ("__basename", "__filenspace", "__filestring")
532 def __init__(self, __filename=None):
533 "Verifie l'existence et importe le script"
534 if __filename is None:
535 raise ValueError("The name of the file, containing the variable to be read, has to be specified.")
536 if not os.path.isfile(__filename):
537 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))
538 if os.path.dirname(__filename) != '':
539 sys.path.insert(0, os.path.dirname(__filename))
540 __basename = os.path.basename(__filename).rstrip(".py")
542 __basename = __filename.rstrip(".py")
543 PlatformInfo.checkFileNameImportability( __basename+".py" )
544 self.__basename = __basename
545 self.__filenspace = __import__(__basename, globals(), locals(), [])
546 self.__filestring = open(__filename,'r').read()
547 def getvalue(self, __varname=None, __synonym=None ):
548 "Renvoie la variable demandee par son nom ou son synonyme"
549 if __varname is None:
550 raise ValueError("The name of the variable to be read has to be specified. Please check the content of the file and the syntax.")
551 if not hasattr(self.__filenspace, __varname):
552 if __synonym is None:
553 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))
554 elif not hasattr(self.__filenspace, __synonym):
555 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))
557 return getattr(self.__filenspace, __synonym)
559 return getattr(self.__filenspace, __varname)
561 "Renvoie le script complet"
562 return self.__filestring
564 # ==============================================================================
565 class ImportDetector(object):
567 Détection des caractéristiques de fichiers ou objets en entrée
570 "__url", "__usr", "__root", "__end")
571 def __enter__(self): return self
572 def __exit__(self, exc_type, exc_val, exc_tb): return False
574 def __init__(self, __url, UserMime=""):
576 raise ValueError("The name or url of the file object has to be specified.")
578 self.__url = __url.decode()
580 self.__url = str(__url)
581 if UserMime is bytes:
582 self.__usr = UserMime.decode().lower()
584 self.__usr = str(UserMime).lower()
585 (self.__root, self.__end) = os.path.splitext(self.__url)
587 mimetypes.add_type('application/numpy.npy', '.npy')
588 mimetypes.add_type('application/numpy.npz', '.npz')
589 mimetypes.add_type('application/dymola.sdf', '.sdf')
590 if sys.platform.startswith("win"):
591 mimetypes.add_type('text/plain', '.txt')
592 mimetypes.add_type('text/csv', '.csv')
593 mimetypes.add_type('text/tab-separated-values', '.tsv')
597 def is_local_file(self):
598 if os.path.isfile(os.path.realpath(self.__url)):
602 def is_not_local_file(self):
603 if not os.path.isfile(os.path.realpath(self.__url)):
607 def raise_error_if_not_local_file(self):
608 if not os.path.isfile(os.path.realpath(self.__url)):
609 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))
613 # Directory related tests
614 # -----------------------
615 def is_local_dir(self):
616 if os.path.isdir(self.__url):
620 def is_not_local_dir(self):
621 if not os.path.isdir(self.__url):
625 def raise_error_if_not_local_dir(self):
626 if not os.path.isdir(self.__url):
627 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))
631 # Mime related functions
632 # ------------------------
633 def get_standard_mime(self):
634 (__mtype, __encoding) = mimetypes.guess_type(self.__url, strict=False)
636 def get_user_mime(self):
637 __fake = "fake."+self.__usr.lower()
638 (__mtype, __encoding) = mimetypes.guess_type(__fake, strict=False)
640 def get_comprehensive_mime(self):
641 if self.get_standard_mime() is not None:
642 return self.get_standard_mime()
643 elif self.get_user_mime() is not None:
644 return self.get_user_mime()
648 # Name related functions
649 # ----------------------
650 def get_user_name(self):
652 def get_absolute_name(self):
653 return os.path.abspath(os.path.realpath(self.__url))
654 def get_extension(self):
657 class ImportFromFile(object):
659 Obtention de variables disrétisées en 1D, définies par une ou des variables
660 nommées, et sous la forme d'une série de points éventuellement indexés. La
661 lecture d'un fichier au format spécifié (ou intuité) permet de charger ces
663 - des fichiers textes en colonnes de type TXT, CSV, TSV...
664 - des fichiers de données binaires NPY, NPZ, SDF...
665 La lecture du fichier complet ne se fait que si nécessaire, pour assurer la
666 performance tout en disposant de l'interprétation du contenu. Les fichiers
667 textes doivent présenter en première ligne (hors commentaire ou ligne vide)
668 les noms des variables de colonnes. Les commentaires commencent par un "#".
671 "_filename", "_colnames", "_colindex", "_varsline", "_format",
672 "_delimiter", "_skiprows", "__url", "__filestring", "__header",
673 "__allowvoid", "__binaryformats", "__supportedformats")
674 def __enter__(self): return self
675 def __exit__(self, exc_type, exc_val, exc_tb): return False
677 def __init__(self, Filename=None, ColNames=None, ColIndex=None, Format="Guess", AllowVoidNameList=True):
679 Verifie l'existence et les informations de définition du fichier. Les
680 noms de colonnes ou de variables sont ignorées si le format ne permet
683 - Filename : nom du fichier
684 - ColNames : noms de la ou des colonnes/variables à lire
685 - ColIndex : nom unique de la colonne/variable servant d'index
686 - Format : format du fichier et/ou des données inclues
687 - AllowVoidNameList : permet, si la liste de noms est vide, de
688 prendre par défaut toutes les colonnes
690 self.__binaryformats =(
691 "application/numpy.npy",
692 "application/numpy.npz",
693 "application/dymola.sdf",
695 self.__url = ImportDetector( Filename, Format)
696 self.__url.raise_error_if_not_local_file()
697 self._filename = self.__url.get_absolute_name()
698 PlatformInfo.checkFileNameConformity( self._filename )
700 self._format = self.__url.get_comprehensive_mime()
702 self.__header, self._varsline, self._skiprows = self.__getentete()
704 if self._format == "text/csv" or Format.upper() == "CSV":
705 self._format = "text/csv"
706 self.__filestring = "".join(self.__header)
707 if self.__filestring.count(",") > 1:
708 self._delimiter = ","
709 elif self.__filestring.count(";") > 1:
710 self._delimiter = ";"
712 self._delimiter = None
713 elif self._format == "text/tab-separated-values" or Format.upper() == "TSV":
714 self._format = "text/tab-separated-values"
715 self._delimiter = "\t"
717 self._delimiter = None
719 if ColNames is not None: self._colnames = tuple(ColNames)
720 else: self._colnames = None
722 if ColIndex is not None: self._colindex = str(ColIndex)
723 else: self._colindex = None
725 self.__allowvoid = bool(AllowVoidNameList)
727 def __getentete(self, __nblines = 3):
728 "Lit l'entête du fichier pour trouver la définition des variables"
729 # La première ligne non vide non commentée est toujours considérée
730 # porter les labels de colonne, donc pas des valeurs
731 __header, __varsline, __skiprows = [], "", 1
732 if self._format in self.__binaryformats:
735 with open(self._filename,'r') as fid:
736 __line = fid.readline().strip()
737 while "#" in __line or len(__line) < 1:
738 __header.append(__line)
740 __line = fid.readline().strip()
742 for i in range(max(0,__nblines)):
743 __header.append(fid.readline())
744 return (__header, __varsline, __skiprows)
746 def __getindices(self, __colnames, __colindex, __delimiter=None ):
747 "Indices de colonnes correspondants à l'index et aux variables"
748 if __delimiter is None:
749 __varserie = self._varsline.strip('#').strip().split()
751 __varserie = self._varsline.strip('#').strip().split(str(__delimiter))
753 if __colnames is not None:
755 __colnames = tuple(__colnames)
757 for i, n in enumerate(__varserie):
758 if v == n: __usecols.append(i)
759 __usecols = tuple(__usecols)
760 if len(__usecols) == 0:
764 raise ValueError("Can not found any column corresponding to the required names %s"%(__colnames,))
768 if __colindex is not None:
770 __colindex = str(__colindex)
771 for i, n in enumerate(__varserie):
772 if __colindex == n: __useindex = i
776 return (__usecols, __useindex)
778 def getsupported(self):
779 self.__supportedformats = {}
780 self.__supportedformats["text/plain"] = True
781 self.__supportedformats["text/csv"] = True
782 self.__supportedformats["text/tab-separated-values"] = True
783 self.__supportedformats["application/numpy.npy"] = True
784 self.__supportedformats["application/numpy.npz"] = True
785 self.__supportedformats["application/dymola.sdf"] = PlatformInfo.has_sdf
786 return self.__supportedformats
788 def getvalue(self, ColNames=None, ColIndex=None ):
789 "Renvoie la ou les variables demandees par la liste de leurs noms"
790 # Uniquement si mise à jour
791 if ColNames is not None: self._colnames = tuple(ColNames)
792 if ColIndex is not None: self._colindex = str(ColIndex)
795 if self._format == "application/numpy.npy":
796 __columns = numpy.load(self._filename)
798 elif self._format == "application/numpy.npz":
800 with numpy.load(self._filename) as __allcolumns:
801 if self._colnames is None:
802 self._colnames = __allcolumns.files
803 for nom in self._colnames: # Si une variable demandée n'existe pas
804 if nom not in __allcolumns.files:
805 self._colnames = tuple( __allcolumns.files )
806 for nom in self._colnames:
807 if nom in __allcolumns.files:
808 if __columns is not None:
809 # Attention : toutes les variables doivent avoir la même taille
810 __columns = numpy.vstack((__columns, numpy.reshape(__allcolumns[nom], (1,-1))))
813 __columns = numpy.reshape(__allcolumns[nom], (1,-1))
814 if self._colindex is not None and self._colindex in __allcolumns.files:
815 __index = numpy.array(numpy.reshape(__allcolumns[self._colindex], (1,-1)), dtype=bytes)
816 elif self._format == "text/plain":
817 __usecols, __useindex = self.__getindices(self._colnames, self._colindex)
818 __columns = numpy.loadtxt(self._filename, usecols = __usecols, skiprows=self._skiprows)
819 if __useindex is not None:
820 __index = numpy.loadtxt(self._filename, dtype = bytes, usecols = (__useindex,), skiprows=self._skiprows)
821 if __usecols is None: # Si une variable demandée n'existe pas
822 self._colnames = None
824 elif self._format == "application/dymola.sdf" and PlatformInfo.has_sdf:
826 __content = sdf.load(self._filename)
828 if self._colnames is None:
829 self._colnames = [__content.datasets[i].name for i in range(len(__content.datasets))]
830 for nom in self._colnames:
832 if __columns is not None:
833 # Attention : toutes les variables doivent avoir la même taille
834 __columns = numpy.vstack((__columns, numpy.reshape(__content[nom].data, (1,-1))))
837 __columns = numpy.reshape(__content[nom].data, (1,-1))
838 if self._colindex is not None and self._colindex in __content:
839 __index = __content[self._colindex].data
841 elif self._format == "text/csv":
842 __usecols, __useindex = self.__getindices(self._colnames, self._colindex, self._delimiter)
843 __columns = numpy.loadtxt(self._filename, usecols = __usecols, delimiter = self._delimiter, skiprows=self._skiprows)
844 if __useindex is not None:
845 __index = numpy.loadtxt(self._filename, dtype = bytes, usecols = (__useindex,), delimiter = self._delimiter, skiprows=self._skiprows)
846 if __usecols is None: # Si une variable demandée n'existe pas
847 self._colnames = None
849 elif self._format == "text/tab-separated-values":
850 __usecols, __useindex = self.__getindices(self._colnames, self._colindex, self._delimiter)
851 __columns = numpy.loadtxt(self._filename, usecols = __usecols, delimiter = self._delimiter, skiprows=self._skiprows)
852 if __useindex is not None:
853 __index = numpy.loadtxt(self._filename, dtype = bytes, usecols = (__useindex,), delimiter = self._delimiter, skiprows=self._skiprows)
854 if __usecols is None: # Si une variable demandée n'existe pas
855 self._colnames = None
857 raise ValueError("Unkown file format \"%s\" or no reader available"%self._format)
858 if __columns is None: __columns = ()
862 return value.decode()
865 if __index is not None:
866 __index = tuple([toString(v) for v in __index])
868 return (self._colnames, __columns, self._colindex, __index)
871 "Renvoie le fichier texte complet"
872 if self._format in self.__binaryformats:
875 with open(self._filename,'r') as fid:
881 class ImportScalarLinesFromFile(ImportFromFile):
883 Importation de fichier contenant des variables scalaires nommées. Le
884 fichier comporte soit 2, soit 4 colonnes, obligatoirement nommées "Name",
885 "Value", "Minimum", "Maximum" si les noms sont précisés. Sur chaque ligne
886 est indiqué le nom, la valeur, et éventuelement deux bornes min et max (ou
887 None si nécessaire pour une borne).
889 Seule la méthode "getvalue" est changée.
891 def __enter__(self): return self
892 def __exit__(self, exc_type, exc_val, exc_tb): return False
894 def __init__(self, Filename=None, ColNames=None, ColIndex=None, Format="Guess"):
895 ImportFromFile.__init__(self, Filename, ColNames, ColIndex, Format)
896 if self._format not in ["text/plain", "text/csv", "text/tab-separated-values"]:
897 raise ValueError("Unkown file format \"%s\""%self._format)
899 def getvalue(self, VarNames = None, HeaderNames=()):
900 "Renvoie la ou les variables demandees par la liste de leurs noms"
901 if VarNames is not None: __varnames = tuple(VarNames)
902 else: __varnames = None
904 if "Name" in self._varsline and "Value" in self._varsline and "Minimum" in self._varsline and "Maximum" in self._varsline:
905 __ftype = "NamValMinMax"
906 __dtypes = {'names' : ('Name', 'Value', 'Minimum', 'Maximum'),
907 'formats': ('S128', 'g', 'g', 'g')}
908 __usecols = (0, 1, 2, 3)
909 def __replaceNoneN( s ):
910 if s.strip() == b'None': return numpy.NINF
912 def __replaceNoneP( s ):
913 if s.strip() == b'None': return numpy.PINF
915 __converters = {2: __replaceNoneN, 3: __replaceNoneP}
916 elif "Name" in self._varsline and "Value" in self._varsline and ("Minimum" not in self._varsline or "Maximum" not in self._varsline):
918 __dtypes = {'names' : ('Name', 'Value'),
919 'formats': ('S128', 'g')}
922 elif len(HeaderNames)>0 and numpy.all([kw in self._varsline for kw in HeaderNames]):
923 __ftype = "NamLotOfVals"
924 __dtypes = {'names' : HeaderNames,
925 'formats': tuple(['S128',]+['g']*(len(HeaderNames)-1))}
926 __usecols = tuple(range(len(HeaderNames)))
927 def __replaceNone( s ):
928 if s.strip() == b'None': return numpy.NAN
930 __converters = dict()
931 for i in range(1,len(HeaderNames)):
932 __converters[i] = __replaceNone
934 raise ValueError("Can not find names of columns for initial values. Wrong first line is:\n \"%s\""%__firstline)
936 if self._format == "text/plain":
937 __content = numpy.loadtxt(self._filename, dtype = __dtypes, usecols = __usecols, skiprows = self._skiprows, converters = __converters)
938 elif self._format in ["text/csv", "text/tab-separated-values"]:
939 __content = numpy.loadtxt(self._filename, dtype = __dtypes, usecols = __usecols, skiprows = self._skiprows, converters = __converters, delimiter = self._delimiter)
941 raise ValueError("Unkown file format \"%s\""%self._format)
943 __names, __thevalue, __bounds = [], [], []
944 for sub in __content:
945 if len(__usecols) == 4:
947 if numpy.isneginf(mi): mi = None # Réattribue les variables None
948 elif numpy.isnan(mi): mi = None # Réattribue les variables None
949 if numpy.isposinf(ma): ma = None # Réattribue les variables None
950 elif numpy.isnan(ma): ma = None # Réattribue les variables None
951 elif len(__usecols) == 2 and __ftype == "NamVal":
957 for i, v in enumerate(nsub[1:]):
958 if numpy.isnan(v): nsub[i+1] = None
962 if (__varnames is None or na in __varnames) and (na not in __names):
963 # Ne stocke que la premiere occurence d'une variable
965 __thevalue.append(va)
966 __bounds.append((mi,ma))
968 __names = tuple(__names)
969 __thevalue = numpy.array(__thevalue)
970 __bounds = tuple(__bounds)
972 return (__names, __thevalue, __bounds)
974 # ==============================================================================
975 class EficasGUI(object):
977 Lancement autonome de l'interface EFICAS/ADAO
979 def __init__(self, __addpath = None):
980 # Chemin pour l'installation (ordre important)
982 self.__path_settings_ok = False
984 if "EFICAS_ROOT" in os.environ:
985 __EFICAS_ROOT = os.environ["EFICAS_ROOT"]
988 self.__msg += "\nKeyError:\n"+\
989 " the required environment variable EFICAS_ROOT is unknown.\n"+\
990 " You have either to be in SALOME environment, or to set\n"+\
991 " this variable in your environment to the right path \"<...>\"\n"+\
992 " to find an installed EFICAS application. For example:\n"+\
993 " EFICAS_ROOT=\"<...>\" command\n"
997 __path_ok = True and __path_ok
999 self.__msg += "\nImportError:\n"+\
1000 " the required ADAO library can not be found to be imported.\n"+\
1001 " You have either to be in ADAO environment, or to be in SALOME\n"+\
1002 " environment, or to set manually in your Python 3 environment the\n"+\
1003 " right path \"<...>\" to find an installed ADAO application. For\n"+\
1005 " PYTHONPATH=\"<...>:${PYTHONPATH}\" command\n"
1009 __path_ok = True and __path_ok
1011 self.__msg += "\nImportError:\n"+\
1012 " the required PyQt5 library can not be found to be imported.\n"+\
1013 " You have either to have a raisonable up-to-date Python 3\n"+\
1014 " installation (less than 5 years), or to be in SALOME environment.\n"
1018 self.__msg += "\nWarning:\n"+\
1019 " It seems you have some troubles with your installation.\n"+\
1020 " Be aware that some other errors may exist, that are not\n"+\
1021 " explained as above, like some incomplete or obsolete\n"+\
1022 " Python 3, or incomplete module installation.\n"+\
1024 " Please correct the above error(s) before launching the\n"+\
1025 " standalone EFICAS/ADAO interface.\n"
1026 logging.debug("Some of the ADAO/EFICAS/QT5 paths have not been found")
1027 self.__path_settings_ok = False
1029 logging.debug("All the ADAO/EFICAS/QT5 paths have been found")
1030 self.__path_settings_ok = True
1032 if self.__path_settings_ok:
1033 sys.path.insert(0,__EFICAS_ROOT)
1034 sys.path.insert(0,os.path.join(adao.adao_py_dir,"daEficas"))
1035 if __addpath is not None and os.path.exists(os.path.abspath(__addpath)):
1036 sys.path.insert(0,os.path.abspath(__addpath))
1037 logging.debug("All the paths have been correctly set up")
1040 logging.debug("Errors in path settings have been found")
1043 if self.__path_settings_ok:
1044 logging.debug("Launching standalone EFICAS/ADAO interface...")
1045 from daEficas import prefs
1046 from InterfaceQT4 import eficas_go
1047 eficas_go.lanceEficas(code=prefs.code)
1049 logging.debug("Can not launch standalone EFICAS/ADAO interface for path errors.")
1051 # ==============================================================================
1052 if __name__ == "__main__":
1053 print('\n AUTODIAGNOSTIC\n')