1 # -*- coding: utf-8 -*-
3 # Copyright (C) 2008-2019 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 creation 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 de commande individuelle en enregistrement"
56 raise NotImplementedError()
57 def _extract(self, *args):
58 "Transformation d'enregistrement en commande individuelle"
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 Etablissement 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 un enregistrement en une commande individuelle"
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 Etablissement 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 un enregistrement en une commande individuelle"
175 if __multilines is not None:
176 __multilines = __multilines.replace("ASSIMILATION_STUDY","dict")
177 __multilines = __multilines.replace("CHECKING_STUDY", "dict")
178 __multilines = __multilines.replace("_F(", "dict(")
179 __multilines = __multilines.replace(",),);", ",),)")
181 for line in __multilines.split("\n"):
182 if len(line) < 1: continue
183 __fulllines += line + "\n"
184 __multilines = __fulllines
185 self._objname = "case"
187 exec("self._objdata = "+__multilines)
189 if self._objdata is None or not(type(self._objdata) is dict) or not('AlgorithmParameters' in self._objdata):
190 raise ValueError("Impossible to load given content as an ADAO COMM one (no dictionnary or no 'AlgorithmParameters' key found).")
191 # ----------------------------------------------------------------------
192 logging.debug("COMM Extracting commands of '%s' object..."%(self._objname,))
194 __UserPostAnalysis = ""
195 for k,r in self._objdata.items():
197 logging.debug("COMM Extracted command: %s:%s"%(k, r))
198 if __command == "StudyName" and len(str(r))>0:
199 __commands.append( "set( Concept='Name', String='%s')"%(str(r),) )
200 elif __command == "StudyRepertory":
201 __commands.append( "set( Concept='Directory', String='%s')"%(str(r),) )
203 elif __command == "UserPostAnalysis" and type(r) is dict:
205 __UserPostAnalysis = r['STRING']
206 elif 'SCRIPT_FILE' in r and os.path.exists(r['SCRIPT_FILE']):
207 __UserPostAnalysis = open(r['SCRIPT_FILE'],'r').read()
208 elif 'Template' in r and 'ValueTemplate' in r:
210 __UserPostAnalysis = r['ValueTemplate']
212 __UserPostAnalysis = ""
213 __UserPostAnalysis = __UserPostAnalysis.replace("ADD",self._objname)
215 elif __command == "AlgorithmParameters" and type(r) is dict and 'Algorithm' in r:
216 if 'data' in r and r['Parameters'] == 'Dict':
218 if 'STRING' in __from:
219 __parameters = ", Parameters=%s"%(repr(eval(__from['STRING'])),)
220 elif 'SCRIPT_FILE' in __from and os.path.exists(__from['SCRIPT_FILE']):
221 __parameters = ", Script='%s'"%(__from['SCRIPT_FILE'],)
222 else: # if 'Parameters' in r and r['Parameters'] == 'Defaults':
223 __Dict = copy.deepcopy(r)
224 __Dict.pop('Algorithm','')
225 __Dict.pop('Parameters','')
226 if 'SetSeed' in __Dict:__Dict['SetSeed'] = int(__Dict['SetSeed'])
227 if 'BoxBounds' in __Dict and type(__Dict['BoxBounds']) is str:
228 __Dict['BoxBounds'] = eval(__Dict['BoxBounds'])
230 __parameters = ', Parameters=%s'%(repr(__Dict),)
233 __commands.append( "set( Concept='AlgorithmParameters', Algorithm='%s'%s )"%(r['Algorithm'],__parameters) )
235 elif __command == "Observers" and type(r) is dict and 'SELECTION' in r:
236 if type(r['SELECTION']) is str:
237 __selection = (r['SELECTION'],)
239 __selection = tuple(r['SELECTION'])
240 for sk in __selection:
241 __idata = r['%s_data'%sk]
242 if __idata['NodeType'] == 'Template' and 'Template' in __idata:
243 __template = __idata['Template']
244 if 'Info' in __idata:
245 __info = ", Info='%s'"%(__idata['Info'],)
248 __commands.append( "set( Concept='Observer', Variable='%s', Template='%s'%s )"%(sk,__template,__info) )
249 if __idata['NodeType'] == 'String' and 'Value' in __idata:
250 __value =__idata['Value']
251 __commands.append( "set( Concept='Observer', Variable='%s', String='%s' )"%(sk,__value) )
253 # Background, ObservationError, ObservationOperator...
254 elif type(r) is dict:
256 if 'Stored' in r and bool(r['Stored']):
257 __argumentsList.append(['Stored',True])
258 if 'INPUT_TYPE' in r and 'data' in r:
259 # Vector, Matrix, ScalarSparseMatrix, DiagonalSparseMatrix, Function
260 __itype = r['INPUT_TYPE']
262 if 'FROM' in __idata:
263 # String, Script, Template, ScriptWithOneFunction, ScriptWithFunctions
264 __ifrom = __idata['FROM']
265 __idata.pop('FROM','')
266 if __ifrom == 'String' or __ifrom == 'Template':
267 __argumentsList.append([__itype,__idata['STRING']])
268 if __ifrom == 'Script':
269 __argumentsList.append([__itype,True])
270 __argumentsList.append(['Script',__idata['SCRIPT_FILE']])
271 if __ifrom == 'DataFile':
272 __argumentsList.append([__itype,True])
273 __argumentsList.append(['DataFile',__idata['DATA_FILE']])
274 if __ifrom == 'ScriptWithOneFunction':
275 __argumentsList.append(['OneFunction',True])
276 __argumentsList.append(['Script',__idata.pop('SCRIPTWITHONEFUNCTION_FILE')])
278 __argumentsList.append(['Parameters',__idata])
279 if __ifrom == 'ScriptWithFunctions':
280 __argumentsList.append(['ThreeFunctions',True])
281 __argumentsList.append(['Script',__idata.pop('SCRIPTWITHFUNCTIONS_FILE')])
283 __argumentsList.append(['Parameters',__idata])
284 __arguments = ["%s = %s"%(k,repr(v)) for k,v in __argumentsList]
285 __commands.append( "set( Concept='%s', %s )"%(__command, ", ".join(__arguments)))
287 # ----------------------------------------------------------------------
288 __commands.sort() # Pour commencer par 'AlgorithmParameters'
289 __commands.append(__UserPostAnalysis)
292 class _SCDViewer(GenericCaseViewer):
294 Etablissement des commandes d'un cas SCD (Study Config Dictionary/Cas->SCD)
296 def __init__(self, __name="", __objname="case", __content=None, __object=None):
297 "Initialisation et enregistrement de l'entete"
298 GenericCaseViewer.__init__(self, __name, __objname, __content, __object)
299 self._addLine("# -*- coding: utf-8 -*-")
300 self._addLine("#\n# Input for ADAO converter to YACS\n#")
301 self._addLine("from numpy import array, matrix")
303 self._addLine("study_config = {}")
304 self._addLine("study_config['StudyType'] = 'ASSIMILATION_STUDY'")
305 self._addLine("study_config['Name'] = '%s'"%self._name)
306 self._addLine("observers = {}")
307 self._addLine("study_config['Observers'] = observers")
309 self._addLine("inputvariables_config = {}")
310 self._addLine("inputvariables_config['Order'] =['adao_default']")
311 self._addLine("inputvariables_config['adao_default'] = -1")
312 self._addLine("study_config['InputVariables'] = inputvariables_config")
314 self._addLine("outputvariables_config = {}")
315 self._addLine("outputvariables_config['Order'] = ['adao_default']")
316 self._addLine("outputvariables_config['adao_default'] = -1")
317 self._addLine("study_config['OutputVariables'] = outputvariables_config")
318 if __content is not None:
319 for command in __content:
320 self._append(*command)
321 def _append(self, __command=None, __keys=None, __local=None, __pre=None, __switchoff=False):
322 "Transformation d'une commande individuelle en un enregistrement"
323 if __command == "set": __command = __local["Concept"]
324 else: __command = __command.replace("set", "", 1)
327 if __command in (None, 'execute', 'executePythonScheme', 'executeYACSScheme', 'get', 'Name'):
329 elif __command in ['Debug', 'setDebug']:
330 __text = "#\nstudy_config['Debug'] = '1'"
331 elif __command in ['NoDebug', 'setNoDebug']:
332 __text = "#\nstudy_config['Debug'] = '0'"
333 elif __command in ['Observer', 'setObserver']:
334 __obs = __local['Variable']
335 self._numobservers += 1
337 __text += "observers['%s'] = {}\n"%__obs
338 if __local['String'] is not None:
339 __text += "observers['%s']['nodetype'] = '%s'\n"%(__obs, 'String')
340 __text += "observers['%s']['String'] = \"\"\"%s\"\"\"\n"%(__obs, __local['String'])
341 if __local['Script'] is not None:
342 __text += "observers['%s']['nodetype'] = '%s'\n"%(__obs, 'Script')
343 __text += "observers['%s']['Script'] = \"%s\"\n"%(__obs, __local['Script'])
344 if __local['Template'] is not None and __local['Template'] in Templates.ObserverTemplates:
345 __text += "observers['%s']['nodetype'] = '%s'\n"%(__obs, 'String')
346 __text += "observers['%s']['String'] = \"\"\"%s\"\"\"\n"%(__obs, Templates.ObserverTemplates[__local['Template']])
347 if __local['Info'] is not None:
348 __text += "observers['%s']['info'] = \"\"\"%s\"\"\"\n"%(__obs, __local['Info'])
350 __text += "observers['%s']['info'] = \"\"\"%s\"\"\"\n"%(__obs, __obs)
351 __text += "observers['%s']['number'] = %s"%(__obs, self._numobservers)
352 elif __local is not None: # __keys is not None and
353 numpy.set_printoptions(precision=15,threshold=1000000,linewidth=1000*15)
355 __text += "%s_config = {}\n"%__command
356 __local.pop('self','')
358 for __k,__v in __local.items():
359 if __v is None: __to_be_removed.append(__k)
360 for __k in __to_be_removed:
362 for __k,__v in __local.items():
363 if __k == "Concept": continue
364 if __k in ['ScalarSparseMatrix','DiagonalSparseMatrix','Matrix','OneFunction','ThreeFunctions'] and 'Script' in __local: continue
365 if __k == 'Algorithm':
366 __text += "study_config['Algorithm'] = %s\n"%(repr(__v))
367 elif __k == 'Script':
370 __v = "'"+repr(__v)+"'"
371 for __lk in ['ScalarSparseMatrix','DiagonalSparseMatrix','Matrix']:
372 if __lk in __local and __local[__lk]: __k = __lk
373 if __command == "AlgorithmParameters": __k = "Dict"
374 if 'OneFunction' in __local and __local['OneFunction']:
375 __text += "%s_ScriptWithOneFunction = {}\n"%(__command,)
376 __text += "%s_ScriptWithOneFunction['Function'] = ['Direct', 'Tangent', 'Adjoint']\n"%(__command,)
377 __text += "%s_ScriptWithOneFunction['Script'] = {}\n"%(__command,)
378 __text += "%s_ScriptWithOneFunction['Script']['Direct'] = %s\n"%(__command,__v)
379 __text += "%s_ScriptWithOneFunction['Script']['Tangent'] = %s\n"%(__command,__v)
380 __text += "%s_ScriptWithOneFunction['Script']['Adjoint'] = %s\n"%(__command,__v)
381 __text += "%s_ScriptWithOneFunction['DifferentialIncrement'] = 1e-06\n"%(__command,)
382 __text += "%s_ScriptWithOneFunction['CenteredFiniteDifference'] = 0\n"%(__command,)
384 __f = 'ScriptWithOneFunction'
385 __v = '%s_ScriptWithOneFunction'%(__command,)
386 if 'ThreeFunctions' in __local and __local['ThreeFunctions']:
387 __text += "%s_ScriptWithFunctions = {}\n"%(__command,)
388 __text += "%s_ScriptWithFunctions['Function'] = ['Direct', 'Tangent', 'Adjoint']\n"%(__command,)
389 __text += "%s_ScriptWithFunctions['Script'] = {}\n"%(__command,)
390 __text += "%s_ScriptWithFunctions['Script']['Direct'] = %s\n"%(__command,__v)
391 __text += "%s_ScriptWithFunctions['Script']['Tangent'] = %s\n"%(__command,__v)
392 __text += "%s_ScriptWithFunctions['Script']['Adjoint'] = %s\n"%(__command,__v)
394 __f = 'ScriptWithFunctions'
395 __v = '%s_ScriptWithFunctions'%(__command,)
396 __text += "%s_config['Type'] = '%s'\n"%(__command,__k)
397 __text += "%s_config['From'] = '%s'\n"%(__command,__f)
398 __text += "%s_config['Data'] = %s\n"%(__command,__v)
399 __text = __text.replace("''","'")
400 elif __k in ('Stored', 'Checked', 'ColMajor', 'InputFunctionAsMulti', 'nextStep'):
402 __text += "%s_config['%s'] = '%s'\n"%(__command,__k,int(bool(__v)))
403 elif __k in ('AvoidRC', 'noDetails'):
405 __text += "%s_config['%s'] = '%s'\n"%(__command,__k,int(bool(__v)))
407 if __k == 'Parameters': __k = "Dict"
408 if isinstance(__v,Persistence.Persistence): __v = __v.values()
409 if callable(__v): __text = self._missing%__v.__name__+__text
410 if isinstance(__v,dict):
411 for val in __v.values():
412 if callable(val): __text = self._missing%val.__name__+__text
413 __text += "%s_config['Type'] = '%s'\n"%(__command,__k)
414 __text += "%s_config['From'] = '%s'\n"%(__command,'String')
415 __text += "%s_config['Data'] = \"\"\"%s\"\"\"\n"%(__command,repr(__v))
416 __text += "study_config['%s'] = %s_config"%(__command,__command)
417 numpy.set_printoptions(precision=8,threshold=1000,linewidth=75)
419 self._switchoff = True
420 if __text is not None: self._addLine(__text)
422 self._switchoff = False
423 def _finalize(self, *__args):
424 self.__loadVariablesByScript()
426 self._addLine("Analysis_config = {}")
427 self._addLine("Analysis_config['From'] = 'String'")
428 self._addLine("Analysis_config['Data'] = \"\"\"import numpy")
429 self._addLine("xa=numpy.ravel(ADD.get('Analysis')[-1])")
430 self._addLine("print('Analysis:',xa)\"\"\"")
431 self._addLine("study_config['UserPostAnalysis'] = Analysis_config")
432 def __loadVariablesByScript(self):
433 __ExecVariables = {} # Necessaire pour recuperer la variable
434 exec("\n".join(self._lineSerie), __ExecVariables)
435 study_config = __ExecVariables['study_config']
436 # Pour Python 3 : self.__hasAlgorithm = bool(study_config['Algorithm'])
437 if 'Algorithm' in study_config:
438 self.__hasAlgorithm = True
440 self.__hasAlgorithm = False
441 if not self.__hasAlgorithm and \
442 "AlgorithmParameters" in study_config and \
443 isinstance(study_config['AlgorithmParameters'], dict) and \
444 "From" in study_config['AlgorithmParameters'] and \
445 "Data" in study_config['AlgorithmParameters'] and \
446 study_config['AlgorithmParameters']['From'] == 'Script':
447 __asScript = study_config['AlgorithmParameters']['Data']
448 __var = ImportFromScript(__asScript).getvalue( "Algorithm" )
449 __text = "#\nstudy_config['Algorithm'] = '%s'"%(__var,)
450 self._addLine(__text)
451 if self.__hasAlgorithm and \
452 "AlgorithmParameters" in study_config and \
453 isinstance(study_config['AlgorithmParameters'], dict) and \
454 "From" not in study_config['AlgorithmParameters'] and \
455 "Data" not in study_config['AlgorithmParameters']:
457 __text += "AlgorithmParameters_config['Type'] = 'Dict'\n"
458 __text += "AlgorithmParameters_config['From'] = 'String'\n"
459 __text += "AlgorithmParameters_config['Data'] = '{}'\n"
460 self._addLine(__text)
463 class _YACSViewer(GenericCaseViewer):
465 Etablissement des commandes d'un cas YACS (Cas->SCD->YACS)
467 def __init__(self, __name="", __objname="case", __content=None, __object=None):
468 "Initialisation et enregistrement de l'entete"
469 GenericCaseViewer.__init__(self, __name, __objname, __content, __object)
470 self.__internalSCD = _SCDViewer(__name, __objname, __content, __object)
471 self._append = self.__internalSCD._append
472 def dump(self, __filename=None, __upa=None):
473 "Restitution normalisée des commandes"
475 if __filename is None:
476 raise ValueError("A file name has to be given for YACS XML output.")
478 __file = os.path.abspath(__filename)
479 if os.path.isfile(__file) or os.path.islink(__file):
482 if not PlatformInfo.has_salome or \
483 not PlatformInfo.has_adao:
485 "Unable to get SALOME or ADAO environnement variables for YACS conversion.\n"+\
486 "Please load the right environnement before trying to use it.")
488 from daYacsSchemaCreator.run import create_schema_from_content
490 self.__internalSCD._finalize(__upa)
491 __SCDdump = self.__internalSCD.dump()
492 create_schema_from_content(__SCDdump, __file)
494 if not os.path.exists(__file):
495 __msg = "An error occured during the ADAO YACS Schema build for\n"
496 __msg += "the target output file:\n"
497 __msg += " %s\n"%__file
498 __msg += "See errors details in your launching terminal log.\n"
499 raise ValueError(__msg)
501 __fid = open(__file,"r")
502 __text = __fid.read()
506 # ==============================================================================
507 class ImportFromScript(object):
509 Obtention d'une variable nommee depuis un fichier script importé
511 __slots__ = ("__basename", "__filenspace", "__filestring")
512 def __init__(self, __filename=None):
513 "Verifie l'existence et importe le script"
514 if __filename is None:
515 raise ValueError("The name of the file, containing the variable to be read, has to be specified.")
516 if not os.path.isfile(__filename):
517 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))
518 if os.path.dirname(__filename) != '':
519 sys.path.insert(0, os.path.dirname(__filename))
520 __basename = os.path.basename(__filename).rstrip(".py")
522 __basename = __filename.rstrip(".py")
523 PlatformInfo.checkFileNameImportability( __basename+".py" )
524 self.__basename = __basename
525 self.__filenspace = __import__(__basename, globals(), locals(), [])
526 self.__filestring = open(__filename,'r').read()
527 def getvalue(self, __varname=None, __synonym=None ):
528 "Renvoie la variable demandee par son nom ou son synonyme"
529 if __varname is None:
530 raise ValueError("The name of the variable to be read has to be specified. Please check the content of the file and the syntax.")
531 if not hasattr(self.__filenspace, __varname):
532 if __synonym is None:
533 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))
534 elif not hasattr(self.__filenspace, __synonym):
535 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))
537 return getattr(self.__filenspace, __synonym)
539 return getattr(self.__filenspace, __varname)
541 "Renvoie le script complet"
542 return self.__filestring
544 # ==============================================================================
545 class ImportDetector(object):
547 Détection des caractéristiques de fichiers ou objets en entrée
550 "__url", "__usr", "__root", "__end")
551 def __enter__(self): return self
552 def __exit__(self, exc_type, exc_val, exc_tb): return False
554 def __init__(self, __url, UserMime=""):
556 raise ValueError("The name or url of the file object has to be specified.")
558 self.__url = __url.decode()
560 self.__url = str(__url)
561 if UserMime is bytes:
562 self.__usr = UserMime.decode().lower()
564 self.__usr = str(UserMime).lower()
565 (self.__root, self.__end) = os.path.splitext(self.__url)
567 mimetypes.add_type('application/numpy.npy', '.npy')
568 mimetypes.add_type('application/numpy.npz', '.npz')
569 mimetypes.add_type('application/dymola.sdf', '.sdf')
570 if sys.platform.startswith("win"):
571 mimetypes.add_type('text/plain', '.txt')
572 mimetypes.add_type('text/csv', '.csv')
573 mimetypes.add_type('text/tab-separated-values', '.tsv')
577 def is_local_file(self):
578 if os.path.isfile(os.path.realpath(self.__url)):
582 def is_not_local_file(self):
583 if not os.path.isfile(os.path.realpath(self.__url)):
587 def raise_error_if_not_local_file(self):
588 if not os.path.isfile(os.path.realpath(self.__url)):
589 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))
593 # Directory related tests
594 # -----------------------
595 def is_local_dir(self):
596 if os.path.isdir(self.__url):
600 def is_not_local_dir(self):
601 if not os.path.isdir(self.__url):
605 def raise_error_if_not_local_dir(self):
606 if not os.path.isdir(self.__url):
607 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))
611 # Mime related functions
612 # ------------------------
613 def get_standard_mime(self):
614 (__mtype, __encoding) = mimetypes.guess_type(self.__url, strict=False)
616 def get_user_mime(self):
617 __fake = "fake."+self.__usr.lower()
618 (__mtype, __encoding) = mimetypes.guess_type(__fake, strict=False)
620 def get_comprehensive_mime(self):
621 if self.get_standard_mime() is not None:
622 return self.get_standard_mime()
623 elif self.get_user_mime() is not None:
624 return self.get_user_mime()
628 # Name related functions
629 # ----------------------
630 def get_user_name(self):
632 def get_absolute_name(self):
633 return os.path.abspath(os.path.realpath(self.__url))
634 def get_extension(self):
637 # ==============================================================================
638 class ImportFromFile(object):
640 Obtention de variables disrétisées en 1D, définies par une ou des variables
641 nommées, et sous la forme d'une série de points éventuellement indexés. La
642 lecture d'un fichier au format spécifié (ou intuité) permet de charger ces
644 - des fichiers textes en colonnes de type TXT, CSV, TSV...
645 - des fichiers de données binaires NPY, NPZ, SDF...
646 La lecture du fichier complet ne se fait que si nécessaire, pour assurer la
647 performance tout en disposant de l'interprétation du contenu. Les fichiers
648 textes doivent présenter en première ligne (hors commentaire ou ligne vide)
649 les noms des variables de colonnes. Les commentaires commencent par un "#".
652 "_filename", "_colnames", "_colindex", "_varsline", "_format",
653 "_delimiter", "_skiprows", "__url", "__filestring", "__header",
654 "__allowvoid", "__binaryformats", "__supportedformats")
655 def __enter__(self): return self
656 def __exit__(self, exc_type, exc_val, exc_tb): return False
658 def __init__(self, Filename=None, ColNames=None, ColIndex=None, Format="Guess", AllowVoidNameList=True):
660 Verifie l'existence et les informations de définition du fichier. Les
661 noms de colonnes ou de variables sont ignorées si le format ne permet
664 - Filename : nom du fichier
665 - ColNames : noms de la ou des colonnes/variables à lire
666 - ColIndex : nom unique de la colonne/variable servant d'index
667 - Format : format du fichier et/ou des données inclues
668 - AllowVoidNameList : permet, si la liste de noms est vide, de
669 prendre par défaut toutes les colonnes
671 self.__binaryformats =(
672 "application/numpy.npy",
673 "application/numpy.npz",
674 "application/dymola.sdf",
676 self.__url = ImportDetector( Filename, Format)
677 self.__url.raise_error_if_not_local_file()
678 self._filename = self.__url.get_absolute_name()
679 PlatformInfo.checkFileNameConformity( self._filename )
681 self._format = self.__url.get_comprehensive_mime()
683 self.__header, self._varsline, self._skiprows = self.__getentete()
685 if self._format == "text/csv" or Format.upper() == "CSV":
686 self._format = "text/csv"
687 self.__filestring = "".join(self.__header)
688 if self.__filestring.count(",") > 1:
689 self._delimiter = ","
690 elif self.__filestring.count(";") > 1:
691 self._delimiter = ";"
693 self._delimiter = None
694 elif self._format == "text/tab-separated-values" or Format.upper() == "TSV":
695 self._format = "text/tab-separated-values"
696 self._delimiter = "\t"
698 self._delimiter = None
700 if ColNames is not None: self._colnames = tuple(ColNames)
701 else: self._colnames = None
703 if ColIndex is not None: self._colindex = str(ColIndex)
704 else: self._colindex = None
706 self.__allowvoid = bool(AllowVoidNameList)
708 def __getentete(self, __nblines = 3):
709 "Lit l'entête du fichier pour trouver la définition des variables"
710 __header, __varsline, __skiprows = [], "", 1
711 if self._format in self.__binaryformats:
714 with open(self._filename,'r') as fid:
715 __line = fid.readline().strip()
716 while "#" in __line or len(__line) < 1:
717 __header.append(__line)
719 __line = fid.readline().strip()
720 __varsline = __line # Première ligne non commentée non vide
721 for i in range(max(0,__nblines)):
722 __header.append(fid.readline())
723 return (__header, __varsline, __skiprows)
725 def __getindices(self, __colnames, __colindex, __delimiter=None ):
726 "Indices de colonnes correspondants à l'index et aux variables"
727 if __delimiter is None:
728 __varserie = self._varsline.strip('#').strip().split()
730 __varserie = self._varsline.strip('#').strip().split(str(__delimiter))
732 if __colnames is not None:
734 __colnames = tuple(__colnames)
736 for i, n in enumerate(__varserie):
737 if v == n: __usecols.append(i)
738 __usecols = tuple(__usecols)
739 if len(__usecols) == 0:
743 raise ValueError("Can not found any column corresponding to the required names %s"%(__colnames,))
747 if __colindex is not None:
749 __colindex = str(__colindex)
750 for i, n in enumerate(__varserie):
751 if __colindex == n: __useindex = i
755 return (__usecols, __useindex)
757 def getsupported(self):
758 self.__supportedformats = {}
759 self.__supportedformats["text/plain"] = True
760 self.__supportedformats["text/csv"] = True
761 self.__supportedformats["text/tab-separated-values"] = True
762 self.__supportedformats["application/numpy.npy"] = True
763 self.__supportedformats["application/numpy.npz"] = True
764 self.__supportedformats["application/dymola.sdf"] = PlatformInfo.has_sdf
765 return self.__supportedformats
767 def getvalue(self, ColNames=None, ColIndex=None ):
768 "Renvoie la ou les variables demandees par la liste de leurs noms"
769 # Uniquement si mise à jour
770 if ColNames is not None: self._colnames = tuple(ColNames)
771 if ColIndex is not None: self._colindex = str(ColIndex)
774 if self._format == "application/numpy.npy":
775 __columns = numpy.load(self._filename)
777 elif self._format == "application/numpy.npz":
779 with numpy.load(self._filename) as __allcolumns:
780 if self._colnames is None:
781 self._colnames = __allcolumns.files
782 for nom in self._colnames:
783 if nom in __allcolumns.files:
784 if __columns is not None:
785 # Attention : toutes les variables doivent avoir la même taille
786 __columns = numpy.vstack((__columns, numpy.reshape(__allcolumns[nom], (1,-1))))
789 __columns = numpy.reshape(__allcolumns[nom], (1,-1))
790 if self._colindex is not None and self._colindex in __allcolumns.files:
791 __index = numpy.array(numpy.reshape(__allcolumns[self._colindex], (1,-1)), dtype=bytes)
792 elif self._format == "text/plain":
793 __usecols, __useindex = self.__getindices(self._colnames, self._colindex)
794 __columns = numpy.loadtxt(self._filename, usecols = __usecols, skiprows=self._skiprows)
795 if __useindex is not None:
796 __index = numpy.loadtxt(self._filename, dtype = bytes, usecols = (__useindex,), skiprows=self._skiprows)
798 elif self._format == "application/dymola.sdf" and PlatformInfo.has_sdf:
800 __content = sdf.load(self._filename)
802 if self._colnames is None:
803 self._colnames = [__content.datasets[i].name for i in range(len(__content.datasets))]
804 for nom in self._colnames:
806 if __columns is not None:
807 # Attention : toutes les variables doivent avoir la même taille
808 __columns = numpy.vstack((__columns, numpy.reshape(__content[nom].data, (1,-1))))
811 __columns = numpy.reshape(__content[nom].data, (1,-1))
812 if self._colindex is not None and self._colindex in __content:
813 __index = __content[self._colindex].data
815 elif self._format == "text/csv":
816 __usecols, __useindex = self.__getindices(self._colnames, self._colindex, self._delimiter)
817 __columns = numpy.loadtxt(self._filename, usecols = __usecols, delimiter = self._delimiter, skiprows=self._skiprows)
818 if __useindex is not None:
819 __index = numpy.loadtxt(self._filename, dtype = bytes, usecols = (__useindex,), delimiter = self._delimiter, skiprows=self._skiprows)
821 elif self._format == "text/tab-separated-values":
822 __usecols, __useindex = self.__getindices(self._colnames, self._colindex, self._delimiter)
823 __columns = numpy.loadtxt(self._filename, usecols = __usecols, delimiter = self._delimiter, skiprows=self._skiprows)
824 if __useindex is not None:
825 __index = numpy.loadtxt(self._filename, dtype = bytes, usecols = (__useindex,), delimiter = self._delimiter, skiprows=self._skiprows)
827 raise ValueError("Unkown file format \"%s\" or no reader available"%self._format)
828 if __columns is None: __columns = ()
832 return value.decode()
835 if __index is not None:
836 __index = tuple([toString(v) for v in __index])
838 return (self._colnames, __columns, self._colindex, __index)
841 "Renvoie le fichier texte complet"
842 if self._format in self.__binaryformats:
845 with open(self._filename,'r') as fid:
851 # ==============================================================================
852 class ImportScalarLinesFromFile(ImportFromFile):
854 Importation de fichier contenant des variables scalaires nommées. Le
855 fichier comporte soit 2, soit 4 colonnes, obligatoirement nommées "Name",
856 "Value", "Minimum", "Maximum" si les noms sont précisés. Sur chaque ligne
857 est indiqué le nom, la valeur, et éventuelement deux bornes min et max (ou
858 None si nécessaire pour une borne).
860 Seule la méthode "getvalue" est changée.
862 def __enter__(self): return self
863 def __exit__(self, exc_type, exc_val, exc_tb): return False
865 def __init__(self, Filename=None, ColNames=None, ColIndex=None, Format="Guess"):
866 ImportFromFile.__init__(self, Filename, ColNames, ColIndex, Format)
867 if self._format not in ["text/plain", "text/csv", "text/tab-separated-values"]:
868 raise ValueError("Unkown file format \"%s\""%self._format)
870 def getvalue(self, VarNames = None, HeaderNames=()):
871 "Renvoie la ou les variables demandees par la liste de leurs noms"
872 if VarNames is not None: __varnames = tuple(VarNames)
873 else: __varnames = None
875 if "Name" in self._varsline and "Value" in self._varsline and "Minimum" in self._varsline and "Maximum" in self._varsline:
876 __ftype = "NamValMinMax"
877 __dtypes = {'names' : ('Name', 'Value', 'Minimum', 'Maximum'),
878 'formats': ('S128', 'g', 'g', 'g')}
879 __usecols = (0, 1, 2, 3)
880 def __replaceNoneN( s ):
881 if s.strip() == b'None': return numpy.NINF
883 def __replaceNoneP( s ):
884 if s.strip() == b'None': return numpy.PINF
886 __converters = {2: __replaceNoneN, 3: __replaceNoneP}
887 elif "Name" in self._varsline and "Value" in self._varsline and ("Minimum" not in self._varsline or "Maximum" not in self._varsline):
889 __dtypes = {'names' : ('Name', 'Value'),
890 'formats': ('S128', 'g')}
893 elif len(HeaderNames)>0 and numpy.all([kw in self._varsline for kw in HeaderNames]):
894 __ftype = "NamLotOfVals"
895 __dtypes = {'names' : HeaderNames,
896 'formats': tuple(['S128',]+['g']*(len(HeaderNames)-1))}
897 __usecols = tuple(range(len(HeaderNames)))
898 def __replaceNone( s ):
899 if s.strip() == b'None': return numpy.NAN
901 __converters = dict()
902 for i in range(1,len(HeaderNames)):
903 __converters[i] = __replaceNone
905 raise ValueError("Can not find names of columns for initial values. Wrong first line is:\n \"%s\""%__firstline)
907 if self._format == "text/plain":
908 __content = numpy.loadtxt(self._filename, dtype = __dtypes, usecols = __usecols, skiprows = self._skiprows, converters = __converters)
909 elif self._format in ["text/csv", "text/tab-separated-values"]:
910 __content = numpy.loadtxt(self._filename, dtype = __dtypes, usecols = __usecols, skiprows = self._skiprows, converters = __converters, delimiter = self._delimiter)
912 raise ValueError("Unkown file format \"%s\""%self._format)
914 __names, __thevalue, __bounds = [], [], []
915 for sub in __content:
916 if len(__usecols) == 4:
918 if numpy.isneginf(mi): mi = None # Réattribue les variables None
919 elif numpy.isnan(mi): mi = None # Réattribue les variables None
920 if numpy.isposinf(ma): ma = None # Réattribue les variables None
921 elif numpy.isnan(ma): ma = None # Réattribue les variables None
922 elif len(__usecols) == 2 and __ftype == "NamVal":
928 for i, v in enumerate(nsub[1:]):
929 if numpy.isnan(v): nsub[i+1] = None
933 if (__varnames is None or na in __varnames) and (na not in __names):
934 # Ne stocke que la premiere occurence d'une variable
936 __thevalue.append(va)
937 __bounds.append((mi,ma))
939 __names = tuple(__names)
940 __thevalue = numpy.array(__thevalue)
941 __bounds = tuple(__bounds)
943 return (__names, __thevalue, __bounds)
945 # ==============================================================================
946 if __name__ == "__main__":
947 print('\n AUTODIAGNOSTIC\n')