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 == 'ScriptWithOneFunction':
272 __argumentsList.append(['OneFunction',True])
273 __argumentsList.append(['Script',__idata.pop('SCRIPTWITHONEFUNCTION_FILE')])
275 __argumentsList.append(['Parameters',__idata])
276 if __ifrom == 'ScriptWithFunctions':
277 __argumentsList.append(['ThreeFunctions',True])
278 __argumentsList.append(['Script',__idata.pop('SCRIPTWITHFUNCTIONS_FILE')])
280 __argumentsList.append(['Parameters',__idata])
281 __arguments = ["%s = %s"%(k,repr(v)) for k,v in __argumentsList]
282 __commands.append( "set( Concept='%s', %s )"%(__command, ", ".join(__arguments)))
284 # ----------------------------------------------------------------------
285 __commands.sort() # Pour commencer par 'AlgorithmParameters'
286 __commands.append(__UserPostAnalysis)
289 class _SCDViewer(GenericCaseViewer):
291 Etablissement des commandes d'un cas SCD (Study Config Dictionary/Cas->SCD)
293 def __init__(self, __name="", __objname="case", __content=None, __object=None):
294 "Initialisation et enregistrement de l'entete"
295 GenericCaseViewer.__init__(self, __name, __objname, __content, __object)
296 self._addLine("# -*- coding: utf-8 -*-")
297 self._addLine("#\n# Input for ADAO converter to YACS\n#")
298 self._addLine("from numpy import array, matrix")
300 self._addLine("study_config = {}")
301 self._addLine("study_config['StudyType'] = 'ASSIMILATION_STUDY'")
302 self._addLine("study_config['Name'] = '%s'"%self._name)
303 self._addLine("observers = {}")
304 self._addLine("study_config['Observers'] = observers")
306 self._addLine("inputvariables_config = {}")
307 self._addLine("inputvariables_config['Order'] =['adao_default']")
308 self._addLine("inputvariables_config['adao_default'] = -1")
309 self._addLine("study_config['InputVariables'] = inputvariables_config")
311 self._addLine("outputvariables_config = {}")
312 self._addLine("outputvariables_config['Order'] = ['adao_default']")
313 self._addLine("outputvariables_config['adao_default'] = -1")
314 self._addLine("study_config['OutputVariables'] = outputvariables_config")
315 if __content is not None:
316 for command in __content:
317 self._append(*command)
318 def _append(self, __command=None, __keys=None, __local=None, __pre=None, __switchoff=False):
319 "Transformation d'une commande individuelle en un enregistrement"
320 if __command == "set": __command = __local["Concept"]
321 else: __command = __command.replace("set", "", 1)
324 if __command in (None, 'execute', 'executePythonScheme', 'executeYACSScheme', 'get', 'Name'):
326 elif __command in ['Debug', 'setDebug']:
327 __text = "#\nstudy_config['Debug'] = '1'"
328 elif __command in ['NoDebug', 'setNoDebug']:
329 __text = "#\nstudy_config['Debug'] = '0'"
330 elif __command in ['Observer', 'setObserver']:
331 __obs = __local['Variable']
332 self._numobservers += 1
334 __text += "observers['%s'] = {}\n"%__obs
335 if __local['String'] is not None:
336 __text += "observers['%s']['nodetype'] = '%s'\n"%(__obs, 'String')
337 __text += "observers['%s']['String'] = \"\"\"%s\"\"\"\n"%(__obs, __local['String'])
338 if __local['Script'] is not None:
339 __text += "observers['%s']['nodetype'] = '%s'\n"%(__obs, 'Script')
340 __text += "observers['%s']['Script'] = \"%s\"\n"%(__obs, __local['Script'])
341 if __local['Template'] is not None and __local['Template'] in Templates.ObserverTemplates:
342 __text += "observers['%s']['nodetype'] = '%s'\n"%(__obs, 'String')
343 __text += "observers['%s']['String'] = \"\"\"%s\"\"\"\n"%(__obs, Templates.ObserverTemplates[__local['Template']])
344 if __local['Info'] is not None:
345 __text += "observers['%s']['info'] = \"\"\"%s\"\"\"\n"%(__obs, __local['Info'])
347 __text += "observers['%s']['info'] = \"\"\"%s\"\"\"\n"%(__obs, __obs)
348 __text += "observers['%s']['number'] = %s"%(__obs, self._numobservers)
349 elif __local is not None: # __keys is not None and
350 numpy.set_printoptions(precision=15,threshold=1000000,linewidth=1000*15)
352 __text += "%s_config = {}\n"%__command
353 __local.pop('self','')
355 for __k,__v in __local.items():
356 if __v is None: __to_be_removed.append(__k)
357 for __k in __to_be_removed:
359 for __k,__v in __local.items():
360 if __k == "Concept": continue
361 if __k in ['ScalarSparseMatrix','DiagonalSparseMatrix','Matrix','OneFunction','ThreeFunctions'] and 'Script' in __local: continue
362 if __k == 'Algorithm':
363 __text += "study_config['Algorithm'] = %s\n"%(repr(__v))
364 elif __k == 'Script':
367 __v = "'"+repr(__v)+"'"
368 for __lk in ['ScalarSparseMatrix','DiagonalSparseMatrix','Matrix']:
369 if __lk in __local and __local[__lk]: __k = __lk
370 if __command == "AlgorithmParameters": __k = "Dict"
371 if 'OneFunction' in __local and __local['OneFunction']:
372 __text += "%s_ScriptWithOneFunction = {}\n"%(__command,)
373 __text += "%s_ScriptWithOneFunction['Function'] = ['Direct', 'Tangent', 'Adjoint']\n"%(__command,)
374 __text += "%s_ScriptWithOneFunction['Script'] = {}\n"%(__command,)
375 __text += "%s_ScriptWithOneFunction['Script']['Direct'] = %s\n"%(__command,__v)
376 __text += "%s_ScriptWithOneFunction['Script']['Tangent'] = %s\n"%(__command,__v)
377 __text += "%s_ScriptWithOneFunction['Script']['Adjoint'] = %s\n"%(__command,__v)
378 __text += "%s_ScriptWithOneFunction['DifferentialIncrement'] = 1e-06\n"%(__command,)
379 __text += "%s_ScriptWithOneFunction['CenteredFiniteDifference'] = 0\n"%(__command,)
381 __f = 'ScriptWithOneFunction'
382 __v = '%s_ScriptWithOneFunction'%(__command,)
383 if 'ThreeFunctions' in __local and __local['ThreeFunctions']:
384 __text += "%s_ScriptWithFunctions = {}\n"%(__command,)
385 __text += "%s_ScriptWithFunctions['Function'] = ['Direct', 'Tangent', 'Adjoint']\n"%(__command,)
386 __text += "%s_ScriptWithFunctions['Script'] = {}\n"%(__command,)
387 __text += "%s_ScriptWithFunctions['Script']['Direct'] = %s\n"%(__command,__v)
388 __text += "%s_ScriptWithFunctions['Script']['Tangent'] = %s\n"%(__command,__v)
389 __text += "%s_ScriptWithFunctions['Script']['Adjoint'] = %s\n"%(__command,__v)
391 __f = 'ScriptWithFunctions'
392 __v = '%s_ScriptWithFunctions'%(__command,)
393 __text += "%s_config['Type'] = '%s'\n"%(__command,__k)
394 __text += "%s_config['From'] = '%s'\n"%(__command,__f)
395 __text += "%s_config['Data'] = %s\n"%(__command,__v)
396 __text = __text.replace("''","'")
397 elif __k in ('Stored', 'Checked', 'ColMajor', 'InputFunctionAsMulti', 'nextStep'):
399 __text += "%s_config['%s'] = '%s'\n"%(__command,__k,int(bool(__v)))
400 elif __k in ('AvoidRC', 'noDetails'):
402 __text += "%s_config['%s'] = '%s'\n"%(__command,__k,int(bool(__v)))
404 if __k == 'Parameters': __k = "Dict"
405 if isinstance(__v,Persistence.Persistence): __v = __v.values()
406 if callable(__v): __text = self._missing%__v.__name__+__text
407 if isinstance(__v,dict):
408 for val in __v.values():
409 if callable(val): __text = self._missing%val.__name__+__text
410 __text += "%s_config['Type'] = '%s'\n"%(__command,__k)
411 __text += "%s_config['From'] = '%s'\n"%(__command,'String')
412 __text += "%s_config['Data'] = \"\"\"%s\"\"\"\n"%(__command,repr(__v))
413 __text += "study_config['%s'] = %s_config"%(__command,__command)
414 numpy.set_printoptions(precision=8,threshold=1000,linewidth=75)
416 self._switchoff = True
417 if __text is not None: self._addLine(__text)
419 self._switchoff = False
420 def _finalize(self, *__args):
421 self.__loadVariablesByScript()
423 self._addLine("Analysis_config = {}")
424 self._addLine("Analysis_config['From'] = 'String'")
425 self._addLine("Analysis_config['Data'] = \"\"\"import numpy")
426 self._addLine("xa=numpy.ravel(ADD.get('Analysis')[-1])")
427 self._addLine("print('Analysis:',xa)\"\"\"")
428 self._addLine("study_config['UserPostAnalysis'] = Analysis_config")
429 def __loadVariablesByScript(self):
430 __ExecVariables = {} # Necessaire pour recuperer la variable
431 exec("\n".join(self._lineSerie), __ExecVariables)
432 study_config = __ExecVariables['study_config']
433 # Pour Python 3 : self.__hasAlgorithm = bool(study_config['Algorithm'])
434 if 'Algorithm' in study_config:
435 self.__hasAlgorithm = True
437 self.__hasAlgorithm = False
438 if not self.__hasAlgorithm and \
439 "AlgorithmParameters" in study_config and \
440 isinstance(study_config['AlgorithmParameters'], dict) and \
441 "From" in study_config['AlgorithmParameters'] and \
442 "Data" in study_config['AlgorithmParameters'] and \
443 study_config['AlgorithmParameters']['From'] == 'Script':
444 __asScript = study_config['AlgorithmParameters']['Data']
445 __var = ImportFromScript(__asScript).getvalue( "Algorithm" )
446 __text = "#\nstudy_config['Algorithm'] = '%s'"%(__var,)
447 self._addLine(__text)
448 if self.__hasAlgorithm and \
449 "AlgorithmParameters" in study_config and \
450 isinstance(study_config['AlgorithmParameters'], dict) and \
451 "From" not in study_config['AlgorithmParameters'] and \
452 "Data" not in study_config['AlgorithmParameters']:
454 __text += "AlgorithmParameters_config['Type'] = 'Dict'\n"
455 __text += "AlgorithmParameters_config['From'] = 'String'\n"
456 __text += "AlgorithmParameters_config['Data'] = '{}'\n"
457 self._addLine(__text)
460 class _YACSViewer(GenericCaseViewer):
462 Etablissement des commandes d'un cas YACS (Cas->SCD->YACS)
464 def __init__(self, __name="", __objname="case", __content=None, __object=None):
465 "Initialisation et enregistrement de l'entete"
466 GenericCaseViewer.__init__(self, __name, __objname, __content, __object)
467 self.__internalSCD = _SCDViewer(__name, __objname, __content, __object)
468 self._append = self.__internalSCD._append
469 def dump(self, __filename=None, __upa=None):
470 "Restitution normalisée des commandes"
472 if __filename is None:
473 raise ValueError("A file name has to be given for YACS XML output.")
475 __file = os.path.abspath(__filename)
476 if os.path.isfile(__file) or os.path.islink(__file):
479 if not PlatformInfo.has_salome or \
480 not PlatformInfo.has_adao:
482 "Unable to get SALOME or ADAO environnement variables for YACS conversion.\n"+\
483 "Please load the right environnement before trying to use it.")
485 from daYacsSchemaCreator.run import create_schema_from_content
487 self.__internalSCD._finalize(__upa)
488 __SCDdump = self.__internalSCD.dump()
489 create_schema_from_content(__SCDdump, __file)
491 if not os.path.exists(__file):
492 __msg = "An error occured during the ADAO YACS Schema build for\n"
493 __msg += "the target output file:\n"
494 __msg += " %s\n"%__file
495 __msg += "See errors details in your launching terminal log.\n"
496 raise ValueError(__msg)
498 __fid = open(__file,"r")
499 __text = __fid.read()
503 # ==============================================================================
504 class ImportFromScript(object):
506 Obtention d'une variable nommee depuis un fichier script importé
508 __slots__ = ("__basename", "__filenspace", "__filestring")
509 def __init__(self, __filename=None):
510 "Verifie l'existence et importe le script"
511 if __filename is None:
512 raise ValueError("The name of the file, containing the variable to be read, has to be specified.")
513 if not os.path.isfile(__filename):
514 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))
515 if os.path.dirname(__filename) != '':
516 sys.path.insert(0, os.path.dirname(__filename))
517 __basename = os.path.basename(__filename).rstrip(".py")
519 __basename = __filename.rstrip(".py")
520 PlatformInfo.checkFileNameImportability( __basename+".py" )
521 self.__basename = __basename
522 self.__filenspace = __import__(__basename, globals(), locals(), [])
523 self.__filestring = open(__filename,'r').read()
524 def getvalue(self, __varname=None, __synonym=None ):
525 "Renvoie la variable demandee par son nom ou son synonyme"
526 if __varname is None:
527 raise ValueError("The name of the variable to be read has to be specified. Please check the content of the file and the syntax.")
528 if not hasattr(self.__filenspace, __varname):
529 if __synonym is None:
530 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))
531 elif not hasattr(self.__filenspace, __synonym):
532 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))
534 return getattr(self.__filenspace, __synonym)
536 return getattr(self.__filenspace, __varname)
538 "Renvoie le script complet"
539 return self.__filestring
541 # ==============================================================================
542 class ImportDetector(object):
544 Détection des caractéristiques de fichiers ou objets en entrée
547 "__url", "__usr", "__root", "__end")
548 def __enter__(self): return self
549 def __exit__(self, exc_type, exc_val, exc_tb): return False
551 def __init__(self, __url, UserMime=""):
553 raise ValueError("The name or url of the file object has to be specified.")
555 self.__url = __url.decode()
557 self.__url = str(__url)
558 if UserMime is bytes:
559 self.__usr = UserMime.decode().lower()
561 self.__usr = str(UserMime).lower()
562 (self.__root, self.__end) = os.path.splitext(self.__url)
564 mimetypes.add_type('application/numpy.npy', '.npy')
565 mimetypes.add_type('application/numpy.npz', '.npz')
566 mimetypes.add_type('application/dymola.sdf', '.sdf')
567 if sys.platform.startswith("win"):
568 mimetypes.add_type('text/plain', '.txt')
569 mimetypes.add_type('text/csv', '.csv')
570 mimetypes.add_type('text/tab-separated-values', '.tsv')
574 def is_local_file(self):
575 if os.path.isfile(os.path.realpath(self.__url)):
579 def is_not_local_file(self):
580 if not os.path.isfile(os.path.realpath(self.__url)):
584 def raise_error_if_not_local_file(self):
585 if not os.path.isfile(os.path.realpath(self.__url)):
586 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))
590 # Directory related tests
591 # -----------------------
592 def is_local_dir(self):
593 if os.path.isdir(self.__url):
597 def is_not_local_dir(self):
598 if not os.path.isdir(self.__url):
602 def raise_error_if_not_local_dir(self):
603 if not os.path.isdir(self.__url):
604 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))
608 # Mime related functions
609 # ------------------------
610 def get_standard_mime(self):
611 (__mtype, __encoding) = mimetypes.guess_type(self.__url, strict=False)
613 def get_user_mime(self):
614 __fake = "fake."+self.__usr.lower()
615 (__mtype, __encoding) = mimetypes.guess_type(__fake, strict=False)
617 def get_comprehensive_mime(self):
618 if self.get_standard_mime() is not None:
619 return self.get_standard_mime()
620 elif self.get_user_mime() is not None:
621 return self.get_user_mime()
625 # Name related functions
626 # ----------------------
627 def get_user_name(self):
629 def get_absolute_name(self):
630 return os.path.abspath(os.path.realpath(self.__url))
631 def get_extension(self):
634 # ==============================================================================
635 class ImportFromFile(object):
637 Obtention de variables disrétisées en 1D, définies par une ou des variables
638 nommées, et sous la forme d'une série de points éventuellement indexés. La
639 lecture d'un fichier au format spécifié (ou intuité) permet de charger ces
641 - des fichiers textes en colonnes de type TXT, CSV, TSV...
642 - des fichiers de données binaires NPY, NPZ, SDF...
643 La lecture du fichier complet ne se fait que si nécessaire, pour assurer la
644 performance tout en disposant de l'interprétation du contenu. Les fichiers
645 textes doivent présenter en première ligne (hors commentaire ou ligne vide)
646 les noms des variables de colonnes. Les commentaires commencent par un "#".
649 "_filename", "_colnames", "_colindex", "_varsline", "_format",
650 "_delimiter", "_skiprows", "__url", "__filestring", "__header",
651 "__allowvoid", "__binaryformats", "__supportedformats")
652 def __enter__(self): return self
653 def __exit__(self, exc_type, exc_val, exc_tb): return False
655 def __init__(self, Filename=None, ColNames=None, ColIndex=None, Format="Guess", AllowVoidNameList=True):
657 Verifie l'existence et les informations de définition du fichier. Les
658 noms de colonnes ou de variables sont ignorées si le format ne permet
661 - Filename : nom du fichier
662 - ColNames : noms de la ou des colonnes/variables à lire
663 - ColIndex : nom unique de la colonne/variable servant d'index
664 - Format : format du fichier et/ou des données inclues
665 - AllowVoidNameList : permet, si la liste de noms est vide, de
666 prendre par défaut toutes les colonnes
668 self.__binaryformats =(
669 "application/numpy.npy",
670 "application/numpy.npz",
671 "application/dymola.sdf",
673 self.__url = ImportDetector( Filename, Format)
674 self.__url.raise_error_if_not_local_file()
675 self._filename = self.__url.get_absolute_name()
676 PlatformInfo.checkFileNameConformity( self._filename )
678 self._format = self.__url.get_comprehensive_mime()
680 self.__header, self._varsline, self._skiprows = self.__getentete()
682 if self._format == "text/csv" or Format.upper() == "CSV":
683 self._format = "text/csv"
684 self.__filestring = "".join(self.__header)
685 if self.__filestring.count(",") > 1:
686 self._delimiter = ","
687 elif self.__filestring.count(";") > 1:
688 self._delimiter = ";"
689 elif self._format == "text/tab-separated-values" or Format.upper() == "TSV":
690 self._format = "text/tab-separated-values"
691 self._delimiter = "\t"
693 self._delimiter = None
695 if ColNames is not None: self._colnames = tuple(ColNames)
696 else: self._colnames = None
698 if ColIndex is not None: self._colindex = str(ColIndex)
699 else: self._colindex = None
701 self.__allowvoid = bool(AllowVoidNameList)
703 def __getentete(self, __nblines = 3):
704 "Lit l'entête du fichier pour trouver la définition des variables"
705 __header, __varsline, __skiprows = [], "", 1
706 if self._format in self.__binaryformats:
709 with open(self._filename,'r') as fid:
710 __line = fid.readline().strip()
711 while "#" in __line or len(__line) < 1:
712 __header.append(__line)
714 __line = fid.readline().strip()
715 __varsline = __line # Première ligne non commentée non vide
716 for i in range(max(0,__nblines)):
717 __header.append(fid.readline())
718 return (__header, __varsline, __skiprows)
720 def __getindices(self, __colnames, __colindex, __delimiter=None ):
721 "Indices de colonnes correspondants à l'index et aux variables"
722 if __delimiter is None:
723 __varserie = self._varsline.strip('#').strip().split()
725 __varserie = self._varsline.strip('#').strip().split(str(__delimiter))
727 if __colnames is not None:
729 __colnames = tuple(__colnames)
731 for i, n in enumerate(__varserie):
732 if v == n: __usecols.append(i)
733 __usecols = tuple(__usecols)
734 if len(__usecols) == 0:
738 raise ValueError("Can not found any column corresponding to the required names %s"%(__colnames,))
742 if __colindex is not None:
744 __colindex = str(__colindex)
745 for i, n in enumerate(__varserie):
746 if __colindex == n: __useindex = i
750 return (__usecols, __useindex)
752 def getsupported(self):
753 self.__supportedformats = {}
754 self.__supportedformats["text/plain"] = True
755 self.__supportedformats["text/csv"] = True
756 self.__supportedformats["text/tab-separated-values"] = True
757 self.__supportedformats["application/numpy.npy"] = True
758 self.__supportedformats["application/numpy.npz"] = True
759 self.__supportedformats["application/dymola.sdf"] = PlatformInfo.has_sdf
760 return self.__supportedformats
762 def getvalue(self, ColNames=None, ColIndex=None ):
763 "Renvoie la ou les variables demandees par la liste de leurs noms"
764 # Uniquement si mise à jour
765 if ColNames is not None: self._colnames = tuple(ColNames)
766 if ColIndex is not None: self._colindex = str(ColIndex)
769 if self._format == "application/numpy.npy":
770 __columns = numpy.load(self._filename)
772 elif self._format == "application/numpy.npz":
774 with numpy.load(self._filename) as __allcolumns:
775 if self._colnames is None:
776 self._colnames = __allcolumns.files
777 for nom in self._colnames:
778 if nom in __allcolumns.files:
779 if __columns is not None:
780 # Attention : toutes les variables doivent avoir la même taille
781 __columns = numpy.vstack((__columns, numpy.reshape(__allcolumns[nom], (1,-1))))
784 __columns = numpy.reshape(__allcolumns[nom], (1,-1))
785 if self._colindex is not None and self._colindex in __allcolumns.files:
786 __index = numpy.array(numpy.reshape(__allcolumns[self._colindex], (1,-1)), dtype=bytes)
787 elif self._format == "text/plain":
788 __usecols, __useindex = self.__getindices(self._colnames, self._colindex)
789 __columns = numpy.loadtxt(self._filename, usecols = __usecols, skiprows=self._skiprows)
790 if __useindex is not None:
791 __index = numpy.loadtxt(self._filename, dtype = bytes, usecols = (__useindex,), skiprows=self._skiprows)
793 elif self._format == "application/dymola.sdf" and PlatformInfo.has_sdf:
795 __content = sdf.load(self._filename)
797 if self._colnames is None:
798 self._colnames = [__content.datasets[i].name for i in range(len(__content.datasets))]
799 for nom in self._colnames:
801 if __columns is not None:
802 # Attention : toutes les variables doivent avoir la même taille
803 __columns = numpy.vstack((__columns, numpy.reshape(__content[nom].data, (1,-1))))
806 __columns = numpy.reshape(__content[nom].data, (1,-1))
807 if self._colindex is not None and self._colindex in __content:
808 __index = __content[self._colindex].data
810 elif self._format == "text/csv":
811 __usecols, __useindex = self.__getindices(self._colnames, self._colindex, self._delimiter)
812 __columns = numpy.loadtxt(self._filename, usecols = __usecols, delimiter = self._delimiter, skiprows=self._skiprows)
813 if __useindex is not None:
814 __index = numpy.loadtxt(self._filename, dtype = bytes, usecols = (__useindex,), delimiter = self._delimiter, skiprows=self._skiprows)
816 elif self._format == "text/tab-separated-values":
817 __usecols, __useindex = self.__getindices(self._colnames, self._colindex, self._delimiter)
818 __columns = numpy.loadtxt(self._filename, usecols = __usecols, delimiter = self._delimiter, skiprows=self._skiprows)
819 if __useindex is not None:
820 __index = numpy.loadtxt(self._filename, dtype = bytes, usecols = (__useindex,), delimiter = self._delimiter, skiprows=self._skiprows)
822 raise ValueError("Unkown file format \"%s\" or no reader available"%self._format)
823 if __columns is None: __columns = ()
827 return value.decode()
830 if __index is not None:
831 __index = tuple([toString(v) for v in __index])
833 return (self._colnames, __columns, self._colindex, __index)
836 "Renvoie le fichier texte complet"
837 if self._format in self.__binaryformats:
840 with open(self._filename,'r') as fid:
846 # ==============================================================================
847 class ImportScalarLinesFromFile(ImportFromFile):
849 Importation de fichier contenant des variables scalaires nommées. Le
850 fichier comporte soit 2, soit 4 colonnes, obligatoirement nommées "Name",
851 "Value", "Minimum", "Maximum" si les noms sont précisés. Sur chaque ligne
852 est indiqué le nom, la valeur, et éventuelement deux bornes min et max (ou
853 None si nécessaire pour une borne).
855 Seule la méthode "getvalue" est changée.
857 def __enter__(self): return self
858 def __exit__(self, exc_type, exc_val, exc_tb): return False
860 def __init__(self, Filename=None, ColNames=None, ColIndex=None, Format="Guess"):
861 ImportFromFile.__init__(self, Filename, ColNames, ColIndex, Format)
862 if self._format not in ["text/plain", "text/csv", "text/tab-separated-values"]:
863 raise ValueError("Unkown file format \"%s\""%self._format)
865 def getvalue(self, VarNames = None, HeaderNames=()):
866 "Renvoie la ou les variables demandees par la liste de leurs noms"
867 if VarNames is not None: __varnames = tuple(VarNames)
868 else: __varnames = None
870 if "Name" in self._varsline and "Value" in self._varsline and "Minimum" in self._varsline and "Maximum" in self._varsline:
871 __ftype = "NamValMinMax"
872 __dtypes = {'names' : ('Name', 'Value', 'Minimum', 'Maximum'),
873 'formats': ('S128', 'g', 'g', 'g')}
874 __usecols = (0, 1, 2, 3)
875 def __replaceNoneN( s ):
876 if s.strip() == b'None': return numpy.NINF
878 def __replaceNoneP( s ):
879 if s.strip() == b'None': return numpy.PINF
881 __converters = {2: __replaceNoneN, 3: __replaceNoneP}
882 elif "Name" in self._varsline and "Value" in self._varsline and ("Minimum" not in self._varsline or "Maximum" not in self._varsline):
884 __dtypes = {'names' : ('Name', 'Value'),
885 'formats': ('S128', 'g')}
888 elif len(HeaderNames)>0 and numpy.all([kw in self._varsline for kw in HeaderNames]):
889 __ftype = "NamLotOfVals"
890 __dtypes = {'names' : HeaderNames,
891 'formats': tuple(['S128',]+['g']*(len(HeaderNames)-1))}
892 __usecols = tuple(range(len(HeaderNames)))
893 def __replaceNone( s ):
894 if s.strip() == b'None': return numpy.NAN
896 __converters = dict()
897 for i in range(1,len(HeaderNames)):
898 __converters[i] = __replaceNone
900 raise ValueError("Can not find names of columns for initial values. Wrong first line is:\n \"%s\""%__firstline)
902 if self._format == "text/plain":
903 __content = numpy.loadtxt(self._filename, dtype = __dtypes, usecols = __usecols, skiprows = self._skiprows, converters = __converters)
904 elif self._format in ["text/csv", "text/tab-separated-values"]:
905 __content = numpy.loadtxt(self._filename, dtype = __dtypes, usecols = __usecols, skiprows = self._skiprows, converters = __converters, delimiter = self._delimiter)
907 raise ValueError("Unkown file format \"%s\""%self._format)
909 __names, __thevalue, __bounds = [], [], []
910 for sub in __content:
911 if len(__usecols) == 4:
913 if numpy.isneginf(mi): mi = None # Réattribue les variables None
914 elif numpy.isnan(mi): mi = None # Réattribue les variables None
915 if numpy.isposinf(ma): ma = None # Réattribue les variables None
916 elif numpy.isnan(ma): ma = None # Réattribue les variables None
917 elif len(__usecols) == 2 and __ftype == "NamVal":
923 for i, v in enumerate(nsub[1:]):
924 if numpy.isnan(v): nsub[i+1] = None
928 if (__varnames is None or na in __varnames) and (na not in __names):
929 # Ne stocke que la premiere occurence d'une variable
931 __thevalue.append(va)
932 __bounds.append((mi,ma))
934 __names = tuple(__names)
935 __thevalue = numpy.array(__thevalue)
936 __bounds = tuple(__bounds)
938 return (__names, __thevalue, __bounds)
940 # ==============================================================================
941 if __name__ == "__main__":
942 print('\n AUTODIAGNOSTIC\n')